mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
Add dwc_otg driver
Signed-off-by: popcornmix <popcornmix@gmail.com> usb: dwc: fix lockdep false positive Signed-off-by: Kari Suvanto <karis79@gmail.com> usb: dwc: fix inconsistent lock state Signed-off-by: Kari Suvanto <karis79@gmail.com> Add FIQ patch to dwc_otg driver. Enable with dwc_otg.fiq_fix_enable=1. Should give about 10% more ARM performance. Thanks to Gordon and Costas Avoid dynamic memory allocation for channel lock in USB driver. Thanks ddv2005. Add NAK holdoff scheme. Enabled by default, disable with dwc_otg.nak_holdoff_enable=0. Thanks gsh Make sure we wait for the reset to finish dwc_otg: fix bug in dwc_otg_hcd.c resulting in silent kernel memory corruption, escalating to OOPS under high USB load. dwc_otg: Fix unsafe access of QTD during URB enqueue In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the transaction could complete almost immediately after the qtd was assigned to a host channel during URB enqueue, which meant the qtd pointer was no longer valid having been completed and removed. Usually, this resulted in an OOPS during URB submission. By predetermining whether transactions need to be queued or not, this unsafe pointer access is avoided. This bug was only evident on the Pi model A where a device was attached that had no periodic endpoints (e.g. USB pendrive or some wlan devices). dwc_otg: Fix incorrect URB allocation error handling If the memory allocation for a dwc_otg_urb failed, the kernel would OOPS because for some reason a member of the *unallocated* struct was set to zero. Error handling changed to fail correctly. dwc_otg: fix potential use-after-free case in interrupt handler If a transaction had previously aborted, certain interrupts are enabled to track error counts and reset where necessary. On IN endpoints the host generates an ACK interrupt near-simultaneously with completion of transfer. In the case where this transfer had previously had an error, this results in a use-after-free on the QTD memory space with a 1-byte length being overwritten to 0x00. dwc_otg: add handling of SPLIT transaction data toggle errors Previously a data toggle error on packets from a USB1.1 device behind a TT would result in the Pi locking up as the driver never handled the associated interrupt. Patch adds basic retry mechanism and interrupt acknowledgement to cater for either a chance toggle error or for devices that have a broken initial toggle state (FT8U232/FT232BM). dwc_otg: implement tasklet for returning URBs to usbcore hcd layer The dwc_otg driver interrupt handler for transfer completion will spend a very long time with interrupts disabled when a URB is completed - this is because usb_hcd_giveback_urb is called from within the handler which for a USB device driver with complicated processing (e.g. webcam) will take an exorbitant amount of time to complete. This results in missed completion interrupts for other USB packets which lead to them being dropped due to microframe overruns. This patch splits returning the URB to the usb hcd layer into a high-priority tasklet. This will have most benefit for isochronous IN transfers but will also have incidental benefit where multiple periodic devices are active at once. dwc_otg: fix NAK holdoff and allow on split transactions only This corrects a bug where if a single active non-periodic endpoint had at least one transaction in its qh, on frnum == MAX_FRNUM the qh would get skipped and never get queued again. This would result in a silent device until error detection (automatic or otherwise) would either reset the device or flush and requeue the URBs. Additionally the NAK holdoff was enabled for all transactions - this would potentially stall a HS endpoint for 1ms if a previous error state enabled this interrupt and the next response was a NAK. Fix so that only split transactions get held off. dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock held in completion handler usb_hcd_unlink_urb_from_ep must be called with the HCD lock held. Calling it asynchronously in the tasklet was not safe (regression inc4564d4a1a). This change unlinks it from the endpoint prior to queueing it for handling in the tasklet, and also adds a check to ensure the urb is OK to be unlinked before doing so. NULL pointer dereference kernel oopses had been observed in usb_hcd_giveback_urb when a USB device was unplugged/replugged during data transfer. This effect was reproduced using automated USB port power control, hundreds of replug events were performed during active transfers to confirm that the problem was eliminated. USB fix using a FIQ to implement split transactions This commit adds a FIQ implementaion that schedules the split transactions using a FIQ so we don't get held off by the interrupt latency of Linux dwc_otg: fix device attributes and avoid kernel warnings on boot dcw_otg: avoid logging function that can cause panics See: https://github.com/raspberrypi/firmware/issues/21 Thanks to cleverca22 for fix dwc_otg: mask correct interrupts after transaction error recovery The dwc_otg driver will unmask certain interrupts on a transaction that previously halted in the error state in order to reset the QTD error count. The various fine-grained interrupt handlers do not consider that other interrupts besides themselves were unmasked. By disabling the two other interrupts only ever enabled in DMA mode for this purpose, we can avoid unnecessary function calls in the IRQ handler. This will also prevent an unneccesary FIQ interrupt from being generated if the FIQ is enabled. dwc_otg: fiq: prevent FIQ thrash and incorrect state passing to IRQ In the case of a transaction to a device that had previously aborted due to an error, several interrupts are enabled to reset the error count when a device responds. This has the side-effect of making the FIQ thrash because the hardware will generate multiple instances of a NAK on an IN bulk/interrupt endpoint and multiple instances of ACK on an OUT bulk/interrupt endpoint. Make the FIQ mask and clear the associated interrupts. Additionally, on non-split transactions make sure that only unmasked interrupts are cleared. This caused a hard-to-trigger but serious race condition when you had the combination of an endpoint awaiting error recovery and a transaction completed on an endpoint - due to the sequencing and timing of interrupts generated by the dwc_otg core, it was possible to confuse the IRQ handler. Fix function tracing dwc_otg: whitespace cleanup in dwc_otg_urb_enqueue dwc_otg: prevent OOPSes during device disconnects The dwc_otg_urb_enqueue function is thread-unsafe. In particular the access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and friends does not occur within a critical section and so if a device was unplugged during activity there was a high chance that the usbcore hub_thread would try to disable the endpoint with partially- formed entries in the URB queue. This would result in BUG() or null pointer dereferences. Fix so that access of urb->hcpriv, enqueuing to the hardware and adding to usbcore endpoint URB lists is contained within a single critical section. dwc_otg: prevent BUG() in TT allocation if hub address is > 16 A fixed-size array is used to track TT allocation. This was previously set to 16 which caused a crash because dwc_otg_hcd_allocate_port would read past the end of the array. This was hit if a hub was plugged in which enumerated as addr > 16, due to previous device resets or unplugs. Also add #ifdef FIQ_DEBUG around hcd->hub_port_alloc[], which grows to a large size if 128 hub addresses are supported. This field is for debug only for tracking which frame an allocate happened in. dwc_otg: make channel halts with unknown state less damaging If the IRQ received a channel halt interrupt through the FIQ with no other bits set, the IRQ would not release the host channel and never complete the URB. Add catchall handling to treat as a transaction error and retry. dwc_otg: fiq_split: use TTs with more granularity This fixes certain issues with split transaction scheduling. - Isochronous multi-packet OUT transactions now hog the TT until they are completed - this prevents hubs aborting transactions if they get a periodic start-split out-of-order - Don't perform TT allocation on non-periodic endpoints - this allows simultaneous use of the TT's bulk/control and periodic transaction buffers This commit will mainly affect USB audio playback. dwc_otg: fix potential sleep while atomic during urb enqueue Fixes a regression introduced witheb1b482a. Kmalloc called from dwc_otg_hcd_qtd_add / dwc_otg_hcd_qtd_create did not always have the GPF_ATOMIC flag set. Force this flag when inside the larger critical section. dwc_otg: make fiq_split_enable imply fiq_fix_enable Failing to set up the FIQ correctly would result in "IRQ 32: nobody cared" errors in dmesg. dwc_otg: prevent crashes on host port disconnects Fix several issues resulting in crashes or inconsistent state if a Model A root port was disconnected. - Clean up queue heads properly in kill_urbs_in_qh_list by removing the empty QHs from the schedule lists - Set the halt status properly to prevent IRQ handlers from using freed memory - Add fiq_split related cleanup for saved registers - Make microframe scheduling reclaim host channels if active during a disconnect - Abort URBs with -ESHUTDOWN status response, informing device drivers so they respond in a more correct fashion and don't try to resubmit URBs - Prevent IRQ handlers from attempting to handle channel interrupts if the associated URB was dequeued (and the driver state was cleared) dwc_otg: prevent leaking URBs during enqueue A dwc_otg_urb would get leaked if the HCD enqueue function failed for any reason. Free the URB at the appropriate points. dwc_otg: Enable NAK holdoff for control split transactions Certain low-speed devices take a very long time to complete a data or status stage of a control transaction, producing NAK responses until they complete internal processing - the USB2.0 spec limit is up to 500mS. This causes the same type of interrupt storm as seen with USB-serial dongles prior toc8edb238. In certain circumstances, usually while booting, this interrupt storm could cause SD card timeouts. dwc_otg: Fix for occasional lockup on boot when doing a USB reset dwc_otg: Don't issue traffic to LS devices in FS mode Issuing low-speed packets when the root port is in full-speed mode causes the root port to stop responding. Explicitly fail when enqueuing URBs to a LS endpoint on a FS bus. Fix ARM architecture issue with local_irq_restore() If local_fiq_enable() is called before a local_irq_restore(flags) where the flags variable has the F bit set, the FIQ will be erroneously disabled. Fixup arch_local_irq_restore to avoid trampling the F bit in CPSR. Also fix some of the hacks previously implemented for previous dwc_otg incarnations. dwc_otg: fiq_fsm: Base commit for driver rewrite This commit removes the previous FIQ fixes entirely and adds fiq_fsm. This rewrite features much more complete support for split transactions and takes into account several OTG hardware bugs. High-speed isochronous transactions are also capable of being performed by fiq_fsm. All driver options have been removed and replaced with: - dwc_otg.fiq_enable (bool) - dwc_otg.fiq_fsm_enable (bool) - dwc_otg.fiq_fsm_mask (bitmask) - dwc_otg.nak_holdoff (unsigned int) Defaults are specified such that fiq_fsm behaves similarly to the previously implemented FIQ fixes. fiq_fsm: Push error recovery into the FIQ when fiq_fsm is used If the transfer associated with a QTD failed due to a bus error, the HCD would retry the transfer up to 3 times (implementing the USB2.0 three-strikes retry in software). Due to the masking mechanism used by fiq_fsm, it is only possible to pass a single interrupt through to the HCD per-transfer. In this instance host channels would fall off the radar because the error reset would function, but the subsequent channel halt would be lost. Push the error count reset into the FIQ handler. fiq_fsm: Implement timeout mechanism For full-speed endpoints with a large packet size, interrupt latency runs the risk of the FIQ starting a transaction too late in a full-speed frame. If the device is still transmitting data when EOF2 for the downstream frame occurs, the hub will disable the port. This change is not reflected in the hub status endpoint and the device becomes unresponsive. Prevent high-bandwidth transactions from being started too late in a frame. The mechanism is not guaranteed: a combination of bit stuffing and hub latency may still result in a device overrunning. fiq_fsm: fix bounce buffer utilisation for Isochronous OUT Multi-packet isochronous OUT transactions were subject to a few bounday bugs. Fix them. Audio playback is now much more robust: however, an issue stands with devices that have adaptive sinks - ALSA plays samples too fast. dwc_otg: Return full-speed frame numbers in HS mode The frame counter increments on every *microframe* in high-speed mode. Most device drivers expect this number to be in full-speed frames - this caused considerable confusion to e.g. snd_usb_audio which uses the frame counter to estimate the number of samples played. fiq_fsm: save PID on completion of interrupt OUT transfers Also add edge case handling for interrupt transports. Note that for periodic split IN, data toggles are unimplemented in the OTG host hardware - it unconditionally accepts any PID. fiq_fsm: add missing case for fiq_fsm_tt_in_use() Certain combinations of bitrate and endpoint activity could result in a periodic transaction erroneously getting started while the previous Isochronous OUT was still active. fiq_fsm: clear hcintmsk for aborted transactions Prevents the FIQ from erroneously handling interrupts on a timed out channel. fiq_fsm: enable by default fiq_fsm: fix dequeues for non-periodic split transactions If a dequeue happened between the SSPLIT and CSPLIT phases of the transaction, the HCD would never receive an interrupt. fiq_fsm: Disable by default fiq_fsm: Handle HC babble errors The HCTSIZ transfer size field raises a babble interrupt if the counter wraps. Handle the resulting interrupt in this case. dwc_otg: fix interrupt registration for fiq_enable=0 Additionally make the module parameter conditional for wherever hcd->fiq_state is touched. fiq_fsm: Enable by default dwc_otg: Fix various issues with root port and transaction errors Process the host port interrupts correctly (and don't trample them). Root port hotplug now functional again. Fix a few thinkos with the transaction error passthrough for fiq_fsm. fiq_fsm: Implement hack for Split Interrupt transactions Hubs aren't too picky about which endpoint we send Control type split transactions to. By treating Interrupt transfers as Control, it is possible to use the non-periodic queue in the OTG core as well as the non-periodic FIFOs in the hub itself. This massively reduces the microframe exclusivity/contention that periodic split transactions otherwise have to enforce. It goes without saying that this is a fairly egregious USB specification violation, but it works. Original idea by Hans Petter Selasky @ FreeBSD.org. dwc_otg: FIQ support on SMP. Set up FIQ stack and handler on Core 0 only. dwc_otg: introduce fiq_fsm_spin(un|)lock() SMP safety for the FIQ relies on register read-modify write cycles being completed in the correct order. Several places in the DWC code modify registers also touched by the FIQ. Protect these by a bare-bones lock mechanism. This also makes it possible to run the FIQ and IRQ handlers on different cores. fiq_fsm: fix build on bcm2708 and bcm2709 platforms dwc_otg: put some barriers back where they should be for UP bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core active dwc_otg: fixup read-modify-write in critical paths Be more careful about read-modify-write on registers that the FIQ also touches. Guard fiq_fsm_spin_lock with fiq_enable check fiq_fsm: Falling out of the state machine isn't fatal This edge case can be hit if the port is disabled while the FIQ is in the middle of a transaction. Make the effects less severe. Also get rid of the useless return value. squash: dwc_otg: Allow to build without SMP usb: core: make overcurrent messages more prominent Hub overcurrent messages are more serious than "debug". Increase loglevel. usb: dwc_otg: Don't use dma_to_virt() Commit6ce0d20changes dma_to_virt() which breaks this driver. Open code the old dma_to_virt() implementation to work around this. Limit the use of __bus_to_virt() to cases where transfer_buffer_length is set and transfer_buffer is not set. This is done to increase the chance that this driver will also work on ARCH_BCM2835. transfer_buffer should not be NULL if the length is set, but the comment in the code indicates that there are situations where this might happen. drivers/usb/isp1760/isp1760-hcd.c also has a similar comment pointing to a possible: 'usb storage / SCSI bug'. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> dwc_otg: Fix crash when fiq_enable=0 dwc_otg: fiq_fsm: Make high-speed isochronous strided transfers work properly Certain low-bandwidth high-speed USB devices (specialist audio devices, compressed-frame webcams) have packet intervals > 1 microframe. Stride these transfers in the FIQ by using the start-of-frame interrupt to restart the channel at the right time. dwc_otg: Force host mode to fix incorrect compute module boards dwc_otg: Add ARCH_BCM2835 support Signed-off-by: Noralf Trønnes <noralf@tronnes.org> dwc_otg: Simplify FIQ irq number code Dropping ATAGS means we can simplify the FIQ irq number code. Also add error checking on the returned irq number. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> dwc_otg: Remove duplicate gadget probe/unregister function dwc_otg: Properly set the HFIR Douglas Anderson reported: According to the most up to date version of the dwc2 databook, the FRINT field of the HFIR register should be programmed to: * 125 us * (PHY clock freq for HS) - 1 * 1000 us * (PHY clock freq for FS/LS) - 1 This is opposed to older versions of the doc that claimed it should be: * 125 us * (PHY clock freq for HS) * 1000 us * (PHY clock freq for FS/LS) and reported lower timing jitter on a USB analyser dcw_otg: trim xfer length when buffer larger than allocated size is received dwc_otg: Don't free qh align buffers in atomic context dwc_otg: Enable the hack for Split Interrupt transactions by default dwc_otg.fiq_fsm_mask=0xF has long been a suggestion for users with audio stutters or other USB bandwidth issues. So far we are aware of many success stories but no failure caused by this setting. Make it a default to learn more. See: https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=70437 Signed-off-by: popcornmix <popcornmix@gmail.com> dwc_otg: Use kzalloc when suitable dwc_otg: Pass struct device to dma_alloc*() This makes it possible to get the bus address from Device Tree. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> dwc_otg: fix summarize urb->actual_length for isochronous transfers Kernel does not copy input data of ISO transfers to userspace if actual_length is set only in ISO transfers and not summarized in urb->actual_length. Fixes raspberrypi/linux#903 fiq_fsm: Use correct states when starting isoc OUT transfers In fiq_fsm_start_next_periodic() if an isochronous OUT transfer was selected, no regard was given as to whether this was a single-packet transfer or a multi-packet staged transfer. For single-packet transfers, this had the effect of repeatedly sending OUT packets with bogus data and lengths. Eventually if the channel was repeatedly enabled enough times, this would lock up the OTG core and no further bus transfers would happen. Set the FSM state up properly if we select a single-packet transfer. Fixes https://github.com/raspberrypi/linux/issues/1842 dwc_otg: make nak_holdoff work as intended with empty queues If URBs reading from non-periodic split endpoints were dequeued and the last transfer from the endpoint was a NAK handshake, the resulting qh->nak_frame value was stale which would result in unnecessarily long polling intervals for the first subsequent transfer with a fresh URB. Fixup qh->nak_frame in dwc_otg_hcd_urb_dequeue and also guard against a case where a single URB is submitted to the endpoint, a NAK was received on the transfer immediately prior to receiving data and the device subsequently resubmits another URB past the qh->nak_frame interval. Fixes https://github.com/raspberrypi/linux/issues/1709 dwc_otg: fix split transaction data toggle handling around dequeues See https://github.com/raspberrypi/linux/issues/1709 Fix several issues regarding endpoint state when URBs are dequeued - If the HCD is disconnected, flush FIQ-enabled channels properly - Save the data toggle state for bulk endpoints if the last transfer from an endpoint where URBs were dequeued returned a data packet - Reset hc->start_pkt_count properly in assign_and_init_hc() dwc_otg: fix several potential crash sources On root port disconnect events, the host driver state is cleared and in-progress host channels are forcibly stopped. This doesn't play well with the FIQ running in the background, so: - Guard the disconnect callback with both the host spinlock and FIQ spinlock - Move qtd dereference in dwc_otg_handle_hc_fsm() after the early-out so we don't dereference a qtd that has gone away - Turn catch-all BUG()s in dwc_otg_handle_hc_fsm() into warnings. dwc_otg: delete hcd->channel_lock The lock serves no purpose as it is only held while the HCD spinlock is already being held. dwc_otg: remove unnecessary dma-mode channel halts on disconnect interrupt Host channels are already halted in kill_urbs_in_qh_list() with the subsequent interrupt processing behaving as if the URB was dequeued via HCD callback. There's no need to clobber the host channel registers a second time as this exposes races between the driver and host channel resulting in hcd->free_hc_list becoming corrupted. dwcotg: Allow to build without FIQ on ARM64 Signed-off-by: popcornmix <popcornmix@gmail.com> dwc_otg: make periodic scheduling behave properly for FS buses If the root port is in full-speed mode, transfer times at 12mbit/s would be calculated but matched against high-speed quotas. Reinitialise hcd->frame_usecs[i] on each port enable event so that full-speed bandwidth can be tracked sensibly. Also, don't bother using the FIQ for transfers when in full-speed mode - at the slower bus speed, interrupt frequency is reduced by an order of magnitude. Related issue: https://github.com/raspberrypi/linux/issues/2020 dwc_otg: fiq_fsm: Make isochronous compatibility checks work properly Get rid of the spammy printk and local pointer mangling. Also, there is a nominal benefit for using fiq_fsm for isochronous transfers in FS mode (~1.1k IRQs per second vs 2.1k IRQs per second) so remove the root port speed check. dwc_otg: add module parameter int_ep_interval_min Add a module parameter (defaulting to ignored) that clamps the polling rate of high-speed Interrupt endpoints to a minimum microframe interval. The parameter is modifiable at runtime as it is used when activating new endpoints (such as on device connect). dwc_otg: fiq_fsm: Add non-periodic TT exclusivity constraints Certain hub types do not discriminate between pipe direction (IN or OUT) when considering non-periodic transfers. Therefore these hubs get confused if multiple transfers are issued in different directions with the same device address and endpoint number. Constrain queuing non-periodic split transactions so they are performed serially in such cases. Related: https://github.com/raspberrypi/linux/issues/2024 dwc_otg: Fixup change to DRIVER_ATTR interface dwc_otg: Fix compilation warnings Signed-off-by: Phil Elwell <phil@raspberrypi.org> USB_DWCOTG: Disable building dwc_otg as a module (#2265) When dwc_otg is built as a module, build will fail with the following error: ERROR: "DWC_TASK_HI_SCHEDULE" [drivers/usb/host/dwc_otg/dwc_otg.ko] undefined! scripts/Makefile.modpost:91: recipe for target '__modpost' failed make[1]: *** [__modpost] Error 1 Makefile:1199: recipe for target 'modules' failed make: *** [modules] Error 2 Even if the error is solved by including the missing DWC_TASK_HI_SCHEDULE function, the kernel will panic when loading dwc_otg. As a workaround, simply prevent user from building dwc_otg as a module as the current kernel does not support it. See: https://github.com/raspberrypi/linux/issues/2258 Signed-off-by: Malik Olivier Boussejra <malik@boussejra.com> dwc_otg: New timer API dwc_otg: Fix removed ACCESS_ONCE->READ_ONCE dwc_otg: don't unconditionally force host mode in dwc_otg_cil_init() Add the ability to disable force_host_mode for those that want to use dwc_otg in both device and host modes. dwc_otg: Fix a regression when dequeueing isochronous transfers In282bed95(dwc_otg: make nak_holdoff work as intended with empty queues) the dequeue mechanism was changed to leave FIQ-enabled transfers to run to completion - to avoid leaving hub TT buffers with stale packets lying around. This broke FIQ-accelerated isochronous transfers, as this then meant that dozens of transfers were performed after the dequeue function returned. Restore the state machine fence for isochronous transfers. fiq_fsm: rewind DMA pointer for OUT transactions that fail (#2288) See: https://github.com/raspberrypi/linux/issues/2140 dwc_otg: add smp_mb() to prevent driver state corruption on boot Occasional crashes have been seen where the FIQ code dereferences invalid/random pointers immediately after being set up, leading to panic on boot. The crash occurs as the FIQ code races against hcd_init_fiq() and the hcd_init_fiq() code races against the outstanding memory stores from dwc_otg_hcd_init(). Use explicit barriers after touching driver state. usb: dwc_otg: fix memory corruption in dwc_otg driver [Upstream commit51b1b64917] The move from the staging tree to the main tree exposed a longstanding memory corruption bug in the dwc2 driver. The reordering of the driver initialization caused the dwc2 driver to corrupt the initialization data of the sdhci driver on the Raspberry Pi platform, which made the bug show up. The error is in calling to_usb_device(hsotg->dev), since ->dev is not a member of struct usb_device. The easiest fix is to just remove the offending code, since it is not really needed. Thanks to Stephen Warren for tracking down the cause of this. Reported-by: Andre Heider <a.heider@gmail.com> Tested-by: Stephen Warren <swarren@wwwdotorg.org> Signed-off-by: Paul Zimmerman <paulz@synopsys.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> [lukas: port from upstream dwc2 to out-of-tree dwc_otg driver] Signed-off-by: Lukas Wunner <lukas@wunner.de> usb: dwb_otg: Fix unreachable switch statement warning This warning appears with GCC 7.3.0 from toolchains.bootlin.com: ../drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c: In function ‘fiq_fsm_update_hs_isoc’: ../drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c:595:61: warning: statement will never be executed [-Wswitch-unreachable] st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps; ~~~~~~~~~~~~~~~~~^~~~ Signed-off-by: Nathan Chancellor <natechancellor@gmail.com> dwc_otg: fiq_fsm: fix incorrect DMA register offset calculation Rationalise the offset and update all call sites. Fixes https://github.com/raspberrypi/linux/issues/2408 dwc_otg: fix bug with port_addr assignment for single-TT hubs See https://github.com/raspberrypi/linux/issues/2734 The "Hub Port" field in the split transaction packet was always set to 1 for single-TT hubs. The majority of single-TT hub products apparently ignore this field and broadcast to all downstream enabled ports, which masked the issue. A subset of hub devices apparently need the port number to be exact or split transactions will fail. usb: dwc_otg: Clean up build warnings on 64bit kernels No functional changes. Almost all are changes to logging lines. Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org> usb: dwc_otg: Use dma allocation for mphi dummy_send buffer The FIQ driver used a kzalloc'ed buffer for dummy_send, passing a kernel virtual address to the hardware block. The buffer is only ever used for a dummy read, so it should be harmless, but there is the chance that it will cause exceptions. Use a dma allocation so that we have a genuine bus address, and read from that. Free the allocation when done for good measure. Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org> dwc_otg: only do_split when we actually need to do a split The previous test would fail if the root port was in fullspeed mode and there was a hub between the FS device and the root port. While the transfer worked, the schedule mangling performed for high-speed split transfers would break leading to an 8ms polling interval. dwc_otg: fix locking around dequeueing and killing URBs kill_urbs_in_qh_list() is practically only ever called with the fiq lock already held, so don't spinlock twice in the case where we need to cancel an isochronous transfer. Also fix up a case where the global interrupt register could be read with the fiq lock not held. Fixes the deadlock seen in https://github.com/raspberrypi/linux/issues/2907 ARM64/DWC_OTG: Port dwc_otg driver to ARM64 In ARM64, the FIQ mechanism used by this driver is not current implemented. As a workaround, reqular IRQ is used instead of FIQ. In a separate change, the IRQ-CPU mapping is round robined on ARM64 to increase concurrency and allow multiple interrupts to be serviced at a time. This reduces the need for FIQ. Tests Run: This mechanism is most likely to break when multiple USB devices are attached at the same time. So the system was tested under stress. Devices: 1. USB Speakers playing back a FLAC audio through VLC at 96KHz.(Higher then typically, but supported on my speakers). 2. sftp transferring large files through the buildin ethernet connection which is connected through USB. 3. Keyboard and mouse attached and being used. Although I do occasionally hear some glitches, the music seems to play quite well. Signed-off-by: Michael Zoran <mzoran@crowfest.net> usb: dwc_otg: Clean up interrupt claiming code The FIQ/IRQ interrupt number identification code is scattered through the dwc_otg driver. Rationalise it, simplifying the code and solving an existing issue. See: https://github.com/raspberrypi/linux/issues/2612 Signed-off-by: Phil Elwell <phil@raspberrypi.org> dwc_otg: Choose appropriate IRQ handover strategy 2711 has no MPHI peripheral, but the ARM Control block can fake interrupts. Use the size of the DTB "mphi" reg block to determine which is required. Signed-off-by: Phil Elwell <phil@raspberrypi.org> usb: host: dwc_otg: fix compiling in separate directory The dwc_otg Makefile does not respect the O=path argument correctly: include paths in CFLAGS are given relatively to object path, not source path. Compiling in a separate directory yields #include errors. Signed-off-by: Marek Behún <marek.behun@nic.cz> dwc_otg: use align_buf for small IN control transfers (#3150) The hardware will do a 4-byte write to memory on any IN packet received that is between 1 and 3 bytes long. This tramples memory in the uvcvideo driver, as it uses a sequence of 1- and 2-byte control transfers to query the min/max/range/step of each individual camera control and gives us buffers that are offsets into a struct. Catch small control transfers in the data phase and use the align_buf to bounce the correct number of bytes into the URB's buffer. In general, short packets on non-control endpoints should be OK as URBs should have enough buffer space for a wMaxPacket size transfer. See: https://github.com/raspberrypi/linux/issues/3148 Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org> dwc_otg: Declare DMA capability with HCD_DMA flag Following [1], USB controllers have to declare DMA capabilities in order for them to be used by adding the HCD_DMA flag to their hc_driver struct. [1]7b81cb6bdd("usb: add a HCD_DMA flag instead of guestimating DMA capabilities") Signed-off-by: Phil Elwell <phil@raspberrypi.org> dwc_otg: checking the urb->transfer_buffer too early (#3332) After enable the HIGHMEM and VMSPLIT_3G, the dwc_otg driver doesn't work well on Pi2/3 boards with 1G physical ram. Users experience the failure when copying a file of 600M size to the USB stick. And at the same time, the dmesg shows: usb 1-1.1.2: reset high-speed USB device number 8 using dwc_otg sd 0:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK blk_update_request: I/O error, dev sda, sector 3024048 op 0x1:(WRITE) flags 0x4000 phys_seg 15 prio class 0 When this happens, the sg_buf sent to the driver is located in the highmem region, the usb_sg_init() in the core/message.c will leave transfer_buffer to NULL if the sg_buf is in highmem, but in the dwc_otg driver, it returns -EINVAL unconditionally if transfer_buffer is NULL. The driver can handle the situation of buffer to be NULL, if it is in DMA mode, it will convert an address from transfer_dma. But if the conversion fails or it is in the PIO mode, we should check buffer and return -EINVAL if it is NULL. BugLink: https://bugs.launchpad.net/bugs/1852510 Signed-off-by: Hui Wang <hui.wang@canonical.com>
This commit is contained in:
@@ -163,13 +163,23 @@ static inline unsigned long arch_local_save_flags(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* restore saved IRQ & FIQ state
|
||||
* restore saved IRQ state
|
||||
*/
|
||||
#define arch_local_irq_restore arch_local_irq_restore
|
||||
static inline void arch_local_irq_restore(unsigned long flags)
|
||||
{
|
||||
asm volatile(
|
||||
" msr " IRQMASK_REG_NAME_W ", %0 @ local_irq_restore"
|
||||
unsigned long temp = 0;
|
||||
flags &= ~(1 << 6);
|
||||
asm volatile (
|
||||
" mrs %0, cpsr"
|
||||
: "=r" (temp)
|
||||
:
|
||||
: "memory", "cc");
|
||||
/* Preserve FIQ bit */
|
||||
temp &= (1 << 6);
|
||||
flags = flags | temp;
|
||||
asm volatile (
|
||||
" msr cpsr_c, %0 @ local_irq_restore"
|
||||
:
|
||||
: "r" (flags)
|
||||
: "memory", "cc");
|
||||
|
||||
@@ -47,3 +47,7 @@ ENTRY(__get_fiq_regs)
|
||||
mov r0, r0 @ avoid hazard prior to ARMv4
|
||||
ret lr
|
||||
ENDPROC(__get_fiq_regs)
|
||||
|
||||
ENTRY(__FIQ_Branch)
|
||||
mov pc, r8
|
||||
ENDPROC(__FIQ_Branch)
|
||||
|
||||
@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_COMMON) += common/
|
||||
obj-$(CONFIG_USB) += core/
|
||||
obj-$(CONFIG_USB_SUPPORT) += phy/
|
||||
|
||||
obj-$(CONFIG_USB_DWCOTG) += host/
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3/
|
||||
obj-$(CONFIG_USB_DWC2) += dwc2/
|
||||
obj-$(CONFIG_USB_ISP1760) += isp1760/
|
||||
|
||||
@@ -190,6 +190,7 @@ int usb_choose_configuration(struct usb_device *udev)
|
||||
dev_warn(&udev->dev,
|
||||
"no configuration chosen from %d choice%s\n",
|
||||
num_configs, plural(num_configs));
|
||||
dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -5417,7 +5417,7 @@ static void port_event(struct usb_hub *hub, int port1)
|
||||
port_dev->over_current_count++;
|
||||
port_over_current_notify(port_dev);
|
||||
|
||||
dev_dbg(&port_dev->dev, "over-current change #%u\n",
|
||||
dev_notice(&port_dev->dev, "over-current change #%u\n",
|
||||
port_dev->over_current_count);
|
||||
usb_clear_port_feature(hdev, port1,
|
||||
USB_PORT_FEAT_C_OVER_CURRENT);
|
||||
|
||||
@@ -1993,6 +1993,85 @@ free_interfaces:
|
||||
if (cp->string == NULL &&
|
||||
!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
|
||||
cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
|
||||
/* Uncomment this define to enable the HS Electrical Test support */
|
||||
#define DWC_HS_ELECT_TST 1
|
||||
#ifdef DWC_HS_ELECT_TST
|
||||
/* Here we implement the HS Electrical Test support. The
|
||||
* tester uses a vendor ID of 0x1A0A to indicate we should
|
||||
* run a special test sequence. The product ID tells us
|
||||
* which sequence to run. We invoke the test sequence by
|
||||
* sending a non-standard SetFeature command to our root
|
||||
* hub port. Our dwc_otg_hcd_hub_control() routine will
|
||||
* recognize the command and perform the desired test
|
||||
* sequence.
|
||||
*/
|
||||
if (dev->descriptor.idVendor == 0x1A0A) {
|
||||
/* HSOTG Electrical Test */
|
||||
dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
|
||||
|
||||
if (dev->bus && dev->bus->root_hub) {
|
||||
struct usb_device *hdev = dev->bus->root_hub;
|
||||
dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct);
|
||||
|
||||
switch (dev->descriptor.idProduct) {
|
||||
case 0x0101: /* TEST_SE0_NAK */
|
||||
dev_warn(&dev->dev, "TEST_SE0_NAK\n");
|
||||
usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
|
||||
USB_REQ_SET_FEATURE, USB_RT_PORT,
|
||||
USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ);
|
||||
break;
|
||||
|
||||
case 0x0102: /* TEST_J */
|
||||
dev_warn(&dev->dev, "TEST_J\n");
|
||||
usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
|
||||
USB_REQ_SET_FEATURE, USB_RT_PORT,
|
||||
USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ);
|
||||
break;
|
||||
|
||||
case 0x0103: /* TEST_K */
|
||||
dev_warn(&dev->dev, "TEST_K\n");
|
||||
usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
|
||||
USB_REQ_SET_FEATURE, USB_RT_PORT,
|
||||
USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ);
|
||||
break;
|
||||
|
||||
case 0x0104: /* TEST_PACKET */
|
||||
dev_warn(&dev->dev, "TEST_PACKET\n");
|
||||
usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
|
||||
USB_REQ_SET_FEATURE, USB_RT_PORT,
|
||||
USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ);
|
||||
break;
|
||||
|
||||
case 0x0105: /* TEST_FORCE_ENABLE */
|
||||
dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n");
|
||||
usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
|
||||
USB_REQ_SET_FEATURE, USB_RT_PORT,
|
||||
USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ);
|
||||
break;
|
||||
|
||||
case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */
|
||||
dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n");
|
||||
usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
|
||||
USB_REQ_SET_FEATURE, USB_RT_PORT,
|
||||
USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ);
|
||||
break;
|
||||
|
||||
case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
|
||||
dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n");
|
||||
usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
|
||||
USB_REQ_SET_FEATURE, USB_RT_PORT,
|
||||
USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ);
|
||||
break;
|
||||
|
||||
case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
|
||||
dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n");
|
||||
usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
|
||||
USB_REQ_SET_FEATURE, USB_RT_PORT,
|
||||
USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DWC_HS_ELECT_TST */
|
||||
|
||||
/* Now that the interfaces are installed, re-enable LPM. */
|
||||
usb_unlocked_enable_lpm(dev);
|
||||
|
||||
@@ -15,33 +15,82 @@
|
||||
static struct usb_device_id whitelist_table[] = {
|
||||
|
||||
/* hubs are optional in OTG, but very handy ... */
|
||||
#define CERT_WITHOUT_HUBS
|
||||
#if defined(CERT_WITHOUT_HUBS)
|
||||
{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/
|
||||
#else
|
||||
{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
|
||||
{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
|
||||
{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), },
|
||||
#endif
|
||||
|
||||
#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) },
|
||||
//{ 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), },
|
||||
//{ USB_DEVICE(0x0525, 0xa4a1), },
|
||||
/* Linux-USB CDC Ethernet + RNDIS gadget */
|
||||
{ USB_DEVICE(0x0525, 0xa4a2), },
|
||||
//{ USB_DEVICE(0x0525, 0xa4a2), },
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_TEST)
|
||||
/* gadget zero, for testing */
|
||||
{ USB_DEVICE(0x0525, 0xa4a0), },
|
||||
//{ USB_DEVICE(0x0525, 0xa4a0), },
|
||||
#endif
|
||||
|
||||
/* OPT Tester */
|
||||
{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */
|
||||
{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */
|
||||
{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */
|
||||
{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */
|
||||
{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */
|
||||
{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME */
|
||||
{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */
|
||||
{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */
|
||||
|
||||
/* Sony cameras */
|
||||
{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), },
|
||||
|
||||
/* Memory Devices */
|
||||
//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */
|
||||
//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */
|
||||
//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */
|
||||
//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD */
|
||||
{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/
|
||||
//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */
|
||||
|
||||
/* HP Printers */
|
||||
//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */
|
||||
//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */
|
||||
|
||||
/* Speakers */
|
||||
//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */
|
||||
//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
static inline void report_errors(struct usb_device *dev)
|
||||
{
|
||||
/* OTG MESSAGE: report errors here, customize to match your product */
|
||||
dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n",
|
||||
le16_to_cpu(dev->descriptor.idVendor),
|
||||
le16_to_cpu(dev->descriptor.idProduct));
|
||||
if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){
|
||||
dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n");
|
||||
} else {
|
||||
dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int is_targeted(struct usb_device *dev)
|
||||
{
|
||||
struct usb_device_id *id = whitelist_table;
|
||||
@@ -91,16 +140,57 @@ static int is_targeted(struct usb_device *dev)
|
||||
continue;
|
||||
|
||||
return 1;
|
||||
/* 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++) {
|
||||
#ifdef DEBUG
|
||||
dev_dbg(&dev->dev,
|
||||
"ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
|
||||
id->idVendor,
|
||||
id->idProduct,
|
||||
id->bDeviceClass,
|
||||
id->bDeviceSubClass,
|
||||
id->bDeviceProtocol);
|
||||
#endif
|
||||
|
||||
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));
|
||||
|
||||
report_errors(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
3676
drivers/usb/gadget/file_storage.c
Normal file
3676
drivers/usb/gadget/file_storage.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -712,6 +712,16 @@ config USB_RENESAS_USBHS_HCD
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called renesas-usbhs.
|
||||
|
||||
config USB_DWCOTG
|
||||
bool "Synopsis DWC host support"
|
||||
depends on USB && (FIQ || ARM64)
|
||||
help
|
||||
The Synopsis DWC controller is a dual-role
|
||||
host/peripheral/OTG ("On The Go") USB controllers.
|
||||
|
||||
Enable this option to support this IP in host controller mode.
|
||||
If unsure, say N.
|
||||
|
||||
config USB_IMX21_HCD
|
||||
tristate "i.MX21 HCD support"
|
||||
depends on ARM && ARCH_MXC
|
||||
|
||||
@@ -79,6 +79,7 @@ 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_DWCOTG) += dwc_otg/ dwc_common_port/
|
||||
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
|
||||
obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o
|
||||
obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o
|
||||
|
||||
58
drivers/usb/host/dwc_common_port/Makefile
Normal file
58
drivers/usb/host/dwc_common_port/Makefile
Normal file
@@ -0,0 +1,58 @@
|
||||
#
|
||||
# Makefile for DWC_common library
|
||||
#
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
ccflags-y += -DDWC_LINUX
|
||||
#ccflags-y += -DDEBUG
|
||||
#ccflags-y += -DDWC_DEBUG_REGS
|
||||
#ccflags-y += -DDWC_DEBUG_MEMORY
|
||||
|
||||
ccflags-y += -DDWC_LIBMODULE
|
||||
ccflags-y += -DDWC_CCLIB
|
||||
#ccflags-y += -DDWC_CRYPTOLIB
|
||||
ccflags-y += -DDWC_NOTIFYLIB
|
||||
ccflags-y += -DDWC_UTFLIB
|
||||
|
||||
obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o
|
||||
dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
|
||||
dwc_crypto.o dwc_notifier.o \
|
||||
dwc_common_linux.o dwc_mem.o
|
||||
|
||||
kernrelwd := $(subst ., ,$(KERNELRELEASE))
|
||||
kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
|
||||
|
||||
ifneq ($(kernrel3),2.6.20)
|
||||
# grayg - I only know that we use ccflags-y in 2.6.31 actually
|
||||
ccflags-y += $(CPPFLAGS)
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
#ifeq ($(KDIR),)
|
||||
#$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
|
||||
#endif
|
||||
|
||||
ifeq ($(ARCH),)
|
||||
$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
|
||||
cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
|
||||
endif
|
||||
|
||||
ifeq ($(DOXYGEN),)
|
||||
DOXYGEN := doxygen
|
||||
endif
|
||||
|
||||
default:
|
||||
$(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
|
||||
|
||||
docs: $(wildcard *.[hc]) doc/doxygen.cfg
|
||||
$(DOXYGEN) doc/doxygen.cfg
|
||||
|
||||
tags: $(wildcard *.[hc])
|
||||
$(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
|
||||
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
|
||||
17
drivers/usb/host/dwc_common_port/Makefile.fbsd
Normal file
17
drivers/usb/host/dwc_common_port/Makefile.fbsd
Normal file
@@ -0,0 +1,17 @@
|
||||
CFLAGS += -I/sys/i386/compile/GENERIC -I/sys/i386/include -I/usr/include
|
||||
CFLAGS += -DDWC_FREEBSD
|
||||
CFLAGS += -DDEBUG
|
||||
#CFLAGS += -DDWC_DEBUG_REGS
|
||||
#CFLAGS += -DDWC_DEBUG_MEMORY
|
||||
|
||||
#CFLAGS += -DDWC_LIBMODULE
|
||||
#CFLAGS += -DDWC_CCLIB
|
||||
#CFLAGS += -DDWC_CRYPTOLIB
|
||||
#CFLAGS += -DDWC_NOTIFYLIB
|
||||
#CFLAGS += -DDWC_UTFLIB
|
||||
|
||||
KMOD = dwc_common_port_lib
|
||||
SRCS = dwc_cc.c dwc_modpow.c dwc_dh.c dwc_crypto.c dwc_notifier.c \
|
||||
dwc_common_fbsd.c dwc_mem.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
49
drivers/usb/host/dwc_common_port/Makefile.linux
Normal file
49
drivers/usb/host/dwc_common_port/Makefile.linux
Normal file
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# Makefile for DWC_common library
|
||||
#
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
ccflags-y += -DDWC_LINUX
|
||||
#ccflags-y += -DDEBUG
|
||||
#ccflags-y += -DDWC_DEBUG_REGS
|
||||
#ccflags-y += -DDWC_DEBUG_MEMORY
|
||||
|
||||
ccflags-y += -DDWC_LIBMODULE
|
||||
ccflags-y += -DDWC_CCLIB
|
||||
ccflags-y += -DDWC_CRYPTOLIB
|
||||
ccflags-y += -DDWC_NOTIFYLIB
|
||||
ccflags-y += -DDWC_UTFLIB
|
||||
|
||||
obj-m := dwc_common_port_lib.o
|
||||
dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
|
||||
dwc_crypto.o dwc_notifier.o \
|
||||
dwc_common_linux.o dwc_mem.o
|
||||
|
||||
else
|
||||
|
||||
ifeq ($(KDIR),)
|
||||
$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),)
|
||||
$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
|
||||
cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
|
||||
endif
|
||||
|
||||
ifeq ($(DOXYGEN),)
|
||||
DOXYGEN := doxygen
|
||||
endif
|
||||
|
||||
default:
|
||||
$(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
|
||||
|
||||
docs: $(wildcard *.[hc]) doc/doxygen.cfg
|
||||
$(DOXYGEN) doc/doxygen.cfg
|
||||
|
||||
tags: $(wildcard *.[hc])
|
||||
$(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
|
||||
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
|
||||
174
drivers/usb/host/dwc_common_port/changes.txt
Normal file
174
drivers/usb/host/dwc_common_port/changes.txt
Normal file
@@ -0,0 +1,174 @@
|
||||
|
||||
dwc_read_reg32() and friends now take an additional parameter, a pointer to an
|
||||
IO context struct. The IO context struct should live in an os-dependent struct
|
||||
in your driver. As an example, the dwc_usb3 driver has an os-dependent struct
|
||||
named 'os_dep' embedded in the main device struct. So there these calls look
|
||||
like this:
|
||||
|
||||
dwc_read_reg32(&usb3_dev->os_dep.ioctx, &pcd->dev_global_regs->dcfg);
|
||||
|
||||
dwc_write_reg32(&usb3_dev->os_dep.ioctx,
|
||||
&pcd->dev_global_regs->dcfg, 0);
|
||||
|
||||
Note that for the existing Linux driver ports, it is not necessary to actually
|
||||
define the 'ioctx' member in the os-dependent struct. Since Linux does not
|
||||
require an IO context, its macros for dwc_read_reg32() and friends do not
|
||||
use the context pointer, so it is optimized away by the compiler. But it is
|
||||
necessary to add the pointer parameter to all of the call sites, to be ready
|
||||
for any future ports (such as FreeBSD) which do require an IO context.
|
||||
|
||||
|
||||
Similarly, dwc_alloc(), dwc_alloc_atomic(), dwc_strdup(), and dwc_free() now
|
||||
take an additional parameter, a pointer to a memory context. Examples:
|
||||
|
||||
addr = dwc_alloc(&usb3_dev->os_dep.memctx, size);
|
||||
|
||||
dwc_free(&usb3_dev->os_dep.memctx, addr);
|
||||
|
||||
Again, for the Linux ports, it is not necessary to actually define the memctx
|
||||
member, but it is necessary to add the pointer parameter to all of the call
|
||||
sites.
|
||||
|
||||
|
||||
Same for dwc_dma_alloc() and dwc_dma_free(). Examples:
|
||||
|
||||
virt_addr = dwc_dma_alloc(&usb3_dev->os_dep.dmactx, size, &phys_addr);
|
||||
|
||||
dwc_dma_free(&usb3_dev->os_dep.dmactx, size, virt_addr, phys_addr);
|
||||
|
||||
|
||||
Same for dwc_mutex_alloc() and dwc_mutex_free(). Examples:
|
||||
|
||||
mutex = dwc_mutex_alloc(&usb3_dev->os_dep.mtxctx);
|
||||
|
||||
dwc_mutex_free(&usb3_dev->os_dep.mtxctx, mutex);
|
||||
|
||||
|
||||
Same for dwc_spinlock_alloc() and dwc_spinlock_free(). Examples:
|
||||
|
||||
lock = dwc_spinlock_alloc(&usb3_dev->osdep.splctx);
|
||||
|
||||
dwc_spinlock_free(&usb3_dev->osdep.splctx, lock);
|
||||
|
||||
|
||||
Same for dwc_timer_alloc(). Example:
|
||||
|
||||
timer = dwc_timer_alloc(&usb3_dev->os_dep.tmrctx, "dwc_usb3_tmr1",
|
||||
cb_func, cb_data);
|
||||
|
||||
|
||||
Same for dwc_waitq_alloc(). Example:
|
||||
|
||||
waitq = dwc_waitq_alloc(&usb3_dev->os_dep.wtqctx);
|
||||
|
||||
|
||||
Same for dwc_thread_run(). Example:
|
||||
|
||||
thread = dwc_thread_run(&usb3_dev->os_dep.thdctx, func,
|
||||
"dwc_usb3_thd1", data);
|
||||
|
||||
|
||||
Same for dwc_workq_alloc(). Example:
|
||||
|
||||
workq = dwc_workq_alloc(&usb3_dev->osdep.wkqctx, "dwc_usb3_wkq1");
|
||||
|
||||
|
||||
Same for dwc_task_alloc(). Example:
|
||||
|
||||
task = dwc_task_alloc(&usb3_dev->os_dep.tskctx, "dwc_usb3_tsk1",
|
||||
cb_func, cb_data);
|
||||
|
||||
|
||||
In addition to the context pointer additions, a few core functions have had
|
||||
other changes made to their parameters:
|
||||
|
||||
The 'flags' parameter to dwc_spinlock_irqsave() and dwc_spinunlock_irqrestore()
|
||||
has been changed from a uint64_t to a dwc_irqflags_t.
|
||||
|
||||
dwc_thread_should_stop() now takes a 'dwc_thread_t *' parameter, because the
|
||||
FreeBSD equivalent of that function requires it.
|
||||
|
||||
And, in addition to the context pointer, dwc_task_alloc() also adds a
|
||||
'char *name' parameter, to be consistent with dwc_thread_run() and
|
||||
dwc_workq_alloc(), and because the FreeBSD equivalent of that function
|
||||
requires a unique name.
|
||||
|
||||
|
||||
Here is a complete list of the core functions that now take a pointer to a
|
||||
context as their first parameter:
|
||||
|
||||
dwc_read_reg32
|
||||
dwc_read_reg64
|
||||
dwc_write_reg32
|
||||
dwc_write_reg64
|
||||
dwc_modify_reg32
|
||||
dwc_modify_reg64
|
||||
dwc_alloc
|
||||
dwc_alloc_atomic
|
||||
dwc_strdup
|
||||
dwc_free
|
||||
dwc_dma_alloc
|
||||
dwc_dma_free
|
||||
dwc_mutex_alloc
|
||||
dwc_mutex_free
|
||||
dwc_spinlock_alloc
|
||||
dwc_spinlock_free
|
||||
dwc_timer_alloc
|
||||
dwc_waitq_alloc
|
||||
dwc_thread_run
|
||||
dwc_workq_alloc
|
||||
dwc_task_alloc Also adds a 'char *name' as its 2nd parameter
|
||||
|
||||
And here are the core functions that have other changes to their parameters:
|
||||
|
||||
dwc_spinlock_irqsave 'flags' param is now a 'dwc_irqflags_t *'
|
||||
dwc_spinunlock_irqrestore 'flags' param is now a 'dwc_irqflags_t'
|
||||
dwc_thread_should_stop Adds a 'dwc_thread_t *' parameter
|
||||
|
||||
|
||||
|
||||
The changes to the core functions also require some of the other library
|
||||
functions to change:
|
||||
|
||||
dwc_cc_if_alloc() and dwc_cc_if_free() now take a 'void *memctx'
|
||||
(for memory allocation) as the 1st param and a 'void *mtxctx'
|
||||
(for mutex allocation) as the 2nd param.
|
||||
|
||||
dwc_cc_clear(), dwc_cc_add(), dwc_cc_change(), dwc_cc_remove(),
|
||||
dwc_cc_data_for_save(), and dwc_cc_restore_from_data() now take a
|
||||
'void *memctx' as the 1st param.
|
||||
|
||||
dwc_dh_modpow(), dwc_dh_pk(), and dwc_dh_derive_keys() now take a
|
||||
'void *memctx' as the 1st param.
|
||||
|
||||
dwc_modpow() now takes a 'void *memctx' as the 1st param.
|
||||
|
||||
dwc_alloc_notification_manager() now takes a 'void *memctx' as the
|
||||
1st param and a 'void *wkqctx' (for work queue allocation) as the 2nd
|
||||
param, and also now returns an integer value that is non-zero if
|
||||
allocation of its data structures or work queue fails.
|
||||
|
||||
dwc_register_notifier() now takes a 'void *memctx' as the 1st param.
|
||||
|
||||
dwc_memory_debug_start() now takes a 'void *mem_ctx' as the first
|
||||
param, and also now returns an integer value that is non-zero if
|
||||
allocation of its data structures fails.
|
||||
|
||||
|
||||
|
||||
Other miscellaneous changes:
|
||||
|
||||
The DEBUG_MEMORY and DEBUG_REGS #define's have been renamed to
|
||||
DWC_DEBUG_MEMORY and DWC_DEBUG_REGS.
|
||||
|
||||
The following #define's have been added to allow selectively compiling library
|
||||
features:
|
||||
|
||||
DWC_CCLIB
|
||||
DWC_CRYPTOLIB
|
||||
DWC_NOTIFYLIB
|
||||
DWC_UTFLIB
|
||||
|
||||
A DWC_LIBMODULE #define has also been added. If this is not defined, then the
|
||||
module code in dwc_common_linux.c is not compiled in. This allows linking the
|
||||
library code directly into a driver module, instead of as a standalone module.
|
||||
270
drivers/usb/host/dwc_common_port/doc/doxygen.cfg
Normal file
270
drivers/usb/host/dwc_common_port/doc/doxygen.cfg
Normal file
@@ -0,0 +1,270 @@
|
||||
# Doxyfile 1.4.5
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB"
|
||||
PROJECT_NUMBER =
|
||||
OUTPUT_DIRECTORY = doc
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = YES
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH = ..
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = YES
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = NO
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = NO
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = .
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.d \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.idl \
|
||||
*.odl \
|
||||
*.cs \
|
||||
*.php \
|
||||
*.php3 \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.mm \
|
||||
*.dox \
|
||||
*.py \
|
||||
*.C \
|
||||
*.CC \
|
||||
*.C++ \
|
||||
*.II \
|
||||
*.I++ \
|
||||
*.H \
|
||||
*.HH \
|
||||
*.H++ \
|
||||
*.CS \
|
||||
*.PHP \
|
||||
*.PHP3 \
|
||||
*.M \
|
||||
*.MM \
|
||||
*.PY
|
||||
RECURSIVE = NO
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = YES
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = DEBUG DEBUG_MEMORY
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = NO
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
||||
532
drivers/usb/host/dwc_common_port/dwc_cc.c
Normal file
532
drivers/usb/host/dwc_common_port/dwc_cc.c
Normal file
@@ -0,0 +1,532 @@
|
||||
/* =========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
|
||||
* $Revision: #4 $
|
||||
* $Date: 2010/11/04 $
|
||||
* $Change: 1621692 $
|
||||
*
|
||||
* Synopsys Portability Library Software and documentation
|
||||
* (hereinafter, "Software") is an Unsupported proprietary work of
|
||||
* Synopsys, Inc. unless otherwise expressly agreed to in writing
|
||||
* between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for
|
||||
* Licensed Product with Synopsys or any supplement thereto. You are
|
||||
* permitted to use and redistribute this Software in source and binary
|
||||
* forms, with or without modification, provided that redistributions
|
||||
* of source code must retain this notice. You may not view, use,
|
||||
* disclose, copy or distribute this file or any information contained
|
||||
* herein except pursuant to this license grant from Synopsys. If you
|
||||
* do not agree with this notice, including the disclaimer below, then
|
||||
* you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
|
||||
* SYNOPSYS 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.
|
||||
* ========================================================================= */
|
||||
#ifdef DWC_CCLIB
|
||||
|
||||
#include "dwc_cc.h"
|
||||
|
||||
typedef struct dwc_cc
|
||||
{
|
||||
uint32_t uid;
|
||||
uint8_t chid[16];
|
||||
uint8_t cdid[16];
|
||||
uint8_t ck[16];
|
||||
uint8_t *name;
|
||||
uint8_t length;
|
||||
DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
|
||||
} dwc_cc_t;
|
||||
|
||||
DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
|
||||
|
||||
/** The main structure for CC management. */
|
||||
struct dwc_cc_if
|
||||
{
|
||||
dwc_mutex_t *mutex;
|
||||
char *filename;
|
||||
|
||||
unsigned is_host:1;
|
||||
|
||||
dwc_notifier_t *notifier;
|
||||
|
||||
struct context_list list;
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
static inline void dump_bytes(char *name, uint8_t *bytes, int len)
|
||||
{
|
||||
int i;
|
||||
DWC_PRINTF("%s: ", name);
|
||||
for (i=0; i<len; i++) {
|
||||
DWC_PRINTF("%02x ", bytes[i]);
|
||||
}
|
||||
DWC_PRINTF("\n");
|
||||
}
|
||||
#else
|
||||
#define dump_bytes(x...)
|
||||
#endif
|
||||
|
||||
static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
|
||||
{
|
||||
dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
|
||||
if (!cc) {
|
||||
return NULL;
|
||||
}
|
||||
DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
|
||||
|
||||
if (name) {
|
||||
cc->length = length;
|
||||
cc->name = dwc_alloc(mem_ctx, length);
|
||||
if (!cc->name) {
|
||||
dwc_free(mem_ctx, cc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWC_MEMCPY(cc->name, name, length);
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
static void free_cc(void *mem_ctx, dwc_cc_t *cc)
|
||||
{
|
||||
if (cc->name) {
|
||||
dwc_free(mem_ctx, cc->name);
|
||||
}
|
||||
dwc_free(mem_ctx, cc);
|
||||
}
|
||||
|
||||
static uint32_t next_uid(dwc_cc_if_t *cc_if)
|
||||
{
|
||||
uint32_t uid = 0;
|
||||
dwc_cc_t *cc;
|
||||
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
||||
if (cc->uid > uid) {
|
||||
uid = cc->uid;
|
||||
}
|
||||
}
|
||||
|
||||
if (uid == 0) {
|
||||
uid = 255;
|
||||
}
|
||||
|
||||
return uid + 1;
|
||||
}
|
||||
|
||||
static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
|
||||
{
|
||||
dwc_cc_t *cc;
|
||||
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
||||
if (cc->uid == uid) {
|
||||
return cc;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
dwc_cc_t *cc;
|
||||
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
||||
size += (48 + 1);
|
||||
if (cc->name) {
|
||||
size += cc->length;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
|
||||
{
|
||||
uint32_t uid = 0;
|
||||
dwc_cc_t *cc;
|
||||
|
||||
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
||||
if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
|
||||
uid = cc->uid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return uid;
|
||||
}
|
||||
static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
|
||||
{
|
||||
uint32_t uid = 0;
|
||||
dwc_cc_t *cc;
|
||||
|
||||
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
||||
if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
|
||||
uid = cc->uid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return uid;
|
||||
}
|
||||
|
||||
/* Internal cc_add */
|
||||
static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
|
||||
uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
|
||||
{
|
||||
dwc_cc_t *cc;
|
||||
uint32_t uid;
|
||||
|
||||
if (cc_if->is_host) {
|
||||
uid = cc_match_cdid(cc_if, cdid);
|
||||
}
|
||||
else {
|
||||
uid = cc_match_chid(cc_if, chid);
|
||||
}
|
||||
|
||||
if (uid) {
|
||||
DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
|
||||
cc = cc_find(cc_if, uid);
|
||||
}
|
||||
else {
|
||||
cc = alloc_cc(mem_ctx, name, length);
|
||||
cc->uid = next_uid(cc_if);
|
||||
DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
|
||||
}
|
||||
|
||||
DWC_MEMCPY(&(cc->chid[0]), chid, 16);
|
||||
DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
|
||||
DWC_MEMCPY(&(cc->ck[0]), ck, 16);
|
||||
|
||||
DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
|
||||
dump_bytes("CHID", cc->chid, 16);
|
||||
dump_bytes("CDID", cc->cdid, 16);
|
||||
dump_bytes("CK", cc->ck, 16);
|
||||
return cc->uid;
|
||||
}
|
||||
|
||||
/* Internal cc_clear */
|
||||
static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
|
||||
{
|
||||
while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
|
||||
dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
|
||||
DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
|
||||
free_cc(mem_ctx, cc);
|
||||
}
|
||||
}
|
||||
|
||||
dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
|
||||
dwc_notifier_t *notifier, unsigned is_host)
|
||||
{
|
||||
dwc_cc_if_t *cc_if = NULL;
|
||||
|
||||
/* Allocate a common_cc_if structure */
|
||||
cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
|
||||
|
||||
if (!cc_if)
|
||||
return NULL;
|
||||
|
||||
#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
|
||||
DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
|
||||
#else
|
||||
cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
|
||||
#endif
|
||||
if (!cc_if->mutex) {
|
||||
dwc_free(mem_ctx, cc_if);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_INIT(&cc_if->list);
|
||||
cc_if->is_host = is_host;
|
||||
cc_if->notifier = notifier;
|
||||
return cc_if;
|
||||
}
|
||||
|
||||
void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
|
||||
{
|
||||
#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
|
||||
DWC_MUTEX_FREE(cc_if->mutex);
|
||||
#else
|
||||
dwc_mutex_free(mtx_ctx, cc_if->mutex);
|
||||
#endif
|
||||
cc_clear(mem_ctx, cc_if);
|
||||
dwc_free(mem_ctx, cc_if);
|
||||
}
|
||||
|
||||
static void cc_changed(dwc_cc_if_t *cc_if)
|
||||
{
|
||||
if (cc_if->notifier) {
|
||||
dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
|
||||
}
|
||||
}
|
||||
|
||||
void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
|
||||
{
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
cc_clear(mem_ctx, cc_if);
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
cc_changed(cc_if);
|
||||
}
|
||||
|
||||
int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
|
||||
uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
|
||||
{
|
||||
uint32_t uid;
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
cc_changed(cc_if);
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
|
||||
uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
|
||||
{
|
||||
dwc_cc_t* cc;
|
||||
|
||||
DWC_DEBUGC("Change connection context %d", id);
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
cc = cc_find(cc_if, id);
|
||||
if (!cc) {
|
||||
DWC_ERROR("Uid %d not found in cc list\n", id);
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (chid) {
|
||||
DWC_MEMCPY(&(cc->chid[0]), chid, 16);
|
||||
}
|
||||
if (cdid) {
|
||||
DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
|
||||
}
|
||||
if (ck) {
|
||||
DWC_MEMCPY(&(cc->ck[0]), ck, 16);
|
||||
}
|
||||
|
||||
if (name) {
|
||||
if (cc->name) {
|
||||
dwc_free(mem_ctx, cc->name);
|
||||
}
|
||||
cc->name = dwc_alloc(mem_ctx, length);
|
||||
if (!cc->name) {
|
||||
DWC_ERROR("Out of memory in dwc_cc_change()\n");
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
return;
|
||||
}
|
||||
cc->length = length;
|
||||
DWC_MEMCPY(cc->name, name, length);
|
||||
}
|
||||
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
|
||||
cc_changed(cc_if);
|
||||
|
||||
DWC_DEBUGC("Changed connection context id=%d\n", id);
|
||||
dump_bytes("New CHID", cc->chid, 16);
|
||||
dump_bytes("New CDID", cc->cdid, 16);
|
||||
dump_bytes("New CK", cc->ck, 16);
|
||||
}
|
||||
|
||||
void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
|
||||
{
|
||||
dwc_cc_t *cc;
|
||||
|
||||
DWC_DEBUGC("Removing connection context %d", id);
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
cc = cc_find(cc_if, id);
|
||||
if (!cc) {
|
||||
DWC_ERROR("Uid %d not found in cc list\n", id);
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
free_cc(mem_ctx, cc);
|
||||
|
||||
cc_changed(cc_if);
|
||||
}
|
||||
|
||||
uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
|
||||
{
|
||||
uint8_t *buf, *x;
|
||||
uint8_t zero = 0;
|
||||
dwc_cc_t *cc;
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
*length = cc_data_size(cc_if);
|
||||
if (!(*length)) {
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWC_DEBUGC("Creating data for saving (length=%d)", *length);
|
||||
|
||||
buf = dwc_alloc(mem_ctx, *length);
|
||||
if (!buf) {
|
||||
*length = 0;
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x = buf;
|
||||
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
||||
DWC_MEMCPY(x, cc->chid, 16);
|
||||
x += 16;
|
||||
DWC_MEMCPY(x, cc->cdid, 16);
|
||||
x += 16;
|
||||
DWC_MEMCPY(x, cc->ck, 16);
|
||||
x += 16;
|
||||
if (cc->name) {
|
||||
DWC_MEMCPY(x, &cc->length, 1);
|
||||
x += 1;
|
||||
DWC_MEMCPY(x, cc->name, cc->length);
|
||||
x += cc->length;
|
||||
}
|
||||
else {
|
||||
DWC_MEMCPY(x, &zero, 1);
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
|
||||
{
|
||||
uint8_t name_length;
|
||||
uint8_t *name;
|
||||
uint8_t *chid;
|
||||
uint8_t *cdid;
|
||||
uint8_t *ck;
|
||||
uint32_t i = 0;
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
cc_clear(mem_ctx, cc_if);
|
||||
|
||||
while (i < length) {
|
||||
chid = &data[i];
|
||||
i += 16;
|
||||
cdid = &data[i];
|
||||
i += 16;
|
||||
ck = &data[i];
|
||||
i += 16;
|
||||
|
||||
name_length = data[i];
|
||||
i ++;
|
||||
|
||||
if (name_length) {
|
||||
name = &data[i];
|
||||
i += name_length;
|
||||
}
|
||||
else {
|
||||
name = NULL;
|
||||
}
|
||||
|
||||
/* check to see if we haven't overflown the buffer */
|
||||
if (i > length) {
|
||||
DWC_ERROR("Data format error while attempting to load CCs "
|
||||
"(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
|
||||
break;
|
||||
}
|
||||
|
||||
cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
|
||||
}
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
|
||||
cc_changed(cc_if);
|
||||
}
|
||||
|
||||
uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
|
||||
{
|
||||
uint32_t uid = 0;
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
uid = cc_match_chid(cc_if, chid);
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
return uid;
|
||||
}
|
||||
uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
|
||||
{
|
||||
uint32_t uid = 0;
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
uid = cc_match_cdid(cc_if, cdid);
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
return uid;
|
||||
}
|
||||
|
||||
uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
|
||||
{
|
||||
uint8_t *ck = NULL;
|
||||
dwc_cc_t *cc;
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
cc = cc_find(cc_if, id);
|
||||
if (cc) {
|
||||
ck = cc->ck;
|
||||
}
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
|
||||
return ck;
|
||||
|
||||
}
|
||||
|
||||
uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
|
||||
{
|
||||
uint8_t *retval = NULL;
|
||||
dwc_cc_t *cc;
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
cc = cc_find(cc_if, id);
|
||||
if (cc) {
|
||||
retval = cc->chid;
|
||||
}
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
|
||||
{
|
||||
uint8_t *retval = NULL;
|
||||
dwc_cc_t *cc;
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
cc = cc_find(cc_if, id);
|
||||
if (cc) {
|
||||
retval = cc->cdid;
|
||||
}
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
|
||||
{
|
||||
uint8_t *retval = NULL;
|
||||
dwc_cc_t *cc;
|
||||
|
||||
DWC_MUTEX_LOCK(cc_if->mutex);
|
||||
*length = 0;
|
||||
cc = cc_find(cc_if, id);
|
||||
if (cc) {
|
||||
*length = cc->length;
|
||||
retval = cc->name;
|
||||
}
|
||||
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif /* DWC_CCLIB */
|
||||
224
drivers/usb/host/dwc_common_port/dwc_cc.h
Normal file
224
drivers/usb/host/dwc_common_port/dwc_cc.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/* =========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
|
||||
* $Revision: #4 $
|
||||
* $Date: 2010/09/28 $
|
||||
* $Change: 1596182 $
|
||||
*
|
||||
* Synopsys Portability Library Software and documentation
|
||||
* (hereinafter, "Software") is an Unsupported proprietary work of
|
||||
* Synopsys, Inc. unless otherwise expressly agreed to in writing
|
||||
* between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for
|
||||
* Licensed Product with Synopsys or any supplement thereto. You are
|
||||
* permitted to use and redistribute this Software in source and binary
|
||||
* forms, with or without modification, provided that redistributions
|
||||
* of source code must retain this notice. You may not view, use,
|
||||
* disclose, copy or distribute this file or any information contained
|
||||
* herein except pursuant to this license grant from Synopsys. If you
|
||||
* do not agree with this notice, including the disclaimer below, then
|
||||
* you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
|
||||
* SYNOPSYS 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 _DWC_CC_H_
|
||||
#define _DWC_CC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @file
|
||||
*
|
||||
* This file defines the Context Context library.
|
||||
*
|
||||
* The main data structure is dwc_cc_if_t which is returned by either the
|
||||
* dwc_cc_if_alloc function or returned by the module to the user via a provided
|
||||
* function. The data structure is opaque and should only be manipulated via the
|
||||
* functions provied in this API.
|
||||
*
|
||||
* It manages a list of connection contexts and operations can be performed to
|
||||
* add, remove, query, search, and change, those contexts. Additionally,
|
||||
* a dwc_notifier_t object can be requested from the manager so that
|
||||
* the user can be notified whenever the context list has changed.
|
||||
*/
|
||||
|
||||
#include "dwc_os.h"
|
||||
#include "dwc_list.h"
|
||||
#include "dwc_notifier.h"
|
||||
|
||||
|
||||
/* Notifications */
|
||||
#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
|
||||
|
||||
struct dwc_cc_if;
|
||||
typedef struct dwc_cc_if dwc_cc_if_t;
|
||||
|
||||
|
||||
/** @name Connection Context Operations */
|
||||
/** @{ */
|
||||
|
||||
/** This function allocates memory for a dwc_cc_if_t structure, initializes
|
||||
* fields to default values, and returns a pointer to the structure or NULL on
|
||||
* error. */
|
||||
extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
|
||||
dwc_notifier_t *notifier, unsigned is_host);
|
||||
|
||||
/** Frees the memory for the specified CC structure allocated from
|
||||
* dwc_cc_if_alloc(). */
|
||||
extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
|
||||
|
||||
/** Removes all contexts from the connection context list */
|
||||
extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
|
||||
|
||||
/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
|
||||
* If a CHID already exists, the CK and name are overwritten. Statistics are
|
||||
* not overwritten.
|
||||
*
|
||||
* @param cc_if The cc_if structure.
|
||||
* @param chid A pointer to the 16-byte CHID. This value will be copied.
|
||||
* @param ck A pointer to the 16-byte CK. This value will be copied.
|
||||
* @param cdid A pointer to the 16-byte CDID. This value will be copied.
|
||||
* @param name An optional host friendly name as defined in the association model
|
||||
* spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
|
||||
* @param length The length othe unicode string.
|
||||
* @return A unique identifier used to refer to this context that is valid for
|
||||
* as long as this context is still in the list. */
|
||||
extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
|
||||
uint8_t *cdid, uint8_t *ck, uint8_t *name,
|
||||
uint8_t length);
|
||||
|
||||
/** Changes the CHID, CK, CDID, or Name values of a connection context in the
|
||||
* list, preserving any accumulated statistics. This would typically be called
|
||||
* if the host decideds to change the context with a SET_CONNECTION request.
|
||||
*
|
||||
* @param cc_if The cc_if structure.
|
||||
* @param id The identifier of the connection context.
|
||||
* @param chid A pointer to the 16-byte CHID. This value will be copied. NULL
|
||||
* indicates no change.
|
||||
* @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL
|
||||
* indicates no change.
|
||||
* @param ck A pointer to the 16-byte CK. This value will be copied. NULL
|
||||
* indicates no change.
|
||||
* @param name Host friendly name UTF16-LE. NULL indicates no change.
|
||||
* @param length Length of name. */
|
||||
extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
|
||||
uint8_t *chid, uint8_t *cdid, uint8_t *ck,
|
||||
uint8_t *name, uint8_t length);
|
||||
|
||||
/** Remove the specified connection context.
|
||||
* @param cc_if The cc_if structure.
|
||||
* @param id The identifier of the connection context to remove. */
|
||||
extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
|
||||
|
||||
/** Get a binary block of data for the connection context list and attributes.
|
||||
* This data can be used by the OS specific driver to save the connection
|
||||
* context list into non-volatile memory.
|
||||
*
|
||||
* @param cc_if The cc_if structure.
|
||||
* @param length Return the length of the data buffer.
|
||||
* @return A pointer to the data buffer. The memory for this buffer should be
|
||||
* freed with DWC_FREE() after use. */
|
||||
extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
|
||||
unsigned int *length);
|
||||
|
||||
/** Restore the connection context list from the binary data that was previously
|
||||
* returned from a call to dwc_cc_data_for_save. This can be used by the OS specific
|
||||
* driver to load a connection context list from non-volatile memory.
|
||||
*
|
||||
* @param cc_if The cc_if structure.
|
||||
* @param data The data bytes as returned from dwc_cc_data_for_save.
|
||||
* @param length The length of the data. */
|
||||
extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
|
||||
uint8_t *data, unsigned int length);
|
||||
|
||||
/** Find the connection context from the specified CHID.
|
||||
*
|
||||
* @param cc_if The cc_if structure.
|
||||
* @param chid A pointer to the CHID data.
|
||||
* @return A non-zero identifier of the connection context if the CHID matches.
|
||||
* Otherwise returns 0. */
|
||||
extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
|
||||
|
||||
/** Find the connection context from the specified CDID.
|
||||
*
|
||||
* @param cc_if The cc_if structure.
|
||||
* @param cdid A pointer to the CDID data.
|
||||
* @return A non-zero identifier of the connection context if the CHID matches.
|
||||
* Otherwise returns 0. */
|
||||
extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
|
||||
|
||||
/** Retrieve the CK from the specified connection context.
|
||||
*
|
||||
* @param cc_if The cc_if structure.
|
||||
* @param id The identifier of the connection context.
|
||||
* @return A pointer to the CK data. The memory does not need to be freed. */
|
||||
extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
|
||||
|
||||
/** Retrieve the CHID from the specified connection context.
|
||||
*
|
||||
* @param cc_if The cc_if structure.
|
||||
* @param id The identifier of the connection context.
|
||||
* @return A pointer to the CHID data. The memory does not need to be freed. */
|
||||
extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
|
||||
|
||||
/** Retrieve the CDID from the specified connection context.
|
||||
*
|
||||
* @param cc_if The cc_if structure.
|
||||
* @param id The identifier of the connection context.
|
||||
* @return A pointer to the CDID data. The memory does not need to be freed. */
|
||||
extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
|
||||
|
||||
extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
|
||||
|
||||
/** Checks a buffer for non-zero.
|
||||
* @param id A pointer to a 16 byte buffer.
|
||||
* @return true if the 16 byte value is non-zero. */
|
||||
static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
|
||||
int i;
|
||||
for (i=0; i<16; i++) {
|
||||
if (id[i]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Checks a buffer for zero.
|
||||
* @param id A pointer to a 16 byte buffer.
|
||||
* @return true if the 16 byte value is zero. */
|
||||
static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
|
||||
return !dwc_assoc_is_not_zero_id(id);
|
||||
}
|
||||
|
||||
/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
|
||||
* buffer. */
|
||||
static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
|
||||
char *ptr = buffer;
|
||||
int i;
|
||||
for (i=0; i<16; i++) {
|
||||
ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
|
||||
if (i < 15) {
|
||||
ptr += DWC_SPRINTF(ptr, " ");
|
||||
}
|
||||
}
|
||||
return ptr - buffer;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DWC_CC_H_ */
|
||||
1308
drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
Normal file
1308
drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
Normal file
File diff suppressed because it is too large
Load Diff
1409
drivers/usb/host/dwc_common_port/dwc_common_linux.c
Normal file
1409
drivers/usb/host/dwc_common_port/dwc_common_linux.c
Normal file
File diff suppressed because it is too large
Load Diff
1275
drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
Normal file
1275
drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
Normal file
File diff suppressed because it is too large
Load Diff
308
drivers/usb/host/dwc_common_port/dwc_crypto.c
Normal file
308
drivers/usb/host/dwc_common_port/dwc_crypto.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/* =========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
|
||||
* $Revision: #5 $
|
||||
* $Date: 2010/09/28 $
|
||||
* $Change: 1596182 $
|
||||
*
|
||||
* Synopsys Portability Library Software and documentation
|
||||
* (hereinafter, "Software") is an Unsupported proprietary work of
|
||||
* Synopsys, Inc. unless otherwise expressly agreed to in writing
|
||||
* between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for
|
||||
* Licensed Product with Synopsys or any supplement thereto. You are
|
||||
* permitted to use and redistribute this Software in source and binary
|
||||
* forms, with or without modification, provided that redistributions
|
||||
* of source code must retain this notice. You may not view, use,
|
||||
* disclose, copy or distribute this file or any information contained
|
||||
* herein except pursuant to this license grant from Synopsys. If you
|
||||
* do not agree with this notice, including the disclaimer below, then
|
||||
* you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
|
||||
* SYNOPSYS 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.
|
||||
* ========================================================================= */
|
||||
|
||||
/** @file
|
||||
* This file contains the WUSB cryptographic routines.
|
||||
*/
|
||||
|
||||
#ifdef DWC_CRYPTOLIB
|
||||
|
||||
#include "dwc_crypto.h"
|
||||
#include "usb.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
static inline void dump_bytes(char *name, uint8_t *bytes, int len)
|
||||
{
|
||||
int i;
|
||||
DWC_PRINTF("%s: ", name);
|
||||
for (i=0; i<len; i++) {
|
||||
DWC_PRINTF("%02x ", bytes[i]);
|
||||
}
|
||||
DWC_PRINTF("\n");
|
||||
}
|
||||
#else
|
||||
#define dump_bytes(x...)
|
||||
#endif
|
||||
|
||||
/* Display a block */
|
||||
void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
|
||||
{
|
||||
#ifdef DWC_DEBUG_CRYPTO
|
||||
int i, blksize = 16;
|
||||
|
||||
DWC_DEBUG("%s", prefix);
|
||||
|
||||
if (suffix == NULL) {
|
||||
suffix = "\n";
|
||||
blksize = a;
|
||||
}
|
||||
|
||||
for (i = 0; i < blksize; i++)
|
||||
DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " ");
|
||||
DWC_PRINT(suffix);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts an array of bytes using the AES encryption engine.
|
||||
* If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
|
||||
* in-place.
|
||||
*
|
||||
* @return 0 on success, negative error code on error.
|
||||
*/
|
||||
int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
|
||||
{
|
||||
u8 block_t[16];
|
||||
DWC_MEMSET(block_t, 0, 16);
|
||||
|
||||
return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
|
||||
* This function takes a data string and returns the encrypted CBC
|
||||
* Counter-mode MIC.
|
||||
*
|
||||
* @param key The 128-bit symmetric key.
|
||||
* @param nonce The CCM nonce.
|
||||
* @param label The unique 14-byte ASCII text label.
|
||||
* @param bytes The byte array to be encrypted.
|
||||
* @param len Length of the byte array.
|
||||
* @param result Byte array to receive the 8-byte encrypted MIC.
|
||||
*/
|
||||
void dwc_wusb_cmf(u8 *key, u8 *nonce,
|
||||
char *label, u8 *bytes, int len, u8 *result)
|
||||
{
|
||||
u8 block_m[16];
|
||||
u8 block_x[16];
|
||||
u8 block_t[8];
|
||||
int idx, blkNum;
|
||||
u16 la = (u16)(len + 14);
|
||||
|
||||
/* Set the AES-128 key */
|
||||
//dwc_aes_setkey(tfm, key, 16);
|
||||
|
||||
/* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
|
||||
block_m[0] = 0x59;
|
||||
for (idx = 0; idx < 13; idx++)
|
||||
block_m[idx + 1] = nonce[idx];
|
||||
block_m[14] = 0;
|
||||
block_m[15] = 0;
|
||||
|
||||
/* Produce the CBC IV */
|
||||
dwc_wusb_aes_encrypt(block_m, key, block_x);
|
||||
show_block(block_m, "CBC IV in: ", "\n", 0);
|
||||
show_block(block_x, "CBC IV out:", "\n", 0);
|
||||
|
||||
/* Fill block B1 from l(a) = Blen + 14, and A */
|
||||
block_x[0] ^= (u8)(la >> 8);
|
||||
block_x[1] ^= (u8)la;
|
||||
for (idx = 0; idx < 14; idx++)
|
||||
block_x[idx + 2] ^= label[idx];
|
||||
show_block(block_x, "After xor: ", "b1\n", 16);
|
||||
|
||||
dwc_wusb_aes_encrypt(block_x, key, block_x);
|
||||
show_block(block_x, "After AES: ", "b1\n", 16);
|
||||
|
||||
idx = 0;
|
||||
blkNum = 0;
|
||||
|
||||
/* Fill remaining blocks with B */
|
||||
while (len-- > 0) {
|
||||
block_x[idx] ^= *bytes++;
|
||||
if (++idx >= 16) {
|
||||
idx = 0;
|
||||
show_block(block_x, "After xor: ", "\n", blkNum);
|
||||
dwc_wusb_aes_encrypt(block_x, key, block_x);
|
||||
show_block(block_x, "After AES: ", "\n", blkNum);
|
||||
blkNum++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle partial last block */
|
||||
if (idx > 0) {
|
||||
show_block(block_x, "After xor: ", "\n", blkNum);
|
||||
dwc_wusb_aes_encrypt(block_x, key, block_x);
|
||||
show_block(block_x, "After AES: ", "\n", blkNum);
|
||||
}
|
||||
|
||||
/* Save the MIC tag */
|
||||
DWC_MEMCPY(block_t, block_x, 8);
|
||||
show_block(block_t, "MIC tag : ", NULL, 8);
|
||||
|
||||
/* Fill block A0 from flags = 0x01, N, and counter = 0 */
|
||||
block_m[0] = 0x01;
|
||||
block_m[14] = 0;
|
||||
block_m[15] = 0;
|
||||
|
||||
/* Encrypt the counter */
|
||||
dwc_wusb_aes_encrypt(block_m, key, block_x);
|
||||
show_block(block_x, "CTR[MIC] : ", NULL, 8);
|
||||
|
||||
/* XOR with MIC tag */
|
||||
for (idx = 0; idx < 8; idx++) {
|
||||
block_t[idx] ^= block_x[idx];
|
||||
}
|
||||
|
||||
/* Return result to caller */
|
||||
DWC_MEMCPY(result, block_t, 8);
|
||||
show_block(result, "CCM-MIC : ", NULL, 8);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The PRF function described in section 6.5 of the WUSB spec. This function
|
||||
* concatenates MIC values returned from dwc_cmf() to create a value of
|
||||
* the requested length.
|
||||
*
|
||||
* @param prf_len Length of the PRF function in bits (64, 128, or 256).
|
||||
* @param key, nonce, label, bytes, len Same as for dwc_cmf().
|
||||
* @param result Byte array to receive the result.
|
||||
*/
|
||||
void dwc_wusb_prf(int prf_len, u8 *key,
|
||||
u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
|
||||
{
|
||||
int i;
|
||||
|
||||
nonce[0] = 0;
|
||||
for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
|
||||
dwc_wusb_cmf(key, nonce, label, bytes, len, result);
|
||||
result += 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills in CCM Nonce per the WUSB spec.
|
||||
*
|
||||
* @param[in] haddr Host address.
|
||||
* @param[in] daddr Device address.
|
||||
* @param[in] tkid Session Key(PTK) identifier.
|
||||
* @param[out] nonce Pointer to where the CCM Nonce output is to be written.
|
||||
*/
|
||||
void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
|
||||
uint8_t *nonce)
|
||||
{
|
||||
|
||||
DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
|
||||
|
||||
DWC_MEMSET(&nonce[0], 0, 16);
|
||||
|
||||
DWC_MEMCPY(&nonce[6], tkid, 3);
|
||||
nonce[9] = daddr & 0xFF;
|
||||
nonce[10] = (daddr >> 8) & 0xFF;
|
||||
nonce[11] = haddr & 0xFF;
|
||||
nonce[12] = (haddr >> 8) & 0xFF;
|
||||
|
||||
dump_bytes("CCM nonce", nonce, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a 16-byte cryptographic-grade random number for the Host/Device
|
||||
* Nonce.
|
||||
*/
|
||||
void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
|
||||
{
|
||||
uint8_t inonce[16];
|
||||
uint32_t temp[4];
|
||||
|
||||
/* Fill in the Nonce */
|
||||
DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
|
||||
inonce[9] = addr & 0xFF;
|
||||
inonce[10] = (addr >> 8) & 0xFF;
|
||||
inonce[11] = inonce[9];
|
||||
inonce[12] = inonce[10];
|
||||
|
||||
/* Collect "randomness samples" */
|
||||
DWC_RANDOM_BYTES((uint8_t *)temp, 16);
|
||||
|
||||
dwc_wusb_prf_128((uint8_t *)temp, nonce,
|
||||
"Random Numbers", (uint8_t *)temp, sizeof(temp),
|
||||
nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
|
||||
* WUSB spec.
|
||||
*
|
||||
* @param[in] ccm_nonce Pointer to CCM Nonce.
|
||||
* @param[in] mk Master Key to derive the session from
|
||||
* @param[in] hnonce Pointer to Host Nonce.
|
||||
* @param[in] dnonce Pointer to Device Nonce.
|
||||
* @param[out] kck Pointer to where the KCK output is to be written.
|
||||
* @param[out] ptk Pointer to where the PTK output is to be written.
|
||||
*/
|
||||
void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
|
||||
uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
|
||||
{
|
||||
uint8_t idata[32];
|
||||
uint8_t odata[32];
|
||||
|
||||
dump_bytes("ck", mk, 16);
|
||||
dump_bytes("hnonce", hnonce, 16);
|
||||
dump_bytes("dnonce", dnonce, 16);
|
||||
|
||||
/* The data is the HNonce and DNonce concatenated */
|
||||
DWC_MEMCPY(&idata[0], hnonce, 16);
|
||||
DWC_MEMCPY(&idata[16], dnonce, 16);
|
||||
|
||||
dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
|
||||
|
||||
/* Low 16 bytes of the result is the KCK, high 16 is the PTK */
|
||||
DWC_MEMCPY(kck, &odata[0], 16);
|
||||
DWC_MEMCPY(ptk, &odata[16], 16);
|
||||
|
||||
dump_bytes("kck", kck, 16);
|
||||
dump_bytes("ptk", ptk, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Message Integrity Code over the Handshake data per the
|
||||
* WUSB spec.
|
||||
*
|
||||
* @param ccm_nonce Pointer to CCM Nonce.
|
||||
* @param kck Pointer to Key Confirmation Key.
|
||||
* @param data Pointer to Handshake data to be checked.
|
||||
* @param mic Pointer to where the MIC output is to be written.
|
||||
*/
|
||||
void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
|
||||
uint8_t *data, uint8_t *mic)
|
||||
{
|
||||
|
||||
dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
|
||||
data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
|
||||
}
|
||||
|
||||
#endif /* DWC_CRYPTOLIB */
|
||||
111
drivers/usb/host/dwc_common_port/dwc_crypto.h
Normal file
111
drivers/usb/host/dwc_common_port/dwc_crypto.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/* =========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
|
||||
* $Revision: #3 $
|
||||
* $Date: 2010/09/28 $
|
||||
* $Change: 1596182 $
|
||||
*
|
||||
* Synopsys Portability Library Software and documentation
|
||||
* (hereinafter, "Software") is an Unsupported proprietary work of
|
||||
* Synopsys, Inc. unless otherwise expressly agreed to in writing
|
||||
* between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for
|
||||
* Licensed Product with Synopsys or any supplement thereto. You are
|
||||
* permitted to use and redistribute this Software in source and binary
|
||||
* forms, with or without modification, provided that redistributions
|
||||
* of source code must retain this notice. You may not view, use,
|
||||
* disclose, copy or distribute this file or any information contained
|
||||
* herein except pursuant to this license grant from Synopsys. If you
|
||||
* do not agree with this notice, including the disclaimer below, then
|
||||
* you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
|
||||
* SYNOPSYS 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 _DWC_CRYPTO_H_
|
||||
#define _DWC_CRYPTO_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @file
|
||||
*
|
||||
* This file contains declarations for the WUSB Cryptographic routines as
|
||||
* defined in the WUSB spec. They are only to be used internally by the DWC UWB
|
||||
* modules.
|
||||
*/
|
||||
|
||||
#include "dwc_os.h"
|
||||
|
||||
int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
|
||||
|
||||
void dwc_wusb_cmf(u8 *key, u8 *nonce,
|
||||
char *label, u8 *bytes, int len, u8 *result);
|
||||
void dwc_wusb_prf(int prf_len, u8 *key,
|
||||
u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
|
||||
|
||||
/**
|
||||
* The PRF-64 function described in section 6.5 of the WUSB spec.
|
||||
*
|
||||
* @param key, nonce, label, bytes, len, result Same as for dwc_prf().
|
||||
*/
|
||||
static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
|
||||
char *label, u8 *bytes, int len, u8 *result)
|
||||
{
|
||||
dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The PRF-128 function described in section 6.5 of the WUSB spec.
|
||||
*
|
||||
* @param key, nonce, label, bytes, len, result Same as for dwc_prf().
|
||||
*/
|
||||
static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
|
||||
char *label, u8 *bytes, int len, u8 *result)
|
||||
{
|
||||
dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The PRF-256 function described in section 6.5 of the WUSB spec.
|
||||
*
|
||||
* @param key, nonce, label, bytes, len, result Same as for dwc_prf().
|
||||
*/
|
||||
static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
|
||||
char *label, u8 *bytes, int len, u8 *result)
|
||||
{
|
||||
dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
|
||||
}
|
||||
|
||||
|
||||
void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
|
||||
uint8_t *nonce);
|
||||
void dwc_wusb_gen_nonce(uint16_t addr,
|
||||
uint8_t *nonce);
|
||||
|
||||
void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
|
||||
uint8_t *hnonce, uint8_t *dnonce,
|
||||
uint8_t *kck, uint8_t *ptk);
|
||||
|
||||
|
||||
void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
|
||||
*kck, uint8_t *data, uint8_t *mic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DWC_CRYPTO_H_ */
|
||||
291
drivers/usb/host/dwc_common_port/dwc_dh.c
Normal file
291
drivers/usb/host/dwc_common_port/dwc_dh.c
Normal file
@@ -0,0 +1,291 @@
|
||||
/* =========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
|
||||
* $Revision: #3 $
|
||||
* $Date: 2010/09/28 $
|
||||
* $Change: 1596182 $
|
||||
*
|
||||
* Synopsys Portability Library Software and documentation
|
||||
* (hereinafter, "Software") is an Unsupported proprietary work of
|
||||
* Synopsys, Inc. unless otherwise expressly agreed to in writing
|
||||
* between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for
|
||||
* Licensed Product with Synopsys or any supplement thereto. You are
|
||||
* permitted to use and redistribute this Software in source and binary
|
||||
* forms, with or without modification, provided that redistributions
|
||||
* of source code must retain this notice. You may not view, use,
|
||||
* disclose, copy or distribute this file or any information contained
|
||||
* herein except pursuant to this license grant from Synopsys. If you
|
||||
* do not agree with this notice, including the disclaimer below, then
|
||||
* you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
|
||||
* SYNOPSYS 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.
|
||||
* ========================================================================= */
|
||||
#ifdef DWC_CRYPTOLIB
|
||||
|
||||
#ifndef CONFIG_MACH_IPMATE
|
||||
|
||||
#include "dwc_dh.h"
|
||||
#include "dwc_modpow.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
/* This function prints out a buffer in the format described in the Association
|
||||
* Model specification. */
|
||||
static void dh_dump(char *str, void *_num, int len)
|
||||
{
|
||||
uint8_t *num = _num;
|
||||
int i;
|
||||
DWC_PRINTF("%s\n", str);
|
||||
for (i = 0; i < len; i ++) {
|
||||
DWC_PRINTF("%02x", num[i]);
|
||||
if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
|
||||
if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
|
||||
}
|
||||
|
||||
DWC_PRINTF("\n");
|
||||
}
|
||||
#else
|
||||
#define dh_dump(_x...) do {; } while(0)
|
||||
#endif
|
||||
|
||||
/* Constant g value */
|
||||
static __u32 dh_g[] = {
|
||||
0x02000000,
|
||||
};
|
||||
|
||||
/* Constant p value */
|
||||
static __u32 dh_p[] = {
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
|
||||
0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
|
||||
0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
|
||||
0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
|
||||
0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
|
||||
0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
|
||||
0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
|
||||
0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
|
||||
0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
|
||||
0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
|
||||
0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
|
||||
0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
|
||||
{
|
||||
uint8_t *in = _in;
|
||||
uint8_t *out = _out;
|
||||
int i;
|
||||
for (i=0; i<len; i++) {
|
||||
out[i] = in[len-1-i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
|
||||
* big endian numbers of size len, in bytes. Each len value must be a multiple
|
||||
* of 4. */
|
||||
int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
|
||||
void *exp, uint32_t exp_len,
|
||||
void *mod, uint32_t mod_len,
|
||||
void *out)
|
||||
{
|
||||
/* modpow() takes little endian numbers. AM uses big-endian. This
|
||||
* function swaps bytes of numbers before passing onto modpow. */
|
||||
|
||||
int retval = 0;
|
||||
uint32_t *result;
|
||||
|
||||
uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
|
||||
uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
|
||||
uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
|
||||
|
||||
dh_swap_bytes(num, &bignum_num[1], num_len);
|
||||
bignum_num[0] = num_len / 4;
|
||||
|
||||
dh_swap_bytes(exp, &bignum_exp[1], exp_len);
|
||||
bignum_exp[0] = exp_len / 4;
|
||||
|
||||
dh_swap_bytes(mod, &bignum_mod[1], mod_len);
|
||||
bignum_mod[0] = mod_len / 4;
|
||||
|
||||
result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
|
||||
if (!result) {
|
||||
retval = -1;
|
||||
goto dh_modpow_nomem;
|
||||
}
|
||||
|
||||
dh_swap_bytes(&result[1], out, result[0] * 4);
|
||||
dwc_free(mem_ctx, result);
|
||||
|
||||
dh_modpow_nomem:
|
||||
dwc_free(mem_ctx, bignum_num);
|
||||
dwc_free(mem_ctx, bignum_exp);
|
||||
dwc_free(mem_ctx, bignum_mod);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
|
||||
{
|
||||
int retval;
|
||||
uint8_t m3[385];
|
||||
|
||||
#ifndef DH_TEST_VECTORS
|
||||
DWC_RANDOM_BYTES(exp, 32);
|
||||
#endif
|
||||
|
||||
/* Compute the pkd */
|
||||
if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
|
||||
exp, 32,
|
||||
dh_p, 384, pk))) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
m3[384] = nd;
|
||||
DWC_MEMCPY(&m3[0], pk, 384);
|
||||
DWC_SHA256(m3, 385, hash);
|
||||
|
||||
dh_dump("PK", pk, 384);
|
||||
dh_dump("SHA-256(M3)", hash, 32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
|
||||
uint8_t *exp, int is_host,
|
||||
char *dd, uint8_t *ck, uint8_t *kdk)
|
||||
{
|
||||
int retval;
|
||||
uint8_t mv[784];
|
||||
uint8_t sha_result[32];
|
||||
uint8_t dhkey[384];
|
||||
uint8_t shared_secret[384];
|
||||
char *message;
|
||||
uint32_t vd;
|
||||
|
||||
uint8_t *pk;
|
||||
|
||||
if (is_host) {
|
||||
pk = pkd;
|
||||
}
|
||||
else {
|
||||
pk = pkh;
|
||||
}
|
||||
|
||||
if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
|
||||
exp, 32,
|
||||
dh_p, 384, shared_secret))) {
|
||||
return retval;
|
||||
}
|
||||
dh_dump("Shared Secret", shared_secret, 384);
|
||||
|
||||
DWC_SHA256(shared_secret, 384, dhkey);
|
||||
dh_dump("DHKEY", dhkey, 384);
|
||||
|
||||
DWC_MEMCPY(&mv[0], pkd, 384);
|
||||
DWC_MEMCPY(&mv[384], pkh, 384);
|
||||
DWC_MEMCPY(&mv[768], "displayed digest", 16);
|
||||
dh_dump("MV", mv, 784);
|
||||
|
||||
DWC_SHA256(mv, 784, sha_result);
|
||||
dh_dump("SHA-256(MV)", sha_result, 32);
|
||||
dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
|
||||
|
||||
dh_swap_bytes(sha_result, &vd, 4);
|
||||
#ifdef DEBUG
|
||||
DWC_PRINTF("Vd (decimal) = %d\n", vd);
|
||||
#endif
|
||||
|
||||
switch (nd) {
|
||||
case 2:
|
||||
vd = vd % 100;
|
||||
DWC_SPRINTF(dd, "%02d", vd);
|
||||
break;
|
||||
case 3:
|
||||
vd = vd % 1000;
|
||||
DWC_SPRINTF(dd, "%03d", vd);
|
||||
break;
|
||||
case 4:
|
||||
vd = vd % 10000;
|
||||
DWC_SPRINTF(dd, "%04d", vd);
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
DWC_PRINTF("Display Digits: %s\n", dd);
|
||||
#endif
|
||||
|
||||
message = "connection key";
|
||||
DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
|
||||
dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
|
||||
DWC_MEMCPY(ck, sha_result, 16);
|
||||
|
||||
message = "key derivation key";
|
||||
DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
|
||||
dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
|
||||
DWC_MEMCPY(kdk, sha_result, 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DH_TEST_VECTORS
|
||||
|
||||
static __u8 dh_a[] = {
|
||||
0x44, 0x00, 0x51, 0xd6,
|
||||
0xf0, 0xb5, 0x5e, 0xa9,
|
||||
0x67, 0xab, 0x31, 0xc6,
|
||||
0x8a, 0x8b, 0x5e, 0x37,
|
||||
0xd9, 0x10, 0xda, 0xe0,
|
||||
0xe2, 0xd4, 0x59, 0xa4,
|
||||
0x86, 0x45, 0x9c, 0xaa,
|
||||
0xdf, 0x36, 0x75, 0x16,
|
||||
};
|
||||
|
||||
static __u8 dh_b[] = {
|
||||
0x5d, 0xae, 0xc7, 0x86,
|
||||
0x79, 0x80, 0xa3, 0x24,
|
||||
0x8c, 0xe3, 0x57, 0x8f,
|
||||
0xc7, 0x5f, 0x1b, 0x0f,
|
||||
0x2d, 0xf8, 0x9d, 0x30,
|
||||
0x6f, 0xa4, 0x52, 0xcd,
|
||||
0xe0, 0x7a, 0x04, 0x8a,
|
||||
0xde, 0xd9, 0x26, 0x56,
|
||||
};
|
||||
|
||||
void dwc_run_dh_test_vectors(void *mem_ctx)
|
||||
{
|
||||
uint8_t pkd[384];
|
||||
uint8_t pkh[384];
|
||||
uint8_t hashd[32];
|
||||
uint8_t hashh[32];
|
||||
uint8_t ck[16];
|
||||
uint8_t kdk[32];
|
||||
char dd[5];
|
||||
|
||||
DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
|
||||
|
||||
/* compute the PKd and SHA-256(PKd || Nd) */
|
||||
DWC_PRINTF("Computing PKd\n");
|
||||
dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
|
||||
|
||||
/* compute the PKd and SHA-256(PKh || Nd) */
|
||||
DWC_PRINTF("Computing PKh\n");
|
||||
dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
|
||||
|
||||
/* compute the dhkey */
|
||||
dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
|
||||
}
|
||||
#endif /* DH_TEST_VECTORS */
|
||||
|
||||
#endif /* !CONFIG_MACH_IPMATE */
|
||||
|
||||
#endif /* DWC_CRYPTOLIB */
|
||||
106
drivers/usb/host/dwc_common_port/dwc_dh.h
Normal file
106
drivers/usb/host/dwc_common_port/dwc_dh.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* =========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
|
||||
* $Revision: #4 $
|
||||
* $Date: 2010/09/28 $
|
||||
* $Change: 1596182 $
|
||||
*
|
||||
* Synopsys Portability Library Software and documentation
|
||||
* (hereinafter, "Software") is an Unsupported proprietary work of
|
||||
* Synopsys, Inc. unless otherwise expressly agreed to in writing
|
||||
* between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for
|
||||
* Licensed Product with Synopsys or any supplement thereto. You are
|
||||
* permitted to use and redistribute this Software in source and binary
|
||||
* forms, with or without modification, provided that redistributions
|
||||
* of source code must retain this notice. You may not view, use,
|
||||
* disclose, copy or distribute this file or any information contained
|
||||
* herein except pursuant to this license grant from Synopsys. If you
|
||||
* do not agree with this notice, including the disclaimer below, then
|
||||
* you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
|
||||
* SYNOPSYS 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 _DWC_DH_H_
|
||||
#define _DWC_DH_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "dwc_os.h"
|
||||
|
||||
/** @file
|
||||
*
|
||||
* This file defines the common functions on device and host for performing
|
||||
* numeric association as defined in the WUSB spec. They are only to be
|
||||
* used internally by the DWC UWB modules. */
|
||||
|
||||
extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
|
||||
extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
|
||||
uint8_t *key, uint32_t keylen,
|
||||
uint8_t *out);
|
||||
extern int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
|
||||
void *exp, uint32_t exp_len,
|
||||
void *mod, uint32_t mod_len,
|
||||
void *out);
|
||||
|
||||
/** Computes PKD or PKH, and SHA-256(PKd || Nd)
|
||||
*
|
||||
* PK = g^exp mod p.
|
||||
*
|
||||
* Input:
|
||||
* Nd = Number of digits on the device.
|
||||
*
|
||||
* Output:
|
||||
* exp = A 32-byte buffer to be filled with a randomly generated number.
|
||||
* used as either A or B.
|
||||
* pk = A 384-byte buffer to be filled with the PKH or PKD.
|
||||
* hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
|
||||
*/
|
||||
extern int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
|
||||
|
||||
/** Computes the DHKEY, and VD.
|
||||
*
|
||||
* If called from host, then it will comput DHKEY=PKD^exp % p.
|
||||
* If called from device, then it will comput DHKEY=PKH^exp % p.
|
||||
*
|
||||
* Input:
|
||||
* pkd = The PKD value.
|
||||
* pkh = The PKH value.
|
||||
* exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
|
||||
* is_host = Set to non zero if a WUSB host is calling this function.
|
||||
*
|
||||
* Output:
|
||||
|
||||
* dd = A pointer to an buffer to be set to the displayed digits string to be shown
|
||||
* to the user. This buffer should be at 5 bytes long to hold 4 digits plus a
|
||||
* null termination character. This buffer can be used directly for display.
|
||||
* ck = A 16-byte buffer to be filled with the CK.
|
||||
* kdk = A 32-byte buffer to be filled with the KDK.
|
||||
*/
|
||||
extern int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
|
||||
uint8_t *exp, int is_host,
|
||||
char *dd, uint8_t *ck, uint8_t *kdk);
|
||||
|
||||
#ifdef DH_TEST_VECTORS
|
||||
extern void dwc_run_dh_test_vectors(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DWC_DH_H_ */
|
||||
594
drivers/usb/host/dwc_common_port/dwc_list.h
Normal file
594
drivers/usb/host/dwc_common_port/dwc_list.h
Normal file
@@ -0,0 +1,594 @@
|
||||
/* $OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $ */
|
||||
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. 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.
|
||||
* 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. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef _DWC_LIST_H_
|
||||
#define _DWC_LIST_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @file
|
||||
*
|
||||
* This file defines linked list operations. It is derived from BSD with
|
||||
* only the MACRO names being prefixed with DWC_. This is because a few of
|
||||
* these names conflict with those on Linux. For documentation on use, see the
|
||||
* inline comments in the source code. The original license for this source
|
||||
* code applies and is preserved in the dwc_list.h source file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines five types of data structures: singly-linked lists,
|
||||
* lists, simple queues, tail queues, and circular queues.
|
||||
*
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The elements
|
||||
* are singly linked for minimum space and pointer manipulation overhead at
|
||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||
* added to the list after an existing element or at the head of the list.
|
||||
* Elements being removed from the head of the list should use the explicit
|
||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||
* for applications with large datasets and few or no removals or for
|
||||
* implementing a LIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A simple queue is headed by a pair of pointers, one the head of the
|
||||
* list and the other to the tail of the list. The elements are singly
|
||||
* linked to save space, so elements can only be removed from the
|
||||
* head of the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the
|
||||
* list. A simple queue may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the list.
|
||||
* A circle queue may be traversed in either direction, but has a more
|
||||
* complex end of list detection.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Double-linked List.
|
||||
*/
|
||||
|
||||
typedef struct dwc_list_link {
|
||||
struct dwc_list_link *next;
|
||||
struct dwc_list_link *prev;
|
||||
} dwc_list_link_t;
|
||||
|
||||
#define DWC_LIST_INIT(link) do { \
|
||||
(link)->next = (link); \
|
||||
(link)->prev = (link); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_LIST_FIRST(link) ((link)->next)
|
||||
#define DWC_LIST_LAST(link) ((link)->prev)
|
||||
#define DWC_LIST_END(link) (link)
|
||||
#define DWC_LIST_NEXT(link) ((link)->next)
|
||||
#define DWC_LIST_PREV(link) ((link)->prev)
|
||||
#define DWC_LIST_EMPTY(link) \
|
||||
(DWC_LIST_FIRST(link) == DWC_LIST_END(link))
|
||||
#define DWC_LIST_ENTRY(link, type, field) \
|
||||
(type *)((uint8_t *)(link) - (size_t)(&((type *)0)->field))
|
||||
|
||||
#if 0
|
||||
#define DWC_LIST_INSERT_HEAD(list, link) do { \
|
||||
(link)->next = (list)->next; \
|
||||
(link)->prev = (list); \
|
||||
(list)->next->prev = (link); \
|
||||
(list)->next = (link); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_LIST_INSERT_TAIL(list, link) do { \
|
||||
(link)->next = (list); \
|
||||
(link)->prev = (list)->prev; \
|
||||
(list)->prev->next = (link); \
|
||||
(list)->prev = (link); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DWC_LIST_INSERT_HEAD(list, link) do { \
|
||||
dwc_list_link_t *__next__ = (list)->next; \
|
||||
__next__->prev = (link); \
|
||||
(link)->next = __next__; \
|
||||
(link)->prev = (list); \
|
||||
(list)->next = (link); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_LIST_INSERT_TAIL(list, link) do { \
|
||||
dwc_list_link_t *__prev__ = (list)->prev; \
|
||||
(list)->prev = (link); \
|
||||
(link)->next = (list); \
|
||||
(link)->prev = __prev__; \
|
||||
__prev__->next = (link); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static inline void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
entry->next = LIST_POISON1;
|
||||
entry->prev = LIST_POISON2;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DWC_LIST_REMOVE(link) do { \
|
||||
(link)->next->prev = (link)->prev; \
|
||||
(link)->prev->next = (link)->next; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_LIST_REMOVE_INIT(link) do { \
|
||||
DWC_LIST_REMOVE(link); \
|
||||
DWC_LIST_INIT(link); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_LIST_MOVE_HEAD(list, link) do { \
|
||||
DWC_LIST_REMOVE(link); \
|
||||
DWC_LIST_INSERT_HEAD(list, link); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_LIST_MOVE_TAIL(list, link) do { \
|
||||
DWC_LIST_REMOVE(link); \
|
||||
DWC_LIST_INSERT_TAIL(list, link); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_LIST_FOREACH(var, list) \
|
||||
for((var) = DWC_LIST_FIRST(list); \
|
||||
(var) != DWC_LIST_END(list); \
|
||||
(var) = DWC_LIST_NEXT(var))
|
||||
|
||||
#define DWC_LIST_FOREACH_SAFE(var, var2, list) \
|
||||
for((var) = DWC_LIST_FIRST(list), (var2) = DWC_LIST_NEXT(var); \
|
||||
(var) != DWC_LIST_END(list); \
|
||||
(var) = (var2), (var2) = DWC_LIST_NEXT(var2))
|
||||
|
||||
#define DWC_LIST_FOREACH_REVERSE(var, list) \
|
||||
for((var) = DWC_LIST_LAST(list); \
|
||||
(var) != DWC_LIST_END(list); \
|
||||
(var) = DWC_LIST_PREV(var))
|
||||
|
||||
/*
|
||||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define DWC_SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define DWC_SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define DWC_SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List access methods.
|
||||
*/
|
||||
#define DWC_SLIST_FIRST(head) ((head)->slh_first)
|
||||
#define DWC_SLIST_END(head) NULL
|
||||
#define DWC_SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
|
||||
#define DWC_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define DWC_SLIST_FOREACH(var, head, field) \
|
||||
for((var) = SLIST_FIRST(head); \
|
||||
(var) != SLIST_END(head); \
|
||||
(var) = SLIST_NEXT(var, field))
|
||||
|
||||
#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field) \
|
||||
for((varp) = &SLIST_FIRST((head)); \
|
||||
((var) = *(varp)) != SLIST_END(head); \
|
||||
(varp) = &SLIST_NEXT((var), field))
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define DWC_SLIST_INIT(head) { \
|
||||
SLIST_FIRST(head) = SLIST_END(head); \
|
||||
}
|
||||
|
||||
#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_SLIST_REMOVE_HEAD(head, field) do { \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->slh_first == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = (head)->slh_first; \
|
||||
while( curelm->field.sle_next != (elm) ) \
|
||||
curelm = curelm->field.sle_next; \
|
||||
curelm->field.sle_next = \
|
||||
curelm->field.sle_next->field.sle_next; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Simple queue definitions.
|
||||
*/
|
||||
#define DWC_SIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sqh_first; /* first element */ \
|
||||
struct type **sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define DWC_SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
|
||||
#define DWC_SIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
*/
|
||||
#define DWC_SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||
#define DWC_SIMPLEQ_END(head) NULL
|
||||
#define DWC_SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
|
||||
#define DWC_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||
|
||||
#define DWC_SIMPLEQ_FOREACH(var, head, field) \
|
||||
for((var) = SIMPLEQ_FIRST(head); \
|
||||
(var) != SIMPLEQ_END(head); \
|
||||
(var) = SIMPLEQ_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define DWC_SIMPLEQ_INIT(head) do { \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define DWC_TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define DWC_TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define DWC_TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* tail queue access methods
|
||||
*/
|
||||
#define DWC_TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define DWC_TAILQ_END(head) NULL
|
||||
#define DWC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
#define DWC_TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
/* XXX */
|
||||
#define DWC_TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
#define DWC_TAILQ_EMPTY(head) \
|
||||
(DWC_TAILQ_FIRST(head) == DWC_TAILQ_END(head))
|
||||
|
||||
#define DWC_TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = DWC_TAILQ_FIRST(head); \
|
||||
(var) != DWC_TAILQ_END(head); \
|
||||
(var) = DWC_TAILQ_NEXT(var, field))
|
||||
|
||||
#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = DWC_TAILQ_LAST(head, headname); \
|
||||
(var) != DWC_TAILQ_END(head); \
|
||||
(var) = DWC_TAILQ_PREV(var, headname, field))
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define DWC_TAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_TAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
||||
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm2)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||
*(elm2)->field.tqe_prev = (elm2); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Circular queue definitions.
|
||||
*/
|
||||
#define DWC_CIRCLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *cqh_first; /* first element */ \
|
||||
struct type *cqh_last; /* last element */ \
|
||||
}
|
||||
|
||||
#define DWC_CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||
{ DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
|
||||
|
||||
#define DWC_CIRCLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *cqe_next; /* next element */ \
|
||||
struct type *cqe_prev; /* previous element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular queue access methods
|
||||
*/
|
||||
#define DWC_CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||
#define DWC_CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||
#define DWC_CIRCLEQ_END(head) ((void *)(head))
|
||||
#define DWC_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||
#define DWC_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||
#define DWC_CIRCLEQ_EMPTY(head) \
|
||||
(DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
|
||||
|
||||
#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
|
||||
|
||||
#define DWC_CIRCLEQ_FOREACH(var, head, field) \
|
||||
for((var) = DWC_CIRCLEQ_FIRST(head); \
|
||||
(var) != DWC_CIRCLEQ_END(head); \
|
||||
(var) = DWC_CIRCLEQ_NEXT(var, field))
|
||||
|
||||
#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field) \
|
||||
for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
|
||||
(var) != DWC_CIRCLEQ_END(head); \
|
||||
(var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
|
||||
|
||||
#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||
for((var) = DWC_CIRCLEQ_LAST(head); \
|
||||
(var) != DWC_CIRCLEQ_END(head); \
|
||||
(var) = DWC_CIRCLEQ_PREV(var, field))
|
||||
|
||||
/*
|
||||
* Circular queue functions.
|
||||
*/
|
||||
#define DWC_CIRCLEQ_INIT(head) do { \
|
||||
(head)->cqh_first = DWC_CIRCLEQ_END(head); \
|
||||
(head)->cqh_last = DWC_CIRCLEQ_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do { \
|
||||
(elm)->field.cqe_next = NULL; \
|
||||
(elm)->field.cqe_prev = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||
(elm)->field.cqe_prev = (listelm); \
|
||||
if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||
(listelm)->field.cqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm); \
|
||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||
if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||
(listelm)->field.cqe_prev = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||
(elm)->field.cqe_prev = DWC_CIRCLEQ_END(head); \
|
||||
if ((head)->cqh_last == DWC_CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||
(head)->cqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = DWC_CIRCLEQ_END(head); \
|
||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||
if ((head)->cqh_first == DWC_CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(head)->cqh_last->field.cqe_next = (elm); \
|
||||
(head)->cqh_last = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||
if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||
else \
|
||||
(elm)->field.cqe_next->field.cqe_prev = \
|
||||
(elm)->field.cqe_prev; \
|
||||
if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||
else \
|
||||
(elm)->field.cqe_prev->field.cqe_next = \
|
||||
(elm)->field.cqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do { \
|
||||
DWC_CIRCLEQ_REMOVE(head, elm, field); \
|
||||
DWC_CIRCLEQ_INIT_ENTRY(elm, field); \
|
||||
} while (0)
|
||||
|
||||
#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
||||
DWC_CIRCLEQ_END(head)) \
|
||||
(head).cqh_last = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
||||
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
||||
DWC_CIRCLEQ_END(head)) \
|
||||
(head).cqh_first = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DWC_LIST_H_ */
|
||||
245
drivers/usb/host/dwc_common_port/dwc_mem.c
Normal file
245
drivers/usb/host/dwc_common_port/dwc_mem.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/* Memory Debugging */
|
||||
#ifdef DWC_DEBUG_MEMORY
|
||||
|
||||
#include "dwc_os.h"
|
||||
#include "dwc_list.h"
|
||||
|
||||
struct allocation {
|
||||
void *addr;
|
||||
void *ctx;
|
||||
char *func;
|
||||
int line;
|
||||
uint32_t size;
|
||||
int dma;
|
||||
DWC_CIRCLEQ_ENTRY(allocation) entry;
|
||||
};
|
||||
|
||||
DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
|
||||
|
||||
struct allocation_manager {
|
||||
void *mem_ctx;
|
||||
struct allocation_queue allocations;
|
||||
|
||||
/* statistics */
|
||||
int num;
|
||||
int num_freed;
|
||||
int num_active;
|
||||
uint32_t total;
|
||||
uint32_t cur;
|
||||
uint32_t max;
|
||||
};
|
||||
|
||||
static struct allocation_manager *manager = NULL;
|
||||
|
||||
static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
|
||||
int dma)
|
||||
{
|
||||
struct allocation *a;
|
||||
|
||||
DWC_ASSERT(manager != NULL, "manager not allocated");
|
||||
|
||||
a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
|
||||
if (!a) {
|
||||
return -DWC_E_NO_MEMORY;
|
||||
}
|
||||
|
||||
a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
|
||||
if (!a->func) {
|
||||
__DWC_FREE(manager->mem_ctx, a);
|
||||
return -DWC_E_NO_MEMORY;
|
||||
}
|
||||
|
||||
DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
|
||||
a->addr = addr;
|
||||
a->ctx = ctx;
|
||||
a->line = line;
|
||||
a->size = size;
|
||||
a->dma = dma;
|
||||
DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
|
||||
|
||||
/* Update stats */
|
||||
manager->num++;
|
||||
manager->num_active++;
|
||||
manager->total += size;
|
||||
manager->cur += size;
|
||||
|
||||
if (manager->max < manager->cur) {
|
||||
manager->max = manager->cur;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct allocation *find_allocation(void *ctx, void *addr)
|
||||
{
|
||||
struct allocation *a;
|
||||
|
||||
DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
|
||||
if (a->ctx == ctx && a->addr == addr) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void free_allocation(void *ctx, void *addr, char const *func, int line)
|
||||
{
|
||||
struct allocation *a = find_allocation(ctx, addr);
|
||||
|
||||
if (!a) {
|
||||
DWC_ASSERT(0,
|
||||
"Free of address %p that was never allocated or already freed %s:%d",
|
||||
addr, func, line);
|
||||
return;
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
|
||||
|
||||
manager->num_active--;
|
||||
manager->num_freed++;
|
||||
manager->cur -= a->size;
|
||||
__DWC_FREE(manager->mem_ctx, a->func);
|
||||
__DWC_FREE(manager->mem_ctx, a);
|
||||
}
|
||||
|
||||
int dwc_memory_debug_start(void *mem_ctx)
|
||||
{
|
||||
DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
|
||||
|
||||
if (manager) {
|
||||
return -DWC_E_BUSY;
|
||||
}
|
||||
|
||||
manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
|
||||
if (!manager) {
|
||||
return -DWC_E_NO_MEMORY;
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_INIT(&manager->allocations);
|
||||
manager->mem_ctx = mem_ctx;
|
||||
manager->num = 0;
|
||||
manager->num_freed = 0;
|
||||
manager->num_active = 0;
|
||||
manager->total = 0;
|
||||
manager->cur = 0;
|
||||
manager->max = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwc_memory_debug_stop(void)
|
||||
{
|
||||
struct allocation *a;
|
||||
|
||||
dwc_memory_debug_report();
|
||||
|
||||
DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
|
||||
DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
|
||||
free_allocation(a->ctx, a->addr, NULL, -1);
|
||||
}
|
||||
|
||||
__DWC_FREE(manager->mem_ctx, manager);
|
||||
}
|
||||
|
||||
void dwc_memory_debug_report(void)
|
||||
{
|
||||
struct allocation *a;
|
||||
|
||||
DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
|
||||
DWC_PRINTF("Num Allocations = %d\n", manager->num);
|
||||
DWC_PRINTF("Freed = %d\n", manager->num_freed);
|
||||
DWC_PRINTF("Active = %d\n", manager->num_active);
|
||||
DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
|
||||
DWC_PRINTF("Total Memory Used = %d\n", manager->total);
|
||||
DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
|
||||
DWC_PRINTF("Unfreed allocations:\n");
|
||||
|
||||
DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
|
||||
DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n",
|
||||
a->addr, a->size, a->func, a->line, a->dma);
|
||||
}
|
||||
}
|
||||
|
||||
/* The replacement functions */
|
||||
void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
|
||||
{
|
||||
void *addr = __DWC_ALLOC(mem_ctx, size);
|
||||
|
||||
if (!addr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
|
||||
__DWC_FREE(mem_ctx, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
|
||||
int line)
|
||||
{
|
||||
void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
|
||||
|
||||
if (!addr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
|
||||
__DWC_FREE(mem_ctx, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
|
||||
{
|
||||
free_allocation(mem_ctx, addr, func, line);
|
||||
__DWC_FREE(mem_ctx, addr);
|
||||
}
|
||||
|
||||
void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
|
||||
char const *func, int line)
|
||||
{
|
||||
void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
|
||||
|
||||
if (!addr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
|
||||
__DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
|
||||
dwc_dma_t *dma_addr, char const *func, int line)
|
||||
{
|
||||
void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
|
||||
|
||||
if (!addr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
|
||||
__DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
|
||||
dwc_dma_t dma_addr, char const *func, int line)
|
||||
{
|
||||
free_allocation(dma_ctx, virt_addr, func, line);
|
||||
__DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
|
||||
}
|
||||
|
||||
#endif /* DWC_DEBUG_MEMORY */
|
||||
636
drivers/usb/host/dwc_common_port/dwc_modpow.c
Normal file
636
drivers/usb/host/dwc_common_port/dwc_modpow.c
Normal file
@@ -0,0 +1,636 @@
|
||||
/* Bignum routines adapted from PUTTY sources. PuTTY copyright notice follows.
|
||||
*
|
||||
* PuTTY is copyright 1997-2007 Simon Tatham.
|
||||
*
|
||||
* Portions copyright Robert de Bath, Joris van Rantwijk, Delian
|
||||
* Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
|
||||
* Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
|
||||
* Kuhn, and CORE SDI S.A.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
|
||||
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifdef DWC_CRYPTOLIB
|
||||
|
||||
#ifndef CONFIG_MACH_IPMATE
|
||||
|
||||
#include "dwc_modpow.h"
|
||||
|
||||
#define BIGNUM_INT_MASK 0xFFFFFFFFUL
|
||||
#define BIGNUM_TOP_BIT 0x80000000UL
|
||||
#define BIGNUM_INT_BITS 32
|
||||
|
||||
|
||||
static void *snmalloc(void *mem_ctx, size_t n, size_t size)
|
||||
{
|
||||
void *p;
|
||||
size *= n;
|
||||
if (size == 0) size = 1;
|
||||
p = dwc_alloc(mem_ctx, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
#define snewn(ctx, n, type) ((type *)snmalloc((ctx), (n), sizeof(type)))
|
||||
#define sfree dwc_free
|
||||
|
||||
/*
|
||||
* Usage notes:
|
||||
* * Do not call the DIVMOD_WORD macro with expressions such as array
|
||||
* subscripts, as some implementations object to this (see below).
|
||||
* * Note that none of the division methods below will cope if the
|
||||
* quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
|
||||
* to avoid this case.
|
||||
* If this condition occurs, in the case of the x86 DIV instruction,
|
||||
* an overflow exception will occur, which (according to a correspondent)
|
||||
* will manifest on Windows as something like
|
||||
* 0xC0000095: Integer overflow
|
||||
* The C variant won't give the right answer, either.
|
||||
*/
|
||||
|
||||
#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
|
||||
|
||||
#if defined __GNUC__ && defined __i386__
|
||||
#define DIVMOD_WORD(q, r, hi, lo, w) \
|
||||
__asm__("div %2" : \
|
||||
"=d" (r), "=a" (q) : \
|
||||
"r" (w), "d" (hi), "a" (lo))
|
||||
#else
|
||||
#define DIVMOD_WORD(q, r, hi, lo, w) do { \
|
||||
BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
|
||||
q = n / w; \
|
||||
r = n % w; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
// q = n / w;
|
||||
// r = n % w;
|
||||
|
||||
#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
|
||||
|
||||
#define BIGNUM_INTERNAL
|
||||
|
||||
static Bignum newbn(void *mem_ctx, int length)
|
||||
{
|
||||
Bignum b = snewn(mem_ctx, length + 1, BignumInt);
|
||||
//if (!b)
|
||||
//abort(); /* FIXME */
|
||||
DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
|
||||
b[0] = length;
|
||||
return b;
|
||||
}
|
||||
|
||||
void freebn(void *mem_ctx, Bignum b)
|
||||
{
|
||||
/*
|
||||
* Burn the evidence, just in case.
|
||||
*/
|
||||
DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
|
||||
sfree(mem_ctx, b);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute c = a * b.
|
||||
* Input is in the first len words of a and b.
|
||||
* Result is returned in the first 2*len words of c.
|
||||
*/
|
||||
static void internal_mul(BignumInt *a, BignumInt *b,
|
||||
BignumInt *c, int len)
|
||||
{
|
||||
int i, j;
|
||||
BignumDblInt t;
|
||||
|
||||
for (j = 0; j < 2 * len; j++)
|
||||
c[j] = 0;
|
||||
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
t = 0;
|
||||
for (j = len - 1; j >= 0; j--) {
|
||||
t += MUL_WORD(a[i], (BignumDblInt) b[j]);
|
||||
t += (BignumDblInt) c[i + j + 1];
|
||||
c[i + j + 1] = (BignumInt) t;
|
||||
t = t >> BIGNUM_INT_BITS;
|
||||
}
|
||||
c[i] = (BignumInt) t;
|
||||
}
|
||||
}
|
||||
|
||||
static void internal_add_shifted(BignumInt *number,
|
||||
unsigned n, int shift)
|
||||
{
|
||||
int word = 1 + (shift / BIGNUM_INT_BITS);
|
||||
int bshift = shift % BIGNUM_INT_BITS;
|
||||
BignumDblInt addend;
|
||||
|
||||
addend = (BignumDblInt)n << bshift;
|
||||
|
||||
while (addend) {
|
||||
addend += number[word];
|
||||
number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
|
||||
addend >>= BIGNUM_INT_BITS;
|
||||
word++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute a = a % m.
|
||||
* Input in first alen words of a and first mlen words of m.
|
||||
* Output in first alen words of a
|
||||
* (of which first alen-mlen words will be zero).
|
||||
* The MSW of m MUST have its high bit set.
|
||||
* Quotient is accumulated in the `quotient' array, which is a Bignum
|
||||
* rather than the internal bigendian format. Quotient parts are shifted
|
||||
* left by `qshift' before adding into quot.
|
||||
*/
|
||||
static void internal_mod(BignumInt *a, int alen,
|
||||
BignumInt *m, int mlen,
|
||||
BignumInt *quot, int qshift)
|
||||
{
|
||||
BignumInt m0, m1;
|
||||
unsigned int h;
|
||||
int i, k;
|
||||
|
||||
m0 = m[0];
|
||||
if (mlen > 1)
|
||||
m1 = m[1];
|
||||
else
|
||||
m1 = 0;
|
||||
|
||||
for (i = 0; i <= alen - mlen; i++) {
|
||||
BignumDblInt t;
|
||||
unsigned int q, r, c, ai1;
|
||||
|
||||
if (i == 0) {
|
||||
h = 0;
|
||||
} else {
|
||||
h = a[i - 1];
|
||||
a[i - 1] = 0;
|
||||
}
|
||||
|
||||
if (i == alen - 1)
|
||||
ai1 = 0;
|
||||
else
|
||||
ai1 = a[i + 1];
|
||||
|
||||
/* Find q = h:a[i] / m0 */
|
||||
if (h >= m0) {
|
||||
/*
|
||||
* Special case.
|
||||
*
|
||||
* To illustrate it, suppose a BignumInt is 8 bits, and
|
||||
* we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
|
||||
* our initial division will be 0xA123 / 0xA1, which
|
||||
* will give a quotient of 0x100 and a divide overflow.
|
||||
* However, the invariants in this division algorithm
|
||||
* are not violated, since the full number A1:23:... is
|
||||
* _less_ than the quotient prefix A1:B2:... and so the
|
||||
* following correction loop would have sorted it out.
|
||||
*
|
||||
* In this situation we set q to be the largest
|
||||
* quotient we _can_ stomach (0xFF, of course).
|
||||
*/
|
||||
q = BIGNUM_INT_MASK;
|
||||
} else {
|
||||
/* Macro doesn't want an array subscript expression passed
|
||||
* into it (see definition), so use a temporary. */
|
||||
BignumInt tmplo = a[i];
|
||||
DIVMOD_WORD(q, r, h, tmplo, m0);
|
||||
|
||||
/* Refine our estimate of q by looking at
|
||||
h:a[i]:a[i+1] / m0:m1 */
|
||||
t = MUL_WORD(m1, q);
|
||||
if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
|
||||
q--;
|
||||
t -= m1;
|
||||
r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */
|
||||
if (r >= (BignumDblInt) m0 &&
|
||||
t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Subtract q * m from a[i...] */
|
||||
c = 0;
|
||||
for (k = mlen - 1; k >= 0; k--) {
|
||||
t = MUL_WORD(q, m[k]);
|
||||
t += c;
|
||||
c = (unsigned)(t >> BIGNUM_INT_BITS);
|
||||
if ((BignumInt) t > a[i + k])
|
||||
c++;
|
||||
a[i + k] -= (BignumInt) t;
|
||||
}
|
||||
|
||||
/* Add back m in case of borrow */
|
||||
if (c != h) {
|
||||
t = 0;
|
||||
for (k = mlen - 1; k >= 0; k--) {
|
||||
t += m[k];
|
||||
t += a[i + k];
|
||||
a[i + k] = (BignumInt) t;
|
||||
t = t >> BIGNUM_INT_BITS;
|
||||
}
|
||||
q--;
|
||||
}
|
||||
if (quot)
|
||||
internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute p % mod.
|
||||
* The most significant word of mod MUST be non-zero.
|
||||
* We assume that the result array is the same size as the mod array.
|
||||
* We optionally write out a quotient if `quotient' is non-NULL.
|
||||
* We can avoid writing out the result if `result' is NULL.
|
||||
*/
|
||||
void bigdivmod(void *mem_ctx, Bignum p, Bignum mod, Bignum result, Bignum quotient)
|
||||
{
|
||||
BignumInt *n, *m;
|
||||
int mshift;
|
||||
int plen, mlen, i, j;
|
||||
|
||||
/* Allocate m of size mlen, copy mod to m */
|
||||
/* We use big endian internally */
|
||||
mlen = mod[0];
|
||||
m = snewn(mem_ctx, mlen, BignumInt);
|
||||
//if (!m)
|
||||
//abort(); /* FIXME */
|
||||
for (j = 0; j < mlen; j++)
|
||||
m[j] = mod[mod[0] - j];
|
||||
|
||||
/* Shift m left to make msb bit set */
|
||||
for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
|
||||
if ((m[0] << mshift) & BIGNUM_TOP_BIT)
|
||||
break;
|
||||
if (mshift) {
|
||||
for (i = 0; i < mlen - 1; i++)
|
||||
m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
|
||||
m[mlen - 1] = m[mlen - 1] << mshift;
|
||||
}
|
||||
|
||||
plen = p[0];
|
||||
/* Ensure plen > mlen */
|
||||
if (plen <= mlen)
|
||||
plen = mlen + 1;
|
||||
|
||||
/* Allocate n of size plen, copy p to n */
|
||||
n = snewn(mem_ctx, plen, BignumInt);
|
||||
//if (!n)
|
||||
//abort(); /* FIXME */
|
||||
for (j = 0; j < plen; j++)
|
||||
n[j] = 0;
|
||||
for (j = 1; j <= (int)p[0]; j++)
|
||||
n[plen - j] = p[j];
|
||||
|
||||
/* Main computation */
|
||||
internal_mod(n, plen, m, mlen, quotient, mshift);
|
||||
|
||||
/* Fixup result in case the modulus was shifted */
|
||||
if (mshift) {
|
||||
for (i = plen - mlen - 1; i < plen - 1; i++)
|
||||
n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
|
||||
n[plen - 1] = n[plen - 1] << mshift;
|
||||
internal_mod(n, plen, m, mlen, quotient, 0);
|
||||
for (i = plen - 1; i >= plen - mlen; i--)
|
||||
n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
|
||||
}
|
||||
|
||||
/* Copy result to buffer */
|
||||
if (result) {
|
||||
for (i = 1; i <= (int)result[0]; i++) {
|
||||
int j = plen - i;
|
||||
result[i] = j >= 0 ? n[j] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free temporary arrays */
|
||||
for (i = 0; i < mlen; i++)
|
||||
m[i] = 0;
|
||||
sfree(mem_ctx, m);
|
||||
for (i = 0; i < plen; i++)
|
||||
n[i] = 0;
|
||||
sfree(mem_ctx, n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple remainder.
|
||||
*/
|
||||
Bignum bigmod(void *mem_ctx, Bignum a, Bignum b)
|
||||
{
|
||||
Bignum r = newbn(mem_ctx, b[0]);
|
||||
bigdivmod(mem_ctx, a, b, r, NULL);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute (base ^ exp) % mod.
|
||||
*/
|
||||
Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod)
|
||||
{
|
||||
BignumInt *a, *b, *n, *m;
|
||||
int mshift;
|
||||
int mlen, i, j;
|
||||
Bignum base, result;
|
||||
|
||||
/*
|
||||
* The most significant word of mod needs to be non-zero. It
|
||||
* should already be, but let's make sure.
|
||||
*/
|
||||
//assert(mod[mod[0]] != 0);
|
||||
|
||||
/*
|
||||
* Make sure the base is smaller than the modulus, by reducing
|
||||
* it modulo the modulus if not.
|
||||
*/
|
||||
base = bigmod(mem_ctx, base_in, mod);
|
||||
|
||||
/* Allocate m of size mlen, copy mod to m */
|
||||
/* We use big endian internally */
|
||||
mlen = mod[0];
|
||||
m = snewn(mem_ctx, mlen, BignumInt);
|
||||
//if (!m)
|
||||
//abort(); /* FIXME */
|
||||
for (j = 0; j < mlen; j++)
|
||||
m[j] = mod[mod[0] - j];
|
||||
|
||||
/* Shift m left to make msb bit set */
|
||||
for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
|
||||
if ((m[0] << mshift) & BIGNUM_TOP_BIT)
|
||||
break;
|
||||
if (mshift) {
|
||||
for (i = 0; i < mlen - 1; i++)
|
||||
m[i] =
|
||||
(m[i] << mshift) | (m[i + 1] >>
|
||||
(BIGNUM_INT_BITS - mshift));
|
||||
m[mlen - 1] = m[mlen - 1] << mshift;
|
||||
}
|
||||
|
||||
/* Allocate n of size mlen, copy base to n */
|
||||
n = snewn(mem_ctx, mlen, BignumInt);
|
||||
//if (!n)
|
||||
//abort(); /* FIXME */
|
||||
i = mlen - base[0];
|
||||
for (j = 0; j < i; j++)
|
||||
n[j] = 0;
|
||||
for (j = 0; j < base[0]; j++)
|
||||
n[i + j] = base[base[0] - j];
|
||||
|
||||
/* Allocate a and b of size 2*mlen. Set a = 1 */
|
||||
a = snewn(mem_ctx, 2 * mlen, BignumInt);
|
||||
//if (!a)
|
||||
//abort(); /* FIXME */
|
||||
b = snewn(mem_ctx, 2 * mlen, BignumInt);
|
||||
//if (!b)
|
||||
//abort(); /* FIXME */
|
||||
for (i = 0; i < 2 * mlen; i++)
|
||||
a[i] = 0;
|
||||
a[2 * mlen - 1] = 1;
|
||||
|
||||
/* Skip leading zero bits of exp. */
|
||||
i = 0;
|
||||
j = BIGNUM_INT_BITS - 1;
|
||||
while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
|
||||
j--;
|
||||
if (j < 0) {
|
||||
i++;
|
||||
j = BIGNUM_INT_BITS - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Main computation */
|
||||
while (i < exp[0]) {
|
||||
while (j >= 0) {
|
||||
internal_mul(a + mlen, a + mlen, b, mlen);
|
||||
internal_mod(b, mlen * 2, m, mlen, NULL, 0);
|
||||
if ((exp[exp[0] - i] & (1 << j)) != 0) {
|
||||
internal_mul(b + mlen, n, a, mlen);
|
||||
internal_mod(a, mlen * 2, m, mlen, NULL, 0);
|
||||
} else {
|
||||
BignumInt *t;
|
||||
t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
j--;
|
||||
}
|
||||
i++;
|
||||
j = BIGNUM_INT_BITS - 1;
|
||||
}
|
||||
|
||||
/* Fixup result in case the modulus was shifted */
|
||||
if (mshift) {
|
||||
for (i = mlen - 1; i < 2 * mlen - 1; i++)
|
||||
a[i] =
|
||||
(a[i] << mshift) | (a[i + 1] >>
|
||||
(BIGNUM_INT_BITS - mshift));
|
||||
a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
|
||||
internal_mod(a, mlen * 2, m, mlen, NULL, 0);
|
||||
for (i = 2 * mlen - 1; i >= mlen; i--)
|
||||
a[i] =
|
||||
(a[i] >> mshift) | (a[i - 1] <<
|
||||
(BIGNUM_INT_BITS - mshift));
|
||||
}
|
||||
|
||||
/* Copy result to buffer */
|
||||
result = newbn(mem_ctx, mod[0]);
|
||||
for (i = 0; i < mlen; i++)
|
||||
result[result[0] - i] = a[i + mlen];
|
||||
while (result[0] > 1 && result[result[0]] == 0)
|
||||
result[0]--;
|
||||
|
||||
/* Free temporary arrays */
|
||||
for (i = 0; i < 2 * mlen; i++)
|
||||
a[i] = 0;
|
||||
sfree(mem_ctx, a);
|
||||
for (i = 0; i < 2 * mlen; i++)
|
||||
b[i] = 0;
|
||||
sfree(mem_ctx, b);
|
||||
for (i = 0; i < mlen; i++)
|
||||
m[i] = 0;
|
||||
sfree(mem_ctx, m);
|
||||
for (i = 0; i < mlen; i++)
|
||||
n[i] = 0;
|
||||
sfree(mem_ctx, n);
|
||||
|
||||
freebn(mem_ctx, base);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef UNITTEST
|
||||
|
||||
static __u32 dh_p[] = {
|
||||
96,
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF,
|
||||
0xA93AD2CA,
|
||||
0x4B82D120,
|
||||
0xE0FD108E,
|
||||
0x43DB5BFC,
|
||||
0x74E5AB31,
|
||||
0x08E24FA0,
|
||||
0xBAD946E2,
|
||||
0x770988C0,
|
||||
0x7A615D6C,
|
||||
0xBBE11757,
|
||||
0x177B200C,
|
||||
0x521F2B18,
|
||||
0x3EC86A64,
|
||||
0xD8760273,
|
||||
0xD98A0864,
|
||||
0xF12FFA06,
|
||||
0x1AD2EE6B,
|
||||
0xCEE3D226,
|
||||
0x4A25619D,
|
||||
0x1E8C94E0,
|
||||
0xDB0933D7,
|
||||
0xABF5AE8C,
|
||||
0xA6E1E4C7,
|
||||
0xB3970F85,
|
||||
0x5D060C7D,
|
||||
0x8AEA7157,
|
||||
0x58DBEF0A,
|
||||
0xECFB8504,
|
||||
0xDF1CBA64,
|
||||
0xA85521AB,
|
||||
0x04507A33,
|
||||
0xAD33170D,
|
||||
0x8AAAC42D,
|
||||
0x15728E5A,
|
||||
0x98FA0510,
|
||||
0x15D22618,
|
||||
0xEA956AE5,
|
||||
0x3995497C,
|
||||
0x95581718,
|
||||
0xDE2BCBF6,
|
||||
0x6F4C52C9,
|
||||
0xB5C55DF0,
|
||||
0xEC07A28F,
|
||||
0x9B2783A2,
|
||||
0x180E8603,
|
||||
0xE39E772C,
|
||||
0x2E36CE3B,
|
||||
0x32905E46,
|
||||
0xCA18217C,
|
||||
0xF1746C08,
|
||||
0x4ABC9804,
|
||||
0x670C354E,
|
||||
0x7096966D,
|
||||
0x9ED52907,
|
||||
0x208552BB,
|
||||
0x1C62F356,
|
||||
0xDCA3AD96,
|
||||
0x83655D23,
|
||||
0xFD24CF5F,
|
||||
0x69163FA8,
|
||||
0x1C55D39A,
|
||||
0x98DA4836,
|
||||
0xA163BF05,
|
||||
0xC2007CB8,
|
||||
0xECE45B3D,
|
||||
0x49286651,
|
||||
0x7C4B1FE6,
|
||||
0xAE9F2411,
|
||||
0x5A899FA5,
|
||||
0xEE386BFB,
|
||||
0xF406B7ED,
|
||||
0x0BFF5CB6,
|
||||
0xA637ED6B,
|
||||
0xF44C42E9,
|
||||
0x625E7EC6,
|
||||
0xE485B576,
|
||||
0x6D51C245,
|
||||
0x4FE1356D,
|
||||
0xF25F1437,
|
||||
0x302B0A6D,
|
||||
0xCD3A431B,
|
||||
0xEF9519B3,
|
||||
0x8E3404DD,
|
||||
0x514A0879,
|
||||
0x3B139B22,
|
||||
0x020BBEA6,
|
||||
0x8A67CC74,
|
||||
0x29024E08,
|
||||
0x80DC1CD1,
|
||||
0xC4C6628B,
|
||||
0x2168C234,
|
||||
0xC90FDAA2,
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF,
|
||||
};
|
||||
|
||||
static __u32 dh_a[] = {
|
||||
8,
|
||||
0xdf367516,
|
||||
0x86459caa,
|
||||
0xe2d459a4,
|
||||
0xd910dae0,
|
||||
0x8a8b5e37,
|
||||
0x67ab31c6,
|
||||
0xf0b55ea9,
|
||||
0x440051d6,
|
||||
};
|
||||
|
||||
static __u32 dh_b[] = {
|
||||
8,
|
||||
0xded92656,
|
||||
0xe07a048a,
|
||||
0x6fa452cd,
|
||||
0x2df89d30,
|
||||
0xc75f1b0f,
|
||||
0x8ce3578f,
|
||||
0x7980a324,
|
||||
0x5daec786,
|
||||
};
|
||||
|
||||
static __u32 dh_g[] = {
|
||||
1,
|
||||
2,
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
__u32 *k;
|
||||
k = dwc_modpow(NULL, dh_g, dh_a, dh_p);
|
||||
|
||||
printf("\n\n");
|
||||
for (i=0; i<k[0]; i++) {
|
||||
__u32 word32 = k[k[0] - i];
|
||||
__u16 l = word32 & 0xffff;
|
||||
__u16 m = (word32 & 0xffff0000) >> 16;
|
||||
printf("%04x %04x ", m, l);
|
||||
if (!((i + 1)%13)) printf("\n");
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
|
||||
printf("PASS\n\n");
|
||||
}
|
||||
else {
|
||||
printf("FAIL\n\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* UNITTEST */
|
||||
|
||||
#endif /* CONFIG_MACH_IPMATE */
|
||||
|
||||
#endif /*DWC_CRYPTOLIB */
|
||||
34
drivers/usb/host/dwc_common_port/dwc_modpow.h
Normal file
34
drivers/usb/host/dwc_common_port/dwc_modpow.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* dwc_modpow.h
|
||||
* See dwc_modpow.c for license and changes
|
||||
*/
|
||||
#ifndef _DWC_MODPOW_H
|
||||
#define _DWC_MODPOW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "dwc_os.h"
|
||||
|
||||
/** @file
|
||||
*
|
||||
* This file defines the module exponentiation function which is only used
|
||||
* internally by the DWC UWB modules for calculation of PKs during numeric
|
||||
* association. The routine is taken from the PUTTY, an open source terminal
|
||||
* emulator. The PUTTY License is preserved in the dwc_modpow.c file.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef uint32_t BignumInt;
|
||||
typedef uint64_t BignumDblInt;
|
||||
typedef BignumInt *Bignum;
|
||||
|
||||
/* Compute modular exponentiaion */
|
||||
extern Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_BIGNUM_H */
|
||||
319
drivers/usb/host/dwc_common_port/dwc_notifier.c
Normal file
319
drivers/usb/host/dwc_common_port/dwc_notifier.c
Normal file
@@ -0,0 +1,319 @@
|
||||
#ifdef DWC_NOTIFYLIB
|
||||
|
||||
#include "dwc_notifier.h"
|
||||
#include "dwc_list.h"
|
||||
|
||||
typedef struct dwc_observer {
|
||||
void *observer;
|
||||
dwc_notifier_callback_t callback;
|
||||
void *data;
|
||||
char *notification;
|
||||
DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
|
||||
} observer_t;
|
||||
|
||||
DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
|
||||
|
||||
typedef struct dwc_notifier {
|
||||
void *mem_ctx;
|
||||
void *object;
|
||||
struct observer_queue observers;
|
||||
DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
|
||||
} notifier_t;
|
||||
|
||||
DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
|
||||
|
||||
typedef struct manager {
|
||||
void *mem_ctx;
|
||||
void *wkq_ctx;
|
||||
dwc_workq_t *wq;
|
||||
// dwc_mutex_t *mutex;
|
||||
struct notifier_queue notifiers;
|
||||
} manager_t;
|
||||
|
||||
static manager_t *manager = NULL;
|
||||
|
||||
static int create_manager(void *mem_ctx, void *wkq_ctx)
|
||||
{
|
||||
manager = dwc_alloc(mem_ctx, sizeof(manager_t));
|
||||
if (!manager) {
|
||||
return -DWC_E_NO_MEMORY;
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_INIT(&manager->notifiers);
|
||||
|
||||
manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
|
||||
if (!manager->wq) {
|
||||
return -DWC_E_NO_MEMORY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_manager(void)
|
||||
{
|
||||
dwc_workq_free(manager->wq);
|
||||
|
||||
/* All notifiers must have unregistered themselves before this module
|
||||
* can be removed. Hitting this assertion indicates a programmer
|
||||
* error. */
|
||||
DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
|
||||
"Notification manager being freed before all notifiers have been removed");
|
||||
dwc_free(manager->mem_ctx, manager);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void dump_manager(void)
|
||||
{
|
||||
notifier_t *n;
|
||||
observer_t *o;
|
||||
|
||||
DWC_ASSERT(manager, "Notification manager not found");
|
||||
|
||||
DWC_DEBUG("List of all notifiers and observers:\n");
|
||||
DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
|
||||
DWC_DEBUG("Notifier %p has observers:\n", n->object);
|
||||
DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
|
||||
DWC_DEBUG(" %p watching %s\n", o->observer, o->notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define dump_manager(...)
|
||||
#endif
|
||||
|
||||
static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
|
||||
dwc_notifier_callback_t callback, void *data)
|
||||
{
|
||||
observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
|
||||
|
||||
if (!new_observer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
|
||||
new_observer->observer = observer;
|
||||
new_observer->notification = notification;
|
||||
new_observer->callback = callback;
|
||||
new_observer->data = data;
|
||||
return new_observer;
|
||||
}
|
||||
|
||||
static void free_observer(void *mem_ctx, observer_t *observer)
|
||||
{
|
||||
dwc_free(mem_ctx, observer);
|
||||
}
|
||||
|
||||
static notifier_t *alloc_notifier(void *mem_ctx, void *object)
|
||||
{
|
||||
notifier_t *notifier;
|
||||
|
||||
if (!object) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
|
||||
if (!notifier) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_INIT(¬ifier->observers);
|
||||
DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
|
||||
|
||||
notifier->mem_ctx = mem_ctx;
|
||||
notifier->object = object;
|
||||
return notifier;
|
||||
}
|
||||
|
||||
static void free_notifier(notifier_t *notifier)
|
||||
{
|
||||
observer_t *observer;
|
||||
|
||||
DWC_CIRCLEQ_FOREACH(observer, ¬ifier->observers, list_entry) {
|
||||
free_observer(notifier->mem_ctx, observer);
|
||||
}
|
||||
|
||||
dwc_free(notifier->mem_ctx, notifier);
|
||||
}
|
||||
|
||||
static notifier_t *find_notifier(void *object)
|
||||
{
|
||||
notifier_t *notifier;
|
||||
|
||||
DWC_ASSERT(manager, "Notification manager not found");
|
||||
|
||||
if (!object) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
|
||||
if (notifier->object == object) {
|
||||
return notifier;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
|
||||
{
|
||||
return create_manager(mem_ctx, wkq_ctx);
|
||||
}
|
||||
|
||||
void dwc_free_notification_manager(void)
|
||||
{
|
||||
free_manager();
|
||||
}
|
||||
|
||||
dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
|
||||
{
|
||||
notifier_t *notifier;
|
||||
|
||||
DWC_ASSERT(manager, "Notification manager not found");
|
||||
|
||||
notifier = find_notifier(object);
|
||||
if (notifier) {
|
||||
DWC_ERROR("Notifier %p is already registered\n", object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
notifier = alloc_notifier(mem_ctx, object);
|
||||
if (!notifier) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
|
||||
|
||||
DWC_INFO("Notifier %p registered", object);
|
||||
dump_manager();
|
||||
|
||||
return notifier;
|
||||
}
|
||||
|
||||
void dwc_unregister_notifier(dwc_notifier_t *notifier)
|
||||
{
|
||||
DWC_ASSERT(manager, "Notification manager not found");
|
||||
|
||||
if (!DWC_CIRCLEQ_EMPTY(¬ifier->observers)) {
|
||||
observer_t *o;
|
||||
|
||||
DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
|
||||
DWC_CIRCLEQ_FOREACH(o, ¬ifier->observers, list_entry) {
|
||||
DWC_DEBUGC(" %p watching %s\n", o->observer, o->notification);
|
||||
}
|
||||
|
||||
DWC_ASSERT(DWC_CIRCLEQ_EMPTY(¬ifier->observers),
|
||||
"Notifier %p has active observers when removing", notifier);
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
|
||||
free_notifier(notifier);
|
||||
|
||||
DWC_INFO("Notifier unregistered");
|
||||
dump_manager();
|
||||
}
|
||||
|
||||
/* Add an observer to observe the notifier for a particular state, event, or notification. */
|
||||
int dwc_add_observer(void *observer, void *object, char *notification,
|
||||
dwc_notifier_callback_t callback, void *data)
|
||||
{
|
||||
notifier_t *notifier = find_notifier(object);
|
||||
observer_t *new_observer;
|
||||
|
||||
if (!notifier) {
|
||||
DWC_ERROR("Notifier %p is not found when adding observer\n", object);
|
||||
return -DWC_E_INVALID;
|
||||
}
|
||||
|
||||
new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
|
||||
if (!new_observer) {
|
||||
return -DWC_E_NO_MEMORY;
|
||||
}
|
||||
|
||||
DWC_CIRCLEQ_INSERT_TAIL(¬ifier->observers, new_observer, list_entry);
|
||||
|
||||
DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
|
||||
observer, object, notification, callback, data);
|
||||
|
||||
dump_manager();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dwc_remove_observer(void *observer)
|
||||
{
|
||||
notifier_t *n;
|
||||
|
||||
DWC_ASSERT(manager, "Notification manager not found");
|
||||
|
||||
DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
|
||||
observer_t *o;
|
||||
observer_t *o2;
|
||||
|
||||
DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
|
||||
if (o->observer == observer) {
|
||||
DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
|
||||
DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
|
||||
o->observer, n->object, o->notification);
|
||||
free_observer(n->mem_ctx, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dump_manager();
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct callback_data {
|
||||
void *mem_ctx;
|
||||
dwc_notifier_callback_t cb;
|
||||
void *observer;
|
||||
void *data;
|
||||
void *object;
|
||||
char *notification;
|
||||
void *notification_data;
|
||||
} cb_data_t;
|
||||
|
||||
static void cb_task(void *data)
|
||||
{
|
||||
cb_data_t *cb = (cb_data_t *)data;
|
||||
|
||||
cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
|
||||
dwc_free(cb->mem_ctx, cb);
|
||||
}
|
||||
|
||||
void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
|
||||
{
|
||||
observer_t *o;
|
||||
|
||||
DWC_ASSERT(manager, "Notification manager not found");
|
||||
|
||||
DWC_CIRCLEQ_FOREACH(o, ¬ifier->observers, list_entry) {
|
||||
int len = DWC_STRLEN(notification);
|
||||
|
||||
if (DWC_STRLEN(o->notification) != len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DWC_STRNCMP(o->notification, notification, len) == 0) {
|
||||
cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
|
||||
|
||||
if (!cb_data) {
|
||||
DWC_ERROR("Failed to allocate callback data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cb_data->mem_ctx = notifier->mem_ctx;
|
||||
cb_data->cb = o->callback;
|
||||
cb_data->observer = o->observer;
|
||||
cb_data->data = o->data;
|
||||
cb_data->object = notifier->object;
|
||||
cb_data->notification = notification;
|
||||
cb_data->notification_data = notification_data;
|
||||
DWC_DEBUGC("Observer found %p for notification %s\n", o->observer, notification);
|
||||
DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
|
||||
"Notify callback from %p for Notification %s, to observer %p",
|
||||
cb_data->object, notification, cb_data->observer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DWC_NOTIFYLIB */
|
||||
122
drivers/usb/host/dwc_common_port/dwc_notifier.h
Normal file
122
drivers/usb/host/dwc_common_port/dwc_notifier.h
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
#ifndef __DWC_NOTIFIER_H__
|
||||
#define __DWC_NOTIFIER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "dwc_os.h"
|
||||
|
||||
/** @file
|
||||
*
|
||||
* A simple implementation of the Observer pattern. Any "module" can
|
||||
* register as an observer or notifier. The notion of "module" is abstract and
|
||||
* can mean anything used to identify either an observer or notifier. Usually
|
||||
* it will be a pointer to a data structure which contains some state, ie an
|
||||
* object.
|
||||
*
|
||||
* Before any notifiers can be added, the global notification manager must be
|
||||
* brought up with dwc_alloc_notification_manager().
|
||||
* dwc_free_notification_manager() will bring it down and free all resources.
|
||||
* These would typically be called upon module load and unload. The
|
||||
* notification manager is a single global instance that handles all registered
|
||||
* observable modules and observers so this should be done only once.
|
||||
*
|
||||
* A module can be observable by using Notifications to publicize some general
|
||||
* information about it's state or operation. It does not care who listens, or
|
||||
* even if anyone listens, or what they do with the information. The observable
|
||||
* modules do not need to know any information about it's observers or their
|
||||
* interface, or their state or data.
|
||||
*
|
||||
* Any module can register to emit Notifications. It should publish a list of
|
||||
* notifications that it can emit and their behavior, such as when they will get
|
||||
* triggered, and what information will be provided to the observer. Then it
|
||||
* should register itself as an observable module. See dwc_register_notifier().
|
||||
*
|
||||
* Any module can observe any observable, registered module, provided it has a
|
||||
* handle to the other module and knows what notifications to observe. See
|
||||
* dwc_add_observer().
|
||||
*
|
||||
* A function of type dwc_notifier_callback_t is called whenever a notification
|
||||
* is triggered with one or more observers observing it. This function is
|
||||
* called in it's own process so it may sleep or block if needed. It is
|
||||
* guaranteed to be called sometime after the notification has occurred and will
|
||||
* be called once per each time the notification is triggered. It will NOT be
|
||||
* called in the same process context used to trigger the notification.
|
||||
*
|
||||
* @section Limitiations
|
||||
*
|
||||
* Keep in mind that Notifications that can be triggered in rapid sucession may
|
||||
* schedule too many processes too handle. Be aware of this limitation when
|
||||
* designing to use notifications, and only add notifications for appropriate
|
||||
* observable information.
|
||||
*
|
||||
* Also Notification callbacks are not synchronous. If you need to synchronize
|
||||
* the behavior between module/observer you must use other means. And perhaps
|
||||
* that will mean Notifications are not the proper solution.
|
||||
*/
|
||||
|
||||
struct dwc_notifier;
|
||||
typedef struct dwc_notifier dwc_notifier_t;
|
||||
|
||||
/** The callback function must be of this type.
|
||||
*
|
||||
* @param object This is the object that is being observed.
|
||||
* @param notification This is the notification that was triggered.
|
||||
* @param observer This is the observer
|
||||
* @param notification_data This is notification-specific data that the notifier
|
||||
* has included in this notification. The value of this should be published in
|
||||
* the documentation of the observable module with the notifications.
|
||||
* @param user_data This is any custom data that the observer provided when
|
||||
* adding itself as an observer to the notification. */
|
||||
typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer,
|
||||
void *notification_data, void *user_data);
|
||||
|
||||
/** Brings up the notification manager. */
|
||||
extern int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx);
|
||||
/** Brings down the notification manager. */
|
||||
extern void dwc_free_notification_manager(void);
|
||||
|
||||
/** This function registers an observable module. A dwc_notifier_t object is
|
||||
* returned to the observable module. This is an opaque object that is used by
|
||||
* the observable module to trigger notifications. This object should only be
|
||||
* accessible to functions that are authorized to trigger notifications for this
|
||||
* module. Observers do not need this object. */
|
||||
extern dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object);
|
||||
|
||||
/** This function unregisters an observable module. All observers have to be
|
||||
* removed prior to unregistration. */
|
||||
extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
|
||||
|
||||
/** Add a module as an observer to the observable module. The observable module
|
||||
* needs to have previously registered with the notification manager.
|
||||
*
|
||||
* @param observer The observer module
|
||||
* @param object The module to observe
|
||||
* @param notification The notification to observe
|
||||
* @param callback The callback function to call
|
||||
* @param user_data Any additional user data to pass into the callback function */
|
||||
extern int dwc_add_observer(void *observer, void *object, char *notification,
|
||||
dwc_notifier_callback_t callback, void *user_data);
|
||||
|
||||
/** Removes the specified observer from all notifications that it is currently
|
||||
* observing. */
|
||||
extern int dwc_remove_observer(void *observer);
|
||||
|
||||
/** This function triggers a Notification. It should be called by the
|
||||
* observable module, or any module or library which the observable module
|
||||
* allows to trigger notification on it's behalf. Such as the dwc_cc_t.
|
||||
*
|
||||
* dwc_notify is a non-blocking function. Callbacks are scheduled called in
|
||||
* their own process context for each trigger. Callbacks can be blocking.
|
||||
* dwc_notify can be called from interrupt context if needed.
|
||||
*
|
||||
*/
|
||||
void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DWC_NOTIFIER_H__ */
|
||||
1276
drivers/usb/host/dwc_common_port/dwc_os.h
Normal file
1276
drivers/usb/host/dwc_common_port/dwc_os.h
Normal file
File diff suppressed because it is too large
Load Diff
946
drivers/usb/host/dwc_common_port/usb.h
Normal file
946
drivers/usb/host/dwc_common_port/usb.h
Normal file
@@ -0,0 +1,946 @@
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Lennart Augustsson (lennart@augustsson.net) at
|
||||
* Carlstedt Research & Technology.
|
||||
*
|
||||
* 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
*/
|
||||
|
||||
/* Modified by Synopsys, Inc, 12/12/2007 */
|
||||
|
||||
|
||||
#ifndef _USB_H_
|
||||
#define _USB_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The USB records contain some unaligned little-endian word
|
||||
* components. The U[SG]ETW macros take care of both the alignment
|
||||
* and endian problem and should always be used to access non-byte
|
||||
* values.
|
||||
*/
|
||||
typedef u_int8_t uByte;
|
||||
typedef u_int8_t uWord[2];
|
||||
typedef u_int8_t uDWord[4];
|
||||
|
||||
#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
|
||||
#define UCONSTW(x) { (x) & 0xff, ((x) >> 8) & 0xff }
|
||||
#define UCONSTDW(x) { (x) & 0xff, ((x) >> 8) & 0xff, \
|
||||
((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
|
||||
|
||||
#if 1
|
||||
#define UGETW(w) ((w)[0] | ((w)[1] << 8))
|
||||
#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
|
||||
#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
|
||||
#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
|
||||
(w)[1] = (u_int8_t)((v) >> 8), \
|
||||
(w)[2] = (u_int8_t)((v) >> 16), \
|
||||
(w)[3] = (u_int8_t)((v) >> 24))
|
||||
#else
|
||||
/*
|
||||
* On little-endian machines that can handle unanliged accesses
|
||||
* (e.g. i386) these macros can be replaced by the following.
|
||||
*/
|
||||
#define UGETW(w) (*(u_int16_t *)(w))
|
||||
#define USETW(w,v) (*(u_int16_t *)(w) = (v))
|
||||
#define UGETDW(w) (*(u_int32_t *)(w))
|
||||
#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macros for accessing UAS IU fields, which are big-endian
|
||||
*/
|
||||
#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
|
||||
#define IUCONSTW(x) { ((x) >> 8) & 0xff, (x) & 0xff }
|
||||
#define IUCONSTDW(x) { ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
|
||||
((x) >> 8) & 0xff, (x) & 0xff }
|
||||
#define IUGETW(w) (((w)[0] << 8) | (w)[1])
|
||||
#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
|
||||
#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
|
||||
#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
|
||||
(w)[1] = (u_int8_t)((v) >> 16), \
|
||||
(w)[2] = (u_int8_t)((v) >> 8), \
|
||||
(w)[3] = (u_int8_t)(v))
|
||||
|
||||
#define UPACKED __attribute__((__packed__))
|
||||
|
||||
typedef struct {
|
||||
uByte bmRequestType;
|
||||
uByte bRequest;
|
||||
uWord wValue;
|
||||
uWord wIndex;
|
||||
uWord wLength;
|
||||
} UPACKED usb_device_request_t;
|
||||
|
||||
#define UT_GET_DIR(a) ((a) & 0x80)
|
||||
#define UT_WRITE 0x00
|
||||
#define UT_READ 0x80
|
||||
|
||||
#define UT_GET_TYPE(a) ((a) & 0x60)
|
||||
#define UT_STANDARD 0x00
|
||||
#define UT_CLASS 0x20
|
||||
#define UT_VENDOR 0x40
|
||||
|
||||
#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
|
||||
#define UT_DEVICE 0x00
|
||||
#define UT_INTERFACE 0x01
|
||||
#define UT_ENDPOINT 0x02
|
||||
#define UT_OTHER 0x03
|
||||
|
||||
#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE)
|
||||
#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE)
|
||||
#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT)
|
||||
#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE)
|
||||
#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE)
|
||||
#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT)
|
||||
#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
|
||||
#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
|
||||
#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
|
||||
#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT)
|
||||
#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
|
||||
#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
|
||||
#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
|
||||
#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT)
|
||||
#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE)
|
||||
#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE)
|
||||
#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER)
|
||||
#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT)
|
||||
#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE)
|
||||
#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
|
||||
#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER)
|
||||
#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
|
||||
|
||||
/* Requests */
|
||||
#define UR_GET_STATUS 0x00
|
||||
#define USTAT_STANDARD_STATUS 0x00
|
||||
#define WUSTAT_WUSB_FEATURE 0x01
|
||||
#define WUSTAT_CHANNEL_INFO 0x02
|
||||
#define WUSTAT_RECEIVED_DATA 0x03
|
||||
#define WUSTAT_MAS_AVAILABILITY 0x04
|
||||
#define WUSTAT_CURRENT_TRANSMIT_POWER 0x05
|
||||
#define UR_CLEAR_FEATURE 0x01
|
||||
#define UR_SET_FEATURE 0x03
|
||||
#define UR_SET_AND_TEST_FEATURE 0x0c
|
||||
#define UR_SET_ADDRESS 0x05
|
||||
#define UR_GET_DESCRIPTOR 0x06
|
||||
#define UDESC_DEVICE 0x01
|
||||
#define UDESC_CONFIG 0x02
|
||||
#define UDESC_STRING 0x03
|
||||
#define UDESC_INTERFACE 0x04
|
||||
#define UDESC_ENDPOINT 0x05
|
||||
#define UDESC_SS_USB_COMPANION 0x30
|
||||
#define UDESC_DEVICE_QUALIFIER 0x06
|
||||
#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
|
||||
#define UDESC_INTERFACE_POWER 0x08
|
||||
#define UDESC_OTG 0x09
|
||||
#define WUDESC_SECURITY 0x0c
|
||||
#define WUDESC_KEY 0x0d
|
||||
#define WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
|
||||
#define WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
|
||||
#define WUD_KEY_TYPE_ASSOC 0x01
|
||||
#define WUD_KEY_TYPE_GTK 0x02
|
||||
#define WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
|
||||
#define WUD_KEY_ORIGIN_HOST 0x00
|
||||
#define WUD_KEY_ORIGIN_DEVICE 0x01
|
||||
#define WUDESC_ENCRYPTION_TYPE 0x0e
|
||||
#define WUDESC_BOS 0x0f
|
||||
#define WUDESC_DEVICE_CAPABILITY 0x10
|
||||
#define WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
|
||||
#define UDESC_BOS 0x0f
|
||||
#define UDESC_DEVICE_CAPABILITY 0x10
|
||||
#define UDESC_CS_DEVICE 0x21 /* class specific */
|
||||
#define UDESC_CS_CONFIG 0x22
|
||||
#define UDESC_CS_STRING 0x23
|
||||
#define UDESC_CS_INTERFACE 0x24
|
||||
#define UDESC_CS_ENDPOINT 0x25
|
||||
#define UDESC_HUB 0x29
|
||||
#define UR_SET_DESCRIPTOR 0x07
|
||||
#define UR_GET_CONFIG 0x08
|
||||
#define UR_SET_CONFIG 0x09
|
||||
#define UR_GET_INTERFACE 0x0a
|
||||
#define UR_SET_INTERFACE 0x0b
|
||||
#define UR_SYNCH_FRAME 0x0c
|
||||
#define WUR_SET_ENCRYPTION 0x0d
|
||||
#define WUR_GET_ENCRYPTION 0x0e
|
||||
#define WUR_SET_HANDSHAKE 0x0f
|
||||
#define WUR_GET_HANDSHAKE 0x10
|
||||
#define WUR_SET_CONNECTION 0x11
|
||||
#define WUR_SET_SECURITY_DATA 0x12
|
||||
#define WUR_GET_SECURITY_DATA 0x13
|
||||
#define WUR_SET_WUSB_DATA 0x14
|
||||
#define WUDATA_DRPIE_INFO 0x01
|
||||
#define WUDATA_TRANSMIT_DATA 0x02
|
||||
#define WUDATA_TRANSMIT_PARAMS 0x03
|
||||
#define WUDATA_RECEIVE_PARAMS 0x04
|
||||
#define WUDATA_TRANSMIT_POWER 0x05
|
||||
#define WUR_LOOPBACK_DATA_WRITE 0x15
|
||||
#define WUR_LOOPBACK_DATA_READ 0x16
|
||||
#define WUR_SET_INTERFACE_DS 0x17
|
||||
|
||||
/* Feature numbers */
|
||||
#define UF_ENDPOINT_HALT 0
|
||||
#define UF_DEVICE_REMOTE_WAKEUP 1
|
||||
#define UF_TEST_MODE 2
|
||||
#define UF_DEVICE_B_HNP_ENABLE 3
|
||||
#define UF_DEVICE_A_HNP_SUPPORT 4
|
||||
#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
|
||||
#define WUF_WUSB 3
|
||||
#define WUF_TX_DRPIE 0x0
|
||||
#define WUF_DEV_XMIT_PACKET 0x1
|
||||
#define WUF_COUNT_PACKETS 0x2
|
||||
#define WUF_CAPTURE_PACKETS 0x3
|
||||
#define UF_FUNCTION_SUSPEND 0
|
||||
#define UF_U1_ENABLE 48
|
||||
#define UF_U2_ENABLE 49
|
||||
#define UF_LTM_ENABLE 50
|
||||
|
||||
/* Class requests from the USB 2.0 hub spec, table 11-15 */
|
||||
#define UCR_CLEAR_HUB_FEATURE (0x2000 | UR_CLEAR_FEATURE)
|
||||
#define UCR_CLEAR_PORT_FEATURE (0x2300 | UR_CLEAR_FEATURE)
|
||||
#define UCR_GET_HUB_DESCRIPTOR (0xa000 | UR_GET_DESCRIPTOR)
|
||||
#define UCR_GET_HUB_STATUS (0xa000 | UR_GET_STATUS)
|
||||
#define UCR_GET_PORT_STATUS (0xa300 | UR_GET_STATUS)
|
||||
#define UCR_SET_HUB_FEATURE (0x2000 | UR_SET_FEATURE)
|
||||
#define UCR_SET_PORT_FEATURE (0x2300 | UR_SET_FEATURE)
|
||||
#define UCR_SET_AND_TEST_PORT_FEATURE (0xa300 | UR_SET_AND_TEST_FEATURE)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <pshpack1.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bDescriptorSubtype;
|
||||
} UPACKED usb_descriptor_t;
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
} UPACKED usb_descriptor_header_t;
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uWord bcdUSB;
|
||||
#define UD_USB_2_0 0x0200
|
||||
#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
|
||||
uByte bDeviceClass;
|
||||
uByte bDeviceSubClass;
|
||||
uByte bDeviceProtocol;
|
||||
uByte bMaxPacketSize;
|
||||
/* The fields below are not part of the initial descriptor. */
|
||||
uWord idVendor;
|
||||
uWord idProduct;
|
||||
uWord bcdDevice;
|
||||
uByte iManufacturer;
|
||||
uByte iProduct;
|
||||
uByte iSerialNumber;
|
||||
uByte bNumConfigurations;
|
||||
} UPACKED usb_device_descriptor_t;
|
||||
#define USB_DEVICE_DESCRIPTOR_SIZE 18
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uWord wTotalLength;
|
||||
uByte bNumInterface;
|
||||
uByte bConfigurationValue;
|
||||
uByte iConfiguration;
|
||||
#define UC_ATT_ONE (1 << 7) /* must be set */
|
||||
#define UC_ATT_SELFPOWER (1 << 6) /* self powered */
|
||||
#define UC_ATT_WAKEUP (1 << 5) /* can wakeup */
|
||||
#define UC_ATT_BATTERY (1 << 4) /* battery powered */
|
||||
uByte bmAttributes;
|
||||
#define UC_BUS_POWERED 0x80
|
||||
#define UC_SELF_POWERED 0x40
|
||||
#define UC_REMOTE_WAKEUP 0x20
|
||||
uByte bMaxPower; /* max current in 2 mA units */
|
||||
#define UC_POWER_FACTOR 2
|
||||
} UPACKED usb_config_descriptor_t;
|
||||
#define USB_CONFIG_DESCRIPTOR_SIZE 9
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bInterfaceNumber;
|
||||
uByte bAlternateSetting;
|
||||
uByte bNumEndpoints;
|
||||
uByte bInterfaceClass;
|
||||
uByte bInterfaceSubClass;
|
||||
uByte bInterfaceProtocol;
|
||||
uByte iInterface;
|
||||
} UPACKED usb_interface_descriptor_t;
|
||||
#define USB_INTERFACE_DESCRIPTOR_SIZE 9
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bEndpointAddress;
|
||||
#define UE_GET_DIR(a) ((a) & 0x80)
|
||||
#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
|
||||
#define UE_DIR_IN 0x80
|
||||
#define UE_DIR_OUT 0x00
|
||||
#define UE_ADDR 0x0f
|
||||
#define UE_GET_ADDR(a) ((a) & UE_ADDR)
|
||||
uByte bmAttributes;
|
||||
#define UE_XFERTYPE 0x03
|
||||
#define UE_CONTROL 0x00
|
||||
#define UE_ISOCHRONOUS 0x01
|
||||
#define UE_BULK 0x02
|
||||
#define UE_INTERRUPT 0x03
|
||||
#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
|
||||
#define UE_ISO_TYPE 0x0c
|
||||
#define UE_ISO_ASYNC 0x04
|
||||
#define UE_ISO_ADAPT 0x08
|
||||
#define UE_ISO_SYNC 0x0c
|
||||
#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE)
|
||||
uWord wMaxPacketSize;
|
||||
uByte bInterval;
|
||||
} UPACKED usb_endpoint_descriptor_t;
|
||||
#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
|
||||
|
||||
typedef struct ss_endpoint_companion_descriptor {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bMaxBurst;
|
||||
#define USSE_GET_MAX_STREAMS(a) ((a) & 0x1f)
|
||||
#define USSE_SET_MAX_STREAMS(a, b) ((a) | ((b) & 0x1f))
|
||||
#define USSE_GET_MAX_PACKET_NUM(a) ((a) & 0x03)
|
||||
#define USSE_SET_MAX_PACKET_NUM(a, b) ((a) | ((b) & 0x03))
|
||||
uByte bmAttributes;
|
||||
uWord wBytesPerInterval;
|
||||
} UPACKED ss_endpoint_companion_descriptor_t;
|
||||
#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uWord bString[127];
|
||||
} UPACKED usb_string_descriptor_t;
|
||||
#define USB_MAX_STRING_LEN 128
|
||||
#define USB_LANGUAGE_TABLE 0 /* # of the string language id table */
|
||||
|
||||
/* Hub specific request */
|
||||
#define UR_GET_BUS_STATE 0x02
|
||||
#define UR_CLEAR_TT_BUFFER 0x08
|
||||
#define UR_RESET_TT 0x09
|
||||
#define UR_GET_TT_STATE 0x0a
|
||||
#define UR_STOP_TT 0x0b
|
||||
|
||||
/* Hub features */
|
||||
#define UHF_C_HUB_LOCAL_POWER 0
|
||||
#define UHF_C_HUB_OVER_CURRENT 1
|
||||
#define UHF_PORT_CONNECTION 0
|
||||
#define UHF_PORT_ENABLE 1
|
||||
#define UHF_PORT_SUSPEND 2
|
||||
#define UHF_PORT_OVER_CURRENT 3
|
||||
#define UHF_PORT_RESET 4
|
||||
#define UHF_PORT_L1 5
|
||||
#define UHF_PORT_POWER 8
|
||||
#define UHF_PORT_LOW_SPEED 9
|
||||
#define UHF_PORT_HIGH_SPEED 10
|
||||
#define UHF_C_PORT_CONNECTION 16
|
||||
#define UHF_C_PORT_ENABLE 17
|
||||
#define UHF_C_PORT_SUSPEND 18
|
||||
#define UHF_C_PORT_OVER_CURRENT 19
|
||||
#define UHF_C_PORT_RESET 20
|
||||
#define UHF_C_PORT_L1 23
|
||||
#define UHF_PORT_TEST 21
|
||||
#define UHF_PORT_INDICATOR 22
|
||||
|
||||
typedef struct {
|
||||
uByte bDescLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bNbrPorts;
|
||||
uWord wHubCharacteristics;
|
||||
#define UHD_PWR 0x0003
|
||||
#define UHD_PWR_GANGED 0x0000
|
||||
#define UHD_PWR_INDIVIDUAL 0x0001
|
||||
#define UHD_PWR_NO_SWITCH 0x0002
|
||||
#define UHD_COMPOUND 0x0004
|
||||
#define UHD_OC 0x0018
|
||||
#define UHD_OC_GLOBAL 0x0000
|
||||
#define UHD_OC_INDIVIDUAL 0x0008
|
||||
#define UHD_OC_NONE 0x0010
|
||||
#define UHD_TT_THINK 0x0060
|
||||
#define UHD_TT_THINK_8 0x0000
|
||||
#define UHD_TT_THINK_16 0x0020
|
||||
#define UHD_TT_THINK_24 0x0040
|
||||
#define UHD_TT_THINK_32 0x0060
|
||||
#define UHD_PORT_IND 0x0080
|
||||
uByte bPwrOn2PwrGood; /* delay in 2 ms units */
|
||||
#define UHD_PWRON_FACTOR 2
|
||||
uByte bHubContrCurrent;
|
||||
uByte DeviceRemovable[32]; /* max 255 ports */
|
||||
#define UHD_NOT_REMOV(desc, i) \
|
||||
(((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
|
||||
/* deprecated */ uByte PortPowerCtrlMask[1];
|
||||
} UPACKED usb_hub_descriptor_t;
|
||||
#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uWord bcdUSB;
|
||||
uByte bDeviceClass;
|
||||
uByte bDeviceSubClass;
|
||||
uByte bDeviceProtocol;
|
||||
uByte bMaxPacketSize0;
|
||||
uByte bNumConfigurations;
|
||||
uByte bReserved;
|
||||
} UPACKED usb_device_qualifier_t;
|
||||
#define USB_DEVICE_QUALIFIER_SIZE 10
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bmAttributes;
|
||||
#define UOTG_SRP 0x01
|
||||
#define UOTG_HNP 0x02
|
||||
} UPACKED usb_otg_descriptor_t;
|
||||
|
||||
/* OTG feature selectors */
|
||||
#define UOTG_B_HNP_ENABLE 3
|
||||
#define UOTG_A_HNP_SUPPORT 4
|
||||
#define UOTG_A_ALT_HNP_SUPPORT 5
|
||||
|
||||
typedef struct {
|
||||
uWord wStatus;
|
||||
/* Device status flags */
|
||||
#define UDS_SELF_POWERED 0x0001
|
||||
#define UDS_REMOTE_WAKEUP 0x0002
|
||||
/* Endpoint status flags */
|
||||
#define UES_HALT 0x0001
|
||||
} UPACKED usb_status_t;
|
||||
|
||||
typedef struct {
|
||||
uWord wHubStatus;
|
||||
#define UHS_LOCAL_POWER 0x0001
|
||||
#define UHS_OVER_CURRENT 0x0002
|
||||
uWord wHubChange;
|
||||
} UPACKED usb_hub_status_t;
|
||||
|
||||
typedef struct {
|
||||
uWord wPortStatus;
|
||||
#define UPS_CURRENT_CONNECT_STATUS 0x0001
|
||||
#define UPS_PORT_ENABLED 0x0002
|
||||
#define UPS_SUSPEND 0x0004
|
||||
#define UPS_OVERCURRENT_INDICATOR 0x0008
|
||||
#define UPS_RESET 0x0010
|
||||
#define UPS_PORT_POWER 0x0100
|
||||
#define UPS_LOW_SPEED 0x0200
|
||||
#define UPS_HIGH_SPEED 0x0400
|
||||
#define UPS_PORT_TEST 0x0800
|
||||
#define UPS_PORT_INDICATOR 0x1000
|
||||
uWord wPortChange;
|
||||
#define UPS_C_CONNECT_STATUS 0x0001
|
||||
#define UPS_C_PORT_ENABLED 0x0002
|
||||
#define UPS_C_SUSPEND 0x0004
|
||||
#define UPS_C_OVERCURRENT_INDICATOR 0x0008
|
||||
#define UPS_C_PORT_RESET 0x0010
|
||||
} UPACKED usb_port_status_t;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
/* Device class codes */
|
||||
#define UDCLASS_IN_INTERFACE 0x00
|
||||
#define UDCLASS_COMM 0x02
|
||||
#define UDCLASS_HUB 0x09
|
||||
#define UDSUBCLASS_HUB 0x00
|
||||
#define UDPROTO_FSHUB 0x00
|
||||
#define UDPROTO_HSHUBSTT 0x01
|
||||
#define UDPROTO_HSHUBMTT 0x02
|
||||
#define UDCLASS_DIAGNOSTIC 0xdc
|
||||
#define UDCLASS_WIRELESS 0xe0
|
||||
#define UDSUBCLASS_RF 0x01
|
||||
#define UDPROTO_BLUETOOTH 0x01
|
||||
#define UDCLASS_VENDOR 0xff
|
||||
|
||||
/* Interface class codes */
|
||||
#define UICLASS_UNSPEC 0x00
|
||||
|
||||
#define UICLASS_AUDIO 0x01
|
||||
#define UISUBCLASS_AUDIOCONTROL 1
|
||||
#define UISUBCLASS_AUDIOSTREAM 2
|
||||
#define UISUBCLASS_MIDISTREAM 3
|
||||
|
||||
#define UICLASS_CDC 0x02 /* communication */
|
||||
#define UISUBCLASS_DIRECT_LINE_CONTROL_MODEL 1
|
||||
#define UISUBCLASS_ABSTRACT_CONTROL_MODEL 2
|
||||
#define UISUBCLASS_TELEPHONE_CONTROL_MODEL 3
|
||||
#define UISUBCLASS_MULTICHANNEL_CONTROL_MODEL 4
|
||||
#define UISUBCLASS_CAPI_CONTROLMODEL 5
|
||||
#define UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
|
||||
#define UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
|
||||
#define UIPROTO_CDC_AT 1
|
||||
|
||||
#define UICLASS_HID 0x03
|
||||
#define UISUBCLASS_BOOT 1
|
||||
#define UIPROTO_BOOT_KEYBOARD 1
|
||||
|
||||
#define UICLASS_PHYSICAL 0x05
|
||||
|
||||
#define UICLASS_IMAGE 0x06
|
||||
|
||||
#define UICLASS_PRINTER 0x07
|
||||
#define UISUBCLASS_PRINTER 1
|
||||
#define UIPROTO_PRINTER_UNI 1
|
||||
#define UIPROTO_PRINTER_BI 2
|
||||
#define UIPROTO_PRINTER_1284 3
|
||||
|
||||
#define UICLASS_MASS 0x08
|
||||
#define UISUBCLASS_RBC 1
|
||||
#define UISUBCLASS_SFF8020I 2
|
||||
#define UISUBCLASS_QIC157 3
|
||||
#define UISUBCLASS_UFI 4
|
||||
#define UISUBCLASS_SFF8070I 5
|
||||
#define UISUBCLASS_SCSI 6
|
||||
#define UIPROTO_MASS_CBI_I 0
|
||||
#define UIPROTO_MASS_CBI 1
|
||||
#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */
|
||||
#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */
|
||||
|
||||
#define UICLASS_HUB 0x09
|
||||
#define UISUBCLASS_HUB 0
|
||||
#define UIPROTO_FSHUB 0
|
||||
#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
|
||||
#define UIPROTO_HSHUBMTT 1
|
||||
|
||||
#define UICLASS_CDC_DATA 0x0a
|
||||
#define UISUBCLASS_DATA 0
|
||||
#define UIPROTO_DATA_ISDNBRI 0x30 /* Physical iface */
|
||||
#define UIPROTO_DATA_HDLC 0x31 /* HDLC */
|
||||
#define UIPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
|
||||
#define UIPROTO_DATA_Q921M 0x50 /* Management for Q921 */
|
||||
#define UIPROTO_DATA_Q921 0x51 /* Data for Q921 */
|
||||
#define UIPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
|
||||
#define UIPROTO_DATA_V42BIS 0x90 /* Data compression */
|
||||
#define UIPROTO_DATA_Q931 0x91 /* Euro-ISDN */
|
||||
#define UIPROTO_DATA_V120 0x92 /* V.24 rate adaption */
|
||||
#define UIPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
|
||||
#define UIPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
|
||||
#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/
|
||||
#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */
|
||||
|
||||
#define UICLASS_SMARTCARD 0x0b
|
||||
|
||||
/*#define UICLASS_FIRM_UPD 0x0c*/
|
||||
|
||||
#define UICLASS_SECURITY 0x0d
|
||||
|
||||
#define UICLASS_DIAGNOSTIC 0xdc
|
||||
|
||||
#define UICLASS_WIRELESS 0xe0
|
||||
#define UISUBCLASS_RF 0x01
|
||||
#define UIPROTO_BLUETOOTH 0x01
|
||||
|
||||
#define UICLASS_APPL_SPEC 0xfe
|
||||
#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
|
||||
#define UISUBCLASS_IRDA 2
|
||||
#define UIPROTO_IRDA 0
|
||||
|
||||
#define UICLASS_VENDOR 0xff
|
||||
|
||||
#define USB_HUB_MAX_DEPTH 5
|
||||
|
||||
/*
|
||||
* Minimum time a device needs to be powered down to go through
|
||||
* a power cycle. XXX Are these time in the spec?
|
||||
*/
|
||||
#define USB_POWER_DOWN_TIME 200 /* ms */
|
||||
#define USB_PORT_POWER_DOWN_TIME 100 /* ms */
|
||||
|
||||
#if 0
|
||||
/* These are the values from the spec. */
|
||||
#define USB_PORT_RESET_DELAY 10 /* ms */
|
||||
#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
|
||||
#define USB_PORT_RESET_RECOVERY 10 /* ms */
|
||||
#define USB_PORT_POWERUP_DELAY 100 /* ms */
|
||||
#define USB_SET_ADDRESS_SETTLE 2 /* ms */
|
||||
#define USB_RESUME_DELAY (20*5) /* ms */
|
||||
#define USB_RESUME_WAIT 10 /* ms */
|
||||
#define USB_RESUME_RECOVERY 10 /* ms */
|
||||
#define USB_EXTRA_POWER_UP_TIME 0 /* ms */
|
||||
#else
|
||||
/* Allow for marginal (i.e. non-conforming) devices. */
|
||||
#define USB_PORT_RESET_DELAY 50 /* ms */
|
||||
#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
|
||||
#define USB_PORT_RESET_RECOVERY 250 /* ms */
|
||||
#define USB_PORT_POWERUP_DELAY 300 /* ms */
|
||||
#define USB_SET_ADDRESS_SETTLE 10 /* ms */
|
||||
#define USB_RESUME_DELAY (50*5) /* ms */
|
||||
#define USB_RESUME_WAIT 50 /* ms */
|
||||
#define USB_RESUME_RECOVERY 50 /* ms */
|
||||
#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
|
||||
#endif
|
||||
|
||||
#define USB_MIN_POWER 100 /* mA */
|
||||
#define USB_MAX_POWER 500 /* mA */
|
||||
|
||||
#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
|
||||
|
||||
#define USB_UNCONFIG_NO 0
|
||||
#define USB_UNCONFIG_INDEX (-1)
|
||||
|
||||
/*** ioctl() related stuff ***/
|
||||
|
||||
struct usb_ctl_request {
|
||||
int ucr_addr;
|
||||
usb_device_request_t ucr_request;
|
||||
void *ucr_data;
|
||||
int ucr_flags;
|
||||
#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */
|
||||
int ucr_actlen; /* actual length transferred */
|
||||
};
|
||||
|
||||
struct usb_alt_interface {
|
||||
int uai_config_index;
|
||||
int uai_interface_index;
|
||||
int uai_alt_no;
|
||||
};
|
||||
|
||||
#define USB_CURRENT_CONFIG_INDEX (-1)
|
||||
#define USB_CURRENT_ALT_INDEX (-1)
|
||||
|
||||
struct usb_config_desc {
|
||||
int ucd_config_index;
|
||||
usb_config_descriptor_t ucd_desc;
|
||||
};
|
||||
|
||||
struct usb_interface_desc {
|
||||
int uid_config_index;
|
||||
int uid_interface_index;
|
||||
int uid_alt_index;
|
||||
usb_interface_descriptor_t uid_desc;
|
||||
};
|
||||
|
||||
struct usb_endpoint_desc {
|
||||
int ued_config_index;
|
||||
int ued_interface_index;
|
||||
int ued_alt_index;
|
||||
int ued_endpoint_index;
|
||||
usb_endpoint_descriptor_t ued_desc;
|
||||
};
|
||||
|
||||
struct usb_full_desc {
|
||||
int ufd_config_index;
|
||||
u_int ufd_size;
|
||||
u_char *ufd_data;
|
||||
};
|
||||
|
||||
struct usb_string_desc {
|
||||
int usd_string_index;
|
||||
int usd_language_id;
|
||||
usb_string_descriptor_t usd_desc;
|
||||
};
|
||||
|
||||
struct usb_ctl_report_desc {
|
||||
int ucrd_size;
|
||||
u_char ucrd_data[1024]; /* filled data size will vary */
|
||||
};
|
||||
|
||||
typedef struct { u_int32_t cookie; } usb_event_cookie_t;
|
||||
|
||||
#define USB_MAX_DEVNAMES 4
|
||||
#define USB_MAX_DEVNAMELEN 16
|
||||
struct usb_device_info {
|
||||
u_int8_t udi_bus;
|
||||
u_int8_t udi_addr; /* device address */
|
||||
usb_event_cookie_t udi_cookie;
|
||||
char udi_product[USB_MAX_STRING_LEN];
|
||||
char udi_vendor[USB_MAX_STRING_LEN];
|
||||
char udi_release[8];
|
||||
u_int16_t udi_productNo;
|
||||
u_int16_t udi_vendorNo;
|
||||
u_int16_t udi_releaseNo;
|
||||
u_int8_t udi_class;
|
||||
u_int8_t udi_subclass;
|
||||
u_int8_t udi_protocol;
|
||||
u_int8_t udi_config;
|
||||
u_int8_t udi_speed;
|
||||
#define USB_SPEED_UNKNOWN 0
|
||||
#define USB_SPEED_LOW 1
|
||||
#define USB_SPEED_FULL 2
|
||||
#define USB_SPEED_HIGH 3
|
||||
#define USB_SPEED_VARIABLE 4
|
||||
#define USB_SPEED_SUPER 5
|
||||
int udi_power; /* power consumption in mA, 0 if selfpowered */
|
||||
int udi_nports;
|
||||
char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
|
||||
u_int8_t udi_ports[16];/* hub only: addresses of devices on ports */
|
||||
#define USB_PORT_ENABLED 0xff
|
||||
#define USB_PORT_SUSPENDED 0xfe
|
||||
#define USB_PORT_POWERED 0xfd
|
||||
#define USB_PORT_DISABLED 0xfc
|
||||
};
|
||||
|
||||
struct usb_ctl_report {
|
||||
int ucr_report;
|
||||
u_char ucr_data[1024]; /* filled data size will vary */
|
||||
};
|
||||
|
||||
struct usb_device_stats {
|
||||
u_long uds_requests[4]; /* indexed by transfer type UE_* */
|
||||
};
|
||||
|
||||
#define WUSB_MIN_IE 0x80
|
||||
#define WUSB_WCTA_IE 0x80
|
||||
#define WUSB_WCONNECTACK_IE 0x81
|
||||
#define WUSB_WHOSTINFO_IE 0x82
|
||||
#define WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
|
||||
#define WUHI_CA_RECONN 0x00
|
||||
#define WUHI_CA_LIMITED 0x01
|
||||
#define WUHI_CA_ALL 0x03
|
||||
#define WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
|
||||
#define WUSB_WCHCHANGEANNOUNCE_IE 0x83
|
||||
#define WUSB_WDEV_DISCONNECT_IE 0x84
|
||||
#define WUSB_WHOST_DISCONNECT_IE 0x85
|
||||
#define WUSB_WRELEASE_CHANNEL_IE 0x86
|
||||
#define WUSB_WWORK_IE 0x87
|
||||
#define WUSB_WCHANNEL_STOP_IE 0x88
|
||||
#define WUSB_WDEV_KEEPALIVE_IE 0x89
|
||||
#define WUSB_WISOCH_DISCARD_IE 0x8A
|
||||
#define WUSB_WRESETDEVICE_IE 0x8B
|
||||
#define WUSB_WXMIT_PACKET_ADJUST_IE 0x8C
|
||||
#define WUSB_MAX_IE 0x8C
|
||||
|
||||
/* Device Notification Types */
|
||||
|
||||
#define WUSB_DN_MIN 0x01
|
||||
#define WUSB_DN_CONNECT 0x01
|
||||
# define WUSB_DA_OLDCONN 0x00
|
||||
# define WUSB_DA_NEWCONN 0x01
|
||||
# define WUSB_DA_SELF_BEACON 0x02
|
||||
# define WUSB_DA_DIR_BEACON 0x04
|
||||
# define WUSB_DA_NO_BEACON 0x06
|
||||
#define WUSB_DN_DISCONNECT 0x02
|
||||
#define WUSB_DN_EPRDY 0x03
|
||||
#define WUSB_DN_MASAVAILCHANGED 0x04
|
||||
#define WUSB_DN_REMOTEWAKEUP 0x05
|
||||
#define WUSB_DN_SLEEP 0x06
|
||||
#define WUSB_DN_ALIVE 0x07
|
||||
#define WUSB_DN_MAX 0x07
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <pshpack1.h>
|
||||
#endif
|
||||
|
||||
/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */
|
||||
typedef struct wusb_hndshk_data {
|
||||
uByte bMessageNumber;
|
||||
uByte bStatus;
|
||||
uByte tTKID[3];
|
||||
uByte bReserved;
|
||||
uByte CDID[16];
|
||||
uByte Nonce[16];
|
||||
uByte MIC[8];
|
||||
} UPACKED wusb_hndshk_data_t;
|
||||
#define WUSB_HANDSHAKE_LEN_FOR_MIC 38
|
||||
|
||||
/* WUSB Connection Context */
|
||||
typedef struct wusb_conn_context {
|
||||
uByte CHID [16];
|
||||
uByte CDID [16];
|
||||
uByte CK [16];
|
||||
} UPACKED wusb_conn_context_t;
|
||||
|
||||
/* WUSB Security Descriptor */
|
||||
typedef struct wusb_security_desc {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uWord wTotalLength;
|
||||
uByte bNumEncryptionTypes;
|
||||
} UPACKED wusb_security_desc_t;
|
||||
|
||||
/* WUSB Encryption Type Descriptor */
|
||||
typedef struct wusb_encrypt_type_desc {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
|
||||
uByte bEncryptionType;
|
||||
#define WUETD_UNSECURE 0
|
||||
#define WUETD_WIRED 1
|
||||
#define WUETD_CCM_1 2
|
||||
#define WUETD_RSA_1 3
|
||||
|
||||
uByte bEncryptionValue;
|
||||
uByte bAuthKeyIndex;
|
||||
} UPACKED wusb_encrypt_type_desc_t;
|
||||
|
||||
/* WUSB Key Descriptor */
|
||||
typedef struct wusb_key_desc {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte tTKID[3];
|
||||
uByte bReserved;
|
||||
uByte KeyData[1]; /* variable length */
|
||||
} UPACKED wusb_key_desc_t;
|
||||
|
||||
/* WUSB BOS Descriptor (Binary device Object Store) */
|
||||
typedef struct wusb_bos_desc {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uWord wTotalLength;
|
||||
uByte bNumDeviceCaps;
|
||||
} UPACKED wusb_bos_desc_t;
|
||||
|
||||
#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02
|
||||
typedef struct usb_dev_cap_20_ext_desc {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bDevCapabilityType;
|
||||
#define USB_20_EXT_LPM 0x02
|
||||
uDWord bmAttributes;
|
||||
} UPACKED usb_dev_cap_20_ext_desc_t;
|
||||
|
||||
#define USB_DEVICE_CAPABILITY_SS_USB 0x03
|
||||
typedef struct usb_dev_cap_ss_usb {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bDevCapabilityType;
|
||||
#define USB_DC_SS_USB_LTM_CAPABLE 0x02
|
||||
uByte bmAttributes;
|
||||
#define USB_DC_SS_USB_SPEED_SUPPORT_LOW 0x01
|
||||
#define USB_DC_SS_USB_SPEED_SUPPORT_FULL 0x02
|
||||
#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH 0x04
|
||||
#define USB_DC_SS_USB_SPEED_SUPPORT_SS 0x08
|
||||
uWord wSpeedsSupported;
|
||||
uByte bFunctionalitySupport;
|
||||
uByte bU1DevExitLat;
|
||||
uWord wU2DevExitLat;
|
||||
} UPACKED usb_dev_cap_ss_usb_t;
|
||||
|
||||
#define USB_DEVICE_CAPABILITY_CONTAINER_ID 0x04
|
||||
typedef struct usb_dev_cap_container_id {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bDevCapabilityType;
|
||||
uByte bReserved;
|
||||
uByte containerID[16];
|
||||
} UPACKED usb_dev_cap_container_id_t;
|
||||
|
||||
/* Device Capability Type Codes */
|
||||
#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
|
||||
|
||||
/* Device Capability Descriptor */
|
||||
typedef struct wusb_dev_cap_desc {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bDevCapabilityType;
|
||||
uByte caps[1]; /* Variable length */
|
||||
} UPACKED wusb_dev_cap_desc_t;
|
||||
|
||||
/* Device Capability Descriptor */
|
||||
typedef struct wusb_dev_cap_uwb_desc {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bDevCapabilityType;
|
||||
uByte bmAttributes;
|
||||
uWord wPHYRates; /* Bitmap */
|
||||
uByte bmTFITXPowerInfo;
|
||||
uByte bmFFITXPowerInfo;
|
||||
uWord bmBandGroup;
|
||||
uByte bReserved;
|
||||
} UPACKED wusb_dev_cap_uwb_desc_t;
|
||||
|
||||
/* Wireless USB Endpoint Companion Descriptor */
|
||||
typedef struct wusb_endpoint_companion_desc {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bMaxBurst;
|
||||
uByte bMaxSequence;
|
||||
uWord wMaxStreamDelay;
|
||||
uWord wOverTheAirPacketSize;
|
||||
uByte bOverTheAirInterval;
|
||||
uByte bmCompAttributes;
|
||||
} UPACKED wusb_endpoint_companion_desc_t;
|
||||
|
||||
/* Wireless USB Numeric Association M1 Data Structure */
|
||||
typedef struct wusb_m1_data {
|
||||
uByte version;
|
||||
uWord langId;
|
||||
uByte deviceFriendlyNameLength;
|
||||
uByte sha_256_m3[32];
|
||||
uByte deviceFriendlyName[256];
|
||||
} UPACKED wusb_m1_data_t;
|
||||
|
||||
typedef struct wusb_m2_data {
|
||||
uByte version;
|
||||
uWord langId;
|
||||
uByte hostFriendlyNameLength;
|
||||
uByte pkh[384];
|
||||
uByte hostFriendlyName[256];
|
||||
} UPACKED wusb_m2_data_t;
|
||||
|
||||
typedef struct wusb_m3_data {
|
||||
uByte pkd[384];
|
||||
uByte nd;
|
||||
} UPACKED wusb_m3_data_t;
|
||||
|
||||
typedef struct wusb_m4_data {
|
||||
uDWord _attributeTypeIdAndLength_1;
|
||||
uWord associationTypeId;
|
||||
|
||||
uDWord _attributeTypeIdAndLength_2;
|
||||
uWord associationSubTypeId;
|
||||
|
||||
uDWord _attributeTypeIdAndLength_3;
|
||||
uDWord length;
|
||||
|
||||
uDWord _attributeTypeIdAndLength_4;
|
||||
uDWord associationStatus;
|
||||
|
||||
uDWord _attributeTypeIdAndLength_5;
|
||||
uByte chid[16];
|
||||
|
||||
uDWord _attributeTypeIdAndLength_6;
|
||||
uByte cdid[16];
|
||||
|
||||
uDWord _attributeTypeIdAndLength_7;
|
||||
uByte bandGroups[2];
|
||||
} UPACKED wusb_m4_data_t;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _USB_H_ */
|
||||
85
drivers/usb/host/dwc_otg/Makefile
Normal file
85
drivers/usb/host/dwc_otg/Makefile
Normal file
@@ -0,0 +1,85 @@
|
||||
#
|
||||
# Makefile for DWC_otg Highspeed USB controller driver
|
||||
#
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
# Use the BUS_INTERFACE variable to compile the software for either
|
||||
# PCI(PCI_INTERFACE) or LM(LM_INTERFACE) bus.
|
||||
ifeq ($(BUS_INTERFACE),)
|
||||
# BUS_INTERFACE = -DPCI_INTERFACE
|
||||
# BUS_INTERFACE = -DLM_INTERFACE
|
||||
BUS_INTERFACE = -DPLATFORM_INTERFACE
|
||||
endif
|
||||
|
||||
#ccflags-y += -DDEBUG
|
||||
#ccflags-y += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs
|
||||
|
||||
# Use one of the following flags to compile the software in host-only or
|
||||
# device-only mode.
|
||||
#ccflags-y += -DDWC_HOST_ONLY
|
||||
#ccflags-y += -DDWC_DEVICE_ONLY
|
||||
|
||||
ccflags-y += -Dlinux -DDWC_HS_ELECT_TST
|
||||
#ccflags-y += -DDWC_EN_ISOC
|
||||
ccflags-y += -I$(srctree)/drivers/usb/host/dwc_common_port
|
||||
#ccflags-y += -I$(PORTLIB)
|
||||
ccflags-y += -DDWC_LINUX
|
||||
ccflags-y += $(CFI)
|
||||
ccflags-y += $(BUS_INTERFACE)
|
||||
#ccflags-y += -DDWC_DEV_SRPCAP
|
||||
|
||||
obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o
|
||||
|
||||
dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o
|
||||
dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
|
||||
dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
|
||||
dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o
|
||||
dwc_otg-objs += dwc_otg_adp.o
|
||||
dwc_otg-objs += dwc_otg_fiq_fsm.o
|
||||
ifneq ($(CONFIG_ARM64),y)
|
||||
dwc_otg-objs += dwc_otg_fiq_stub.o
|
||||
endif
|
||||
|
||||
ifneq ($(CFI),)
|
||||
dwc_otg-objs += dwc_otg_cfi.o
|
||||
endif
|
||||
|
||||
kernrelwd := $(subst ., ,$(KERNELRELEASE))
|
||||
kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
|
||||
|
||||
ifneq ($(kernrel3),2.6.20)
|
||||
ccflags-y += $(CPPFLAGS)
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
PWD := $(shell pwd)
|
||||
PORTLIB := $(PWD)/../dwc_common_port
|
||||
|
||||
# Command paths
|
||||
CTAGS := $(CTAGS)
|
||||
DOXYGEN := $(DOXYGEN)
|
||||
|
||||
default: portlib
|
||||
$(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
|
||||
|
||||
install: default
|
||||
$(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install
|
||||
$(MAKE) -C$(KDIR) M=$(PWD) modules_install
|
||||
|
||||
portlib:
|
||||
$(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
|
||||
cp $(PORTLIB)/Module.symvers $(PWD)/
|
||||
|
||||
docs: $(wildcard *.[hc]) doc/doxygen.cfg
|
||||
$(DOXYGEN) doc/doxygen.cfg
|
||||
|
||||
tags: $(wildcard *.[hc])
|
||||
$(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
|
||||
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers
|
||||
|
||||
endif
|
||||
224
drivers/usb/host/dwc_otg/doc/doxygen.cfg
Normal file
224
drivers/usb/host/dwc_otg/doc/doxygen.cfg
Normal file
@@ -0,0 +1,224 @@
|
||||
# Doxyfile 1.3.9.1
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = "DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver"
|
||||
PROJECT_NUMBER = v3.00a
|
||||
OUTPUT_DIRECTORY = ./doc/
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SUBGROUPING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = NO
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = .
|
||||
FILE_PATTERNS = *.c \
|
||||
*.h \
|
||||
./linux/*.c \
|
||||
./linux/*.h
|
||||
RECURSIVE = NO
|
||||
EXCLUDE = ./test/ \
|
||||
./dwc_otg/.AppleDouble/
|
||||
EXCLUDE_SYMLINKS = YES
|
||||
EXCLUDE_PATTERNS = *.mod.*
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = YES
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = DEVICE_ATTR DWC_EN_ISOC
|
||||
EXPAND_AS_DEFINED = DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW DWC_OTG_DEVICE_ATTR_BITFIELD_STORE DWC_OTG_DEVICE_ATTR_BITFIELD_RW DWC_OTG_DEVICE_ATTR_BITFIELD_RO DWC_OTG_DEVICE_ATTR_REG_SHOW DWC_OTG_DEVICE_ATTR_REG_STORE DWC_OTG_DEVICE_ATTR_REG32_RW DWC_OTG_DEVICE_ATTR_REG32_RO DWC_EN_ISOC
|
||||
SKIP_FUNCTION_MACROS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
||||
1574
drivers/usb/host/dwc_otg/dummy_audio.c
Normal file
1574
drivers/usb/host/dwc_otg/dummy_audio.c
Normal file
File diff suppressed because it is too large
Load Diff
142
drivers/usb/host/dwc_otg/dwc_cfi_common.h
Normal file
142
drivers/usb/host/dwc_otg/dwc_cfi_common.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/* ==========================================================================
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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(__DWC_CFI_COMMON_H__)
|
||||
#define __DWC_CFI_COMMON_H__
|
||||
|
||||
//#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* This file contains the CFI specific common constants, interfaces
|
||||
* (functions and macros) and structures for Linux. No PCD specific
|
||||
* data structure or definition is to be included in this file.
|
||||
*
|
||||
*/
|
||||
|
||||
/** This is a request for all Core Features */
|
||||
#define VEN_CORE_GET_FEATURES 0xB1
|
||||
|
||||
/** This is a request to get the value of a specific Core Feature */
|
||||
#define VEN_CORE_GET_FEATURE 0xB2
|
||||
|
||||
/** This command allows the host to set the value of a specific Core Feature */
|
||||
#define VEN_CORE_SET_FEATURE 0xB3
|
||||
|
||||
/** This command allows the host to set the default values of
|
||||
* either all or any specific Core Feature
|
||||
*/
|
||||
#define VEN_CORE_RESET_FEATURES 0xB4
|
||||
|
||||
/** This command forces the PCD to write the deferred values of a Core Features */
|
||||
#define VEN_CORE_ACTIVATE_FEATURES 0xB5
|
||||
|
||||
/** This request reads a DWORD value from a register at the specified offset */
|
||||
#define VEN_CORE_READ_REGISTER 0xB6
|
||||
|
||||
/** This request writes a DWORD value into a register at the specified offset */
|
||||
#define VEN_CORE_WRITE_REGISTER 0xB7
|
||||
|
||||
/** This structure is the header of the Core Features dataset returned to
|
||||
* the Host
|
||||
*/
|
||||
struct cfi_all_features_header {
|
||||
/** The features header structure length is */
|
||||
#define CFI_ALL_FEATURES_HDR_LEN 8
|
||||
/**
|
||||
* The total length of the features dataset returned to the Host
|
||||
*/
|
||||
uint16_t wTotalLen;
|
||||
|
||||
/**
|
||||
* CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
|
||||
* This field identifies the version of the CFI Specification with which
|
||||
* the device is compliant.
|
||||
*/
|
||||
uint16_t wVersion;
|
||||
|
||||
/** The ID of the Core */
|
||||
uint16_t wCoreID;
|
||||
#define CFI_CORE_ID_UDC 1
|
||||
#define CFI_CORE_ID_OTG 2
|
||||
#define CFI_CORE_ID_WUDEV 3
|
||||
|
||||
/** Number of features returned by VEN_CORE_GET_FEATURES request */
|
||||
uint16_t wNumFeatures;
|
||||
} UPACKED;
|
||||
|
||||
typedef struct cfi_all_features_header cfi_all_features_header_t;
|
||||
|
||||
/** This structure is a header of the Core Feature descriptor dataset returned to
|
||||
* the Host after the VEN_CORE_GET_FEATURES request
|
||||
*/
|
||||
struct cfi_feature_desc_header {
|
||||
#define CFI_FEATURE_DESC_HDR_LEN 8
|
||||
|
||||
/** The feature ID */
|
||||
uint16_t wFeatureID;
|
||||
|
||||
/** Length of this feature descriptor in bytes - including the
|
||||
* length of the feature name string
|
||||
*/
|
||||
uint16_t wLength;
|
||||
|
||||
/** The data length of this feature in bytes */
|
||||
uint16_t wDataLength;
|
||||
|
||||
/**
|
||||
* Attributes of this features
|
||||
* D0: Access rights
|
||||
* 0 - Read/Write
|
||||
* 1 - Read only
|
||||
*/
|
||||
uint8_t bmAttributes;
|
||||
#define CFI_FEATURE_ATTR_RO 1
|
||||
#define CFI_FEATURE_ATTR_RW 0
|
||||
|
||||
/** Length of the feature name in bytes */
|
||||
uint8_t bNameLen;
|
||||
|
||||
/** The feature name buffer */
|
||||
//uint8_t *name;
|
||||
} UPACKED;
|
||||
|
||||
typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
|
||||
|
||||
/**
|
||||
* This structure describes a NULL terminated string referenced by its id field.
|
||||
* It is very similar to usb_string structure but has the id field type set to 16-bit.
|
||||
*/
|
||||
struct cfi_string {
|
||||
uint16_t id;
|
||||
const uint8_t *s;
|
||||
};
|
||||
typedef struct cfi_string cfi_string_t;
|
||||
|
||||
#endif
|
||||
854
drivers/usb/host/dwc_otg/dwc_otg_adp.c
Normal file
854
drivers/usb/host/dwc_otg/dwc_otg_adp.c
Normal file
@@ -0,0 +1,854 @@
|
||||
/* ==========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
|
||||
* $Revision: #12 $
|
||||
* $Date: 2011/10/26 $
|
||||
* $Change: 1873028 $
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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 "dwc_os.h"
|
||||
#include "dwc_otg_regs.h"
|
||||
#include "dwc_otg_cil.h"
|
||||
#include "dwc_otg_adp.h"
|
||||
|
||||
/** @file
|
||||
*
|
||||
* This file contains the most of the Attach Detect Protocol implementation for
|
||||
* the driver to support OTG Rev2.0.
|
||||
*
|
||||
*/
|
||||
|
||||
void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
|
||||
{
|
||||
adpctl_data_t adpctl;
|
||||
|
||||
adpctl.d32 = value;
|
||||
adpctl.b.ar = 0x2;
|
||||
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
|
||||
|
||||
while (adpctl.b.ar) {
|
||||
adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Function is called to read ADP registers
|
||||
*/
|
||||
uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
adpctl_data_t adpctl;
|
||||
|
||||
adpctl.d32 = 0;
|
||||
adpctl.b.ar = 0x1;
|
||||
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
|
||||
|
||||
while (adpctl.b.ar) {
|
||||
adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
|
||||
}
|
||||
|
||||
return adpctl.d32;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function is called to read ADPCTL register and filter Write-clear bits
|
||||
*/
|
||||
uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
adpctl_data_t adpctl;
|
||||
|
||||
adpctl.d32 = dwc_otg_adp_read_reg(core_if);
|
||||
adpctl.b.adp_tmout_int = 0;
|
||||
adpctl.b.adp_prb_int = 0;
|
||||
adpctl.b.adp_tmout_int = 0;
|
||||
|
||||
return adpctl.d32;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function is called to write ADP registers
|
||||
*/
|
||||
void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
|
||||
uint32_t set)
|
||||
{
|
||||
dwc_otg_adp_write_reg(core_if,
|
||||
(dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
|
||||
}
|
||||
|
||||
static void adp_sense_timeout(void *ptr)
|
||||
{
|
||||
dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
|
||||
core_if->adp.sense_timer_started = 0;
|
||||
DWC_PRINTF("ADP SENSE TIMEOUT\n");
|
||||
if (core_if->adp_enable) {
|
||||
dwc_otg_adp_sense_stop(core_if);
|
||||
dwc_otg_adp_probe_start(core_if);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when the ADP vbus timer expires. Timeout is 1.1s.
|
||||
*/
|
||||
static void adp_vbuson_timeout(void *ptr)
|
||||
{
|
||||
gpwrdn_data_t gpwrdn;
|
||||
dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
|
||||
hprt0_data_t hprt0 = {.d32 = 0 };
|
||||
pcgcctl_data_t pcgcctl = {.d32 = 0 };
|
||||
DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
|
||||
if (core_if) {
|
||||
core_if->adp.vbuson_timer_started = 0;
|
||||
/* Turn off vbus */
|
||||
hprt0.b.prtpwr = 1;
|
||||
DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
|
||||
gpwrdn.d32 = 0;
|
||||
|
||||
/* Power off the core */
|
||||
if (core_if->power_down == 2) {
|
||||
/* Enable Wakeup Logic */
|
||||
// gpwrdn.b.wkupactiv = 1;
|
||||
gpwrdn.b.pmuactv = 0;
|
||||
gpwrdn.b.pwrdnrstn = 1;
|
||||
gpwrdn.b.pwrdnclmp = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
|
||||
gpwrdn.d32);
|
||||
|
||||
/* Suspend the Phy Clock */
|
||||
pcgcctl.b.stoppclk = 1;
|
||||
DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
|
||||
|
||||
/* Switch on VDD */
|
||||
// gpwrdn.b.wkupactiv = 1;
|
||||
gpwrdn.b.pmuactv = 1;
|
||||
gpwrdn.b.pwrdnrstn = 1;
|
||||
gpwrdn.b.pwrdnclmp = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
|
||||
gpwrdn.d32);
|
||||
} else {
|
||||
/* Enable Power Down Logic */
|
||||
gpwrdn.b.pmuintsel = 1;
|
||||
gpwrdn.b.pmuactv = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
|
||||
}
|
||||
|
||||
/* Power off the core */
|
||||
if (core_if->power_down == 2) {
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.pwrdnswtch = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
|
||||
gpwrdn.d32, 0);
|
||||
}
|
||||
|
||||
/* Unmask SRP detected interrupt from Power Down Logic */
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.srp_det_msk = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
|
||||
|
||||
dwc_otg_adp_probe_start(core_if);
|
||||
dwc_otg_dump_global_registers(core_if);
|
||||
dwc_otg_dump_host_registers(core_if);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the ADP Initial Probe timer to detect if Port Connected interrupt is
|
||||
* not asserted within 1.1 seconds.
|
||||
*
|
||||
* @param core_if the pointer to core_if strucure.
|
||||
*/
|
||||
void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
core_if->adp.vbuson_timer_started = 1;
|
||||
if (core_if->adp.vbuson_timer)
|
||||
{
|
||||
DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
|
||||
/* 1.1 secs + 60ms necessary for cil_hcd_start*/
|
||||
DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
|
||||
} else {
|
||||
DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Masks all DWC OTG core interrupts
|
||||
*
|
||||
*/
|
||||
static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
int i;
|
||||
gahbcfg_data_t ahbcfg = {.d32 = 0 };
|
||||
|
||||
/* Mask Host Interrupts */
|
||||
|
||||
/* Clear and disable HCINTs */
|
||||
for (i = 0; i < core_if->core_params->host_channels; i++) {
|
||||
DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
|
||||
DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
|
||||
|
||||
}
|
||||
|
||||
/* Clear and disable HAINT */
|
||||
DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
|
||||
DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
|
||||
|
||||
/* Mask Device Interrupts */
|
||||
if (!core_if->multiproc_int_enable) {
|
||||
/* Clear and disable IN Endpoint interrupts */
|
||||
DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
|
||||
for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
|
||||
DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
|
||||
diepint, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
/* Clear and disable OUT Endpoint interrupts */
|
||||
DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
|
||||
for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
|
||||
DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
|
||||
doepint, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
/* Clear and disable DAINT */
|
||||
DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
|
||||
0xFFFFFFFF);
|
||||
DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
|
||||
} else {
|
||||
for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
|
||||
DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
|
||||
diepeachintmsk[i], 0);
|
||||
DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
|
||||
diepint, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
|
||||
DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
|
||||
doepeachintmsk[i], 0);
|
||||
DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
|
||||
doepint, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
|
||||
0);
|
||||
DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
|
||||
0xFFFFFFFF);
|
||||
|
||||
}
|
||||
|
||||
/* Disable interrupts */
|
||||
ahbcfg.b.glblintrmsk = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
|
||||
|
||||
/* Disable all interrupts. */
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
|
||||
|
||||
/* Clear any pending interrupts */
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
|
||||
|
||||
/* Clear any pending OTG Interrupts */
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmask Port Connection Detected interrupt
|
||||
*
|
||||
*/
|
||||
static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
|
||||
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Starts the ADP Probing
|
||||
*
|
||||
* @param core_if the pointer to core_if structure.
|
||||
*/
|
||||
uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
|
||||
adpctl_data_t adpctl = {.d32 = 0};
|
||||
gpwrdn_data_t gpwrdn;
|
||||
#if 0
|
||||
adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
|
||||
.b.adp_sns_int = 1, b.adp_tmout_int};
|
||||
#endif
|
||||
dwc_otg_disable_global_interrupts(core_if);
|
||||
DWC_PRINTF("ADP Probe Start\n");
|
||||
core_if->adp.probe_enabled = 1;
|
||||
|
||||
adpctl.b.adpres = 1;
|
||||
dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
|
||||
while (adpctl.b.adpres) {
|
||||
adpctl.d32 = dwc_otg_adp_read_reg(core_if);
|
||||
}
|
||||
|
||||
adpctl.d32 = 0;
|
||||
gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
|
||||
|
||||
/* In Host mode unmask SRP detected interrupt */
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.sts_chngint_msk = 1;
|
||||
if (!gpwrdn.b.idsts) {
|
||||
gpwrdn.b.srp_det_msk = 1;
|
||||
}
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
|
||||
|
||||
adpctl.b.adp_tmout_int_msk = 1;
|
||||
adpctl.b.adp_prb_int_msk = 1;
|
||||
adpctl.b.prb_dschg = 1;
|
||||
adpctl.b.prb_delta = 1;
|
||||
adpctl.b.prb_per = 1;
|
||||
adpctl.b.adpen = 1;
|
||||
adpctl.b.enaprb = 1;
|
||||
|
||||
dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
DWC_PRINTF("ADP Probe Finish\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted
|
||||
* within 3 seconds.
|
||||
*
|
||||
* @param core_if the pointer to core_if strucure.
|
||||
*/
|
||||
void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
core_if->adp.sense_timer_started = 1;
|
||||
DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the ADP Sense
|
||||
*
|
||||
* @param core_if the pointer to core_if strucure.
|
||||
*/
|
||||
uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
adpctl_data_t adpctl;
|
||||
|
||||
DWC_PRINTF("ADP Sense Start\n");
|
||||
|
||||
/* Unmask ADP sense interrupt and mask all other from the core */
|
||||
adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
|
||||
adpctl.b.adp_sns_int_msk = 1;
|
||||
dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
dwc_otg_disable_global_interrupts(core_if); // vahrama
|
||||
|
||||
/* Set ADP reset bit*/
|
||||
adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
|
||||
adpctl.b.adpres = 1;
|
||||
dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
|
||||
while (adpctl.b.adpres) {
|
||||
adpctl.d32 = dwc_otg_adp_read_reg(core_if);
|
||||
}
|
||||
|
||||
adpctl.b.adpres = 0;
|
||||
adpctl.b.adpen = 1;
|
||||
adpctl.b.enasns = 1;
|
||||
dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
|
||||
dwc_otg_adp_sense_timer_start(core_if);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the ADP Probing
|
||||
*
|
||||
* @param core_if the pointer to core_if strucure.
|
||||
*/
|
||||
uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
|
||||
adpctl_data_t adpctl;
|
||||
DWC_PRINTF("Stop ADP probe\n");
|
||||
core_if->adp.probe_enabled = 0;
|
||||
core_if->adp.probe_counter = 0;
|
||||
adpctl.d32 = dwc_otg_adp_read_reg(core_if);
|
||||
|
||||
adpctl.b.adpen = 0;
|
||||
adpctl.b.adp_prb_int = 1;
|
||||
adpctl.b.adp_tmout_int = 1;
|
||||
adpctl.b.adp_sns_int = 1;
|
||||
dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the ADP Sensing
|
||||
*
|
||||
* @param core_if the pointer to core_if strucure.
|
||||
*/
|
||||
uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
adpctl_data_t adpctl;
|
||||
|
||||
core_if->adp.sense_enabled = 0;
|
||||
|
||||
adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
|
||||
adpctl.b.enasns = 0;
|
||||
adpctl.b.adp_sns_int = 1;
|
||||
dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to turn on the VBUS after initial ADP probe in host mode.
|
||||
* If port power was already enabled in cil_hcd_start function then
|
||||
* only schedule a timer.
|
||||
*
|
||||
* @param core_if the pointer to core_if structure.
|
||||
*/
|
||||
void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
hprt0_data_t hprt0 = {.d32 = 0 };
|
||||
hprt0.d32 = dwc_otg_read_hprt0(core_if);
|
||||
DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
|
||||
|
||||
if (hprt0.b.prtpwr == 0) {
|
||||
hprt0.b.prtpwr = 1;
|
||||
//DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
|
||||
}
|
||||
|
||||
dwc_otg_adp_vbuson_timer_start(core_if);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called right after driver is loaded
|
||||
* to perform initial actions for ADP
|
||||
*
|
||||
* @param core_if the pointer to core_if structure.
|
||||
* @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
|
||||
*/
|
||||
void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
|
||||
{
|
||||
gpwrdn_data_t gpwrdn;
|
||||
|
||||
DWC_PRINTF("ADP Initial Start\n");
|
||||
core_if->adp.adp_started = 1;
|
||||
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
|
||||
dwc_otg_disable_global_interrupts(core_if);
|
||||
if (is_host) {
|
||||
DWC_PRINTF("HOST MODE\n");
|
||||
/* Enable Power Down Logic Interrupt*/
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.pmuintsel = 1;
|
||||
gpwrdn.b.pmuactv = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
|
||||
/* Initialize first ADP probe to obtain Ramp Time value */
|
||||
core_if->adp.initial_probe = 1;
|
||||
dwc_otg_adp_probe_start(core_if);
|
||||
} else {
|
||||
gotgctl_data_t gotgctl;
|
||||
gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
|
||||
DWC_PRINTF("DEVICE MODE\n");
|
||||
if (gotgctl.b.bsesvld == 0) {
|
||||
/* Enable Power Down Logic Interrupt*/
|
||||
gpwrdn.d32 = 0;
|
||||
DWC_PRINTF("VBUS is not valid - start ADP probe\n");
|
||||
gpwrdn.b.pmuintsel = 1;
|
||||
gpwrdn.b.pmuactv = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
|
||||
core_if->adp.initial_probe = 1;
|
||||
dwc_otg_adp_probe_start(core_if);
|
||||
} else {
|
||||
DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
|
||||
core_if->op_state = B_PERIPHERAL;
|
||||
dwc_otg_core_init(core_if);
|
||||
dwc_otg_enable_global_interrupts(core_if);
|
||||
cil_pcd_start(core_if);
|
||||
dwc_otg_dump_global_registers(core_if);
|
||||
dwc_otg_dump_dev_registers(core_if);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
core_if->adp.adp_started = 0;
|
||||
core_if->adp.initial_probe = 0;
|
||||
core_if->adp.probe_timer_values[0] = -1;
|
||||
core_if->adp.probe_timer_values[1] = -1;
|
||||
core_if->adp.probe_enabled = 0;
|
||||
core_if->adp.sense_enabled = 0;
|
||||
core_if->adp.sense_timer_started = 0;
|
||||
core_if->adp.vbuson_timer_started = 0;
|
||||
core_if->adp.probe_counter = 0;
|
||||
core_if->adp.gpwrdn = 0;
|
||||
core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
|
||||
/* Initialize timers */
|
||||
core_if->adp.sense_timer =
|
||||
DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
|
||||
core_if->adp.vbuson_timer =
|
||||
DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
|
||||
if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
|
||||
{
|
||||
DWC_ERROR("Could not allocate memory for ADP timers\n");
|
||||
}
|
||||
}
|
||||
|
||||
void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
gpwrdn_data_t gpwrdn = { .d32 = 0 };
|
||||
gpwrdn.b.pmuintsel = 1;
|
||||
gpwrdn.b.pmuactv = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
|
||||
|
||||
if (core_if->adp.probe_enabled)
|
||||
dwc_otg_adp_probe_stop(core_if);
|
||||
if (core_if->adp.sense_enabled)
|
||||
dwc_otg_adp_sense_stop(core_if);
|
||||
if (core_if->adp.sense_timer_started)
|
||||
DWC_TIMER_CANCEL(core_if->adp.sense_timer);
|
||||
if (core_if->adp.vbuson_timer_started)
|
||||
DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
|
||||
DWC_TIMER_FREE(core_if->adp.sense_timer);
|
||||
DWC_TIMER_FREE(core_if->adp.vbuson_timer);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////// ADP Interrupt Handlers ///////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* This function sets Ramp Timer values
|
||||
*/
|
||||
static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
|
||||
{
|
||||
if (core_if->adp.probe_timer_values[0] == -1) {
|
||||
core_if->adp.probe_timer_values[0] = val;
|
||||
core_if->adp.probe_timer_values[1] = -1;
|
||||
return 1;
|
||||
} else {
|
||||
core_if->adp.probe_timer_values[1] =
|
||||
core_if->adp.probe_timer_values[0];
|
||||
core_if->adp.probe_timer_values[0] = val;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function compares Ramp Timer values
|
||||
*/
|
||||
static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
uint32_t diff;
|
||||
if (core_if->adp.probe_timer_values[0]>=core_if->adp.probe_timer_values[1])
|
||||
diff = core_if->adp.probe_timer_values[0]-core_if->adp.probe_timer_values[1];
|
||||
else
|
||||
diff = core_if->adp.probe_timer_values[1]-core_if->adp.probe_timer_values[0];
|
||||
if(diff < 2) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles ADP Probe Interrupts
|
||||
*/
|
||||
static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
|
||||
uint32_t val)
|
||||
{
|
||||
adpctl_data_t adpctl = {.d32 = 0 };
|
||||
gpwrdn_data_t gpwrdn, temp;
|
||||
adpctl.d32 = val;
|
||||
|
||||
temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
|
||||
core_if->adp.probe_counter++;
|
||||
core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
|
||||
if (adpctl.b.rtim == 0 && !temp.b.idsts){
|
||||
DWC_PRINTF("RTIM value is 0\n");
|
||||
goto exit;
|
||||
}
|
||||
if (set_timer_value(core_if, adpctl.b.rtim) &&
|
||||
core_if->adp.initial_probe) {
|
||||
core_if->adp.initial_probe = 0;
|
||||
dwc_otg_adp_probe_stop(core_if);
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.pmuactv = 1;
|
||||
gpwrdn.b.pmuintsel = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
|
||||
|
||||
/* check which value is for device mode and which for Host mode */
|
||||
if (!temp.b.idsts) { /* considered host mode value is 0 */
|
||||
/*
|
||||
* Turn on VBUS after initial ADP probe.
|
||||
*/
|
||||
core_if->op_state = A_HOST;
|
||||
dwc_otg_enable_global_interrupts(core_if);
|
||||
DWC_SPINUNLOCK(core_if->lock);
|
||||
cil_hcd_start(core_if);
|
||||
dwc_otg_adp_turnon_vbus(core_if);
|
||||
DWC_SPINLOCK(core_if->lock);
|
||||
} else {
|
||||
/*
|
||||
* Initiate SRP after initial ADP probe.
|
||||
*/
|
||||
dwc_otg_enable_global_interrupts(core_if);
|
||||
dwc_otg_initiate_srp(core_if);
|
||||
}
|
||||
} else if (core_if->adp.probe_counter > 2){
|
||||
gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
|
||||
if (compare_timer_values(core_if)) {
|
||||
DWC_PRINTF("Difference in timer values !!! \n");
|
||||
// core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
|
||||
dwc_otg_adp_probe_stop(core_if);
|
||||
|
||||
/* Power on the core */
|
||||
if (core_if->power_down == 2) {
|
||||
gpwrdn.b.pwrdnswtch = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->
|
||||
gpwrdn, 0, gpwrdn.d32);
|
||||
}
|
||||
|
||||
/* check which value is for device mode and which for Host mode */
|
||||
if (!temp.b.idsts) { /* considered host mode value is 0 */
|
||||
/* Disable Interrupt from Power Down Logic */
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.pmuintsel = 1;
|
||||
gpwrdn.b.pmuactv = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->
|
||||
gpwrdn, gpwrdn.d32, 0);
|
||||
|
||||
/*
|
||||
* Initialize the Core for Host mode.
|
||||
*/
|
||||
core_if->op_state = A_HOST;
|
||||
dwc_otg_core_init(core_if);
|
||||
dwc_otg_enable_global_interrupts(core_if);
|
||||
cil_hcd_start(core_if);
|
||||
} else {
|
||||
gotgctl_data_t gotgctl;
|
||||
/* Mask SRP detected interrupt from Power Down Logic */
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.srp_det_msk = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->
|
||||
gpwrdn, gpwrdn.d32, 0);
|
||||
|
||||
/* Disable Power Down Logic */
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.pmuintsel = 1;
|
||||
gpwrdn.b.pmuactv = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->
|
||||
gpwrdn, gpwrdn.d32, 0);
|
||||
|
||||
/*
|
||||
* Initialize the Core for Device mode.
|
||||
*/
|
||||
core_if->op_state = B_PERIPHERAL;
|
||||
dwc_otg_core_init(core_if);
|
||||
dwc_otg_enable_global_interrupts(core_if);
|
||||
cil_pcd_start(core_if);
|
||||
|
||||
gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
|
||||
if (!gotgctl.b.bsesvld) {
|
||||
dwc_otg_initiate_srp(core_if);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (core_if->power_down == 2) {
|
||||
if (gpwrdn.b.bsessvld) {
|
||||
/* Mask SRP detected interrupt from Power Down Logic */
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.srp_det_msk = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
|
||||
|
||||
/* Disable Power Down Logic */
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.pmuactv = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
|
||||
|
||||
/*
|
||||
* Initialize the Core for Device mode.
|
||||
*/
|
||||
core_if->op_state = B_PERIPHERAL;
|
||||
dwc_otg_core_init(core_if);
|
||||
dwc_otg_enable_global_interrupts(core_if);
|
||||
cil_pcd_start(core_if);
|
||||
}
|
||||
}
|
||||
}
|
||||
exit:
|
||||
/* Clear interrupt */
|
||||
adpctl.d32 = dwc_otg_adp_read_reg(core_if);
|
||||
adpctl.b.adp_prb_int = 1;
|
||||
dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function hadles ADP Sense Interrupt
|
||||
*/
|
||||
static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
adpctl_data_t adpctl;
|
||||
/* Stop ADP Sense timer */
|
||||
DWC_TIMER_CANCEL(core_if->adp.sense_timer);
|
||||
|
||||
/* Restart ADP Sense timer */
|
||||
dwc_otg_adp_sense_timer_start(core_if);
|
||||
|
||||
/* Clear interrupt */
|
||||
adpctl.d32 = dwc_otg_adp_read_reg(core_if);
|
||||
adpctl.b.adp_sns_int = 1;
|
||||
dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles ADP Probe Interrupts
|
||||
*/
|
||||
static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
|
||||
uint32_t val)
|
||||
{
|
||||
adpctl_data_t adpctl = {.d32 = 0 };
|
||||
adpctl.d32 = val;
|
||||
set_timer_value(core_if, adpctl.b.rtim);
|
||||
|
||||
/* Clear interrupt */
|
||||
adpctl.d32 = dwc_otg_adp_read_reg(core_if);
|
||||
adpctl.b.adp_tmout_int = 1;
|
||||
dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ADP Interrupt handler.
|
||||
*
|
||||
*/
|
||||
int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
int retval = 0;
|
||||
adpctl_data_t adpctl = {.d32 = 0};
|
||||
|
||||
adpctl.d32 = dwc_otg_adp_read_reg(core_if);
|
||||
DWC_PRINTF("ADPCTL = %08x\n",adpctl.d32);
|
||||
|
||||
if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
|
||||
DWC_PRINTF("ADP Sense interrupt\n");
|
||||
retval |= dwc_otg_adp_handle_sns_intr(core_if);
|
||||
}
|
||||
if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
|
||||
DWC_PRINTF("ADP timeout interrupt\n");
|
||||
retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
|
||||
}
|
||||
if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
|
||||
DWC_PRINTF("ADP Probe interrupt\n");
|
||||
adpctl.b.adp_prb_int = 1;
|
||||
retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
|
||||
}
|
||||
|
||||
// dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
|
||||
//dwc_otg_adp_write_reg(core_if, adpctl.d32);
|
||||
DWC_PRINTF("RETURN FROM ADP ISR\n");
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param core_if Programming view of DWC_otg controller.
|
||||
*/
|
||||
int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
|
||||
#ifndef DWC_HOST_ONLY
|
||||
hprt0_data_t hprt0;
|
||||
gpwrdn_data_t gpwrdn;
|
||||
DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
|
||||
|
||||
gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
|
||||
/* check which value is for device mode and which for Host mode */
|
||||
if (!gpwrdn.b.idsts) { /* considered host mode value is 0 */
|
||||
DWC_PRINTF("SRP: Host mode\n");
|
||||
|
||||
if (core_if->adp_enable) {
|
||||
dwc_otg_adp_probe_stop(core_if);
|
||||
|
||||
/* Power on the core */
|
||||
if (core_if->power_down == 2) {
|
||||
gpwrdn.b.pwrdnswtch = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->
|
||||
gpwrdn, 0, gpwrdn.d32);
|
||||
}
|
||||
|
||||
core_if->op_state = A_HOST;
|
||||
dwc_otg_core_init(core_if);
|
||||
dwc_otg_enable_global_interrupts(core_if);
|
||||
cil_hcd_start(core_if);
|
||||
}
|
||||
|
||||
/* Turn on the port power bit. */
|
||||
hprt0.d32 = dwc_otg_read_hprt0(core_if);
|
||||
hprt0.b.prtpwr = 1;
|
||||
DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
|
||||
|
||||
/* Start the Connection timer. So a message can be displayed
|
||||
* if connect does not occur within 10 seconds. */
|
||||
cil_hcd_session_start(core_if);
|
||||
} else {
|
||||
DWC_PRINTF("SRP: Device mode %s\n", __FUNCTION__);
|
||||
if (core_if->adp_enable) {
|
||||
dwc_otg_adp_probe_stop(core_if);
|
||||
|
||||
/* Power on the core */
|
||||
if (core_if->power_down == 2) {
|
||||
gpwrdn.b.pwrdnswtch = 1;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->
|
||||
gpwrdn, 0, gpwrdn.d32);
|
||||
}
|
||||
|
||||
gpwrdn.d32 = 0;
|
||||
gpwrdn.b.pmuactv = 0;
|
||||
DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
|
||||
gpwrdn.d32);
|
||||
|
||||
core_if->op_state = B_PERIPHERAL;
|
||||
dwc_otg_core_init(core_if);
|
||||
dwc_otg_enable_global_interrupts(core_if);
|
||||
cil_pcd_start(core_if);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
80
drivers/usb/host/dwc_otg/dwc_otg_adp.h
Normal file
80
drivers/usb/host/dwc_otg/dwc_otg_adp.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* ==========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.h $
|
||||
* $Revision: #7 $
|
||||
* $Date: 2011/10/24 $
|
||||
* $Change: 1871159 $
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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 __DWC_OTG_ADP_H__
|
||||
#define __DWC_OTG_ADP_H__
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* This file contains the Attach Detect Protocol interfaces and defines
|
||||
* (functions) and structures for Linux.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DWC_OTG_ADP_UNATTACHED 0
|
||||
#define DWC_OTG_ADP_ATTACHED 1
|
||||
#define DWC_OTG_ADP_UNKOWN 2
|
||||
|
||||
typedef struct dwc_otg_adp {
|
||||
uint32_t adp_started;
|
||||
uint32_t initial_probe;
|
||||
int32_t probe_timer_values[2];
|
||||
uint32_t probe_enabled;
|
||||
uint32_t sense_enabled;
|
||||
dwc_timer_t *sense_timer;
|
||||
uint32_t sense_timer_started;
|
||||
dwc_timer_t *vbuson_timer;
|
||||
uint32_t vbuson_timer_started;
|
||||
uint32_t attached;
|
||||
uint32_t probe_counter;
|
||||
uint32_t gpwrdn;
|
||||
} dwc_otg_adp_t;
|
||||
|
||||
/**
|
||||
* Attach Detect Protocol functions
|
||||
*/
|
||||
|
||||
extern void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value);
|
||||
extern uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if);
|
||||
extern uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if);
|
||||
extern uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if);
|
||||
extern uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if);
|
||||
extern uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if);
|
||||
extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
|
||||
extern void dwc_otg_adp_init(dwc_otg_core_if_t * core_if);
|
||||
extern void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if);
|
||||
extern int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if);
|
||||
extern int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if);
|
||||
|
||||
#endif //__DWC_OTG_ADP_H__
|
||||
1212
drivers/usb/host/dwc_otg/dwc_otg_attr.c
Normal file
1212
drivers/usb/host/dwc_otg/dwc_otg_attr.c
Normal file
File diff suppressed because it is too large
Load Diff
89
drivers/usb/host/dwc_otg/dwc_otg_attr.h
Normal file
89
drivers/usb/host/dwc_otg/dwc_otg_attr.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* ==========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
|
||||
* $Revision: #13 $
|
||||
* $Date: 2010/06/21 $
|
||||
* $Change: 1532021 $
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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(__DWC_OTG_ATTR_H__)
|
||||
#define __DWC_OTG_ATTR_H__
|
||||
|
||||
/** @file
|
||||
* This file contains the interface to the Linux device attributes.
|
||||
*/
|
||||
extern struct device_attribute dev_attr_regoffset;
|
||||
extern struct device_attribute dev_attr_regvalue;
|
||||
|
||||
extern struct device_attribute dev_attr_mode;
|
||||
extern struct device_attribute dev_attr_hnpcapable;
|
||||
extern struct device_attribute dev_attr_srpcapable;
|
||||
extern struct device_attribute dev_attr_hnp;
|
||||
extern struct device_attribute dev_attr_srp;
|
||||
extern struct device_attribute dev_attr_buspower;
|
||||
extern struct device_attribute dev_attr_bussuspend;
|
||||
extern struct device_attribute dev_attr_mode_ch_tim_en;
|
||||
extern struct device_attribute dev_attr_fr_interval;
|
||||
extern struct device_attribute dev_attr_busconnected;
|
||||
extern struct device_attribute dev_attr_gotgctl;
|
||||
extern struct device_attribute dev_attr_gusbcfg;
|
||||
extern struct device_attribute dev_attr_grxfsiz;
|
||||
extern struct device_attribute dev_attr_gnptxfsiz;
|
||||
extern struct device_attribute dev_attr_gpvndctl;
|
||||
extern struct device_attribute dev_attr_ggpio;
|
||||
extern struct device_attribute dev_attr_guid;
|
||||
extern struct device_attribute dev_attr_gsnpsid;
|
||||
extern struct device_attribute dev_attr_devspeed;
|
||||
extern struct device_attribute dev_attr_enumspeed;
|
||||
extern struct device_attribute dev_attr_hptxfsiz;
|
||||
extern struct device_attribute dev_attr_hprt0;
|
||||
#ifdef CONFIG_USB_DWC_OTG_LPM
|
||||
extern struct device_attribute dev_attr_lpm_response;
|
||||
extern struct device_attribute devi_attr_sleep_status;
|
||||
#endif
|
||||
|
||||
void dwc_otg_attr_create(
|
||||
#ifdef LM_INTERFACE
|
||||
struct lm_device *dev
|
||||
#elif defined(PCI_INTERFACE)
|
||||
struct pci_dev *dev
|
||||
#elif defined(PLATFORM_INTERFACE)
|
||||
struct platform_device *dev
|
||||
#endif
|
||||
);
|
||||
|
||||
void dwc_otg_attr_remove(
|
||||
#ifdef LM_INTERFACE
|
||||
struct lm_device *dev
|
||||
#elif defined(PCI_INTERFACE)
|
||||
struct pci_dev *dev
|
||||
#elif defined(PLATFORM_INTERFACE)
|
||||
struct platform_device *dev
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
1876
drivers/usb/host/dwc_otg/dwc_otg_cfi.c
Normal file
1876
drivers/usb/host/dwc_otg/dwc_otg_cfi.c
Normal file
File diff suppressed because it is too large
Load Diff
320
drivers/usb/host/dwc_otg/dwc_otg_cfi.h
Normal file
320
drivers/usb/host/dwc_otg/dwc_otg_cfi.h
Normal file
@@ -0,0 +1,320 @@
|
||||
/* ==========================================================================
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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(__DWC_OTG_CFI_H__)
|
||||
#define __DWC_OTG_CFI_H__
|
||||
|
||||
#include "dwc_otg_pcd.h"
|
||||
#include "dwc_cfi_common.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file contains the CFI related OTG PCD specific common constants,
|
||||
* interfaces(functions and macros) and data structures.The CFI Protocol is an
|
||||
* optional interface for internal testing purposes that a DUT may implement to
|
||||
* support testing of configurable features.
|
||||
*
|
||||
*/
|
||||
|
||||
struct dwc_otg_pcd;
|
||||
struct dwc_otg_pcd_ep;
|
||||
|
||||
/** OTG CFI Features (properties) ID constants */
|
||||
/** This is a request for all Core Features */
|
||||
#define FT_ID_DMA_MODE 0x0001
|
||||
#define FT_ID_DMA_BUFFER_SETUP 0x0002
|
||||
#define FT_ID_DMA_BUFF_ALIGN 0x0003
|
||||
#define FT_ID_DMA_CONCAT_SETUP 0x0004
|
||||
#define FT_ID_DMA_CIRCULAR 0x0005
|
||||
#define FT_ID_THRESHOLD_SETUP 0x0006
|
||||
#define FT_ID_DFIFO_DEPTH 0x0007
|
||||
#define FT_ID_TX_FIFO_DEPTH 0x0008
|
||||
#define FT_ID_RX_FIFO_DEPTH 0x0009
|
||||
|
||||
/**********************************************************/
|
||||
#define CFI_INFO_DEF
|
||||
|
||||
#ifdef CFI_INFO_DEF
|
||||
#define CFI_INFO(fmt...) DWC_PRINTF("CFI: " fmt);
|
||||
#else
|
||||
#define CFI_INFO(fmt...)
|
||||
#endif
|
||||
|
||||
#define min(x,y) ({ \
|
||||
x < y ? x : y; })
|
||||
|
||||
#define max(x,y) ({ \
|
||||
x > y ? x : y; })
|
||||
|
||||
/**
|
||||
* Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
|
||||
* also used for setting up a buffer for Circular DDMA.
|
||||
*/
|
||||
struct _ddma_sg_buffer_setup {
|
||||
#define BS_SG_VAL_DESC_LEN 6
|
||||
/* The OUT EP address */
|
||||
uint8_t bOutEndpointAddress;
|
||||
/* The IN EP address */
|
||||
uint8_t bInEndpointAddress;
|
||||
/* Number of bytes to put between transfer segments (must be DWORD boundaries) */
|
||||
uint8_t bOffset;
|
||||
/* The number of transfer segments (a DMA descriptors per each segment) */
|
||||
uint8_t bCount;
|
||||
/* Size (in byte) of each transfer segment */
|
||||
uint16_t wSize;
|
||||
} __attribute__ ((packed));
|
||||
typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
|
||||
|
||||
/** Descriptor DMA Concatenation Buffer setup structure */
|
||||
struct _ddma_concat_buffer_setup_hdr {
|
||||
#define BS_CONCAT_VAL_HDR_LEN 4
|
||||
/* The endpoint for which the buffer is to be set up */
|
||||
uint8_t bEndpointAddress;
|
||||
/* The count of descriptors to be used */
|
||||
uint8_t bDescCount;
|
||||
/* The total size of the transfer */
|
||||
uint16_t wSize;
|
||||
} __attribute__ ((packed));
|
||||
typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
|
||||
|
||||
/** Descriptor DMA Concatenation Buffer setup structure */
|
||||
struct _ddma_concat_buffer_setup {
|
||||
/* The SG header */
|
||||
ddma_concat_buffer_setup_hdr_t hdr;
|
||||
|
||||
/* The XFER sizes pointer (allocated dynamically) */
|
||||
uint16_t *wTxBytes;
|
||||
} __attribute__ ((packed));
|
||||
typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
|
||||
|
||||
/** Descriptor DMA Alignment Buffer setup structure */
|
||||
struct _ddma_align_buffer_setup {
|
||||
#define BS_ALIGN_VAL_HDR_LEN 2
|
||||
uint8_t bEndpointAddress;
|
||||
uint8_t bAlign;
|
||||
} __attribute__ ((packed));
|
||||
typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
|
||||
|
||||
/** Transmit FIFO Size setup structure */
|
||||
struct _tx_fifo_size_setup {
|
||||
uint8_t bEndpointAddress;
|
||||
uint16_t wDepth;
|
||||
} __attribute__ ((packed));
|
||||
typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
|
||||
|
||||
/** Transmit FIFO Size setup structure */
|
||||
struct _rx_fifo_size_setup {
|
||||
uint16_t wDepth;
|
||||
} __attribute__ ((packed));
|
||||
typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
|
||||
|
||||
/**
|
||||
* struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
|
||||
* This structure encapsulates the standard usb_ctrlrequest and adds a pointer
|
||||
* to the data returned in the data stage of a 3-stage Control Write requests.
|
||||
*/
|
||||
struct cfi_usb_ctrlrequest {
|
||||
uint8_t bRequestType;
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
uint8_t *data;
|
||||
} UPACKED;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
|
||||
* This structure is used to store the buffer setup data for any
|
||||
* enabled endpoint in the PCD.
|
||||
*/
|
||||
struct cfi_ep {
|
||||
/* Entry for the list container */
|
||||
dwc_list_link_t lh;
|
||||
/* Pointer to the active PCD endpoint structure */
|
||||
struct dwc_otg_pcd_ep *ep;
|
||||
/* The last descriptor in the chain of DMA descriptors of the endpoint */
|
||||
struct dwc_otg_dma_desc *dma_desc_last;
|
||||
/* The SG feature value */
|
||||
ddma_sg_buffer_setup_t *bm_sg;
|
||||
/* The Circular feature value */
|
||||
ddma_sg_buffer_setup_t *bm_circ;
|
||||
/* The Concatenation feature value */
|
||||
ddma_concat_buffer_setup_t *bm_concat;
|
||||
/* The Alignment feature value */
|
||||
ddma_align_buffer_setup_t *bm_align;
|
||||
/* XFER length */
|
||||
uint32_t xfer_len;
|
||||
/*
|
||||
* Count of DMA descriptors currently used.
|
||||
* The total should not exceed the MAX_DMA_DESCS_PER_EP value
|
||||
* defined in the dwc_otg_cil.h
|
||||
*/
|
||||
uint32_t desc_count;
|
||||
};
|
||||
typedef struct cfi_ep cfi_ep_t;
|
||||
|
||||
typedef struct cfi_dma_buff {
|
||||
#define CFI_IN_BUF_LEN 1024
|
||||
#define CFI_OUT_BUF_LEN 1024
|
||||
dma_addr_t addr;
|
||||
uint8_t *buf;
|
||||
} cfi_dma_buff_t;
|
||||
|
||||
struct cfiobject;
|
||||
|
||||
/**
|
||||
* This is the interface for the CFI operations.
|
||||
*
|
||||
* @param ep_enable Called when any endpoint is enabled and activated.
|
||||
* @param release Called when the CFI object is released and it needs to correctly
|
||||
* deallocate the dynamic memory
|
||||
* @param ctrl_write_complete Called when the data stage of the request is complete
|
||||
*/
|
||||
typedef struct cfi_ops {
|
||||
int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
|
||||
struct dwc_otg_pcd_ep * ep);
|
||||
void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
|
||||
struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
|
||||
unsigned size, gfp_t flags);
|
||||
void (*release) (struct cfiobject * cfi);
|
||||
int (*ctrl_write_complete) (struct cfiobject * cfi,
|
||||
struct dwc_otg_pcd * pcd);
|
||||
void (*build_descriptors) (struct cfiobject * cfi,
|
||||
struct dwc_otg_pcd * pcd,
|
||||
struct dwc_otg_pcd_ep * ep,
|
||||
dwc_otg_pcd_request_t * req);
|
||||
} cfi_ops_t;
|
||||
|
||||
struct cfiobject {
|
||||
cfi_ops_t ops;
|
||||
struct dwc_otg_pcd *pcd;
|
||||
struct usb_gadget *gadget;
|
||||
|
||||
/* Buffers used to send/receive CFI-related request data */
|
||||
cfi_dma_buff_t buf_in;
|
||||
cfi_dma_buff_t buf_out;
|
||||
|
||||
/* CFI specific Control request wrapper */
|
||||
struct cfi_usb_ctrlrequest ctrl_req;
|
||||
|
||||
/* The list of active EP's in the PCD of type cfi_ep_t */
|
||||
dwc_list_link_t active_eps;
|
||||
|
||||
/* This flag shall control the propagation of a specific request
|
||||
* to the gadget's processing routines.
|
||||
* 0 - no gadget handling
|
||||
* 1 - the gadget needs to know about this request (w/o completing a status
|
||||
* phase - just return a 0 to the _setup callback)
|
||||
*/
|
||||
uint8_t need_gadget_att;
|
||||
|
||||
/* Flag indicating whether the status IN phase needs to be
|
||||
* completed by the PCD
|
||||
*/
|
||||
uint8_t need_status_in_complete;
|
||||
};
|
||||
typedef struct cfiobject cfiobject_t;
|
||||
|
||||
#define DUMP_MSG
|
||||
|
||||
#if defined(DUMP_MSG)
|
||||
static inline void dump_msg(const u8 * buf, unsigned int length)
|
||||
{
|
||||
unsigned int start, num, i;
|
||||
char line[52], *p;
|
||||
|
||||
if (length >= 512)
|
||||
return;
|
||||
|
||||
start = 0;
|
||||
while (length > 0) {
|
||||
num = min(length, 16u);
|
||||
p = line;
|
||||
for (i = 0; i < num; ++i) {
|
||||
if (i == 8)
|
||||
*p++ = ' ';
|
||||
DWC_SPRINTF(p, " %02x", buf[i]);
|
||||
p += 3;
|
||||
}
|
||||
*p = 0;
|
||||
DWC_DEBUG("%6x: %s\n", start, line);
|
||||
buf += num;
|
||||
start += num;
|
||||
length -= num;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void dump_msg(const u8 * buf, unsigned int length)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function returns a pointer to cfi_ep_t object with the addr address.
|
||||
*/
|
||||
static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
|
||||
uint8_t addr)
|
||||
{
|
||||
struct cfi_ep *pcfiep;
|
||||
dwc_list_link_t *tmp;
|
||||
|
||||
DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
|
||||
pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
|
||||
|
||||
if (pcfiep->ep->desc->bEndpointAddress == addr) {
|
||||
return pcfiep;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns a pointer to cfi_ep_t object that matches
|
||||
* the dwc_otg_pcd_ep object.
|
||||
*/
|
||||
static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
|
||||
struct dwc_otg_pcd_ep *ep)
|
||||
{
|
||||
struct cfi_ep *pcfiep = NULL;
|
||||
dwc_list_link_t *tmp;
|
||||
|
||||
DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
|
||||
pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
|
||||
if (pcfiep->ep == ep) {
|
||||
return pcfiep;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
|
||||
|
||||
#endif /* (__DWC_OTG_CFI_H__) */
|
||||
7146
drivers/usb/host/dwc_otg/dwc_otg_cil.c
Normal file
7146
drivers/usb/host/dwc_otg/dwc_otg_cil.c
Normal file
File diff suppressed because it is too large
Load Diff
1464
drivers/usb/host/dwc_otg/dwc_otg_cil.h
Normal file
1464
drivers/usb/host/dwc_otg/dwc_otg_cil.h
Normal file
File diff suppressed because it is too large
Load Diff
1601
drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
Normal file
1601
drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
Normal file
File diff suppressed because it is too large
Load Diff
705
drivers/usb/host/dwc_otg/dwc_otg_core_if.h
Normal file
705
drivers/usb/host/dwc_otg/dwc_otg_core_if.h
Normal file
@@ -0,0 +1,705 @@
|
||||
/* ==========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
|
||||
* $Revision: #13 $
|
||||
* $Date: 2012/08/10 $
|
||||
* $Change: 2047372 $
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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(__DWC_CORE_IF_H__)
|
||||
#define __DWC_CORE_IF_H__
|
||||
|
||||
#include "dwc_os.h"
|
||||
|
||||
/** @file
|
||||
* This file defines DWC_OTG Core API
|
||||
*/
|
||||
|
||||
struct dwc_otg_core_if;
|
||||
typedef struct dwc_otg_core_if dwc_otg_core_if_t;
|
||||
|
||||
/** Maximum number of Periodic FIFOs */
|
||||
#define MAX_PERIO_FIFOS 15
|
||||
/** Maximum number of Periodic FIFOs */
|
||||
#define MAX_TX_FIFOS 15
|
||||
|
||||
/** Maximum number of Endpoints/HostChannels */
|
||||
#define MAX_EPS_CHANNELS 16
|
||||
|
||||
extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
|
||||
extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
|
||||
extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
|
||||
|
||||
extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
|
||||
extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
|
||||
|
||||
extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
|
||||
extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
|
||||
|
||||
extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/** This function should be called on every hardware interrupt. */
|
||||
extern int32_t dwc_otg_handle_common_intr(void *otg_dev);
|
||||
|
||||
/** @name OTG Core Parameters */
|
||||
/** @{ */
|
||||
|
||||
/**
|
||||
* Specifies the OTG capabilities. The driver will automatically
|
||||
* detect the value for this parameter if none is specified.
|
||||
* 0 - HNP and SRP capable (default)
|
||||
* 1 - SRP Only capable
|
||||
* 2 - No HNP/SRP capable
|
||||
*/
|
||||
extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
|
||||
#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
|
||||
#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
|
||||
#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
|
||||
#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
|
||||
|
||||
extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_opt_default 1
|
||||
|
||||
/**
|
||||
* Specifies whether to use slave or DMA mode for accessing the data
|
||||
* FIFOs. The driver will automatically detect the value for this
|
||||
* parameter if none is specified.
|
||||
* 0 - Slave
|
||||
* 1 - DMA (default, if available)
|
||||
*/
|
||||
extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_dma_enable_default 1
|
||||
|
||||
/**
|
||||
* When DMA mode is enabled specifies whether to use
|
||||
* address DMA or DMA Descritor mode for accessing the data
|
||||
* FIFOs in device mode. The driver will automatically detect
|
||||
* the value for this parameter if none is specified.
|
||||
* 0 - address DMA
|
||||
* 1 - DMA Descriptor(default, if available)
|
||||
*/
|
||||
extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
|
||||
//#define dwc_param_dma_desc_enable_default 1
|
||||
#define dwc_param_dma_desc_enable_default 0 // Broadcom BCM2708
|
||||
|
||||
/** The DMA Burst size (applicable only for External DMA
|
||||
* Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
|
||||
*/
|
||||
extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_dma_burst_size_default 32
|
||||
|
||||
/**
|
||||
* Specifies the maximum speed of operation in host and device mode.
|
||||
* The actual speed depends on the speed of the attached device and
|
||||
* the value of phy_type. The actual speed depends on the speed of the
|
||||
* attached device.
|
||||
* 0 - High Speed (default)
|
||||
* 1 - Full Speed
|
||||
*/
|
||||
extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_speed_default 0
|
||||
#define DWC_SPEED_PARAM_HIGH 0
|
||||
#define DWC_SPEED_PARAM_FULL 1
|
||||
|
||||
/** Specifies whether low power mode is supported when attached
|
||||
* to a Full Speed or Low Speed device in host mode.
|
||||
* 0 - Don't support low power mode (default)
|
||||
* 1 - Support low power mode
|
||||
*/
|
||||
extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
|
||||
core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
|
||||
* core_if);
|
||||
#define dwc_param_host_support_fs_ls_low_power_default 0
|
||||
|
||||
/** Specifies the PHY clock rate in low power mode when connected to a
|
||||
* Low Speed device in host mode. This parameter is applicable only if
|
||||
* HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
|
||||
* then defaults to 6 MHZ otherwise 48 MHZ.
|
||||
*
|
||||
* 0 - 48 MHz
|
||||
* 1 - 6 MHz
|
||||
*/
|
||||
extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
|
||||
core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
|
||||
core_if);
|
||||
#define dwc_param_host_ls_low_power_phy_clk_default 0
|
||||
#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
|
||||
#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
|
||||
|
||||
/**
|
||||
* 0 - Use cC FIFO size parameters
|
||||
* 1 - Allow dynamic FIFO sizing (default)
|
||||
*/
|
||||
extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
|
||||
core_if);
|
||||
#define dwc_param_enable_dynamic_fifo_default 1
|
||||
|
||||
/** Total number of 4-byte words in the data FIFO memory. This
|
||||
* memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
|
||||
* Tx FIFOs.
|
||||
* 32 to 32768 (default 8192)
|
||||
* Note: The total FIFO memory depth in the FPGA configuration is 8192.
|
||||
*/
|
||||
extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
|
||||
//#define dwc_param_data_fifo_size_default 8192
|
||||
#define dwc_param_data_fifo_size_default 0xFF0 // Broadcom BCM2708
|
||||
|
||||
/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
|
||||
* FIFO sizing is enabled.
|
||||
* 16 to 32768 (default 1064)
|
||||
*/
|
||||
extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_dev_rx_fifo_size_default 1064
|
||||
|
||||
/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
|
||||
* when dynamic FIFO sizing is enabled.
|
||||
* 16 to 32768 (default 1024)
|
||||
*/
|
||||
extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
|
||||
core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
|
||||
core_if);
|
||||
#define dwc_param_dev_nperio_tx_fifo_size_default 1024
|
||||
|
||||
/** Number of 4-byte words in each of the periodic Tx FIFOs in device
|
||||
* mode when dynamic FIFO sizing is enabled.
|
||||
* 4 to 768 (default 256)
|
||||
*/
|
||||
extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
|
||||
int32_t val, int fifo_num);
|
||||
extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
|
||||
core_if, int fifo_num);
|
||||
#define dwc_param_dev_perio_tx_fifo_size_default 256
|
||||
|
||||
/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
|
||||
* FIFO sizing is enabled.
|
||||
* 16 to 32768 (default 1024)
|
||||
*/
|
||||
extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
|
||||
//#define dwc_param_host_rx_fifo_size_default 1024
|
||||
#define dwc_param_host_rx_fifo_size_default 774 // Broadcom BCM2708
|
||||
|
||||
/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
|
||||
* when Dynamic FIFO sizing is enabled in the core.
|
||||
* 16 to 32768 (default 1024)
|
||||
*/
|
||||
extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
|
||||
core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
|
||||
core_if);
|
||||
//#define dwc_param_host_nperio_tx_fifo_size_default 1024
|
||||
#define dwc_param_host_nperio_tx_fifo_size_default 0x100 // Broadcom BCM2708
|
||||
|
||||
/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
|
||||
* FIFO sizing is enabled.
|
||||
* 16 to 32768 (default 1024)
|
||||
*/
|
||||
extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
|
||||
core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
|
||||
core_if);
|
||||
//#define dwc_param_host_perio_tx_fifo_size_default 1024
|
||||
#define dwc_param_host_perio_tx_fifo_size_default 0x200 // Broadcom BCM2708
|
||||
|
||||
/** The maximum transfer size supported in bytes.
|
||||
* 2047 to 65,535 (default 65,535)
|
||||
*/
|
||||
extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_max_transfer_size_default 65535
|
||||
|
||||
/** The maximum number of packets in a transfer.
|
||||
* 15 to 511 (default 511)
|
||||
*/
|
||||
extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_max_packet_count_default 511
|
||||
|
||||
/** The number of host channel registers to use.
|
||||
* 1 to 16 (default 12)
|
||||
* Note: The FPGA configuration supports a maximum of 12 host channels.
|
||||
*/
|
||||
extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
|
||||
//#define dwc_param_host_channels_default 12
|
||||
#define dwc_param_host_channels_default 8 // Broadcom BCM2708
|
||||
|
||||
/** The number of endpoints in addition to EP0 available for device
|
||||
* mode operations.
|
||||
* 1 to 15 (default 6 IN and OUT)
|
||||
* Note: The FPGA configuration supports a maximum of 6 IN and OUT
|
||||
* endpoints in addition to EP0.
|
||||
*/
|
||||
extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_dev_endpoints_default 6
|
||||
|
||||
/**
|
||||
* Specifies the type of PHY interface to use. By default, the driver
|
||||
* will automatically detect the phy_type.
|
||||
*
|
||||
* 0 - Full Speed PHY
|
||||
* 1 - UTMI+ (default)
|
||||
* 2 - ULPI
|
||||
*/
|
||||
extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
|
||||
#define DWC_PHY_TYPE_PARAM_FS 0
|
||||
#define DWC_PHY_TYPE_PARAM_UTMI 1
|
||||
#define DWC_PHY_TYPE_PARAM_ULPI 2
|
||||
#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
|
||||
|
||||
/**
|
||||
* Specifies the UTMI+ Data Width. This parameter is
|
||||
* applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
|
||||
* PHY_TYPE, this parameter indicates the data width between
|
||||
* the MAC and the ULPI Wrapper.) Also, this parameter is
|
||||
* applicable only if the OTG_HSPHY_WIDTH cC parameter was set
|
||||
* to "8 and 16 bits", meaning that the core has been
|
||||
* configured to work at either data path width.
|
||||
*
|
||||
* 8 or 16 bits (default 16)
|
||||
*/
|
||||
extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
|
||||
//#define dwc_param_phy_utmi_width_default 16
|
||||
#define dwc_param_phy_utmi_width_default 8 // Broadcom BCM2708
|
||||
|
||||
/**
|
||||
* Specifies whether the ULPI operates at double or single
|
||||
* data rate. This parameter is only applicable if PHY_TYPE is
|
||||
* ULPI.
|
||||
*
|
||||
* 0 - single data rate ULPI interface with 8 bit wide data
|
||||
* bus (default)
|
||||
* 1 - double data rate ULPI interface with 4 bit wide data
|
||||
* bus
|
||||
*/
|
||||
extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_phy_ulpi_ddr_default 0
|
||||
|
||||
/**
|
||||
* Specifies whether to use the internal or external supply to
|
||||
* drive the vbus with a ULPI phy.
|
||||
*/
|
||||
extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
|
||||
#define DWC_PHY_ULPI_INTERNAL_VBUS 0
|
||||
#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
|
||||
#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
|
||||
|
||||
/**
|
||||
* Specifies whether to use the I2Cinterface for full speed PHY. This
|
||||
* parameter is only applicable if PHY_TYPE is FS.
|
||||
* 0 - No (default)
|
||||
* 1 - Yes
|
||||
*/
|
||||
extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_i2c_enable_default 0
|
||||
|
||||
extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_ulpi_fs_ls_default 0
|
||||
|
||||
extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_ts_dline_default 0
|
||||
|
||||
/**
|
||||
* Specifies whether dedicated transmit FIFOs are
|
||||
* enabled for non periodic IN endpoints in device mode
|
||||
* 0 - No
|
||||
* 1 - Yes
|
||||
*/
|
||||
extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
|
||||
core_if);
|
||||
#define dwc_param_en_multiple_tx_fifo_default 1
|
||||
|
||||
/** Number of 4-byte words in each of the Tx FIFOs in device
|
||||
* mode when dynamic FIFO sizing is enabled.
|
||||
* 4 to 768 (default 256)
|
||||
*/
|
||||
extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
|
||||
int fifo_num, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
|
||||
int fifo_num);
|
||||
#define dwc_param_dev_tx_fifo_size_default 768
|
||||
|
||||
/** Thresholding enable flag-
|
||||
* bit 0 - enable non-ISO Tx thresholding
|
||||
* bit 1 - enable ISO Tx thresholding
|
||||
* bit 2 - enable Rx thresholding
|
||||
*/
|
||||
extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
|
||||
#define dwc_param_thr_ctl_default 0
|
||||
|
||||
/** Thresholding length for Tx
|
||||
* FIFOs in 32 bit DWORDs
|
||||
*/
|
||||
extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_tx_thr_length_default 64
|
||||
|
||||
/** Thresholding length for Rx
|
||||
* FIFOs in 32 bit DWORDs
|
||||
*/
|
||||
extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_rx_thr_length_default 64
|
||||
|
||||
/**
|
||||
* Specifies whether LPM (Link Power Management) support is enabled
|
||||
*/
|
||||
extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_lpm_enable_default 1
|
||||
|
||||
/**
|
||||
* Specifies whether PTI enhancement is enabled
|
||||
*/
|
||||
extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_pti_enable_default 0
|
||||
|
||||
/**
|
||||
* Specifies whether MPI enhancement is enabled
|
||||
*/
|
||||
extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_mpi_enable_default 0
|
||||
|
||||
/**
|
||||
* Specifies whether ADP capability is enabled
|
||||
*/
|
||||
extern int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_adp_enable_default 0
|
||||
|
||||
/**
|
||||
* Specifies whether IC_USB capability is enabled
|
||||
*/
|
||||
|
||||
extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_ic_usb_cap_default 0
|
||||
|
||||
extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_ahb_thr_ratio_default 0
|
||||
|
||||
extern int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_power_down_default 0
|
||||
|
||||
extern int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_reload_ctl_default 0
|
||||
|
||||
extern int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_dev_out_nak_default 0
|
||||
|
||||
extern int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_cont_on_bna_default 0
|
||||
|
||||
extern int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if,
|
||||
int32_t val);
|
||||
extern int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_ahb_single_default 0
|
||||
|
||||
extern int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val);
|
||||
extern int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if);
|
||||
#define dwc_param_otg_ver_default 0
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name Access to registers and bit-fields */
|
||||
|
||||
/**
|
||||
* Dump core registers and SPRAM
|
||||
*/
|
||||
extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
|
||||
extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
|
||||
extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
|
||||
extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
|
||||
|
||||
/**
|
||||
* Get host negotiation status.
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Get srp status
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Set hnpreq bit in the GOTGCTL register.
|
||||
*/
|
||||
extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Get Content of SNPSID register.
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Get current mode.
|
||||
* Returns 0 if in device mode, and 1 if in host mode.
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Get value of hnpcapable field in the GUSBCFG register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
|
||||
/**
|
||||
* Set value of hnpcapable field in the GUSBCFG register
|
||||
*/
|
||||
extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Get value of srpcapable field in the GUSBCFG register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
|
||||
/**
|
||||
* Set value of srpcapable field in the GUSBCFG register
|
||||
*/
|
||||
extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Get value of devspeed field in the DCFG register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
|
||||
/**
|
||||
* Set value of devspeed field in the DCFG register
|
||||
*/
|
||||
extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Get the value of busconnected field from the HPRT0 register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Gets the device enumeration Speed.
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Get value of prtpwr field from the HPRT0 register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Get value of flag indicating core state - hibernated or not
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Set value of prtpwr field from the HPRT0 register
|
||||
*/
|
||||
extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Get value of prtsusp field from the HPRT0 regsiter
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
|
||||
/**
|
||||
* Set value of prtpwr field from the HPRT0 register
|
||||
*/
|
||||
extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Get value of ModeChTimEn field from the HCFG regsiter
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if);
|
||||
/**
|
||||
* Set value of ModeChTimEn field from the HCFG regsiter
|
||||
*/
|
||||
extern void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Get value of Fram Interval field from the HFIR regsiter
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if);
|
||||
/**
|
||||
* Set value of Frame Interval field from the HFIR regsiter
|
||||
*/
|
||||
extern void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Set value of prtres field from the HPRT0 register
|
||||
*FIXME Remove?
|
||||
*/
|
||||
extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Get value of rmtwkupsig bit in DCTL register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Get value of prt_sleep_sts field from the GLPMCFG register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Get value of rem_wkup_en field from the GLPMCFG register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Get value of appl_resp field from the GLPMCFG register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
|
||||
/**
|
||||
* Set value of appl_resp field from the GLPMCFG register
|
||||
*/
|
||||
extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Get value of hsic_connect field from the GLPMCFG register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
|
||||
/**
|
||||
* Set value of hsic_connect field from the GLPMCFG register
|
||||
*/
|
||||
extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* Get value of inv_sel_hsic field from the GLPMCFG register.
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
|
||||
/**
|
||||
* Set value of inv_sel_hsic field from the GLPMFG register.
|
||||
*/
|
||||
extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/*
|
||||
* Some functions for accessing registers
|
||||
*/
|
||||
|
||||
/**
|
||||
* GOTGCTL register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
|
||||
extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* GUSBCFG register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
|
||||
extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* GRXFSIZ register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
|
||||
extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* GNPTXFSIZ register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
|
||||
extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
|
||||
extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* GGPIO register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
|
||||
extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* GUID register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
|
||||
extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* HPRT0 register
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
|
||||
extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
|
||||
|
||||
/**
|
||||
* GHPTXFSIZE
|
||||
*/
|
||||
extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* __DWC_CORE_IF_H__ */
|
||||
117
drivers/usb/host/dwc_otg/dwc_otg_dbg.h
Normal file
117
drivers/usb/host/dwc_otg/dwc_otg_dbg.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/* ==========================================================================
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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 __DWC_OTG_DBG_H__
|
||||
#define __DWC_OTG_DBG_H__
|
||||
|
||||
/** @file
|
||||
* This file defines debug levels.
|
||||
* Debugging support vanishes in non-debug builds.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Debug Level bit-mask variable.
|
||||
*/
|
||||
extern uint32_t g_dbg_lvl;
|
||||
/**
|
||||
* Set the Debug Level variable.
|
||||
*/
|
||||
static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
|
||||
{
|
||||
uint32_t old = g_dbg_lvl;
|
||||
g_dbg_lvl = new;
|
||||
return old;
|
||||
}
|
||||
|
||||
#define DBG_USER (0x1)
|
||||
/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
|
||||
#define DBG_CIL (0x2)
|
||||
/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
|
||||
* messages */
|
||||
#define DBG_CILV (0x20)
|
||||
/** When debug level has the DBG_PCD bit set, display PCD (Device) debug
|
||||
* messages */
|
||||
#define DBG_PCD (0x4)
|
||||
/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
|
||||
* messages */
|
||||
#define DBG_PCDV (0x40)
|
||||
/** When debug level has the DBG_HCD bit set, display Host debug messages */
|
||||
#define DBG_HCD (0x8)
|
||||
/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
|
||||
* messages */
|
||||
#define DBG_HCDV (0x80)
|
||||
/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
|
||||
* mode. */
|
||||
#define DBG_HCD_URB (0x800)
|
||||
/** When debug level has the DBG_HCDI bit set, display host interrupt
|
||||
* messages. */
|
||||
#define DBG_HCDI (0x1000)
|
||||
|
||||
/** When debug level has any bit set, display debug messages */
|
||||
#define DBG_ANY (0xFF)
|
||||
|
||||
/** All debug messages off */
|
||||
#define DBG_OFF 0
|
||||
|
||||
/** Prefix string for DWC_DEBUG print macros. */
|
||||
#define USB_DWC "DWC_otg: "
|
||||
|
||||
/**
|
||||
* Print a debug message when the Global debug level variable contains
|
||||
* the bit defined in <code>lvl</code>.
|
||||
*
|
||||
* @param[in] lvl - Debug level, use one of the DBG_ constants above.
|
||||
* @param[in] x - like printf
|
||||
*
|
||||
* Example:<p>
|
||||
* <code>
|
||||
* DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
|
||||
* </code>
|
||||
* <br>
|
||||
* results in:<br>
|
||||
* <code>
|
||||
* usb-DWC_otg: dwc_otg_cil_init(ca867000)
|
||||
* </code>
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
|
||||
# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
|
||||
# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x )
|
||||
|
||||
# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
|
||||
|
||||
#else
|
||||
|
||||
# define DWC_DEBUGPL(lvl, x...) do{}while(0)
|
||||
# define DWC_DEBUGP(x...)
|
||||
|
||||
# define CHK_DEBUG_LEVEL(level) (0)
|
||||
|
||||
#endif /*DEBUG*/
|
||||
#endif
|
||||
1772
drivers/usb/host/dwc_otg/dwc_otg_driver.c
Normal file
1772
drivers/usb/host/dwc_otg/dwc_otg_driver.c
Normal file
File diff suppressed because it is too large
Load Diff
86
drivers/usb/host/dwc_otg/dwc_otg_driver.h
Normal file
86
drivers/usb/host/dwc_otg/dwc_otg_driver.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* ==========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
|
||||
* $Revision: #19 $
|
||||
* $Date: 2010/11/15 $
|
||||
* $Change: 1627671 $
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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 __DWC_OTG_DRIVER_H__
|
||||
#define __DWC_OTG_DRIVER_H__
|
||||
|
||||
/** @file
|
||||
* This file contains the interface to the Linux driver.
|
||||
*/
|
||||
#include "dwc_otg_os_dep.h"
|
||||
#include "dwc_otg_core_if.h"
|
||||
|
||||
/* Type declarations */
|
||||
struct dwc_otg_pcd;
|
||||
struct dwc_otg_hcd;
|
||||
|
||||
/**
|
||||
* This structure is a wrapper that encapsulates the driver components used to
|
||||
* manage a single DWC_otg controller.
|
||||
*/
|
||||
typedef struct dwc_otg_device {
|
||||
/** Structure containing OS-dependent stuff. KEEP THIS STRUCT AT THE
|
||||
* VERY BEGINNING OF THE DEVICE STRUCT. OSes such as FreeBSD and NetBSD
|
||||
* require this. */
|
||||
struct os_dependent os_dep;
|
||||
|
||||
/** Pointer to the core interface structure. */
|
||||
dwc_otg_core_if_t *core_if;
|
||||
|
||||
/** Pointer to the PCD structure. */
|
||||
struct dwc_otg_pcd *pcd;
|
||||
|
||||
/** Pointer to the HCD structure. */
|
||||
struct dwc_otg_hcd *hcd;
|
||||
|
||||
/** Flag to indicate whether the common IRQ handler is installed. */
|
||||
uint8_t common_irq_installed;
|
||||
|
||||
} dwc_otg_device_t;
|
||||
|
||||
/*We must clear S3C24XX_EINTPEND external interrupt register
|
||||
* because after clearing in this register trigerred IRQ from
|
||||
* H/W core in kernel interrupt can be occured again before OTG
|
||||
* handlers clear all IRQ sources of Core registers because of
|
||||
* timing latencies and Low Level IRQ Type.
|
||||
*/
|
||||
#ifdef CONFIG_MACH_IPMATE
|
||||
#define S3C2410X_CLEAR_EINTPEND() \
|
||||
do { \
|
||||
__raw_writel(1UL << 11,S3C24XX_EINTPEND); \
|
||||
} while (0)
|
||||
#else
|
||||
#define S3C2410X_CLEAR_EINTPEND() do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1425
drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
Normal file
1425
drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
Normal file
File diff suppressed because it is too large
Load Diff
399
drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
Normal file
399
drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* dwc_otg_fiq_fsm.h - Finite state machine FIQ header definitions
|
||||
*
|
||||
* Copyright (c) 2013 Raspberry Pi Foundation
|
||||
*
|
||||
* Author: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of Raspberry Pi nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 <COPYRIGHT HOLDER> 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.
|
||||
*
|
||||
* This FIQ implements functionality that performs split transactions on
|
||||
* the dwc_otg hardware without any outside intervention. A split transaction
|
||||
* is "queued" by nominating a specific host channel to perform the entirety
|
||||
* of a split transaction. This FIQ will then perform the microframe-precise
|
||||
* scheduling required in each phase of the transaction until completion.
|
||||
*
|
||||
* The FIQ functionality has been surgically implanted into the Synopsys
|
||||
* vendor-provided driver.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DWC_OTG_FIQ_FSM_H_
|
||||
#define DWC_OTG_FIQ_FSM_H_
|
||||
|
||||
#include "dwc_otg_regs.h"
|
||||
#include "dwc_otg_cil.h"
|
||||
#include "dwc_otg_hcd.h"
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/irqflags.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
#if 0
|
||||
#define FLAME_ON(x) \
|
||||
do { \
|
||||
int gpioreg; \
|
||||
\
|
||||
gpioreg = readl(__io_address(0x20200000+0x8)); \
|
||||
gpioreg &= ~(7 << (x-20)*3); \
|
||||
gpioreg |= 0x1 << (x-20)*3; \
|
||||
writel(gpioreg, __io_address(0x20200000+0x8)); \
|
||||
\
|
||||
writel(1<<x, __io_address(0x20200000+(0x1C))); \
|
||||
} while (0)
|
||||
|
||||
#define FLAME_OFF(x) \
|
||||
do { \
|
||||
writel(1<<x, __io_address(0x20200000+(0x28))); \
|
||||
} while (0)
|
||||
#else
|
||||
#define FLAME_ON(x) do { } while (0)
|
||||
#define FLAME_OFF(X) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* This is a quick-and-dirty arch-specific register read/write. We know that
|
||||
* writes to a peripheral on BCM2835 will always arrive in-order, also that
|
||||
* reads and writes are executed in-order therefore the need for memory barriers
|
||||
* is obviated if we're only talking to USB.
|
||||
*/
|
||||
#define FIQ_WRITE(_addr_,_data_) (*(volatile unsigned int *) (_addr_) = (_data_))
|
||||
#define FIQ_READ(_addr_) (*(volatile unsigned int *) (_addr_))
|
||||
|
||||
/* FIQ-ified register definitions. Offsets are from dwc_regs_base. */
|
||||
#define GINTSTS 0x014
|
||||
#define GINTMSK 0x018
|
||||
/* Debug register. Poll the top of the received packets FIFO. */
|
||||
#define GRXSTSR 0x01C
|
||||
#define HFNUM 0x408
|
||||
#define HAINT 0x414
|
||||
#define HAINTMSK 0x418
|
||||
#define HPRT0 0x440
|
||||
|
||||
/* HC_regs start from an offset of 0x500 */
|
||||
#define HC_START 0x500
|
||||
#define HC_OFFSET 0x020
|
||||
|
||||
#define HC_DMA 0x14
|
||||
|
||||
#define HCCHAR 0x00
|
||||
#define HCSPLT 0x04
|
||||
#define HCINT 0x08
|
||||
#define HCINTMSK 0x0C
|
||||
#define HCTSIZ 0x10
|
||||
|
||||
#define ISOC_XACTPOS_ALL 0b11
|
||||
#define ISOC_XACTPOS_BEGIN 0b10
|
||||
#define ISOC_XACTPOS_MID 0b00
|
||||
#define ISOC_XACTPOS_END 0b01
|
||||
|
||||
#define DWC_PID_DATA2 0b01
|
||||
#define DWC_PID_MDATA 0b11
|
||||
#define DWC_PID_DATA1 0b10
|
||||
#define DWC_PID_DATA0 0b00
|
||||
|
||||
typedef struct {
|
||||
volatile void* base;
|
||||
volatile void* ctrl;
|
||||
volatile void* outdda;
|
||||
volatile void* outddb;
|
||||
volatile void* intstat;
|
||||
volatile void* swirq_set;
|
||||
volatile void* swirq_clr;
|
||||
} mphi_regs_t;
|
||||
|
||||
enum fiq_debug_level {
|
||||
FIQDBG_SCHED = (1 << 0),
|
||||
FIQDBG_INT = (1 << 1),
|
||||
FIQDBG_ERR = (1 << 2),
|
||||
FIQDBG_PORTHUB = (1 << 3),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
|
||||
typedef spinlock_t fiq_lock_t;
|
||||
|
||||
#else
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint32_t slock;
|
||||
struct _tickets {
|
||||
uint16_t owner;
|
||||
uint16_t next;
|
||||
} tickets;
|
||||
};
|
||||
} fiq_lock_t;
|
||||
|
||||
#endif
|
||||
|
||||
struct fiq_state;
|
||||
|
||||
extern void _fiq_print (enum fiq_debug_level dbg_lvl, volatile struct fiq_state *state, char *fmt, ...);
|
||||
#if 0
|
||||
#define fiq_print _fiq_print
|
||||
#else
|
||||
#define fiq_print(x, y, ...)
|
||||
#endif
|
||||
|
||||
extern bool fiq_enable, fiq_fsm_enable;
|
||||
extern ushort nak_holdoff;
|
||||
|
||||
/**
|
||||
* enum fiq_fsm_state - The FIQ FSM states.
|
||||
*
|
||||
* This is the "core" of the FIQ FSM. Broadly, the FSM states follow the
|
||||
* USB2.0 specification for host responses to various transaction states.
|
||||
* There are modifications to this host state machine because of a variety of
|
||||
* quirks and limitations in the dwc_otg hardware.
|
||||
*
|
||||
* The fsm state is also used to communicate back to the driver on completion of
|
||||
* a split transaction. The end states are used in conjunction with the interrupts
|
||||
* raised by the final transaction.
|
||||
*/
|
||||
enum fiq_fsm_state {
|
||||
/* FIQ isn't enabled for this host channel */
|
||||
FIQ_PASSTHROUGH = 0,
|
||||
/* For the first interrupt received for this channel,
|
||||
* the FIQ has to ack any interrupts indicating success. */
|
||||
FIQ_PASSTHROUGH_ERRORSTATE = 31,
|
||||
/* Nonperiodic state groups */
|
||||
FIQ_NP_SSPLIT_STARTED = 1,
|
||||
FIQ_NP_SSPLIT_RETRY = 2,
|
||||
/* TT contention - working around hub bugs */
|
||||
FIQ_NP_SSPLIT_PENDING = 33,
|
||||
FIQ_NP_OUT_CSPLIT_RETRY = 3,
|
||||
FIQ_NP_IN_CSPLIT_RETRY = 4,
|
||||
FIQ_NP_SPLIT_DONE = 5,
|
||||
FIQ_NP_SPLIT_LS_ABORTED = 6,
|
||||
/* This differentiates a HS transaction error from a LS one
|
||||
* (handling the hub state is different) */
|
||||
FIQ_NP_SPLIT_HS_ABORTED = 7,
|
||||
|
||||
/* Periodic state groups */
|
||||
/* Periodic transactions are either started directly by the IRQ handler
|
||||
* or deferred if the TT is already in use.
|
||||
*/
|
||||
FIQ_PER_SSPLIT_QUEUED = 8,
|
||||
FIQ_PER_SSPLIT_STARTED = 9,
|
||||
FIQ_PER_SSPLIT_LAST = 10,
|
||||
|
||||
|
||||
FIQ_PER_ISO_OUT_PENDING = 11,
|
||||
FIQ_PER_ISO_OUT_ACTIVE = 12,
|
||||
FIQ_PER_ISO_OUT_LAST = 13,
|
||||
FIQ_PER_ISO_OUT_DONE = 27,
|
||||
|
||||
FIQ_PER_CSPLIT_WAIT = 14,
|
||||
FIQ_PER_CSPLIT_NYET1 = 15,
|
||||
FIQ_PER_CSPLIT_BROKEN_NYET1 = 28,
|
||||
FIQ_PER_CSPLIT_NYET_FAFF = 29,
|
||||
/* For multiple CSPLITs (large isoc IN, or delayed interrupt) */
|
||||
FIQ_PER_CSPLIT_POLL = 16,
|
||||
/* The last CSPLIT for a transaction has been issued, differentiates
|
||||
* for the state machine to queue the next packet.
|
||||
*/
|
||||
FIQ_PER_CSPLIT_LAST = 17,
|
||||
|
||||
FIQ_PER_SPLIT_DONE = 18,
|
||||
FIQ_PER_SPLIT_LS_ABORTED = 19,
|
||||
FIQ_PER_SPLIT_HS_ABORTED = 20,
|
||||
FIQ_PER_SPLIT_NYET_ABORTED = 21,
|
||||
/* Frame rollover has occurred without the transaction finishing. */
|
||||
FIQ_PER_SPLIT_TIMEOUT = 22,
|
||||
|
||||
/* FIQ-accelerated HS Isochronous state groups */
|
||||
FIQ_HS_ISOC_TURBO = 23,
|
||||
/* For interval > 1, SOF wakes up the isochronous FSM */
|
||||
FIQ_HS_ISOC_SLEEPING = 24,
|
||||
FIQ_HS_ISOC_DONE = 25,
|
||||
FIQ_HS_ISOC_ABORTED = 26,
|
||||
FIQ_DEQUEUE_ISSUED = 30,
|
||||
FIQ_TEST = 32,
|
||||
};
|
||||
|
||||
struct fiq_stack {
|
||||
int magic1;
|
||||
uint8_t stack[2048];
|
||||
int magic2;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct fiq_dma_info - DMA bounce buffer utilisation information (per-channel)
|
||||
* @index: Number of slots reported used for IN transactions / number of slots
|
||||
* transmitted for an OUT transaction
|
||||
* @slot_len[6]: Number of actual transfer bytes in each slot (255 if unused)
|
||||
*
|
||||
* Split transaction transfers can have variable length depending on other bus
|
||||
* traffic. The OTG core DMA engine requires 4-byte aligned addresses therefore
|
||||
* each transaction needs a guaranteed aligned address. A maximum of 6 split transfers
|
||||
* can happen per-frame.
|
||||
*/
|
||||
struct fiq_dma_info {
|
||||
u8 index;
|
||||
u8 slot_len[6];
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) fiq_split_dma_slot {
|
||||
u8 buf[188];
|
||||
};
|
||||
|
||||
struct fiq_dma_channel {
|
||||
struct __attribute__((packed)) fiq_split_dma_slot index[6];
|
||||
};
|
||||
|
||||
struct fiq_dma_blob {
|
||||
struct __attribute__((packed)) fiq_dma_channel channel[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fiq_hs_isoc_info - USB2.0 isochronous data
|
||||
* @iso_frame: Pointer to the array of OTG URB iso_frame_descs.
|
||||
* @nrframes: Total length of iso_frame_desc array
|
||||
* @index: Current index (FIQ-maintained)
|
||||
* @stride: Interval in uframes between HS isoc transactions
|
||||
*/
|
||||
struct fiq_hs_isoc_info {
|
||||
struct dwc_otg_hcd_iso_packet_desc *iso_desc;
|
||||
unsigned int nrframes;
|
||||
unsigned int index;
|
||||
unsigned int stride;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fiq_channel_state - FIQ state machine storage
|
||||
* @fsm: Current state of the channel as understood by the FIQ
|
||||
* @nr_errors: Number of transaction errors on this split-transaction
|
||||
* @hub_addr: SSPLIT/CSPLIT destination hub
|
||||
* @port_addr: SSPLIT/CSPLIT destination port - always 1 if single TT hub
|
||||
* @nrpackets: For isoc OUT, the number of split-OUT packets to transmit. For
|
||||
* split-IN, number of CSPLIT data packets that were received.
|
||||
* @hcchar_copy:
|
||||
* @hcsplt_copy:
|
||||
* @hcintmsk_copy:
|
||||
* @hctsiz_copy: Copies of the host channel registers.
|
||||
* For use as scratch, or for returning state.
|
||||
*
|
||||
* The fiq_channel_state is state storage between interrupts for a host channel. The
|
||||
* FSM state is stored here. Members of this structure must only be set up by the
|
||||
* driver prior to enabling the FIQ for this host channel, and not touched until the FIQ
|
||||
* has updated the state to either a COMPLETE state group or ABORT state group.
|
||||
*/
|
||||
|
||||
struct fiq_channel_state {
|
||||
enum fiq_fsm_state fsm;
|
||||
unsigned int nr_errors;
|
||||
unsigned int hub_addr;
|
||||
unsigned int port_addr;
|
||||
/* Hardware bug workaround: sometimes channel halt interrupts are
|
||||
* delayed until the next SOF. Keep track of when we expected to get interrupted. */
|
||||
unsigned int expected_uframe;
|
||||
/* number of uframes remaining (for interval > 1 HS isoc transfers) before next transfer */
|
||||
unsigned int uframe_sleeps;
|
||||
/* in/out for communicating number of dma buffers used, or number of ISOC to do */
|
||||
unsigned int nrpackets;
|
||||
struct fiq_dma_info dma_info;
|
||||
struct fiq_hs_isoc_info hs_isoc_info;
|
||||
/* Copies of HC registers - in/out communication from/to IRQ handler
|
||||
* and for ease of channel setup. A bit of mungeing is performed - for
|
||||
* example the hctsiz.b.maxp is _always_ the max packet size of the endpoint.
|
||||
*/
|
||||
hcchar_data_t hcchar_copy;
|
||||
hcsplt_data_t hcsplt_copy;
|
||||
hcint_data_t hcint_copy;
|
||||
hcintmsk_data_t hcintmsk_copy;
|
||||
hctsiz_data_t hctsiz_copy;
|
||||
hcdma_data_t hcdma_copy;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fiq_state - top-level FIQ state machine storage
|
||||
* @mphi_regs: virtual address of the MPHI peripheral register file
|
||||
* @dwc_regs_base: virtual address of the base of the DWC core register file
|
||||
* @dma_base: physical address for the base of the DMA bounce buffers
|
||||
* @dummy_send: Scratch area for sending a fake message to the MPHI peripheral
|
||||
* @gintmsk_saved: Top-level mask of interrupts that the FIQ has not handled.
|
||||
* Used for determining which interrupts fired to set off the IRQ handler.
|
||||
* @haintmsk_saved: Mask of interrupts from host channels that the FIQ did not handle internally.
|
||||
* @np_count: Non-periodic transactions in the active queue
|
||||
* @np_sent: Count of non-periodic transactions that have completed
|
||||
* @next_sched_frame: For periodic transactions handled by the driver's SOF-driven queuing mechanism,
|
||||
* this is the next frame on which a SOF interrupt is required. Used to hold off
|
||||
* passing SOF through to the driver until necessary.
|
||||
* @channel[n]: Per-channel FIQ state. Allocated during init depending on the number of host
|
||||
* channels configured into the core logic.
|
||||
*
|
||||
* This is passed as the first argument to the dwc_otg_fiq_fsm top-level FIQ handler from the asm stub.
|
||||
* It contains top-level state information.
|
||||
*/
|
||||
struct fiq_state {
|
||||
fiq_lock_t lock;
|
||||
mphi_regs_t mphi_regs;
|
||||
void *dwc_regs_base;
|
||||
dma_addr_t dma_base;
|
||||
struct fiq_dma_blob *fiq_dmab;
|
||||
void *dummy_send;
|
||||
dma_addr_t dummy_send_dma;
|
||||
gintmsk_data_t gintmsk_saved;
|
||||
haintmsk_data_t haintmsk_saved;
|
||||
int mphi_int_count;
|
||||
unsigned int fiq_done;
|
||||
unsigned int kick_np_queues;
|
||||
unsigned int next_sched_frame;
|
||||
#ifdef FIQ_DEBUG
|
||||
char * buffer;
|
||||
unsigned int bufsiz;
|
||||
#endif
|
||||
struct fiq_channel_state channel[0];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
|
||||
#ifdef local_fiq_enable
|
||||
#undef local_fiq_enable
|
||||
#endif
|
||||
|
||||
#ifdef local_fiq_disable
|
||||
#undef local_fiq_disable
|
||||
#endif
|
||||
|
||||
extern void local_fiq_enable(void);
|
||||
|
||||
extern void local_fiq_disable(void);
|
||||
|
||||
#endif
|
||||
|
||||
extern void fiq_fsm_spin_lock(fiq_lock_t *lock);
|
||||
|
||||
extern void fiq_fsm_spin_unlock(fiq_lock_t *lock);
|
||||
|
||||
extern int fiq_fsm_too_late(struct fiq_state *st, int n);
|
||||
|
||||
extern int fiq_fsm_tt_in_use(struct fiq_state *st, int num_channels, int n);
|
||||
|
||||
extern void dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels);
|
||||
|
||||
extern void dwc_otg_fiq_nop(struct fiq_state *state);
|
||||
|
||||
#endif /* DWC_OTG_FIQ_FSM_H_ */
|
||||
80
drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S
Normal file
80
drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* dwc_otg_fiq_fsm.S - assembly stub for the FSM FIQ
|
||||
*
|
||||
* Copyright (c) 2013 Raspberry Pi Foundation
|
||||
*
|
||||
* Author: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of Raspberry Pi nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 <COPYRIGHT HOLDER> 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 <asm/assembler.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
|
||||
.text
|
||||
|
||||
.global _dwc_otg_fiq_stub_end;
|
||||
|
||||
/**
|
||||
* _dwc_otg_fiq_stub() - entry copied to the FIQ vector page to allow
|
||||
* a C-style function call with arguments from the FIQ banked registers.
|
||||
* r0 = &hcd->fiq_state
|
||||
* r1 = &hcd->num_channels
|
||||
* r2 = &hcd->dma_buffers
|
||||
* Tramples: r0, r1, r2, r4, fp, ip
|
||||
*/
|
||||
|
||||
ENTRY(_dwc_otg_fiq_stub)
|
||||
/* Stash unbanked regs - SP will have been set up for us */
|
||||
mov ip, sp;
|
||||
stmdb sp!, {r0-r12, lr};
|
||||
#ifdef FIQ_DEBUG
|
||||
// Cycle profiling - read cycle counter at start
|
||||
mrc p15, 0, r5, c15, c12, 1;
|
||||
#endif
|
||||
/* r11 = fp, don't trample it */
|
||||
mov r4, fp;
|
||||
/* set EABI frame size */
|
||||
sub fp, ip, #512;
|
||||
|
||||
/* for fiq NOP mode - just need state */
|
||||
mov r0, r8;
|
||||
/* r9 = num_channels */
|
||||
mov r1, r9;
|
||||
/* r10 = struct *dma_bufs */
|
||||
// mov r2, r10;
|
||||
|
||||
/* r4 = &fiq_c_function */
|
||||
blx r4;
|
||||
#ifdef FIQ_DEBUG
|
||||
mrc p15, 0, r4, c15, c12, 1;
|
||||
subs r5, r5, r4;
|
||||
// r5 is now the cycle count time for executing the FIQ. Store it somewhere?
|
||||
#endif
|
||||
ldmia sp!, {r0-r12, lr};
|
||||
subs pc, lr, #4;
|
||||
_dwc_otg_fiq_stub_end:
|
||||
END(_dwc_otg_fiq_stub)
|
||||
4327
drivers/usb/host/dwc_otg/dwc_otg_hcd.c
Normal file
4327
drivers/usb/host/dwc_otg/dwc_otg_hcd.c
Normal file
File diff suppressed because it is too large
Load Diff
870
drivers/usb/host/dwc_otg/dwc_otg_hcd.h
Normal file
870
drivers/usb/host/dwc_otg/dwc_otg_hcd.h
Normal file
@@ -0,0 +1,870 @@
|
||||
/* ==========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
|
||||
* $Revision: #58 $
|
||||
* $Date: 2011/09/15 $
|
||||
* $Change: 1846647 $
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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 DWC_DEVICE_ONLY
|
||||
#ifndef __DWC_HCD_H__
|
||||
#define __DWC_HCD_H__
|
||||
|
||||
#include "dwc_otg_os_dep.h"
|
||||
#include "usb.h"
|
||||
#include "dwc_otg_hcd_if.h"
|
||||
#include "dwc_otg_core_if.h"
|
||||
#include "dwc_list.h"
|
||||
#include "dwc_otg_cil.h"
|
||||
#include "dwc_otg_fiq_fsm.h"
|
||||
#include "dwc_otg_driver.h"
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* This file contains the structures, constants, and interfaces for
|
||||
* the Host Contoller Driver (HCD).
|
||||
*
|
||||
* The Host Controller Driver (HCD) is responsible for translating requests
|
||||
* from the USB Driver into the appropriate actions on the DWC_otg controller.
|
||||
* It isolates the USBD from the specifics of the controller by providing an
|
||||
* API to the USBD.
|
||||
*/
|
||||
|
||||
struct dwc_otg_hcd_pipe_info {
|
||||
uint8_t dev_addr;
|
||||
uint8_t ep_num;
|
||||
uint8_t pipe_type;
|
||||
uint8_t pipe_dir;
|
||||
uint16_t mps;
|
||||
};
|
||||
|
||||
struct dwc_otg_hcd_iso_packet_desc {
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
uint32_t actual_length;
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
struct dwc_otg_qtd;
|
||||
|
||||
struct dwc_otg_hcd_urb {
|
||||
void *priv;
|
||||
struct dwc_otg_qtd *qtd;
|
||||
void *buf;
|
||||
dwc_dma_t dma;
|
||||
void *setup_packet;
|
||||
dwc_dma_t setup_dma;
|
||||
uint32_t length;
|
||||
uint32_t actual_length;
|
||||
uint32_t status;
|
||||
uint32_t error_count;
|
||||
uint32_t packet_count;
|
||||
uint32_t flags;
|
||||
uint16_t interval;
|
||||
struct dwc_otg_hcd_pipe_info pipe_info;
|
||||
struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
|
||||
};
|
||||
|
||||
static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
|
||||
{
|
||||
return pipe->ep_num;
|
||||
}
|
||||
|
||||
static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
|
||||
*pipe)
|
||||
{
|
||||
return pipe->pipe_type;
|
||||
}
|
||||
|
||||
static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
|
||||
{
|
||||
return pipe->mps;
|
||||
}
|
||||
|
||||
static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
|
||||
*pipe)
|
||||
{
|
||||
return pipe->dev_addr;
|
||||
}
|
||||
|
||||
static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
|
||||
*pipe)
|
||||
{
|
||||
return (pipe->pipe_type == UE_ISOCHRONOUS);
|
||||
}
|
||||
|
||||
static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
|
||||
*pipe)
|
||||
{
|
||||
return (pipe->pipe_type == UE_INTERRUPT);
|
||||
}
|
||||
|
||||
static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
|
||||
*pipe)
|
||||
{
|
||||
return (pipe->pipe_type == UE_BULK);
|
||||
}
|
||||
|
||||
static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
|
||||
*pipe)
|
||||
{
|
||||
return (pipe->pipe_type == UE_CONTROL);
|
||||
}
|
||||
|
||||
static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
|
||||
{
|
||||
return (pipe->pipe_dir == UE_DIR_IN);
|
||||
}
|
||||
|
||||
static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
|
||||
*pipe)
|
||||
{
|
||||
return (!dwc_otg_hcd_is_pipe_in(pipe));
|
||||
}
|
||||
|
||||
static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
|
||||
uint8_t devaddr, uint8_t ep_num,
|
||||
uint8_t pipe_type, uint8_t pipe_dir,
|
||||
uint16_t mps)
|
||||
{
|
||||
pipe->dev_addr = devaddr;
|
||||
pipe->ep_num = ep_num;
|
||||
pipe->pipe_type = pipe_type;
|
||||
pipe->pipe_dir = pipe_dir;
|
||||
pipe->mps = mps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Phases for control transfers.
|
||||
*/
|
||||
typedef enum dwc_otg_control_phase {
|
||||
DWC_OTG_CONTROL_SETUP,
|
||||
DWC_OTG_CONTROL_DATA,
|
||||
DWC_OTG_CONTROL_STATUS
|
||||
} dwc_otg_control_phase_e;
|
||||
|
||||
/** Transaction types. */
|
||||
typedef enum dwc_otg_transaction_type {
|
||||
DWC_OTG_TRANSACTION_NONE = 0,
|
||||
DWC_OTG_TRANSACTION_PERIODIC = 1,
|
||||
DWC_OTG_TRANSACTION_NON_PERIODIC = 2,
|
||||
DWC_OTG_TRANSACTION_ALL = DWC_OTG_TRANSACTION_PERIODIC + DWC_OTG_TRANSACTION_NON_PERIODIC
|
||||
} dwc_otg_transaction_type_e;
|
||||
|
||||
struct dwc_otg_qh;
|
||||
|
||||
/**
|
||||
* A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
|
||||
* interrupt, or isochronous transfer. A single QTD is created for each URB
|
||||
* (of one of these types) submitted to the HCD. The transfer associated with
|
||||
* a QTD may require one or multiple transactions.
|
||||
*
|
||||
* A QTD is linked to a Queue Head, which is entered in either the
|
||||
* non-periodic or periodic schedule for execution. When a QTD is chosen for
|
||||
* execution, some or all of its transactions may be executed. After
|
||||
* execution, the state of the QTD is updated. The QTD may be retired if all
|
||||
* its transactions are complete or if an error occurred. Otherwise, it
|
||||
* remains in the schedule so more transactions can be executed later.
|
||||
*/
|
||||
typedef struct dwc_otg_qtd {
|
||||
/**
|
||||
* Determines the PID of the next data packet for the data phase of
|
||||
* control transfers. Ignored for other transfer types.<br>
|
||||
* One of the following values:
|
||||
* - DWC_OTG_HC_PID_DATA0
|
||||
* - DWC_OTG_HC_PID_DATA1
|
||||
*/
|
||||
uint8_t data_toggle;
|
||||
|
||||
/** Current phase for control transfers (Setup, Data, or Status). */
|
||||
dwc_otg_control_phase_e control_phase;
|
||||
|
||||
/** Keep track of the current split type
|
||||
* for FS/LS endpoints on a HS Hub */
|
||||
uint8_t complete_split;
|
||||
|
||||
/** How many bytes transferred during SSPLIT OUT */
|
||||
uint32_t ssplit_out_xfer_count;
|
||||
|
||||
/**
|
||||
* Holds the number of bus errors that have occurred for a transaction
|
||||
* within this transfer.
|
||||
*/
|
||||
uint8_t error_count;
|
||||
|
||||
/**
|
||||
* Index of the next frame descriptor for an isochronous transfer. A
|
||||
* frame descriptor describes the buffer position and length of the
|
||||
* data to be transferred in the next scheduled (micro)frame of an
|
||||
* isochronous transfer. It also holds status for that transaction.
|
||||
* The frame index starts at 0.
|
||||
*/
|
||||
uint16_t isoc_frame_index;
|
||||
|
||||
/** Position of the ISOC split on full/low speed */
|
||||
uint8_t isoc_split_pos;
|
||||
|
||||
/** Position of the ISOC split in the buffer for the current frame */
|
||||
uint16_t isoc_split_offset;
|
||||
|
||||
/** URB for this transfer */
|
||||
struct dwc_otg_hcd_urb *urb;
|
||||
|
||||
struct dwc_otg_qh *qh;
|
||||
|
||||
/** This list of QTDs */
|
||||
DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
|
||||
|
||||
/** Indicates if this QTD is currently processed by HW. */
|
||||
uint8_t in_process;
|
||||
|
||||
/** Number of DMA descriptors for this QTD */
|
||||
uint8_t n_desc;
|
||||
|
||||
/**
|
||||
* Last activated frame(packet) index.
|
||||
* Used in Descriptor DMA mode only.
|
||||
*/
|
||||
uint16_t isoc_frame_index_last;
|
||||
|
||||
} dwc_otg_qtd_t;
|
||||
|
||||
DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
|
||||
|
||||
/**
|
||||
* A Queue Head (QH) holds the static characteristics of an endpoint and
|
||||
* maintains a list of transfers (QTDs) for that endpoint. A QH structure may
|
||||
* be entered in either the non-periodic or periodic schedule.
|
||||
*/
|
||||
typedef struct dwc_otg_qh {
|
||||
/**
|
||||
* Endpoint type.
|
||||
* One of the following values:
|
||||
* - UE_CONTROL
|
||||
* - UE_BULK
|
||||
* - UE_INTERRUPT
|
||||
* - UE_ISOCHRONOUS
|
||||
*/
|
||||
uint8_t ep_type;
|
||||
uint8_t ep_is_in;
|
||||
|
||||
/** wMaxPacketSize Field of Endpoint Descriptor. */
|
||||
uint16_t maxp;
|
||||
|
||||
/**
|
||||
* Device speed.
|
||||
* One of the following values:
|
||||
* - DWC_OTG_EP_SPEED_LOW
|
||||
* - DWC_OTG_EP_SPEED_FULL
|
||||
* - DWC_OTG_EP_SPEED_HIGH
|
||||
*/
|
||||
uint8_t dev_speed;
|
||||
|
||||
/**
|
||||
* Determines the PID of the next data packet for non-control
|
||||
* transfers. Ignored for control transfers.<br>
|
||||
* One of the following values:
|
||||
* - DWC_OTG_HC_PID_DATA0
|
||||
* - DWC_OTG_HC_PID_DATA1
|
||||
*/
|
||||
uint8_t data_toggle;
|
||||
|
||||
/** Ping state if 1. */
|
||||
uint8_t ping_state;
|
||||
|
||||
/**
|
||||
* List of QTDs for this QH.
|
||||
*/
|
||||
struct dwc_otg_qtd_list qtd_list;
|
||||
|
||||
/** Host channel currently processing transfers for this QH. */
|
||||
struct dwc_hc *channel;
|
||||
|
||||
/** Full/low speed endpoint on high-speed hub requires split. */
|
||||
uint8_t do_split;
|
||||
|
||||
/** @name Periodic schedule information */
|
||||
/** @{ */
|
||||
|
||||
/** Bandwidth in microseconds per (micro)frame. */
|
||||
uint16_t usecs;
|
||||
|
||||
/** Interval between transfers in (micro)frames. */
|
||||
uint16_t interval;
|
||||
|
||||
/**
|
||||
* (micro)frame to initialize a periodic transfer. The transfer
|
||||
* executes in the following (micro)frame.
|
||||
*/
|
||||
uint16_t sched_frame;
|
||||
|
||||
/*
|
||||
** Frame a NAK was received on this queue head, used to minimise NAK retransmission
|
||||
*/
|
||||
uint16_t nak_frame;
|
||||
|
||||
/** (micro)frame at which last start split was initialized. */
|
||||
uint16_t start_split_frame;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Used instead of original buffer if
|
||||
* it(physical address) is not dword-aligned.
|
||||
*/
|
||||
uint8_t *dw_align_buf;
|
||||
dwc_dma_t dw_align_buf_dma;
|
||||
|
||||
/** Entry for QH in either the periodic or non-periodic schedule. */
|
||||
dwc_list_link_t qh_list_entry;
|
||||
|
||||
/** @name Descriptor DMA support */
|
||||
/** @{ */
|
||||
|
||||
/** Descriptor List. */
|
||||
dwc_otg_host_dma_desc_t *desc_list;
|
||||
|
||||
/** Descriptor List physical address. */
|
||||
dwc_dma_t desc_list_dma;
|
||||
|
||||
/**
|
||||
* Xfer Bytes array.
|
||||
* Each element corresponds to a descriptor and indicates
|
||||
* original XferSize size value for the descriptor.
|
||||
*/
|
||||
uint32_t *n_bytes;
|
||||
|
||||
/** Actual number of transfer descriptors in a list. */
|
||||
uint16_t ntd;
|
||||
|
||||
/** First activated isochronous transfer descriptor index. */
|
||||
uint8_t td_first;
|
||||
/** Last activated isochronous transfer descriptor index. */
|
||||
uint8_t td_last;
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
uint16_t speed;
|
||||
uint16_t frame_usecs[8];
|
||||
|
||||
uint32_t skip_count;
|
||||
} dwc_otg_qh_t;
|
||||
|
||||
DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
|
||||
|
||||
typedef struct urb_tq_entry {
|
||||
struct urb *urb;
|
||||
DWC_TAILQ_ENTRY(urb_tq_entry) urb_tq_entries;
|
||||
} urb_tq_entry_t;
|
||||
|
||||
DWC_TAILQ_HEAD(urb_list, urb_tq_entry);
|
||||
|
||||
/**
|
||||
* This structure holds the state of the HCD, including the non-periodic and
|
||||
* periodic schedules.
|
||||
*/
|
||||
struct dwc_otg_hcd {
|
||||
/** The DWC otg device pointer */
|
||||
struct dwc_otg_device *otg_dev;
|
||||
/** DWC OTG Core Interface Layer */
|
||||
dwc_otg_core_if_t *core_if;
|
||||
|
||||
/** Function HCD driver callbacks */
|
||||
struct dwc_otg_hcd_function_ops *fops;
|
||||
|
||||
/** Internal DWC HCD Flags */
|
||||
volatile union dwc_otg_hcd_internal_flags {
|
||||
uint32_t d32;
|
||||
struct {
|
||||
unsigned port_connect_status_change:1;
|
||||
unsigned port_connect_status:1;
|
||||
unsigned port_reset_change:1;
|
||||
unsigned port_enable_change:1;
|
||||
unsigned port_suspend_change:1;
|
||||
unsigned port_over_current_change:1;
|
||||
unsigned port_l1_change:1;
|
||||
unsigned port_speed:2;
|
||||
unsigned reserved:24;
|
||||
} b;
|
||||
} flags;
|
||||
|
||||
/**
|
||||
* Inactive items in the non-periodic schedule. This is a list of
|
||||
* Queue Heads. Transfers associated with these Queue Heads are not
|
||||
* currently assigned to a host channel.
|
||||
*/
|
||||
dwc_list_link_t non_periodic_sched_inactive;
|
||||
|
||||
/**
|
||||
* Active items in the non-periodic schedule. This is a list of
|
||||
* Queue Heads. Transfers associated with these Queue Heads are
|
||||
* currently assigned to a host channel.
|
||||
*/
|
||||
dwc_list_link_t non_periodic_sched_active;
|
||||
|
||||
/**
|
||||
* Pointer to the next Queue Head to process in the active
|
||||
* non-periodic schedule.
|
||||
*/
|
||||
dwc_list_link_t *non_periodic_qh_ptr;
|
||||
|
||||
/**
|
||||
* Inactive items in the periodic schedule. This is a list of QHs for
|
||||
* periodic transfers that are _not_ scheduled for the next frame.
|
||||
* Each QH in the list has an interval counter that determines when it
|
||||
* needs to be scheduled for execution. This scheduling mechanism
|
||||
* allows only a simple calculation for periodic bandwidth used (i.e.
|
||||
* must assume that all periodic transfers may need to execute in the
|
||||
* same frame). However, it greatly simplifies scheduling and should
|
||||
* be sufficient for the vast majority of OTG hosts, which need to
|
||||
* connect to a small number of peripherals at one time.
|
||||
*
|
||||
* Items move from this list to periodic_sched_ready when the QH
|
||||
* interval counter is 0 at SOF.
|
||||
*/
|
||||
dwc_list_link_t periodic_sched_inactive;
|
||||
|
||||
/**
|
||||
* List of periodic QHs that are ready for execution in the next
|
||||
* frame, but have not yet been assigned to host channels.
|
||||
*
|
||||
* Items move from this list to periodic_sched_assigned as host
|
||||
* channels become available during the current frame.
|
||||
*/
|
||||
dwc_list_link_t periodic_sched_ready;
|
||||
|
||||
/**
|
||||
* List of periodic QHs to be executed in the next frame that are
|
||||
* assigned to host channels.
|
||||
*
|
||||
* Items move from this list to periodic_sched_queued as the
|
||||
* transactions for the QH are queued to the DWC_otg controller.
|
||||
*/
|
||||
dwc_list_link_t periodic_sched_assigned;
|
||||
|
||||
/**
|
||||
* List of periodic QHs that have been queued for execution.
|
||||
*
|
||||
* Items move from this list to either periodic_sched_inactive or
|
||||
* periodic_sched_ready when the channel associated with the transfer
|
||||
* is released. If the interval for the QH is 1, the item moves to
|
||||
* periodic_sched_ready because it must be rescheduled for the next
|
||||
* frame. Otherwise, the item moves to periodic_sched_inactive.
|
||||
*/
|
||||
dwc_list_link_t periodic_sched_queued;
|
||||
|
||||
/**
|
||||
* Total bandwidth claimed so far for periodic transfers. This value
|
||||
* is in microseconds per (micro)frame. The assumption is that all
|
||||
* periodic transfers may occur in the same (micro)frame.
|
||||
*/
|
||||
uint16_t periodic_usecs;
|
||||
|
||||
/**
|
||||
* Total bandwidth claimed so far for all periodic transfers
|
||||
* in a frame.
|
||||
* This will include a mixture of HS and FS transfers.
|
||||
* Units are microseconds per (micro)frame.
|
||||
* We have a budget per frame and have to schedule
|
||||
* transactions accordingly.
|
||||
* Watch out for the fact that things are actually scheduled for the
|
||||
* "next frame".
|
||||
*/
|
||||
uint16_t frame_usecs[8];
|
||||
|
||||
|
||||
/**
|
||||
* Frame number read from the core at SOF. The value ranges from 0 to
|
||||
* DWC_HFNUM_MAX_FRNUM.
|
||||
*/
|
||||
uint16_t frame_number;
|
||||
|
||||
/**
|
||||
* Count of periodic QHs, if using several eps. For SOF enable/disable.
|
||||
*/
|
||||
uint16_t periodic_qh_count;
|
||||
|
||||
/**
|
||||
* Free host channels in the controller. This is a list of
|
||||
* dwc_hc_t items.
|
||||
*/
|
||||
struct hc_list free_hc_list;
|
||||
/**
|
||||
* Number of host channels assigned to periodic transfers. Currently
|
||||
* assuming that there is a dedicated host channel for each periodic
|
||||
* transaction and at least one host channel available for
|
||||
* non-periodic transactions.
|
||||
*/
|
||||
int periodic_channels; /* microframe_schedule==0 */
|
||||
|
||||
/**
|
||||
* Number of host channels assigned to non-periodic transfers.
|
||||
*/
|
||||
int non_periodic_channels; /* microframe_schedule==0 */
|
||||
|
||||
/**
|
||||
* Number of host channels assigned to non-periodic transfers.
|
||||
*/
|
||||
int available_host_channels;
|
||||
|
||||
/**
|
||||
* Array of pointers to the host channel descriptors. Allows accessing
|
||||
* a host channel descriptor given the host channel number. This is
|
||||
* useful in interrupt handlers.
|
||||
*/
|
||||
struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
|
||||
|
||||
/**
|
||||
* Buffer to use for any data received during the status phase of a
|
||||
* control transfer. Normally no data is transferred during the status
|
||||
* phase. This buffer is used as a bit bucket.
|
||||
*/
|
||||
uint8_t *status_buf;
|
||||
|
||||
/**
|
||||
* DMA address for status_buf.
|
||||
*/
|
||||
dma_addr_t status_buf_dma;
|
||||
#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
|
||||
|
||||
/**
|
||||
* Connection timer. An OTG host must display a message if the device
|
||||
* does not connect. Started when the VBus power is turned on via
|
||||
* sysfs attribute "buspower".
|
||||
*/
|
||||
dwc_timer_t *conn_timer;
|
||||
|
||||
/* Tasket to do a reset */
|
||||
dwc_tasklet_t *reset_tasklet;
|
||||
|
||||
dwc_tasklet_t *completion_tasklet;
|
||||
struct urb_list completed_urb_list;
|
||||
|
||||
/* */
|
||||
dwc_spinlock_t *lock;
|
||||
/**
|
||||
* Private data that could be used by OS wrapper.
|
||||
*/
|
||||
void *priv;
|
||||
|
||||
uint8_t otg_port;
|
||||
|
||||
/** Frame List */
|
||||
uint32_t *frame_list;
|
||||
|
||||
/** Hub - Port assignment */
|
||||
int hub_port[128];
|
||||
#ifdef FIQ_DEBUG
|
||||
int hub_port_alloc[2048];
|
||||
#endif
|
||||
|
||||
/** Frame List DMA address */
|
||||
dma_addr_t frame_list_dma;
|
||||
|
||||
struct fiq_stack *fiq_stack;
|
||||
struct fiq_state *fiq_state;
|
||||
|
||||
/** Virtual address for split transaction DMA bounce buffers */
|
||||
struct fiq_dma_blob *fiq_dmab;
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32_t frrem_samples;
|
||||
uint64_t frrem_accum;
|
||||
|
||||
uint32_t hfnum_7_samples_a;
|
||||
uint64_t hfnum_7_frrem_accum_a;
|
||||
uint32_t hfnum_0_samples_a;
|
||||
uint64_t hfnum_0_frrem_accum_a;
|
||||
uint32_t hfnum_other_samples_a;
|
||||
uint64_t hfnum_other_frrem_accum_a;
|
||||
|
||||
uint32_t hfnum_7_samples_b;
|
||||
uint64_t hfnum_7_frrem_accum_b;
|
||||
uint32_t hfnum_0_samples_b;
|
||||
uint64_t hfnum_0_frrem_accum_b;
|
||||
uint32_t hfnum_other_samples_b;
|
||||
uint64_t hfnum_other_frrem_accum_b;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline struct device *dwc_otg_hcd_to_dev(struct dwc_otg_hcd *hcd)
|
||||
{
|
||||
return &hcd->otg_dev->os_dep.platformdev->dev;
|
||||
}
|
||||
|
||||
/** @name Transaction Execution Functions */
|
||||
/** @{ */
|
||||
extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
|
||||
* hcd);
|
||||
extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
|
||||
dwc_otg_transaction_type_e tr_type);
|
||||
|
||||
int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh);
|
||||
void dwc_otg_hcd_release_port(dwc_otg_hcd_t * dwc_otg_hcd, dwc_otg_qh_t *qh);
|
||||
|
||||
extern int fiq_fsm_queue_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh);
|
||||
extern int fiq_fsm_transaction_suitable(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh);
|
||||
extern void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name Interrupt Handler Functions */
|
||||
/** @{ */
|
||||
extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
|
||||
dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
|
||||
dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
|
||||
dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
|
||||
dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
|
||||
dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
|
||||
uint32_t num);
|
||||
extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
|
||||
extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
|
||||
dwc_otg_hcd);
|
||||
/** @} */
|
||||
|
||||
/** @name Schedule Queue Functions */
|
||||
/** @{ */
|
||||
|
||||
/* Implemented in dwc_otg_hcd_queue.c */
|
||||
extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
|
||||
dwc_otg_hcd_urb_t * urb, int atomic_alloc);
|
||||
extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
|
||||
extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
|
||||
extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
|
||||
extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
|
||||
int sched_csplit);
|
||||
|
||||
/** Remove and free a QH */
|
||||
static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
|
||||
dwc_otg_qh_t * qh)
|
||||
{
|
||||
dwc_irqflags_t flags;
|
||||
DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
|
||||
dwc_otg_hcd_qh_remove(hcd, qh);
|
||||
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
|
||||
dwc_otg_hcd_qh_free(hcd, qh);
|
||||
}
|
||||
|
||||
/** Allocates memory for a QH structure.
|
||||
* @return Returns the memory allocate or NULL on error. */
|
||||
static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(int atomic_alloc)
|
||||
{
|
||||
if (atomic_alloc)
|
||||
return (dwc_otg_qh_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qh_t));
|
||||
else
|
||||
return (dwc_otg_qh_t *) DWC_ALLOC(sizeof(dwc_otg_qh_t));
|
||||
}
|
||||
|
||||
extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb,
|
||||
int atomic_alloc);
|
||||
extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
|
||||
extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
|
||||
dwc_otg_qh_t ** qh, int atomic_alloc);
|
||||
|
||||
/** Allocates memory for a QTD structure.
|
||||
* @return Returns the memory allocate or NULL on error. */
|
||||
static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(int atomic_alloc)
|
||||
{
|
||||
if (atomic_alloc)
|
||||
return (dwc_otg_qtd_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qtd_t));
|
||||
else
|
||||
return (dwc_otg_qtd_t *) DWC_ALLOC(sizeof(dwc_otg_qtd_t));
|
||||
}
|
||||
|
||||
/** Frees the memory for a QTD structure. QTD should already be removed from
|
||||
* list.
|
||||
* @param qtd QTD to free.*/
|
||||
static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
|
||||
{
|
||||
DWC_FREE(qtd);
|
||||
}
|
||||
|
||||
/** Removes a QTD from list.
|
||||
* @param hcd HCD instance.
|
||||
* @param qtd QTD to remove from list.
|
||||
* @param qh QTD belongs to.
|
||||
*/
|
||||
static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
|
||||
dwc_otg_qtd_t * qtd,
|
||||
dwc_otg_qh_t * qh)
|
||||
{
|
||||
DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
|
||||
}
|
||||
|
||||
/** Remove and free a QTD
|
||||
* Need to disable IRQ and hold hcd lock while calling this function out of
|
||||
* interrupt servicing chain */
|
||||
static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
|
||||
dwc_otg_qtd_t * qtd,
|
||||
dwc_otg_qh_t * qh)
|
||||
{
|
||||
dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
|
||||
dwc_otg_hcd_qtd_free(qtd);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name Descriptor DMA Supporting Functions */
|
||||
/** @{ */
|
||||
|
||||
extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
|
||||
extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
|
||||
dwc_hc_t * hc,
|
||||
dwc_otg_hc_regs_t * hc_regs,
|
||||
dwc_otg_halt_status_e halt_status);
|
||||
|
||||
extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
|
||||
extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name Internal Functions */
|
||||
/** @{ */
|
||||
dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
|
||||
/** @} */
|
||||
|
||||
#ifdef CONFIG_USB_DWC_OTG_LPM
|
||||
extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
|
||||
uint8_t devaddr);
|
||||
extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
|
||||
#endif
|
||||
|
||||
/** Gets the QH that contains the list_head */
|
||||
#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
|
||||
|
||||
/** Gets the QTD that contains the list_head */
|
||||
#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
|
||||
|
||||
/** Check if QH is non-periodic */
|
||||
#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
|
||||
(_qh_ptr_->ep_type == UE_CONTROL))
|
||||
|
||||
/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
|
||||
#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
|
||||
|
||||
/** Packet size for any kind of endpoint descriptor */
|
||||
#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
|
||||
|
||||
/**
|
||||
* Returns true if _frame1 is less than or equal to _frame2. The comparison is
|
||||
* done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
|
||||
* frame number when the max frame number is reached.
|
||||
*/
|
||||
static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
|
||||
{
|
||||
return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
|
||||
(DWC_HFNUM_MAX_FRNUM >> 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if _frame1 is greater than _frame2. The comparison is done
|
||||
* modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
|
||||
* number when the max frame number is reached.
|
||||
*/
|
||||
static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
|
||||
{
|
||||
return (frame1 != frame2) &&
|
||||
(((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
|
||||
(DWC_HFNUM_MAX_FRNUM >> 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments _frame by the amount specified by _inc. The addition is done
|
||||
* modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
|
||||
*/
|
||||
static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
|
||||
{
|
||||
return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
|
||||
}
|
||||
|
||||
static inline uint16_t dwc_full_frame_num(uint16_t frame)
|
||||
{
|
||||
return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
|
||||
}
|
||||
|
||||
static inline uint16_t dwc_micro_frame_num(uint16_t frame)
|
||||
{
|
||||
return frame & 0x7;
|
||||
}
|
||||
|
||||
extern void init_hcd_usecs(dwc_otg_hcd_t *_hcd);
|
||||
|
||||
void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
|
||||
dwc_otg_hc_regs_t * hc_regs,
|
||||
dwc_otg_qtd_t * qtd);
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Macro to sample the remaining PHY clocks left in the current frame. This
|
||||
* may be used during debugging to determine the average time it takes to
|
||||
* execute sections of code. There are two possible sample points, "a" and
|
||||
* "b", so the _letter argument must be one of these values.
|
||||
*
|
||||
* To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
|
||||
* example, "cat /sys/devices/lm0/hcd_frrem".
|
||||
*/
|
||||
#define dwc_sample_frrem(_hcd, _qh, _letter) \
|
||||
{ \
|
||||
hfnum_data_t hfnum; \
|
||||
dwc_otg_qtd_t *qtd; \
|
||||
qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
|
||||
if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
|
||||
hfnum.d32 = DWC_READ_REG32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
|
||||
switch (hfnum.b.frnum & 0x7) { \
|
||||
case 7: \
|
||||
_hcd->hfnum_7_samples_##_letter++; \
|
||||
_hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
|
||||
break; \
|
||||
case 0: \
|
||||
_hcd->hfnum_0_samples_##_letter++; \
|
||||
_hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
|
||||
break; \
|
||||
default: \
|
||||
_hcd->hfnum_other_samples_##_letter++; \
|
||||
_hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define dwc_sample_frrem(_hcd, _qh, _letter)
|
||||
#endif
|
||||
#endif
|
||||
#endif /* DWC_DEVICE_ONLY */
|
||||
1134
drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
Normal file
1134
drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
Normal file
File diff suppressed because it is too large
Load Diff
421
drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
Normal file
421
drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
Normal file
@@ -0,0 +1,421 @@
|
||||
/* ==========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
|
||||
* $Revision: #12 $
|
||||
* $Date: 2011/10/26 $
|
||||
* $Change: 1873028 $
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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 DWC_DEVICE_ONLY
|
||||
#ifndef __DWC_HCD_IF_H__
|
||||
#define __DWC_HCD_IF_H__
|
||||
|
||||
#include "dwc_otg_core_if.h"
|
||||
|
||||
/** @file
|
||||
* This file defines DWC_OTG HCD Core API.
|
||||
*/
|
||||
|
||||
struct dwc_otg_hcd;
|
||||
typedef struct dwc_otg_hcd dwc_otg_hcd_t;
|
||||
|
||||
struct dwc_otg_hcd_urb;
|
||||
typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
|
||||
|
||||
/** @name HCD Function Driver Callbacks */
|
||||
/** @{ */
|
||||
|
||||
/** This function is called whenever core switches to host mode. */
|
||||
typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
|
||||
|
||||
/** This function is called when device has been disconnected */
|
||||
typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
|
||||
|
||||
/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */
|
||||
typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
|
||||
void *urb_handle,
|
||||
uint32_t * hub_addr,
|
||||
uint32_t * port_addr);
|
||||
/** Via this function HCD core gets device speed */
|
||||
typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
|
||||
void *urb_handle);
|
||||
|
||||
/** This function is called when urb is completed */
|
||||
typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
|
||||
void *urb_handle,
|
||||
dwc_otg_hcd_urb_t * dwc_otg_urb,
|
||||
int32_t status);
|
||||
|
||||
/** Via this function HCD core gets b_hnp_enable parameter */
|
||||
typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
|
||||
|
||||
struct dwc_otg_hcd_function_ops {
|
||||
dwc_otg_hcd_start_cb_t start;
|
||||
dwc_otg_hcd_disconnect_cb_t disconnect;
|
||||
dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
|
||||
dwc_otg_hcd_speed_from_urb_cb_t speed;
|
||||
dwc_otg_hcd_complete_urb_cb_t complete;
|
||||
dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/** @name HCD Core API */
|
||||
/** @{ */
|
||||
/** This function allocates dwc_otg_hcd structure and returns pointer on it. */
|
||||
extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
|
||||
|
||||
/** This function should be called to initiate HCD Core.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param core_if The DWC_OTG Core
|
||||
*
|
||||
* Returns -DWC_E_NO_MEMORY if no enough memory.
|
||||
* Returns 0 on success
|
||||
*/
|
||||
extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
|
||||
|
||||
/** Frees HCD
|
||||
*
|
||||
* @param hcd The HCD
|
||||
*/
|
||||
extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
|
||||
|
||||
/** This function should be called on every hardware interrupt.
|
||||
*
|
||||
* @param dwc_otg_hcd The HCD
|
||||
*
|
||||
* Returns non zero if interrupt is handled
|
||||
* Return 0 if interrupt is not handled
|
||||
*/
|
||||
extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
|
||||
|
||||
/** This function is used to handle the fast interrupt
|
||||
*
|
||||
*/
|
||||
#ifdef CONFIG_ARM64
|
||||
extern void dwc_otg_hcd_handle_fiq(void);
|
||||
#else
|
||||
extern void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns private data set by
|
||||
* dwc_otg_hcd_set_priv_data function.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
*/
|
||||
extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
|
||||
|
||||
/**
|
||||
* Set private data.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param priv_data pointer to be stored in private data
|
||||
*/
|
||||
extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
|
||||
|
||||
/**
|
||||
* This function initializes the HCD Core.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param fops The Function Driver Operations data structure containing pointers to all callbacks.
|
||||
*
|
||||
* Returns -DWC_E_NO_DEVICE if Core is currently is in device mode.
|
||||
* Returns 0 on success
|
||||
*/
|
||||
extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
|
||||
struct dwc_otg_hcd_function_ops *fops);
|
||||
|
||||
/**
|
||||
* Halts the DWC_otg host mode operations in a clean manner. USB transfers are
|
||||
* stopped.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
*/
|
||||
extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
|
||||
|
||||
/**
|
||||
* Handles hub class-specific requests.
|
||||
*
|
||||
* @param dwc_otg_hcd The HCD
|
||||
* @param typeReq Request Type
|
||||
* @param wValue wValue from control request
|
||||
* @param wIndex wIndex from control request
|
||||
* @param buf data buffer
|
||||
* @param wLength data buffer length
|
||||
*
|
||||
* Returns -DWC_E_INVALID if invalid argument is passed
|
||||
* Returns 0 on success
|
||||
*/
|
||||
extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
|
||||
uint16_t typeReq, uint16_t wValue,
|
||||
uint16_t wIndex, uint8_t * buf,
|
||||
uint16_t wLength);
|
||||
|
||||
/**
|
||||
* Returns otg port number.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
*/
|
||||
extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
|
||||
|
||||
/**
|
||||
* Returns OTG version - either 1.3 or 2.0.
|
||||
*
|
||||
* @param core_if The core_if structure pointer
|
||||
*/
|
||||
extern uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if);
|
||||
|
||||
/**
|
||||
* Returns 1 if currently core is acting as B host, and 0 otherwise.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
*/
|
||||
extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
|
||||
|
||||
/**
|
||||
* Returns current frame number.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
*/
|
||||
extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
|
||||
|
||||
/**
|
||||
* Dumps hcd state.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
*/
|
||||
extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
|
||||
|
||||
/**
|
||||
* Dump the average frame remaining at SOF. This can be used to
|
||||
* determine average interrupt latency. Frame remaining is also shown for
|
||||
* start transfer and two additional sample points.
|
||||
* Currently this function is not implemented.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
*/
|
||||
extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
|
||||
|
||||
/**
|
||||
* Sends LPM transaction to the local device.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param devaddr Device Address
|
||||
* @param hird Host initiated resume duration
|
||||
* @param bRemoteWake Value of bRemoteWake field in LPM transaction
|
||||
*
|
||||
* Returns negative value if sending LPM transaction was not succeeded.
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
|
||||
uint8_t hird, uint8_t bRemoteWake);
|
||||
|
||||
/* URB interface */
|
||||
|
||||
/**
|
||||
* Allocates memory for dwc_otg_hcd_urb structure.
|
||||
* Allocated memory should be freed by call of DWC_FREE.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param iso_desc_count Count of ISOC descriptors
|
||||
* @param atomic_alloc Specefies whether to perform atomic allocation.
|
||||
*/
|
||||
extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
|
||||
int iso_desc_count,
|
||||
int atomic_alloc);
|
||||
|
||||
/**
|
||||
* Set pipe information in URB.
|
||||
*
|
||||
* @param hcd_urb DWC_OTG URB
|
||||
* @param devaddr Device Address
|
||||
* @param ep_num Endpoint Number
|
||||
* @param ep_type Endpoint Type
|
||||
* @param ep_dir Endpoint Direction
|
||||
* @param mps Max Packet Size
|
||||
*/
|
||||
extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
|
||||
uint8_t devaddr, uint8_t ep_num,
|
||||
uint8_t ep_type, uint8_t ep_dir,
|
||||
uint16_t mps);
|
||||
|
||||
/* Transfer flags */
|
||||
#define URB_GIVEBACK_ASAP 0x1
|
||||
#define URB_SEND_ZERO_PACKET 0x2
|
||||
|
||||
/**
|
||||
* Sets dwc_otg_hcd_urb parameters.
|
||||
*
|
||||
* @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
|
||||
* @param urb_handle Unique handle for request, this will be passed back
|
||||
* to function driver in completion callback.
|
||||
* @param buf The buffer for the data
|
||||
* @param dma The DMA buffer for the data
|
||||
* @param buflen Transfer length
|
||||
* @param sp Buffer for setup data
|
||||
* @param sp_dma DMA address of setup data buffer
|
||||
* @param flags Transfer flags
|
||||
* @param interval Polling interval for interrupt or isochronous transfers.
|
||||
*/
|
||||
extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
|
||||
void *urb_handle, void *buf,
|
||||
dwc_dma_t dma, uint32_t buflen, void *sp,
|
||||
dwc_dma_t sp_dma, uint32_t flags,
|
||||
uint16_t interval);
|
||||
|
||||
/** Gets status from dwc_otg_hcd_urb
|
||||
*
|
||||
* @param dwc_otg_urb DWC_OTG URB
|
||||
*/
|
||||
extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
|
||||
|
||||
/** Gets actual length from dwc_otg_hcd_urb
|
||||
*
|
||||
* @param dwc_otg_urb DWC_OTG URB
|
||||
*/
|
||||
extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
|
||||
dwc_otg_urb);
|
||||
|
||||
/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs
|
||||
*
|
||||
* @param dwc_otg_urb DWC_OTG URB
|
||||
*/
|
||||
extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
|
||||
dwc_otg_urb);
|
||||
|
||||
/** Set ISOC descriptor offset and length
|
||||
*
|
||||
* @param dwc_otg_urb DWC_OTG URB
|
||||
* @param desc_num ISOC descriptor number
|
||||
* @param offset Offset from beginig of buffer.
|
||||
* @param length Transaction length
|
||||
*/
|
||||
extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
|
||||
int desc_num, uint32_t offset,
|
||||
uint32_t length);
|
||||
|
||||
/** Get status of ISOC descriptor, specified by desc_num
|
||||
*
|
||||
* @param dwc_otg_urb DWC_OTG URB
|
||||
* @param desc_num ISOC descriptor number
|
||||
*/
|
||||
extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
|
||||
dwc_otg_urb, int desc_num);
|
||||
|
||||
/** Get actual length of ISOC descriptor, specified by desc_num
|
||||
*
|
||||
* @param dwc_otg_urb DWC_OTG URB
|
||||
* @param desc_num ISOC descriptor number
|
||||
*/
|
||||
extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
|
||||
dwc_otg_urb,
|
||||
int desc_num);
|
||||
|
||||
/** Queue URB. After transfer is completes, the complete callback will be called with the URB status
|
||||
*
|
||||
* @param dwc_otg_hcd The HCD
|
||||
* @param dwc_otg_urb DWC_OTG URB
|
||||
* @param ep_handle Out parameter for returning endpoint handle
|
||||
* @param atomic_alloc Flag to do atomic allocation if needed
|
||||
*
|
||||
* Returns -DWC_E_NO_DEVICE if no device is connected.
|
||||
* Returns -DWC_E_NO_MEMORY if there is no enough memory.
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
|
||||
dwc_otg_hcd_urb_t * dwc_otg_urb,
|
||||
void **ep_handle, int atomic_alloc);
|
||||
|
||||
/** De-queue the specified URB
|
||||
*
|
||||
* @param dwc_otg_hcd The HCD
|
||||
* @param dwc_otg_urb DWC_OTG URB
|
||||
*/
|
||||
extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
|
||||
dwc_otg_hcd_urb_t * dwc_otg_urb);
|
||||
|
||||
/** Frees resources in the DWC_otg controller related to a given endpoint.
|
||||
* Any URBs for the endpoint must already be dequeued.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
|
||||
* @param retry Number of retries if there are queued transfers.
|
||||
*
|
||||
* Returns -DWC_E_INVALID if invalid arguments are passed.
|
||||
* Returns 0 on success
|
||||
*/
|
||||
extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
|
||||
int retry);
|
||||
|
||||
/* Resets the data toggle in qh structure. This function can be called from
|
||||
* usb_clear_halt routine.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
|
||||
*
|
||||
* Returns -DWC_E_INVALID if invalid arguments are passed.
|
||||
* Returns 0 on success
|
||||
*/
|
||||
extern int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle);
|
||||
|
||||
/** Returns 1 if status of specified port is changed and 0 otherwise.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param port Port number
|
||||
*/
|
||||
extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
|
||||
|
||||
/** Call this function to check if bandwidth was allocated for specified endpoint.
|
||||
* Only for ISOC and INTERRUPT endpoints.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param ep_handle Endpoint handle
|
||||
*/
|
||||
extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
|
||||
void *ep_handle);
|
||||
|
||||
/** Call this function to check if bandwidth was freed for specified endpoint.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param ep_handle Endpoint handle
|
||||
*/
|
||||
extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
|
||||
|
||||
/** Returns bandwidth allocated for specified endpoint in microseconds.
|
||||
* Only for ISOC and INTERRUPT endpoints.
|
||||
*
|
||||
* @param hcd The HCD
|
||||
* @param ep_handle Endpoint handle
|
||||
*/
|
||||
extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
|
||||
void *ep_handle);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* __DWC_HCD_IF_H__ */
|
||||
#endif /* DWC_DEVICE_ONLY */
|
||||
2757
drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
Normal file
2757
drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
Normal file
File diff suppressed because it is too large
Load Diff
1086
drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
Normal file
1086
drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
Normal file
File diff suppressed because it is too large
Load Diff
970
drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
Normal file
970
drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
Normal file
@@ -0,0 +1,970 @@
|
||||
/* ==========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
|
||||
* $Revision: #44 $
|
||||
* $Date: 2011/10/26 $
|
||||
* $Change: 1873028 $
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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 DWC_DEVICE_ONLY
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* This file contains the functions to manage Queue Heads and Queue
|
||||
* Transfer Descriptors.
|
||||
*/
|
||||
|
||||
#include "dwc_otg_hcd.h"
|
||||
#include "dwc_otg_regs.h"
|
||||
|
||||
extern bool microframe_schedule;
|
||||
extern unsigned short int_ep_interval_min;
|
||||
|
||||
/**
|
||||
* Free each QTD in the QH's QTD-list then free the QH. QH should already be
|
||||
* removed from a list. QTD list should already be empty if called from URB
|
||||
* Dequeue.
|
||||
*
|
||||
* @param hcd HCD instance.
|
||||
* @param qh The QH to free.
|
||||
*/
|
||||
void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
{
|
||||
dwc_otg_qtd_t *qtd, *qtd_tmp;
|
||||
dwc_irqflags_t flags;
|
||||
uint32_t buf_size = 0;
|
||||
uint8_t *align_buf_virt = NULL;
|
||||
dwc_dma_t align_buf_dma;
|
||||
struct device *dev = dwc_otg_hcd_to_dev(hcd);
|
||||
|
||||
/* Free each QTD in the QTD list */
|
||||
DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
|
||||
DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
|
||||
DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
|
||||
dwc_otg_hcd_qtd_free(qtd);
|
||||
}
|
||||
|
||||
if (hcd->core_if->dma_desc_enable) {
|
||||
dwc_otg_hcd_qh_free_ddma(hcd, qh);
|
||||
} else if (qh->dw_align_buf) {
|
||||
if (qh->ep_type == UE_ISOCHRONOUS) {
|
||||
buf_size = 4096;
|
||||
} else {
|
||||
buf_size = hcd->core_if->core_params->max_transfer_size;
|
||||
}
|
||||
align_buf_virt = qh->dw_align_buf;
|
||||
align_buf_dma = qh->dw_align_buf_dma;
|
||||
}
|
||||
|
||||
DWC_FREE(qh);
|
||||
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
|
||||
if (align_buf_virt)
|
||||
DWC_DMA_FREE(dev, buf_size, align_buf_virt, align_buf_dma);
|
||||
return;
|
||||
}
|
||||
|
||||
#define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6)
|
||||
#define HS_HOST_DELAY 5 /* nanoseconds */
|
||||
#define FS_LS_HOST_DELAY 1000 /* nanoseconds */
|
||||
#define HUB_LS_SETUP 333 /* nanoseconds */
|
||||
#define NS_TO_US(ns) ((ns + 500) / 1000)
|
||||
/* convert & round nanoseconds to microseconds */
|
||||
|
||||
static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
|
||||
{
|
||||
unsigned long retval;
|
||||
|
||||
switch (speed) {
|
||||
case USB_SPEED_HIGH:
|
||||
if (is_isoc) {
|
||||
retval =
|
||||
((38 * 8 * 2083) +
|
||||
(2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
|
||||
HS_HOST_DELAY;
|
||||
} else {
|
||||
retval =
|
||||
((55 * 8 * 2083) +
|
||||
(2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
|
||||
HS_HOST_DELAY;
|
||||
}
|
||||
break;
|
||||
case USB_SPEED_FULL:
|
||||
if (is_isoc) {
|
||||
retval =
|
||||
(8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
|
||||
if (is_in) {
|
||||
retval = 7268 + FS_LS_HOST_DELAY + retval;
|
||||
} else {
|
||||
retval = 6265 + FS_LS_HOST_DELAY + retval;
|
||||
}
|
||||
} else {
|
||||
retval =
|
||||
(8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
|
||||
retval = 9107 + FS_LS_HOST_DELAY + retval;
|
||||
}
|
||||
break;
|
||||
case USB_SPEED_LOW:
|
||||
if (is_in) {
|
||||
retval =
|
||||
(67667 * (31 + 10 * BitStuffTime(bytecount))) /
|
||||
1000;
|
||||
retval =
|
||||
64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
|
||||
retval;
|
||||
} else {
|
||||
retval =
|
||||
(66700 * (31 + 10 * BitStuffTime(bytecount))) /
|
||||
1000;
|
||||
retval =
|
||||
64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
|
||||
retval;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DWC_WARN("Unknown device speed\n");
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
return NS_TO_US(retval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a QH structure.
|
||||
*
|
||||
* @param hcd The HCD state structure for the DWC OTG controller.
|
||||
* @param qh The QH to init.
|
||||
* @param urb Holds the information about the device/endpoint that we need
|
||||
* to initialize the QH.
|
||||
*/
|
||||
#define SCHEDULE_SLOP 10
|
||||
void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
|
||||
{
|
||||
char *speed, *type;
|
||||
int dev_speed;
|
||||
uint32_t hub_addr, hub_port;
|
||||
hprt0_data_t hprt;
|
||||
|
||||
dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
|
||||
hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
|
||||
|
||||
/* Initialize QH */
|
||||
qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
|
||||
qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
|
||||
|
||||
qh->data_toggle = DWC_OTG_HC_PID_DATA0;
|
||||
qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
|
||||
DWC_CIRCLEQ_INIT(&qh->qtd_list);
|
||||
DWC_LIST_INIT(&qh->qh_list_entry);
|
||||
qh->channel = NULL;
|
||||
|
||||
/* FS/LS Enpoint on HS Hub
|
||||
* NOT virtual root hub */
|
||||
dev_speed = hcd->fops->speed(hcd, urb->priv);
|
||||
|
||||
hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
|
||||
qh->do_split = 0;
|
||||
if (microframe_schedule)
|
||||
qh->speed = dev_speed;
|
||||
|
||||
qh->nak_frame = 0xffff;
|
||||
|
||||
if (hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED &&
|
||||
dev_speed != USB_SPEED_HIGH) {
|
||||
DWC_DEBUGPL(DBG_HCD,
|
||||
"QH init: EP %d: TT found at hub addr %d, for port %d\n",
|
||||
dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
|
||||
hub_port);
|
||||
qh->do_split = 1;
|
||||
qh->skip_count = 0;
|
||||
}
|
||||
|
||||
if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
|
||||
/* Compute scheduling parameters once and save them. */
|
||||
|
||||
/** @todo Account for split transfers in the bus time. */
|
||||
int bytecount =
|
||||
dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
|
||||
|
||||
qh->usecs =
|
||||
calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
|
||||
qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
|
||||
bytecount);
|
||||
/* Start in a slightly future (micro)frame. */
|
||||
qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
|
||||
SCHEDULE_SLOP);
|
||||
qh->interval = urb->interval;
|
||||
|
||||
if (hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) {
|
||||
if (dev_speed == USB_SPEED_LOW ||
|
||||
dev_speed == USB_SPEED_FULL) {
|
||||
qh->interval *= 8;
|
||||
qh->sched_frame |= 0x7;
|
||||
qh->start_split_frame = qh->sched_frame;
|
||||
} else if (int_ep_interval_min >= 2 &&
|
||||
qh->interval < int_ep_interval_min &&
|
||||
qh->ep_type == UE_INTERRUPT) {
|
||||
qh->interval = int_ep_interval_min;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
|
||||
DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh);
|
||||
DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n",
|
||||
dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
|
||||
DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n",
|
||||
dwc_otg_hcd_get_ep_num(&urb->pipe_info),
|
||||
dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
|
||||
switch (dev_speed) {
|
||||
case USB_SPEED_LOW:
|
||||
qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
|
||||
speed = "low";
|
||||
break;
|
||||
case USB_SPEED_FULL:
|
||||
qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
|
||||
speed = "full";
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
|
||||
speed = "high";
|
||||
break;
|
||||
default:
|
||||
speed = "?";
|
||||
break;
|
||||
}
|
||||
DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed);
|
||||
|
||||
switch (qh->ep_type) {
|
||||
case UE_ISOCHRONOUS:
|
||||
type = "isochronous";
|
||||
break;
|
||||
case UE_INTERRUPT:
|
||||
type = "interrupt";
|
||||
break;
|
||||
case UE_CONTROL:
|
||||
type = "control";
|
||||
break;
|
||||
case UE_BULK:
|
||||
type = "bulk";
|
||||
break;
|
||||
default:
|
||||
type = "?";
|
||||
break;
|
||||
}
|
||||
|
||||
DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (qh->ep_type == UE_INTERRUPT) {
|
||||
DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
|
||||
qh->usecs);
|
||||
DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
|
||||
qh->interval);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allocates and initializes a QH.
|
||||
*
|
||||
* @param hcd The HCD state structure for the DWC OTG controller.
|
||||
* @param urb Holds the information about the device/endpoint that we need
|
||||
* to initialize the QH.
|
||||
* @param atomic_alloc Flag to do atomic allocation if needed
|
||||
*
|
||||
* @return Returns pointer to the newly allocated QH, or NULL on error. */
|
||||
dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
|
||||
dwc_otg_hcd_urb_t * urb, int atomic_alloc)
|
||||
{
|
||||
dwc_otg_qh_t *qh;
|
||||
|
||||
/* Allocate memory */
|
||||
/** @todo add memflags argument */
|
||||
qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
|
||||
if (qh == NULL) {
|
||||
DWC_ERROR("qh allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qh_init(hcd, qh, urb);
|
||||
|
||||
if (hcd->core_if->dma_desc_enable
|
||||
&& (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
|
||||
dwc_otg_hcd_qh_free(hcd, qh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return qh;
|
||||
}
|
||||
|
||||
/* microframe_schedule=0 start */
|
||||
|
||||
/**
|
||||
* Checks that a channel is available for a periodic transfer.
|
||||
*
|
||||
* @return 0 if successful, negative error code otherise.
|
||||
*/
|
||||
static int periodic_channel_available(dwc_otg_hcd_t * hcd)
|
||||
{
|
||||
/*
|
||||
* Currently assuming that there is a dedicated host channnel for each
|
||||
* periodic transaction plus at least one host channel for
|
||||
* non-periodic transactions.
|
||||
*/
|
||||
int status;
|
||||
int num_channels;
|
||||
|
||||
num_channels = hcd->core_if->core_params->host_channels;
|
||||
if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
|
||||
&& (hcd->periodic_channels < num_channels - 1)) {
|
||||
status = 0;
|
||||
} else {
|
||||
DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
|
||||
__func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels); //NOTICE
|
||||
status = -DWC_E_NO_SPACE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that there is sufficient bandwidth for the specified QH in the
|
||||
* periodic schedule. For simplicity, this calculation assumes that all the
|
||||
* transfers in the periodic schedule may occur in the same (micro)frame.
|
||||
*
|
||||
* @param hcd The HCD state structure for the DWC OTG controller.
|
||||
* @param qh QH containing periodic bandwidth required.
|
||||
*
|
||||
* @return 0 if successful, negative error code otherwise.
|
||||
*/
|
||||
static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
{
|
||||
int status;
|
||||
int16_t max_claimed_usecs;
|
||||
|
||||
status = 0;
|
||||
|
||||
if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
|
||||
/*
|
||||
* High speed mode.
|
||||
* Max periodic usecs is 80% x 125 usec = 100 usec.
|
||||
*/
|
||||
|
||||
max_claimed_usecs = 100 - qh->usecs;
|
||||
} else {
|
||||
/*
|
||||
* Full speed mode.
|
||||
* Max periodic usecs is 90% x 1000 usec = 900 usec.
|
||||
*/
|
||||
max_claimed_usecs = 900 - qh->usecs;
|
||||
}
|
||||
|
||||
if (hcd->periodic_usecs > max_claimed_usecs) {
|
||||
DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs); //NOTICE
|
||||
status = -DWC_E_NO_SPACE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* microframe_schedule=0 end */
|
||||
|
||||
/**
|
||||
* Microframe scheduler
|
||||
* track the total use in hcd->frame_usecs
|
||||
* keep each qh use in qh->frame_usecs
|
||||
* when surrendering the qh then donate the time back
|
||||
*/
|
||||
const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 };
|
||||
|
||||
/*
|
||||
* called from dwc_otg_hcd.c:dwc_otg_hcd_init
|
||||
*/
|
||||
void init_hcd_usecs(dwc_otg_hcd_t *_hcd)
|
||||
{
|
||||
int i;
|
||||
if (_hcd->flags.b.port_speed == DWC_HPRT0_PRTSPD_FULL_SPEED) {
|
||||
_hcd->frame_usecs[0] = 900;
|
||||
for (i = 1; i < 8; i++)
|
||||
_hcd->frame_usecs[i] = 0;
|
||||
} else {
|
||||
for (i = 0; i < 8; i++)
|
||||
_hcd->frame_usecs[i] = max_uframe_usecs[i];
|
||||
}
|
||||
}
|
||||
|
||||
static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
|
||||
{
|
||||
int i;
|
||||
unsigned short utime;
|
||||
int t_left;
|
||||
int ret;
|
||||
int done;
|
||||
|
||||
ret = -1;
|
||||
utime = _qh->usecs;
|
||||
t_left = utime;
|
||||
i = 0;
|
||||
done = 0;
|
||||
while (done == 0) {
|
||||
/* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */
|
||||
if (utime <= _hcd->frame_usecs[i]) {
|
||||
_hcd->frame_usecs[i] -= utime;
|
||||
_qh->frame_usecs[i] += utime;
|
||||
t_left -= utime;
|
||||
ret = i;
|
||||
done = 1;
|
||||
return ret;
|
||||
} else {
|
||||
i++;
|
||||
if (i == 8) {
|
||||
done = 1;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* use this for FS apps that can span multiple uframes
|
||||
*/
|
||||
static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
unsigned short utime;
|
||||
int t_left;
|
||||
int ret;
|
||||
int done;
|
||||
unsigned short xtime;
|
||||
|
||||
ret = -1;
|
||||
utime = _qh->usecs;
|
||||
t_left = utime;
|
||||
i = 0;
|
||||
done = 0;
|
||||
loop:
|
||||
while (done == 0) {
|
||||
if(_hcd->frame_usecs[i] <= 0) {
|
||||
i++;
|
||||
if (i == 8) {
|
||||
done = 1;
|
||||
ret = -1;
|
||||
}
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* we need n consecutive slots
|
||||
* so use j as a start slot j plus j+1 must be enough time (for now)
|
||||
*/
|
||||
xtime= _hcd->frame_usecs[i];
|
||||
for (j = i+1 ; j < 8 ; j++ ) {
|
||||
/*
|
||||
* if we add this frame remaining time to xtime we may
|
||||
* be OK, if not we need to test j for a complete frame
|
||||
*/
|
||||
if ((xtime+_hcd->frame_usecs[j]) < utime) {
|
||||
if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) {
|
||||
j = 8;
|
||||
ret = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (xtime >= utime) {
|
||||
ret = i;
|
||||
j = 8; /* stop loop with a good value ret */
|
||||
continue;
|
||||
}
|
||||
/* add the frame time to x time */
|
||||
xtime += _hcd->frame_usecs[j];
|
||||
/* we must have a fully available next frame or break */
|
||||
if ((xtime < utime)
|
||||
&& (_hcd->frame_usecs[j] == max_uframe_usecs[j])) {
|
||||
ret = -1;
|
||||
j = 8; /* stop loop with a bad value ret */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ret >= 0) {
|
||||
t_left = utime;
|
||||
for (j = i; (t_left>0) && (j < 8); j++ ) {
|
||||
t_left -= _hcd->frame_usecs[j];
|
||||
if ( t_left <= 0 ) {
|
||||
_qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left;
|
||||
_hcd->frame_usecs[j]= -t_left;
|
||||
ret = i;
|
||||
done = 1;
|
||||
} else {
|
||||
_qh->frame_usecs[j] += _hcd->frame_usecs[j];
|
||||
_hcd->frame_usecs[j] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
if (i == 8) {
|
||||
done = 1;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
|
||||
{
|
||||
int ret;
|
||||
ret = -1;
|
||||
|
||||
if (_qh->speed == USB_SPEED_HIGH ||
|
||||
_hcd->flags.b.port_speed == DWC_HPRT0_PRTSPD_FULL_SPEED) {
|
||||
/* if this is a hs transaction we need a full frame - or account for FS usecs */
|
||||
ret = find_single_uframe(_hcd, _qh);
|
||||
} else {
|
||||
/* if this is a fs transaction we may need a sequence of frames */
|
||||
ret = find_multi_uframe(_hcd, _qh);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the max transfer size allowed in a host channel is large enough
|
||||
* to handle the maximum data transfer in a single (micro)frame for a periodic
|
||||
* transfer.
|
||||
*
|
||||
* @param hcd The HCD state structure for the DWC OTG controller.
|
||||
* @param qh QH for a periodic endpoint.
|
||||
*
|
||||
* @return 0 if successful, negative error code otherwise.
|
||||
*/
|
||||
static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
{
|
||||
int status;
|
||||
uint32_t max_xfer_size;
|
||||
uint32_t max_channel_xfer_size;
|
||||
|
||||
status = 0;
|
||||
|
||||
max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
|
||||
max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
|
||||
|
||||
if (max_xfer_size > max_channel_xfer_size) {
|
||||
DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
|
||||
__func__, max_xfer_size, max_channel_xfer_size); //NOTICE
|
||||
status = -DWC_E_NO_SPACE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Schedules an interrupt or isochronous transfer in the periodic schedule.
|
||||
*
|
||||
* @param hcd The HCD state structure for the DWC OTG controller.
|
||||
* @param qh QH for the periodic transfer. The QH should already contain the
|
||||
* scheduling information.
|
||||
*
|
||||
* @return 0 if successful, negative error code otherwise.
|
||||
*/
|
||||
static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (microframe_schedule) {
|
||||
int frame;
|
||||
status = find_uframe(hcd, qh);
|
||||
frame = -1;
|
||||
if (status == 0) {
|
||||
frame = 7;
|
||||
} else {
|
||||
if (status > 0 )
|
||||
frame = status-1;
|
||||
}
|
||||
|
||||
/* Set the new frame up */
|
||||
if (frame > -1) {
|
||||
qh->sched_frame &= ~0x7;
|
||||
qh->sched_frame |= (frame & 7);
|
||||
}
|
||||
|
||||
if (status != -1)
|
||||
status = 0;
|
||||
} else {
|
||||
status = periodic_channel_available(hcd);
|
||||
if (status) {
|
||||
DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE
|
||||
return status;
|
||||
}
|
||||
|
||||
status = check_periodic_bandwidth(hcd, qh);
|
||||
}
|
||||
if (status) {
|
||||
DWC_INFO("%s: Insufficient periodic bandwidth for "
|
||||
"periodic transfer.\n", __func__);
|
||||
return -DWC_E_NO_SPACE;
|
||||
}
|
||||
status = check_max_xfer_size(hcd, qh);
|
||||
if (status) {
|
||||
DWC_INFO("%s: Channel max transfer size too small "
|
||||
"for periodic transfer.\n", __func__);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (hcd->core_if->dma_desc_enable) {
|
||||
/* Don't rely on SOF and start in ready schedule */
|
||||
DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
|
||||
}
|
||||
else {
|
||||
if(fiq_enable && (DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, hcd->fiq_state->next_sched_frame)))
|
||||
{
|
||||
hcd->fiq_state->next_sched_frame = qh->sched_frame;
|
||||
|
||||
}
|
||||
/* Always start in the inactive schedule. */
|
||||
DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
|
||||
}
|
||||
|
||||
if (!microframe_schedule) {
|
||||
/* Reserve the periodic channel. */
|
||||
hcd->periodic_channels++;
|
||||
}
|
||||
|
||||
/* Update claimed usecs per (micro)frame. */
|
||||
hcd->periodic_usecs += qh->usecs;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function adds a QH to either the non periodic or periodic schedule if
|
||||
* it is not already in the schedule. If the QH is already in the schedule, no
|
||||
* action is taken.
|
||||
*
|
||||
* @return 0 if successful, negative error code otherwise.
|
||||
*/
|
||||
int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
{
|
||||
int status = 0;
|
||||
gintmsk_data_t intr_mask = {.d32 = 0 };
|
||||
|
||||
if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
|
||||
/* QH already in a schedule. */
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Add the new QH to the appropriate schedule */
|
||||
if (dwc_qh_is_non_per(qh)) {
|
||||
/* Always start in the inactive schedule. */
|
||||
DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
|
||||
&qh->qh_list_entry);
|
||||
//hcd->fiq_state->kick_np_queues = 1;
|
||||
} else {
|
||||
status = schedule_periodic(hcd, qh);
|
||||
if ( !hcd->periodic_qh_count ) {
|
||||
intr_mask.b.sofintr = 1;
|
||||
if (fiq_enable) {
|
||||
local_fiq_disable();
|
||||
fiq_fsm_spin_lock(&hcd->fiq_state->lock);
|
||||
DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
|
||||
fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
|
||||
local_fiq_enable();
|
||||
} else {
|
||||
DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
|
||||
}
|
||||
}
|
||||
hcd->periodic_qh_count++;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an interrupt or isochronous transfer from the periodic schedule.
|
||||
*
|
||||
* @param hcd The HCD state structure for the DWC OTG controller.
|
||||
* @param qh QH for the periodic transfer.
|
||||
*/
|
||||
static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
{
|
||||
int i;
|
||||
DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
|
||||
|
||||
/* Update claimed usecs per (micro)frame. */
|
||||
hcd->periodic_usecs -= qh->usecs;
|
||||
|
||||
if (!microframe_schedule) {
|
||||
/* Release the periodic channel reservation. */
|
||||
hcd->periodic_channels--;
|
||||
} else {
|
||||
for (i = 0; i < 8; i++) {
|
||||
hcd->frame_usecs[i] += qh->frame_usecs[i];
|
||||
qh->frame_usecs[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a QH from either the non-periodic or periodic schedule. Memory is
|
||||
* not freed.
|
||||
*
|
||||
* @param hcd The HCD state structure.
|
||||
* @param qh QH to remove from schedule. */
|
||||
void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
{
|
||||
gintmsk_data_t intr_mask = {.d32 = 0 };
|
||||
|
||||
if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
|
||||
/* QH is not in a schedule. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (dwc_qh_is_non_per(qh)) {
|
||||
if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
|
||||
hcd->non_periodic_qh_ptr =
|
||||
hcd->non_periodic_qh_ptr->next;
|
||||
}
|
||||
DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
|
||||
//if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_inactive))
|
||||
// hcd->fiq_state->kick_np_queues = 1;
|
||||
} else {
|
||||
deschedule_periodic(hcd, qh);
|
||||
hcd->periodic_qh_count--;
|
||||
if( !hcd->periodic_qh_count && !fiq_fsm_enable ) {
|
||||
intr_mask.b.sofintr = 1;
|
||||
if (fiq_enable) {
|
||||
local_fiq_disable();
|
||||
fiq_fsm_spin_lock(&hcd->fiq_state->lock);
|
||||
DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
|
||||
fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
|
||||
local_fiq_enable();
|
||||
} else {
|
||||
DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates a QH. For non-periodic QHs, removes the QH from the active
|
||||
* non-periodic schedule. The QH is added to the inactive non-periodic
|
||||
* schedule if any QTDs are still attached to the QH.
|
||||
*
|
||||
* For periodic QHs, the QH is removed from the periodic queued schedule. If
|
||||
* there are any QTDs still attached to the QH, the QH is added to either the
|
||||
* periodic inactive schedule or the periodic ready schedule and its next
|
||||
* scheduled frame is calculated. The QH is placed in the ready schedule if
|
||||
* the scheduled frame has been reached already. Otherwise it's placed in the
|
||||
* inactive schedule. If there are no QTDs attached to the QH, the QH is
|
||||
* completely removed from the periodic schedule.
|
||||
*/
|
||||
void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
|
||||
int sched_next_periodic_split)
|
||||
{
|
||||
if (dwc_qh_is_non_per(qh)) {
|
||||
dwc_otg_hcd_qh_remove(hcd, qh);
|
||||
if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
|
||||
/* Add back to inactive non-periodic schedule. */
|
||||
dwc_otg_hcd_qh_add(hcd, qh);
|
||||
//hcd->fiq_state->kick_np_queues = 1;
|
||||
} else {
|
||||
if(nak_holdoff && qh->do_split) {
|
||||
qh->nak_frame = 0xFFFF;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
|
||||
|
||||
if (qh->do_split) {
|
||||
/* Schedule the next continuing periodic split transfer */
|
||||
if (sched_next_periodic_split) {
|
||||
|
||||
qh->sched_frame = frame_number;
|
||||
|
||||
if (dwc_frame_num_le(frame_number,
|
||||
dwc_frame_num_inc
|
||||
(qh->start_split_frame,
|
||||
1))) {
|
||||
/*
|
||||
* Allow one frame to elapse after start
|
||||
* split microframe before scheduling
|
||||
* complete split, but DONT if we are
|
||||
* doing the next start split in the
|
||||
* same frame for an ISOC out.
|
||||
*/
|
||||
if ((qh->ep_type != UE_ISOCHRONOUS) ||
|
||||
(qh->ep_is_in != 0)) {
|
||||
qh->sched_frame =
|
||||
dwc_frame_num_inc(qh->sched_frame, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qh->sched_frame =
|
||||
dwc_frame_num_inc(qh->start_split_frame,
|
||||
qh->interval);
|
||||
if (dwc_frame_num_le
|
||||
(qh->sched_frame, frame_number)) {
|
||||
qh->sched_frame = frame_number;
|
||||
}
|
||||
qh->sched_frame |= 0x7;
|
||||
qh->start_split_frame = qh->sched_frame;
|
||||
}
|
||||
} else {
|
||||
qh->sched_frame =
|
||||
dwc_frame_num_inc(qh->sched_frame, qh->interval);
|
||||
if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
|
||||
qh->sched_frame = frame_number;
|
||||
}
|
||||
}
|
||||
|
||||
if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
|
||||
dwc_otg_hcd_qh_remove(hcd, qh);
|
||||
} else {
|
||||
/*
|
||||
* Remove from periodic_sched_queued and move to
|
||||
* appropriate queue.
|
||||
*/
|
||||
if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) ||
|
||||
(!microframe_schedule && qh->sched_frame == frame_number)) {
|
||||
DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
|
||||
&qh->qh_list_entry);
|
||||
} else {
|
||||
if(fiq_enable && !dwc_frame_num_le(hcd->fiq_state->next_sched_frame, qh->sched_frame))
|
||||
{
|
||||
hcd->fiq_state->next_sched_frame = qh->sched_frame;
|
||||
}
|
||||
|
||||
DWC_LIST_MOVE_HEAD
|
||||
(&hcd->periodic_sched_inactive,
|
||||
&qh->qh_list_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allocates and initializes a QTD.
|
||||
*
|
||||
* @param urb The URB to create a QTD from. Each URB-QTD pair will end up
|
||||
* pointing to each other so each pair should have a unique correlation.
|
||||
* @param atomic_alloc Flag to do atomic alloc if needed
|
||||
*
|
||||
* @return Returns pointer to the newly allocated QTD, or NULL on error. */
|
||||
dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
|
||||
{
|
||||
dwc_otg_qtd_t *qtd;
|
||||
|
||||
qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
|
||||
if (qtd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dwc_otg_hcd_qtd_init(qtd, urb);
|
||||
return qtd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a QTD structure.
|
||||
*
|
||||
* @param qtd The QTD to initialize.
|
||||
* @param urb The URB to use for initialization. */
|
||||
void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
|
||||
{
|
||||
dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
|
||||
qtd->urb = urb;
|
||||
if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
|
||||
/*
|
||||
* The only time the QTD data toggle is used is on the data
|
||||
* phase of control transfers. This phase always starts with
|
||||
* DATA1.
|
||||
*/
|
||||
qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
|
||||
qtd->control_phase = DWC_OTG_CONTROL_SETUP;
|
||||
}
|
||||
|
||||
/* start split */
|
||||
qtd->complete_split = 0;
|
||||
qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
|
||||
qtd->isoc_split_offset = 0;
|
||||
qtd->in_process = 0;
|
||||
|
||||
/* Store the qtd ptr in the urb to reference what QTD. */
|
||||
urb->qtd = qtd;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function adds a QTD to the QTD-list of a QH. It will find the correct
|
||||
* QH to place the QTD into. If it does not find a QH, then it will create a
|
||||
* new QH. If the QH to which the QTD is added is not currently scheduled, it
|
||||
* is placed into the proper schedule based on its EP type.
|
||||
* HCD lock must be held and interrupts must be disabled on entry
|
||||
*
|
||||
* @param[in] qtd The QTD to add
|
||||
* @param[in] hcd The DWC HCD structure
|
||||
* @param[out] qh out parameter to return queue head
|
||||
* @param atomic_alloc Flag to do atomic alloc if needed
|
||||
*
|
||||
* @return 0 if successful, negative error code otherwise.
|
||||
*/
|
||||
int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
|
||||
dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
|
||||
{
|
||||
int retval = 0;
|
||||
dwc_otg_hcd_urb_t *urb = qtd->urb;
|
||||
|
||||
/*
|
||||
* Get the QH which holds the QTD-list to insert to. Create QH if it
|
||||
* doesn't exist.
|
||||
*/
|
||||
if (*qh == NULL) {
|
||||
*qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
|
||||
if (*qh == NULL) {
|
||||
retval = -DWC_E_NO_MEMORY;
|
||||
goto done;
|
||||
} else {
|
||||
if (fiq_enable)
|
||||
hcd->fiq_state->kick_np_queues = 1;
|
||||
}
|
||||
}
|
||||
retval = dwc_otg_hcd_qh_add(hcd, *qh);
|
||||
if (retval == 0) {
|
||||
DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
|
||||
qtd_list_entry);
|
||||
qtd->qh = *qh;
|
||||
}
|
||||
done:
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif /* DWC_DEVICE_ONLY */
|
||||
199
drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
Normal file
199
drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
Normal file
@@ -0,0 +1,199 @@
|
||||
#ifndef _DWC_OS_DEP_H_
|
||||
#define _DWC_OS_DEP_H_
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* This file contains OS dependent structures.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
|
||||
# include <linux/irq.h>
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
|
||||
# include <linux/usb/ch9.h>
|
||||
#else
|
||||
# include <linux/usb_ch9.h>
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
|
||||
# include <linux/usb/gadget.h>
|
||||
#else
|
||||
# include <linux/usb_gadget.h>
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
|
||||
# include <asm/irq.h>
|
||||
#endif
|
||||
|
||||
#ifdef PCI_INTERFACE
|
||||
# include <asm/io.h>
|
||||
#endif
|
||||
|
||||
#ifdef LM_INTERFACE
|
||||
# include <asm/unaligned.h>
|
||||
# include <asm/sizes.h>
|
||||
# include <asm/param.h>
|
||||
# include <asm/io.h>
|
||||
# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
|
||||
# include <asm/arch/hardware.h>
|
||||
# include <asm/arch/lm.h>
|
||||
# include <asm/arch/irqs.h>
|
||||
# include <asm/arch/regs-irq.h>
|
||||
# else
|
||||
/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure -
|
||||
here we assume that the machine architecture provides definitions
|
||||
in its own header
|
||||
*/
|
||||
# include <mach/lm.h>
|
||||
# include <mach/hardware.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_INTERFACE
|
||||
#include <linux/platform_device.h>
|
||||
#ifdef CONFIG_ARM
|
||||
#include <asm/mach/map.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** The OS page size */
|
||||
#define DWC_OS_PAGE_SIZE PAGE_SIZE
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
|
||||
typedef int gfp_t;
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
|
||||
# define IRQF_SHARED SA_SHIRQ
|
||||
#endif
|
||||
|
||||
typedef struct os_dependent {
|
||||
/** Base address returned from ioremap() */
|
||||
void *base;
|
||||
|
||||
/** Register offset for Diagnostic API */
|
||||
uint32_t reg_offset;
|
||||
|
||||
/** Base address for MPHI peripheral */
|
||||
void *mphi_base;
|
||||
|
||||
/** mphi_base actually points to the SWIRQ block */
|
||||
bool use_swirq;
|
||||
|
||||
/** IRQ number (<0 if not valid) */
|
||||
int irq_num;
|
||||
|
||||
/** FIQ number (<0 if not valid) */
|
||||
int fiq_num;
|
||||
|
||||
#ifdef LM_INTERFACE
|
||||
struct lm_device *lmdev;
|
||||
#elif defined(PCI_INTERFACE)
|
||||
struct pci_dev *pcidev;
|
||||
|
||||
/** Start address of a PCI region */
|
||||
resource_size_t rsrc_start;
|
||||
|
||||
/** Length address of a PCI region */
|
||||
resource_size_t rsrc_len;
|
||||
#elif defined(PLATFORM_INTERFACE)
|
||||
struct platform_device *platformdev;
|
||||
#endif
|
||||
|
||||
} os_dependent_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type for the our device on the chosen bus */
|
||||
#if defined(LM_INTERFACE)
|
||||
typedef struct lm_device dwc_bus_dev_t;
|
||||
#elif defined(PCI_INTERFACE)
|
||||
typedef struct pci_dev dwc_bus_dev_t;
|
||||
#elif defined(PLATFORM_INTERFACE)
|
||||
typedef struct platform_device dwc_bus_dev_t;
|
||||
#endif
|
||||
|
||||
/* Helper macro to retrieve drvdata from the device on the chosen bus */
|
||||
#if defined(LM_INTERFACE)
|
||||
#define DWC_OTG_BUSDRVDATA(_dev) lm_get_drvdata(_dev)
|
||||
#elif defined(PCI_INTERFACE)
|
||||
#define DWC_OTG_BUSDRVDATA(_dev) pci_get_drvdata(_dev)
|
||||
#elif defined(PLATFORM_INTERFACE)
|
||||
#define DWC_OTG_BUSDRVDATA(_dev) platform_get_drvdata(_dev)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Helper macro returning the otg_device structure of a given struct device
|
||||
*
|
||||
* c.f. static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
|
||||
*/
|
||||
#ifdef LM_INTERFACE
|
||||
#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
|
||||
struct lm_device *lm_dev = \
|
||||
container_of(_dev, struct lm_device, dev); \
|
||||
_var = lm_get_drvdata(lm_dev); \
|
||||
} while (0)
|
||||
|
||||
#elif defined(PCI_INTERFACE)
|
||||
#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
|
||||
_var = dev_get_drvdata(_dev); \
|
||||
} while (0)
|
||||
|
||||
#elif defined(PLATFORM_INTERFACE)
|
||||
#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
|
||||
struct platform_device *platform_dev = \
|
||||
container_of(_dev, struct platform_device, dev); \
|
||||
_var = platform_get_drvdata(platform_dev); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Helper macro returning the struct dev of the given struct os_dependent
|
||||
*
|
||||
* c.f. static struct device *dwc_otg_getdev(struct os_dependent *osdep)
|
||||
*/
|
||||
#ifdef LM_INTERFACE
|
||||
#define DWC_OTG_OS_GETDEV(_osdep) \
|
||||
((_osdep).lmdev == NULL? NULL: &(_osdep).lmdev->dev)
|
||||
#elif defined(PCI_INTERFACE)
|
||||
#define DWC_OTG_OS_GETDEV(_osdep) \
|
||||
((_osdep).pci_dev == NULL? NULL: &(_osdep).pci_dev->dev)
|
||||
#elif defined(PLATFORM_INTERFACE)
|
||||
#define DWC_OTG_OS_GETDEV(_osdep) \
|
||||
((_osdep).platformdev == NULL? NULL: &(_osdep).platformdev->dev)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* _DWC_OS_DEP_H_ */
|
||||
2725
drivers/usb/host/dwc_otg/dwc_otg_pcd.c
Normal file
2725
drivers/usb/host/dwc_otg/dwc_otg_pcd.c
Normal file
File diff suppressed because it is too large
Load Diff
273
drivers/usb/host/dwc_otg/dwc_otg_pcd.h
Normal file
273
drivers/usb/host/dwc_otg/dwc_otg_pcd.h
Normal file
@@ -0,0 +1,273 @@
|
||||
/* ==========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
|
||||
* $Revision: #48 $
|
||||
* $Date: 2012/08/10 $
|
||||
* $Change: 2047372 $
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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 DWC_HOST_ONLY
|
||||
#if !defined(__DWC_PCD_H__)
|
||||
#define __DWC_PCD_H__
|
||||
|
||||
#include "dwc_otg_os_dep.h"
|
||||
#include "usb.h"
|
||||
#include "dwc_otg_cil.h"
|
||||
#include "dwc_otg_pcd_if.h"
|
||||
#include "dwc_otg_driver.h"
|
||||
|
||||
struct cfiobject;
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* This file contains the structures, constants, and interfaces for
|
||||
* the Perpherial Contoller Driver (PCD).
|
||||
*
|
||||
* The Peripheral Controller Driver (PCD) for Linux will implement the
|
||||
* Gadget API, so that the existing Gadget drivers can be used. For
|
||||
* the Mass Storage Function driver the File-backed USB Storage Gadget
|
||||
* (FBS) driver will be used. The FBS driver supports the
|
||||
* Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
|
||||
* transports.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Invalid DMA Address */
|
||||
#define DWC_DMA_ADDR_INVALID (~(dwc_dma_t)0)
|
||||
|
||||
/** Max Transfer size for any EP */
|
||||
#define DDMA_MAX_TRANSFER_SIZE 65535
|
||||
|
||||
/**
|
||||
* Get the pointer to the core_if from the pcd pointer.
|
||||
*/
|
||||
#define GET_CORE_IF( _pcd ) (_pcd->core_if)
|
||||
|
||||
/**
|
||||
* States of EP0.
|
||||
*/
|
||||
typedef enum ep0_state {
|
||||
EP0_DISCONNECT, /* no host */
|
||||
EP0_IDLE,
|
||||
EP0_IN_DATA_PHASE,
|
||||
EP0_OUT_DATA_PHASE,
|
||||
EP0_IN_STATUS_PHASE,
|
||||
EP0_OUT_STATUS_PHASE,
|
||||
EP0_STALL,
|
||||
} ep0state_e;
|
||||
|
||||
/** Fordward declaration.*/
|
||||
struct dwc_otg_pcd;
|
||||
|
||||
/** DWC_otg iso request structure.
|
||||
*
|
||||
*/
|
||||
typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
|
||||
|
||||
#ifdef DWC_UTE_PER_IO
|
||||
|
||||
/**
|
||||
* This shall be the exact analogy of the same type structure defined in the
|
||||
* usb_gadget.h. Each descriptor contains
|
||||
*/
|
||||
struct dwc_iso_pkt_desc_port {
|
||||
uint32_t offset;
|
||||
uint32_t length; /* expected length */
|
||||
uint32_t actual_length;
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
struct dwc_iso_xreq_port {
|
||||
/** transfer/submission flag */
|
||||
uint32_t tr_sub_flags;
|
||||
/** Start the request ASAP */
|
||||
#define DWC_EREQ_TF_ASAP 0x00000002
|
||||
/** Just enqueue the request w/o initiating a transfer */
|
||||
#define DWC_EREQ_TF_ENQUEUE 0x00000004
|
||||
|
||||
/**
|
||||
* count of ISO packets attached to this request - shall
|
||||
* not exceed the pio_alloc_pkt_count
|
||||
*/
|
||||
uint32_t pio_pkt_count;
|
||||
/** count of ISO packets allocated for this request */
|
||||
uint32_t pio_alloc_pkt_count;
|
||||
/** number of ISO packet errors */
|
||||
uint32_t error_count;
|
||||
/** reserved for future extension */
|
||||
uint32_t res;
|
||||
/** Will be allocated and freed in the UTE gadget and based on the CFC value */
|
||||
struct dwc_iso_pkt_desc_port *per_io_frame_descs;
|
||||
};
|
||||
#endif
|
||||
/** DWC_otg request structure.
|
||||
* This structure is a list of requests.
|
||||
*/
|
||||
typedef struct dwc_otg_pcd_request {
|
||||
void *priv;
|
||||
void *buf;
|
||||
dwc_dma_t dma;
|
||||
uint32_t length;
|
||||
uint32_t actual;
|
||||
unsigned sent_zlp:1;
|
||||
/**
|
||||
* Used instead of original buffer if
|
||||
* it(physical address) is not dword-aligned.
|
||||
**/
|
||||
uint8_t *dw_align_buf;
|
||||
dwc_dma_t dw_align_buf_dma;
|
||||
|
||||
DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
|
||||
#ifdef DWC_UTE_PER_IO
|
||||
struct dwc_iso_xreq_port ext_req;
|
||||
//void *priv_ereq_nport; /* */
|
||||
#endif
|
||||
} dwc_otg_pcd_request_t;
|
||||
|
||||
DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
|
||||
|
||||
/** PCD EP structure.
|
||||
* This structure describes an EP, there is an array of EPs in the PCD
|
||||
* structure.
|
||||
*/
|
||||
typedef struct dwc_otg_pcd_ep {
|
||||
/** USB EP Descriptor */
|
||||
const usb_endpoint_descriptor_t *desc;
|
||||
|
||||
/** queue of dwc_otg_pcd_requests. */
|
||||
struct req_list queue;
|
||||
unsigned stopped:1;
|
||||
unsigned disabling:1;
|
||||
unsigned dma:1;
|
||||
unsigned queue_sof:1;
|
||||
|
||||
#ifdef DWC_EN_ISOC
|
||||
/** ISOC req handle passed */
|
||||
void *iso_req_handle;
|
||||
#endif //_EN_ISOC_
|
||||
|
||||
/** DWC_otg ep data. */
|
||||
dwc_ep_t dwc_ep;
|
||||
|
||||
/** Pointer to PCD */
|
||||
struct dwc_otg_pcd *pcd;
|
||||
|
||||
void *priv;
|
||||
} dwc_otg_pcd_ep_t;
|
||||
|
||||
/** DWC_otg PCD Structure.
|
||||
* This structure encapsulates the data for the dwc_otg PCD.
|
||||
*/
|
||||
struct dwc_otg_pcd {
|
||||
const struct dwc_otg_pcd_function_ops *fops;
|
||||
/** The DWC otg device pointer */
|
||||
struct dwc_otg_device *otg_dev;
|
||||
/** Core Interface */
|
||||
dwc_otg_core_if_t *core_if;
|
||||
/** State of EP0 */
|
||||
ep0state_e ep0state;
|
||||
/** EP0 Request is pending */
|
||||
unsigned ep0_pending:1;
|
||||
/** Indicates when SET CONFIGURATION Request is in process */
|
||||
unsigned request_config:1;
|
||||
/** The state of the Remote Wakeup Enable. */
|
||||
unsigned remote_wakeup_enable:1;
|
||||
/** The state of the B-Device HNP Enable. */
|
||||
unsigned b_hnp_enable:1;
|
||||
/** The state of A-Device HNP Support. */
|
||||
unsigned a_hnp_support:1;
|
||||
/** The state of the A-Device Alt HNP support. */
|
||||
unsigned a_alt_hnp_support:1;
|
||||
/** Count of pending Requests */
|
||||
unsigned request_pending;
|
||||
|
||||
/** SETUP packet for EP0
|
||||
* This structure is allocated as a DMA buffer on PCD initialization
|
||||
* with enough space for up to 3 setup packets.
|
||||
*/
|
||||
union {
|
||||
usb_device_request_t req;
|
||||
uint32_t d32[2];
|
||||
} *setup_pkt;
|
||||
|
||||
dwc_dma_t setup_pkt_dma_handle;
|
||||
|
||||
/* Additional buffer and flag for CTRL_WR premature case */
|
||||
uint8_t *backup_buf;
|
||||
unsigned data_terminated;
|
||||
|
||||
/** 2-byte dma buffer used to return status from GET_STATUS */
|
||||
uint16_t *status_buf;
|
||||
dwc_dma_t status_buf_dma_handle;
|
||||
|
||||
/** EP0 */
|
||||
dwc_otg_pcd_ep_t ep0;
|
||||
|
||||
/** Array of IN EPs. */
|
||||
dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
|
||||
/** Array of OUT EPs. */
|
||||
dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
|
||||
/** number of valid EPs in the above array. */
|
||||
// unsigned num_eps : 4;
|
||||
dwc_spinlock_t *lock;
|
||||
|
||||
/** Tasklet to defer starting of TEST mode transmissions until
|
||||
* Status Phase has been completed.
|
||||
*/
|
||||
dwc_tasklet_t *test_mode_tasklet;
|
||||
|
||||
/** Tasklet to delay starting of xfer in DMA mode */
|
||||
dwc_tasklet_t *start_xfer_tasklet;
|
||||
|
||||
/** The test mode to enter when the tasklet is executed. */
|
||||
unsigned test_mode;
|
||||
/** The cfi_api structure that implements most of the CFI API
|
||||
* and OTG specific core configuration functionality
|
||||
*/
|
||||
#ifdef DWC_UTE_CFI
|
||||
struct cfiobject *cfi;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
static inline struct device *dwc_otg_pcd_to_dev(struct dwc_otg_pcd *pcd)
|
||||
{
|
||||
return &pcd->otg_dev->os_dep.platformdev->dev;
|
||||
}
|
||||
|
||||
//FIXME this functions should be static, and this prototypes should be removed
|
||||
extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
|
||||
extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
|
||||
dwc_otg_pcd_request_t * req, int32_t status);
|
||||
|
||||
void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
|
||||
void *req_handle);
|
||||
|
||||
extern void do_test_mode(void *data);
|
||||
#endif
|
||||
#endif /* DWC_HOST_ONLY */
|
||||
361
drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
Normal file
361
drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
Normal file
@@ -0,0 +1,361 @@
|
||||
/* ==========================================================================
|
||||
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
|
||||
* $Revision: #11 $
|
||||
* $Date: 2011/10/26 $
|
||||
* $Change: 1873028 $
|
||||
*
|
||||
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
|
||||
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
|
||||
* otherwise expressly agreed to in writing between Synopsys and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product under
|
||||
* any End User Software License Agreement or Agreement for Licensed Product
|
||||
* with Synopsys or any supplement thereto. You are permitted to use and
|
||||
* redistribute this Software in source and binary forms, with or without
|
||||
* modification, provided that redistributions of source code must retain this
|
||||
* notice. You may not view, use, disclose, copy or distribute this file or
|
||||
* any information contained herein except pursuant to this license grant from
|
||||
* Synopsys. If you do not agree with this notice, including the disclaimer
|
||||
* below, then you are not authorized to use the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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 DWC_HOST_ONLY
|
||||
|
||||
#if !defined(__DWC_PCD_IF_H__)
|
||||
#define __DWC_PCD_IF_H__
|
||||
|
||||
//#include "dwc_os.h"
|
||||
#include "dwc_otg_core_if.h"
|
||||
#include "dwc_otg_driver.h"
|
||||
|
||||
/** @file
|
||||
* This file defines DWC_OTG PCD Core API.
|
||||
*/
|
||||
|
||||
struct dwc_otg_pcd;
|
||||
typedef struct dwc_otg_pcd dwc_otg_pcd_t;
|
||||
|
||||
/** Maxpacket size for EP0 */
|
||||
#define MAX_EP0_SIZE 64
|
||||
/** Maxpacket size for any EP */
|
||||
#define MAX_PACKET_SIZE 1024
|
||||
|
||||
/** @name Function Driver Callbacks */
|
||||
/** @{ */
|
||||
|
||||
/** This function will be called whenever a previously queued request has
|
||||
* completed. The status value will be set to -DWC_E_SHUTDOWN to indicated a
|
||||
* failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset,
|
||||
* or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid
|
||||
* parameters. */
|
||||
typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
|
||||
void *req_handle, int32_t status,
|
||||
uint32_t actual);
|
||||
/**
|
||||
* This function will be called whenever a previousle queued ISOC request has
|
||||
* completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count
|
||||
* function.
|
||||
* The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_*
|
||||
* functions.
|
||||
*/
|
||||
typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
|
||||
void *req_handle, int proc_buf_num);
|
||||
/** This function should handle any SETUP request that cannot be handled by the
|
||||
* PCD Core. This includes most GET_DESCRIPTORs, SET_CONFIGS, Any
|
||||
* class-specific requests, etc. The function must non-blocking.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -DWC_E_NOT_SUPPORTED if the request is not supported.
|
||||
* Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes.
|
||||
* Returns -DWC_E_SHUTDOWN on any other error. */
|
||||
typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
|
||||
/** This is called whenever the device has been disconnected. The function
|
||||
* driver should take appropriate action to clean up all pending requests in the
|
||||
* PCD Core, remove all endpoints (except ep0), and initialize back to reset
|
||||
* state. */
|
||||
typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
|
||||
/** This function is called when device has been connected. */
|
||||
typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
|
||||
/** This function is called when device has been suspended */
|
||||
typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
|
||||
/** This function is called when device has received LPM tokens, i.e.
|
||||
* device has been sent to sleep state. */
|
||||
typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
|
||||
/** This function is called when device has been resumed
|
||||
* from suspend(L2) or L1 sleep state. */
|
||||
typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
|
||||
/** This function is called whenever hnp params has been changed.
|
||||
* User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions
|
||||
* to get hnp parameters. */
|
||||
typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
|
||||
/** This function is called whenever USB RESET is detected. */
|
||||
typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
|
||||
|
||||
typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ep_handle Void pointer to the usb_ep structure
|
||||
* @param ereq_port Pointer to the extended request structure created in the
|
||||
* portable part.
|
||||
*/
|
||||
typedef int (*xiso_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
|
||||
void *req_handle, int32_t status,
|
||||
void *ereq_port);
|
||||
/** Function Driver Ops Data Structure */
|
||||
struct dwc_otg_pcd_function_ops {
|
||||
dwc_connect_cb_t connect;
|
||||
dwc_disconnect_cb_t disconnect;
|
||||
dwc_setup_cb_t setup;
|
||||
dwc_completion_cb_t complete;
|
||||
dwc_isoc_completion_cb_t isoc_complete;
|
||||
dwc_suspend_cb_t suspend;
|
||||
dwc_sleep_cb_t sleep;
|
||||
dwc_resume_cb_t resume;
|
||||
dwc_reset_cb_t reset;
|
||||
dwc_hnp_params_changed_cb_t hnp_changed;
|
||||
cfi_setup_cb_t cfi_setup;
|
||||
#ifdef DWC_UTE_PER_IO
|
||||
xiso_completion_cb_t xisoc_complete;
|
||||
#endif
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/** @name Function Driver Functions */
|
||||
/** @{ */
|
||||
|
||||
/** Call this function to get pointer on dwc_otg_pcd_t,
|
||||
* this pointer will be used for all PCD API functions.
|
||||
*
|
||||
* @param core_if The DWC_OTG Core
|
||||
*/
|
||||
extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_device_t *otg_dev);
|
||||
|
||||
/** Frees PCD allocated by dwc_otg_pcd_init
|
||||
*
|
||||
* @param pcd The PCD
|
||||
*/
|
||||
extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
|
||||
|
||||
/** Call this to bind the function driver to the PCD Core.
|
||||
*
|
||||
* @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
|
||||
* @param fops The Function Driver Ops data structure containing pointers to all callbacks.
|
||||
*/
|
||||
extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
|
||||
const struct dwc_otg_pcd_function_ops *fops);
|
||||
|
||||
/** Enables an endpoint for use. This function enables an endpoint in
|
||||
* the PCD. The endpoint is described by the ep_desc which has the
|
||||
* same format as a USB ep descriptor. The ep_handle parameter is used to refer
|
||||
* to the endpoint from other API functions and in callbacks. Normally this
|
||||
* should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the
|
||||
* core for that interface.
|
||||
*
|
||||
* Returns -DWC_E_INVALID if invalid parameters were passed.
|
||||
* Returns -DWC_E_SHUTDOWN if any other error ocurred.
|
||||
* Returns 0 on success.
|
||||
*
|
||||
* @param pcd The PCD
|
||||
* @param ep_desc Endpoint descriptor
|
||||
* @param usb_ep Handle on endpoint, that will be used to identify endpoint.
|
||||
*/
|
||||
extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
|
||||
const uint8_t * ep_desc, void *usb_ep);
|
||||
|
||||
/** Disable the endpoint referenced by ep_handle.
|
||||
*
|
||||
* Returns -DWC_E_INVALID if invalid parameters were passed.
|
||||
* Returns -DWC_E_SHUTDOWN if any other error occurred.
|
||||
* Returns 0 on success. */
|
||||
extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
|
||||
|
||||
/** Queue a data transfer request on the endpoint referenced by ep_handle.
|
||||
* After the transfer is completes, the complete callback will be called with
|
||||
* the request status.
|
||||
*
|
||||
* @param pcd The PCD
|
||||
* @param ep_handle The handle of the endpoint
|
||||
* @param buf The buffer for the data
|
||||
* @param dma_buf The DMA buffer for the data
|
||||
* @param buflen The length of the data transfer
|
||||
* @param zero Specifies whether to send zero length last packet.
|
||||
* @param req_handle Set this handle to any value to use to reference this
|
||||
* request in the ep_dequeue function or from the complete callback
|
||||
* @param atomic_alloc If driver need to perform atomic allocations
|
||||
* for internal data structures.
|
||||
*
|
||||
* Returns -DWC_E_INVALID if invalid parameters were passed.
|
||||
* Returns -DWC_E_SHUTDOWN if any other error ocurred.
|
||||
* Returns 0 on success. */
|
||||
extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
|
||||
uint8_t * buf, dwc_dma_t dma_buf,
|
||||
uint32_t buflen, int zero, void *req_handle,
|
||||
int atomic_alloc);
|
||||
#ifdef DWC_UTE_PER_IO
|
||||
/**
|
||||
*
|
||||
* @param ereq_nonport Pointer to the extended request part of the
|
||||
* usb_request structure defined in usb_gadget.h file.
|
||||
*/
|
||||
extern int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
|
||||
uint8_t * buf, dwc_dma_t dma_buf,
|
||||
uint32_t buflen, int zero,
|
||||
void *req_handle, int atomic_alloc,
|
||||
void *ereq_nonport);
|
||||
|
||||
#endif
|
||||
|
||||
/** De-queue the specified data transfer that has not yet completed.
|
||||
*
|
||||
* Returns -DWC_E_INVALID if invalid parameters were passed.
|
||||
* Returns -DWC_E_SHUTDOWN if any other error ocurred.
|
||||
* Returns 0 on success. */
|
||||
extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
|
||||
void *req_handle);
|
||||
|
||||
/** Halt (STALL) an endpoint or clear it.
|
||||
*
|
||||
* Returns -DWC_E_INVALID if invalid parameters were passed.
|
||||
* Returns -DWC_E_SHUTDOWN if any other error ocurred.
|
||||
* Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later
|
||||
* Returns 0 on success. */
|
||||
extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
|
||||
|
||||
/** This function */
|
||||
extern int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle);
|
||||
|
||||
/** This function should be called on every hardware interrupt */
|
||||
extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
|
||||
|
||||
/** This function returns current frame number */
|
||||
extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
|
||||
|
||||
/**
|
||||
* Start isochronous transfers on the endpoint referenced by ep_handle.
|
||||
* For isochronous transfers duble buffering is used.
|
||||
* After processing each of buffers comlete callback will be called with
|
||||
* status for each transaction.
|
||||
*
|
||||
* @param pcd The PCD
|
||||
* @param ep_handle The handle of the endpoint
|
||||
* @param buf0 The virtual address of first data buffer
|
||||
* @param buf1 The virtual address of second data buffer
|
||||
* @param dma0 The DMA address of first data buffer
|
||||
* @param dma1 The DMA address of second data buffer
|
||||
* @param sync_frame Data pattern frame number
|
||||
* @param dp_frame Data size for pattern frame
|
||||
* @param data_per_frame Data size for regular frame
|
||||
* @param start_frame Frame number to start transfers, if -1 then start transfers ASAP.
|
||||
* @param buf_proc_intrvl Interval of ISOC Buffer processing
|
||||
* @param req_handle Handle of ISOC request
|
||||
* @param atomic_alloc Specefies whether to perform atomic allocation for
|
||||
* internal data structures.
|
||||
*
|
||||
* Returns -DWC_E_NO_MEMORY if there is no enough memory.
|
||||
* Returns -DWC_E_INVALID if incorrect arguments are passed to the function.
|
||||
* Returns -DW_E_SHUTDOWN for any other error.
|
||||
* Returns 0 on success
|
||||
*/
|
||||
extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
|
||||
uint8_t * buf0, uint8_t * buf1,
|
||||
dwc_dma_t dma0, dwc_dma_t dma1,
|
||||
int sync_frame, int dp_frame,
|
||||
int data_per_frame, int start_frame,
|
||||
int buf_proc_intrvl, void *req_handle,
|
||||
int atomic_alloc);
|
||||
|
||||
/** Stop ISOC transfers on endpoint referenced by ep_handle.
|
||||
*
|
||||
* @param pcd The PCD
|
||||
* @param ep_handle The handle of the endpoint
|
||||
* @param req_handle Handle of ISOC request
|
||||
*
|
||||
* Returns -DWC_E_INVALID if incorrect arguments are passed to the function
|
||||
* Returns 0 on success
|
||||
*/
|
||||
int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
|
||||
void *req_handle);
|
||||
|
||||
/** Get ISOC packet status.
|
||||
*
|
||||
* @param pcd The PCD
|
||||
* @param ep_handle The handle of the endpoint
|
||||
* @param iso_req_handle Isochronoush request handle
|
||||
* @param packet Number of packet
|
||||
* @param status Out parameter for returning status
|
||||
* @param actual Out parameter for returning actual length
|
||||
* @param offset Out parameter for returning offset
|
||||
*
|
||||
*/
|
||||
extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
|
||||
void *ep_handle,
|
||||
void *iso_req_handle, int packet,
|
||||
int *status, int *actual,
|
||||
int *offset);
|
||||
|
||||
/** Get ISOC packet count.
|
||||
*
|
||||
* @param pcd The PCD
|
||||
* @param ep_handle The handle of the endpoint
|
||||
* @param iso_req_handle
|
||||
*/
|
||||
extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
|
||||
void *ep_handle,
|
||||
void *iso_req_handle);
|
||||
|
||||
/** This function starts the SRP Protocol if no session is in progress. If
|
||||
* a session is already in progress, but the device is suspended,
|
||||
* remote wakeup signaling is started.
|
||||
*/
|
||||
extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
|
||||
|
||||
/** This function returns 1 if LPM support is enabled, and 0 otherwise. */
|
||||
extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
|
||||
|
||||
/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */
|
||||
extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
|
||||
|
||||
/** Initiate SRP */
|
||||
extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
|
||||
|
||||
/** Starts remote wakeup signaling. */
|
||||
extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
|
||||
|
||||
/** Starts micorsecond soft disconnect. */
|
||||
extern void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs);
|
||||
/** This function returns whether device is dualspeed.*/
|
||||
extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
|
||||
|
||||
/** This function returns whether device is otg. */
|
||||
extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
|
||||
|
||||
/** These functions allow to get hnp parameters */
|
||||
extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
|
||||
extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
|
||||
extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
|
||||
|
||||
/** CFI specific Interface functions */
|
||||
/** Allocate a cfi buffer */
|
||||
extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
|
||||
dwc_dma_t * addr, size_t buflen,
|
||||
int flags);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* __DWC_PCD_IF_H__ */
|
||||
|
||||
#endif /* DWC_HOST_ONLY */
|
||||
5148
drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
Normal file
5148
drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
Normal file
File diff suppressed because it is too large
Load Diff
1262
drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
Normal file
1262
drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
Normal file
File diff suppressed because it is too large
Load Diff
2550
drivers/usb/host/dwc_otg/dwc_otg_regs.h
Normal file
2550
drivers/usb/host/dwc_otg/dwc_otg_regs.h
Normal file
File diff suppressed because it is too large
Load Diff
16
drivers/usb/host/dwc_otg/test/Makefile
Normal file
16
drivers/usb/host/dwc_otg/test/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
PERL=/usr/bin/perl
|
||||
PL_TESTS=test_sysfs.pl test_mod_param.pl
|
||||
|
||||
.PHONY : test
|
||||
test : perl_tests
|
||||
|
||||
perl_tests :
|
||||
@echo
|
||||
@echo Running perl tests
|
||||
@for test in $(PL_TESTS); do \
|
||||
if $(PERL) ./$$test ; then \
|
||||
echo "=======> $$test, PASSED" ; \
|
||||
else echo "=======> $$test, FAILED" ; \
|
||||
fi \
|
||||
done
|
||||
337
drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
Normal file
337
drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
Normal file
@@ -0,0 +1,337 @@
|
||||
package dwc_otg_test;
|
||||
|
||||
use strict;
|
||||
use Exporter ();
|
||||
|
||||
use vars qw(@ISA @EXPORT
|
||||
$sysfsdir $paramdir $errors $params
|
||||
);
|
||||
|
||||
@ISA = qw(Exporter);
|
||||
|
||||
#
|
||||
# Globals
|
||||
#
|
||||
$sysfsdir = "/sys/devices/lm0";
|
||||
$paramdir = "/sys/module/dwc_otg";
|
||||
$errors = 0;
|
||||
|
||||
$params = [
|
||||
{
|
||||
NAME => "otg_cap",
|
||||
DEFAULT => 0,
|
||||
ENUM => [],
|
||||
LOW => 0,
|
||||
HIGH => 2
|
||||
},
|
||||
{
|
||||
NAME => "dma_enable",
|
||||
DEFAULT => 0,
|
||||
ENUM => [],
|
||||
LOW => 0,
|
||||
HIGH => 1
|
||||
},
|
||||
{
|
||||
NAME => "dma_burst_size",
|
||||
DEFAULT => 32,
|
||||
ENUM => [1, 4, 8, 16, 32, 64, 128, 256],
|
||||
LOW => 1,
|
||||
HIGH => 256
|
||||
},
|
||||
{
|
||||
NAME => "host_speed",
|
||||
DEFAULT => 0,
|
||||
ENUM => [],
|
||||
LOW => 0,
|
||||
HIGH => 1
|
||||
},
|
||||
{
|
||||
NAME => "host_support_fs_ls_low_power",
|
||||
DEFAULT => 0,
|
||||
ENUM => [],
|
||||
LOW => 0,
|
||||
HIGH => 1
|
||||
},
|
||||
{
|
||||
NAME => "host_ls_low_power_phy_clk",
|
||||
DEFAULT => 0,
|
||||
ENUM => [],
|
||||
LOW => 0,
|
||||
HIGH => 1
|
||||
},
|
||||
{
|
||||
NAME => "dev_speed",
|
||||
DEFAULT => 0,
|
||||
ENUM => [],
|
||||
LOW => 0,
|
||||
HIGH => 1
|
||||
},
|
||||
{
|
||||
NAME => "enable_dynamic_fifo",
|
||||
DEFAULT => 1,
|
||||
ENUM => [],
|
||||
LOW => 0,
|
||||
HIGH => 1
|
||||
},
|
||||
{
|
||||
NAME => "data_fifo_size",
|
||||
DEFAULT => 8192,
|
||||
ENUM => [],
|
||||
LOW => 32,
|
||||
HIGH => 32768
|
||||
},
|
||||
{
|
||||
NAME => "dev_rx_fifo_size",
|
||||
DEFAULT => 1064,
|
||||
ENUM => [],
|
||||
LOW => 16,
|
||||
HIGH => 32768
|
||||
},
|
||||
{
|
||||
NAME => "dev_nperio_tx_fifo_size",
|
||||
DEFAULT => 1024,
|
||||
ENUM => [],
|
||||
LOW => 16,
|
||||
HIGH => 32768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_1",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_2",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_3",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_4",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_5",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_6",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_7",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_8",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_9",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_10",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_11",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_12",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_13",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_14",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "dev_perio_tx_fifo_size_15",
|
||||
DEFAULT => 256,
|
||||
ENUM => [],
|
||||
LOW => 4,
|
||||
HIGH => 768
|
||||
},
|
||||
{
|
||||
NAME => "host_rx_fifo_size",
|
||||
DEFAULT => 1024,
|
||||
ENUM => [],
|
||||
LOW => 16,
|
||||
HIGH => 32768
|
||||
},
|
||||
{
|
||||
NAME => "host_nperio_tx_fifo_size",
|
||||
DEFAULT => 1024,
|
||||
ENUM => [],
|
||||
LOW => 16,
|
||||
HIGH => 32768
|
||||
},
|
||||
{
|
||||
NAME => "host_perio_tx_fifo_size",
|
||||
DEFAULT => 1024,
|
||||
ENUM => [],
|
||||
LOW => 16,
|
||||
HIGH => 32768
|
||||
},
|
||||
{
|
||||
NAME => "max_transfer_size",
|
||||
DEFAULT => 65535,
|
||||
ENUM => [],
|
||||
LOW => 2047,
|
||||
HIGH => 65535
|
||||
},
|
||||
{
|
||||
NAME => "max_packet_count",
|
||||
DEFAULT => 511,
|
||||
ENUM => [],
|
||||
LOW => 15,
|
||||
HIGH => 511
|
||||
},
|
||||
{
|
||||
NAME => "host_channels",
|
||||
DEFAULT => 12,
|
||||
ENUM => [],
|
||||
LOW => 1,
|
||||
HIGH => 16
|
||||
},
|
||||
{
|
||||
NAME => "dev_endpoints",
|
||||
DEFAULT => 6,
|
||||
ENUM => [],
|
||||
LOW => 1,
|
||||
HIGH => 15
|
||||
},
|
||||
{
|
||||
NAME => "phy_type",
|
||||
DEFAULT => 1,
|
||||
ENUM => [],
|
||||
LOW => 0,
|
||||
HIGH => 2
|
||||
},
|
||||
{
|
||||
NAME => "phy_utmi_width",
|
||||
DEFAULT => 16,
|
||||
ENUM => [8, 16],
|
||||
LOW => 8,
|
||||
HIGH => 16
|
||||
},
|
||||
{
|
||||
NAME => "phy_ulpi_ddr",
|
||||
DEFAULT => 0,
|
||||
ENUM => [],
|
||||
LOW => 0,
|
||||
HIGH => 1
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
sub check_arch {
|
||||
$_ = `uname -m`;
|
||||
chomp;
|
||||
unless (m/armv4tl/) {
|
||||
warn "# \n# Can't execute on $_. Run on integrator platform.\n# \n";
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#
|
||||
#
|
||||
sub load_module {
|
||||
my $params = shift;
|
||||
print "\nRemoving Module\n";
|
||||
system "rmmod dwc_otg";
|
||||
print "Loading Module\n";
|
||||
if ($params ne "") {
|
||||
print "Module Parameters: $params\n";
|
||||
}
|
||||
if (system("modprobe dwc_otg $params")) {
|
||||
warn "Unable to load module\n";
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#
|
||||
#
|
||||
sub test_status {
|
||||
my $arg = shift;
|
||||
|
||||
print "\n";
|
||||
|
||||
if (defined $arg) {
|
||||
warn "WARNING: $arg\n";
|
||||
}
|
||||
|
||||
if ($errors > 0) {
|
||||
warn "TEST FAILED with $errors errors\n";
|
||||
return 0;
|
||||
} else {
|
||||
print "TEST PASSED\n";
|
||||
return 0 if (defined $arg);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#
|
||||
#
|
||||
@EXPORT = qw(
|
||||
$sysfsdir
|
||||
$paramdir
|
||||
$params
|
||||
$errors
|
||||
check_arch
|
||||
load_module
|
||||
test_status
|
||||
);
|
||||
|
||||
1;
|
||||
133
drivers/usb/host/dwc_otg/test/test_mod_param.pl
Normal file
133
drivers/usb/host/dwc_otg/test/test_mod_param.pl
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Run this program on the integrator.
|
||||
#
|
||||
# - Tests module parameter default values.
|
||||
# - Tests setting of valid module parameter values via modprobe.
|
||||
# - Tests invalid module parameter values.
|
||||
# -----------------------------------------------------------------------------
|
||||
use strict;
|
||||
use dwc_otg_test;
|
||||
|
||||
check_arch() or die;
|
||||
|
||||
#
|
||||
#
|
||||
sub test {
|
||||
my ($param,$expected) = @_;
|
||||
my $value = get($param);
|
||||
|
||||
if ($value == $expected) {
|
||||
print "$param = $value, okay\n";
|
||||
}
|
||||
|
||||
else {
|
||||
warn "ERROR: value of $param != $expected, $value\n";
|
||||
$errors ++;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
#
|
||||
sub get {
|
||||
my $param = shift;
|
||||
my $tmp = `cat $paramdir/$param`;
|
||||
chomp $tmp;
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
#
|
||||
#
|
||||
sub test_main {
|
||||
|
||||
print "\nTesting Module Parameters\n";
|
||||
|
||||
load_module("") or die;
|
||||
|
||||
# Test initial values
|
||||
print "\nTesting Default Values\n";
|
||||
foreach (@{$params}) {
|
||||
test ($_->{NAME}, $_->{DEFAULT});
|
||||
}
|
||||
|
||||
# Test low value
|
||||
print "\nTesting Low Value\n";
|
||||
my $cmd_params = "";
|
||||
foreach (@{$params}) {
|
||||
$cmd_params = $cmd_params . "$_->{NAME}=$_->{LOW} ";
|
||||
}
|
||||
load_module($cmd_params) or die;
|
||||
|
||||
foreach (@{$params}) {
|
||||
test ($_->{NAME}, $_->{LOW});
|
||||
}
|
||||
|
||||
# Test high value
|
||||
print "\nTesting High Value\n";
|
||||
$cmd_params = "";
|
||||
foreach (@{$params}) {
|
||||
$cmd_params = $cmd_params . "$_->{NAME}=$_->{HIGH} ";
|
||||
}
|
||||
load_module($cmd_params) or die;
|
||||
|
||||
foreach (@{$params}) {
|
||||
test ($_->{NAME}, $_->{HIGH});
|
||||
}
|
||||
|
||||
# Test Enum
|
||||
print "\nTesting Enumerated\n";
|
||||
foreach (@{$params}) {
|
||||
if (defined $_->{ENUM}) {
|
||||
my $value;
|
||||
foreach $value (@{$_->{ENUM}}) {
|
||||
$cmd_params = "$_->{NAME}=$value";
|
||||
load_module($cmd_params) or die;
|
||||
test ($_->{NAME}, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Test Invalid Values
|
||||
print "\nTesting Invalid Values\n";
|
||||
$cmd_params = "";
|
||||
foreach (@{$params}) {
|
||||
$cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{LOW}-1;
|
||||
}
|
||||
load_module($cmd_params) or die;
|
||||
|
||||
foreach (@{$params}) {
|
||||
test ($_->{NAME}, $_->{DEFAULT});
|
||||
}
|
||||
|
||||
$cmd_params = "";
|
||||
foreach (@{$params}) {
|
||||
$cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{HIGH}+1;
|
||||
}
|
||||
load_module($cmd_params) or die;
|
||||
|
||||
foreach (@{$params}) {
|
||||
test ($_->{NAME}, $_->{DEFAULT});
|
||||
}
|
||||
|
||||
print "\nTesting Enumerated\n";
|
||||
foreach (@{$params}) {
|
||||
if (defined $_->{ENUM}) {
|
||||
my $value;
|
||||
foreach $value (@{$_->{ENUM}}) {
|
||||
$value = $value + 1;
|
||||
$cmd_params = "$_->{NAME}=$value";
|
||||
load_module($cmd_params) or die;
|
||||
test ($_->{NAME}, $_->{DEFAULT});
|
||||
$value = $value - 2;
|
||||
$cmd_params = "$_->{NAME}=$value";
|
||||
load_module($cmd_params) or die;
|
||||
test ($_->{NAME}, $_->{DEFAULT});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_status() or die;
|
||||
}
|
||||
|
||||
test_main();
|
||||
0;
|
||||
193
drivers/usb/host/dwc_otg/test/test_sysfs.pl
Normal file
193
drivers/usb/host/dwc_otg/test/test_sysfs.pl
Normal file
@@ -0,0 +1,193 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Run this program on the integrator
|
||||
# - Tests select sysfs attributes.
|
||||
# - Todo ... test more attributes, hnp/srp, buspower/bussuspend, etc.
|
||||
# -----------------------------------------------------------------------------
|
||||
use strict;
|
||||
use dwc_otg_test;
|
||||
|
||||
check_arch() or die;
|
||||
|
||||
#
|
||||
#
|
||||
sub test {
|
||||
my ($attr,$expected) = @_;
|
||||
my $string = get($attr);
|
||||
|
||||
if ($string eq $expected) {
|
||||
printf("$attr = $string, okay\n");
|
||||
}
|
||||
else {
|
||||
warn "ERROR: value of $attr != $expected, $string\n";
|
||||
$errors ++;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
#
|
||||
sub set {
|
||||
my ($reg, $value) = @_;
|
||||
system "echo $value > $sysfsdir/$reg";
|
||||
}
|
||||
|
||||
#
|
||||
#
|
||||
sub get {
|
||||
my $attr = shift;
|
||||
my $string = `cat $sysfsdir/$attr`;
|
||||
chomp $string;
|
||||
if ($string =~ m/\s\=\s/) {
|
||||
my $tmp;
|
||||
($tmp, $string) = split /\s=\s/, $string;
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
#
|
||||
#
|
||||
sub test_main {
|
||||
print("\nTesting Sysfs Attributes\n");
|
||||
|
||||
load_module("") or die;
|
||||
|
||||
# Test initial values of regoffset/regvalue/guid/gsnpsid
|
||||
print("\nTesting Default Values\n");
|
||||
|
||||
test("regoffset", "0xffffffff");
|
||||
test("regvalue", "invalid offset");
|
||||
test("guid", "0x12345678"); # this will fail if it has been changed
|
||||
test("gsnpsid", "0x4f54200a");
|
||||
|
||||
# Test operation of regoffset/regvalue
|
||||
print("\nTesting regoffset\n");
|
||||
set('regoffset', '5a5a5a5a');
|
||||
test("regoffset", "0xffffffff");
|
||||
|
||||
set('regoffset', '0');
|
||||
test("regoffset", "0x00000000");
|
||||
|
||||
set('regoffset', '40000');
|
||||
test("regoffset", "0x00000000");
|
||||
|
||||
set('regoffset', '3ffff');
|
||||
test("regoffset", "0x0003ffff");
|
||||
|
||||
set('regoffset', '1');
|
||||
test("regoffset", "0x00000001");
|
||||
|
||||
print("\nTesting regvalue\n");
|
||||
set('regoffset', '3c');
|
||||
test("regvalue", "0x12345678");
|
||||
set('regvalue', '5a5a5a5a');
|
||||
test("regvalue", "0x5a5a5a5a");
|
||||
set('regvalue','a5a5a5a5');
|
||||
test("regvalue", "0xa5a5a5a5");
|
||||
set('guid','12345678');
|
||||
|
||||
# Test HNP Capable
|
||||
print("\nTesting HNP Capable bit\n");
|
||||
set('hnpcapable', '1');
|
||||
test("hnpcapable", "0x1");
|
||||
set('hnpcapable','0');
|
||||
test("hnpcapable", "0x0");
|
||||
|
||||
set('regoffset','0c');
|
||||
|
||||
my $old = get('gusbcfg');
|
||||
print("setting hnpcapable\n");
|
||||
set('hnpcapable', '1');
|
||||
test("hnpcapable", "0x1");
|
||||
test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<9)));
|
||||
test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<9)));
|
||||
|
||||
$old = get('gusbcfg');
|
||||
print("clearing hnpcapable\n");
|
||||
set('hnpcapable', '0');
|
||||
test("hnpcapable", "0x0");
|
||||
test ('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<9)));
|
||||
test ('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<9)));
|
||||
|
||||
# Test SRP Capable
|
||||
print("\nTesting SRP Capable bit\n");
|
||||
set('srpcapable', '1');
|
||||
test("srpcapable", "0x1");
|
||||
set('srpcapable','0');
|
||||
test("srpcapable", "0x0");
|
||||
|
||||
set('regoffset','0c');
|
||||
|
||||
$old = get('gusbcfg');
|
||||
print("setting srpcapable\n");
|
||||
set('srpcapable', '1');
|
||||
test("srpcapable", "0x1");
|
||||
test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<8)));
|
||||
test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<8)));
|
||||
|
||||
$old = get('gusbcfg');
|
||||
print("clearing srpcapable\n");
|
||||
set('srpcapable', '0');
|
||||
test("srpcapable", "0x0");
|
||||
test('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<8)));
|
||||
test('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<8)));
|
||||
|
||||
# Test GGPIO
|
||||
print("\nTesting GGPIO\n");
|
||||
set('ggpio','5a5a5a5a');
|
||||
test('ggpio','0x5a5a0000');
|
||||
set('ggpio','a5a5a5a5');
|
||||
test('ggpio','0xa5a50000');
|
||||
set('ggpio','11110000');
|
||||
test('ggpio','0x11110000');
|
||||
set('ggpio','00001111');
|
||||
test('ggpio','0x00000000');
|
||||
|
||||
# Test DEVSPEED
|
||||
print("\nTesting DEVSPEED\n");
|
||||
set('regoffset','800');
|
||||
$old = get('regvalue');
|
||||
set('devspeed','0');
|
||||
test('devspeed','0x0');
|
||||
test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
|
||||
set('devspeed','1');
|
||||
test('devspeed','0x1');
|
||||
test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
|
||||
set('devspeed','2');
|
||||
test('devspeed','0x2');
|
||||
test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 2));
|
||||
set('devspeed','3');
|
||||
test('devspeed','0x3');
|
||||
test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 3));
|
||||
set('devspeed','4');
|
||||
test('devspeed','0x0');
|
||||
test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
|
||||
set('devspeed','5');
|
||||
test('devspeed','0x1');
|
||||
test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
|
||||
|
||||
|
||||
# mode Returns the current mode:0 for device mode1 for host mode Read
|
||||
# hnp Initiate the Host Negotiation Protocol. Read returns the status. Read/Write
|
||||
# srp Initiate the Session Request Protocol. Read returns the status. Read/Write
|
||||
# buspower Get or Set the Power State of the bus (0 - Off or 1 - On) Read/Write
|
||||
# bussuspend Suspend the USB bus. Read/Write
|
||||
# busconnected Get the connection status of the bus Read
|
||||
|
||||
# gotgctl Get or set the Core Control Status Register. Read/Write
|
||||
## gusbcfg Get or set the Core USB Configuration Register Read/Write
|
||||
# grxfsiz Get or set the Receive FIFO Size Register Read/Write
|
||||
# gnptxfsiz Get or set the non-periodic Transmit Size Register Read/Write
|
||||
# gpvndctl Get or set the PHY Vendor Control Register Read/Write
|
||||
## ggpio Get the value in the lower 16-bits of the General Purpose IO Register or Set the upper 16 bits. Read/Write
|
||||
## guid Get or set the value of the User ID Register Read/Write
|
||||
## gsnpsid Get the value of the Synopsys ID Regester Read
|
||||
## devspeed Get or set the device speed setting in the DCFG register Read/Write
|
||||
# enumspeed Gets the device enumeration Speed. Read
|
||||
# hptxfsiz Get the value of the Host Periodic Transmit FIFO Read
|
||||
# hprt0 Get or Set the value in the Host Port Control and Status Register Read/Write
|
||||
|
||||
test_status("TEST NYI") or die;
|
||||
}
|
||||
|
||||
test_main();
|
||||
0;
|
||||
Reference in New Issue
Block a user