Author: wmb Date: 2010-01-08 08:30:03 +0100 (Fri, 08 Jan 2010) New Revision: 1651
Modified: dev/usb2/hcd/dev-info.fth dev/usb2/hcd/ehci/bulk.fth dev/usb2/hcd/ehci/control.fth dev/usb2/hcd/ehci/intr.fth dev/usb2/hcd/ehci/probe.fth dev/usb2/hcd/ehci/qhtd.fth Log: OLPC trac 9969 - make USB work after resume - sort of. USB 2.0 devices like mass storage devices and LANs work after resume, so long as you don't suspend/resume too many times. Eventually the system dies with "user area used up", because the device nodes get reloaded every time. I need to work out how to reuse the device nodes instead of reloading, but that could get complicated. I also need to do something about USB 1.1 devices.
Modified: dev/usb2/hcd/dev-info.fth =================================================================== --- dev/usb2/hcd/dev-info.fth 2010-01-08 07:23:30 UTC (rev 1650) +++ dev/usb2/hcd/dev-info.fth 2010-01-08 07:30:03 UTC (rev 1651) @@ -25,9 +25,9 @@ 1+ \ Padding for word alignment /di-ep-struct #max-endpoint * field >di-ep \ Endpoint structure -dup constant /di-entry +constant /di-entry
-#max-dev * constant /di +/di-entry #max-dev * constant /di 0 value di \ device-info
0 value cur-dev \ Value of the last assigned usb address @@ -60,14 +60,17 @@ ;
: init-di ( -- ) - \ allocate and initialize the device descriptors - /di alloc-mem to di - di /di erase - /pipe0 0 0 di-maxpayload! \ Default max payload + di 0= if + \ allocate and initialize the device descriptors + /di alloc-mem to di + di /di erase + /pipe0 0 0 di-maxpayload! \ Default max payload + then ;
: init-struct ( -- ) init-di + 0 to cur-dev ;
headers
Modified: dev/usb2/hcd/ehci/bulk.fth =================================================================== --- dev/usb2/hcd/ehci/bulk.fth 2010-01-08 07:23:30 UTC (rev 1650) +++ dev/usb2/hcd/ehci/bulk.fth 2010-01-08 07:30:03 UTC (rev 1651) @@ -76,9 +76,9 @@ then ( #qtds ) bulk-qh reuse-qhqtds ; -: free-bulk-qhqtds ( -- ) +: free-bulk-qh ( -- ) bulk-qh ?dup if ( qh ) - free-qhqtds ( ) + free-qh ( ) 0 to bulk-qh then ; @@ -512,7 +512,7 @@
headers
-: (end-extra) ( -- ) end-bulk-in free-bulk-qhqtds ; +: (end-extra) ( -- ) end-bulk-in free-bulk-qh ;
\ LICENSE_BEGIN
Modified: dev/usb2/hcd/ehci/control.fth =================================================================== --- dev/usb2/hcd/ehci/control.fth 2010-01-08 07:23:30 UTC (rev 1650) +++ dev/usb2/hcd/ehci/control.fth 2010-01-08 07:30:03 UTC (rev 1651) @@ -149,7 +149,7 @@ then then
- my-qh dup remove-qh free-qhqtds ( actual ) + my-qh dup remove-qh free-qh ( actual ) usb-error ( actual usberr ) ;
@@ -161,7 +161,7 @@ \ Process results my-qh done? 0= if my-qh error? drop then
- my-qh dup remove-qh free-qhqtds + my-qh dup remove-qh free-qh usb-error ;
Modified: dev/usb2/hcd/ehci/intr.fth =================================================================== --- dev/usb2/hcd/ehci/intr.fth 2010-01-08 07:23:30 UTC (rev 1650) +++ dev/usb2/hcd/ehci/intr.fth 2010-01-08 07:30:03 UTC (rev 1651) @@ -112,7 +112,7 @@ intr-in-qh 0= if exit then intr-in-qh dup fixup-intr-in-data intr-in-qtd map-out-bptrs - dup remove-intr-qh free-qhqtds + dup remove-intr-qh free-qh 0 to intr-in-qh 0 to intr-in-qtd ;
Modified: dev/usb2/hcd/ehci/probe.fth =================================================================== --- dev/usb2/hcd/ehci/probe.fth 2010-01-08 07:23:30 UTC (rev 1650) +++ dev/usb2/hcd/ehci/probe.fth 2010-01-08 07:30:03 UTC (rev 1651) @@ -134,6 +134,17 @@ probe-teardown ;
+: do-resume ( -- ) + init-ehci-regs + start-usb + claim-ownership + init-struct + init-extra +; + +\ This is a sneaky way to determine if the hardware has been turned off without the software's knowledge +: suspended? ( -- flag ) asynclist@ 0= qh-ptr 0<> and ; + : open ( -- flag ) parse-my-args open-count 0= if @@ -148,25 +159,15 @@ then 0 ehci-reg@ h# ff and to op-reg-offset reset-usb - init-ehci-regs - start-usb - claim-ownership - init-struct - init-extra + do-resume then + suspended? if do-resume then probe-root-hub then open-count 1+ to open-count true ;
-: do-resume ( -- ) - init-ehci-regs - start-usb - claim-ownership - framelist-phys periodic! -; - : close ( -- ) open-count 1- to open-count end-extra
Modified: dev/usb2/hcd/ehci/qhtd.fth =================================================================== --- dev/usb2/hcd/ehci/qhtd.fth 2010-01-08 07:23:30 UTC (rev 1650) +++ dev/usb2/hcd/ehci/qhtd.fth 2010-01-08 07:30:03 UTC (rev 1651) @@ -47,14 +47,16 @@ : framelist! ( n idx -- ) 4 * framelist + le-l! ;
: init-framelist ( -- ) - \ Allocate framelist - /framelist /align4kb aligned-alloc ( unaligned virt ) - swap to framelist-unaligned ( virt ) - dup to framelist ( virt ) - /framelist true dma-map-in to framelist-phys ( ) + framelist 0= if + \ Allocate framelist + /framelist /align4kb aligned-alloc ( unaligned virt ) + swap to framelist-unaligned ( virt ) + dup to framelist ( virt ) + /framelist true dma-map-in to framelist-phys ( )
- \ Initialize framelist - #framelist 0 do TERMINATE i framelist! loop + \ Initialize framelist + #framelist 0 do TERMINATE i framelist! loop + then framelist-phys periodic! ;
@@ -77,8 +79,10 @@ : intr-tail! ( adr idx -- ) 'intr >intr-tail l! ;
: init-intr ( -- ) - /intr alloc-mem dup to intr \ Allocate intr - /intr erase \ Initialize intr + intr 0= if + /intr alloc-mem dup to intr \ Allocate intr + /intr erase \ Initialize intr + then ;
\ --------------------------------------------------------------------------- @@ -283,17 +287,8 @@ r> 4 pick link-qhqtds ( qh qtd ) ;
-: free-qh ( qh -- ) - >r ( R: qh ) - r@ >qh-unaligned l@ ( qh.u ) ( R: qh ) - r@ dup >qh-phys l@ ( qh.u,v,p ) ( R: qh ) - r> >qh-size l@ ( qh.u,v,p size ) - aligned32-free-map-out ( ) -; +\ Qtds will be freed automatically when the qh is freed
-\ Same as free-qh because the size field tells all -: free-qhqtds ( qh -- ) free-qh ; - : reuse-qhqtds ( #qtds qh -- qh qtd ) swap dup >r /qtd * /qh + >r ( qh ) ( R: #qtds len ) dup >qh-unaligned l@ swap ( qh.u,v ) ( R: #qtds len ) @@ -367,36 +362,41 @@ usbcmd@ h# 20 and 5 >> usbsts@ h# 8000 and d# 15 >> = until ; -: enable-async ( phys -- ) - asynclist! async-wait +: enable-async ( qh -- ) + >qh-phys l@ asynclist! async-wait usbcmd@ h# 20 or usbcmd! async-wait ; : disable-async ( -- ) async-wait usbcmd@ h# 20 invert and usbcmd! async-wait + 0 to qh-ptr ;
+: link-to-qh-ptr ( qh -- ) + dup qh-ptr >qh-next l! ( qh ) + dup >qh-phys l@ TYP_QH or qh-ptr >hcqh-next le-l! ( qh ) + sync-qhqtds ( ) +; : insert-qh ( qh -- ) - >r - qh-ptr if - \ If there is another qh in the system, link the new qh to the existing - \ qh head. - qh-ptr r@ >qh-prev l! - qh-ptr >qh-next l@ r@ >qh-next l! - qh-ptr >hcqh-next le-l@ r@ >hcqh-next le-l! - r@ qh-ptr >qh-next l! - r@ >qh-phys l@ TYP_QH or qh-ptr >hcqh-next le-l! + qh-ptr if ( qh ) + \ If there is another qh, link the new qh to the existing qh head. + qh-ptr over >qh-prev l! ( qh ) + qh-ptr >qh-next l@ over >qh-next l! ( qh ) + qh-ptr >hcqh-next le-l@ over >hcqh-next le-l! ( qh )
- r> sync-qhqtds - qh-ptr sync-qh - else - \ If there is no qh in the system, link it to itself and mark it the - \ head. - r@ to qh-ptr - r@ >hcqh-endp-char dup le-l@ QH_HEAD or swap le-l! - r@ dup >qh-next l! - r@ >qh-phys l@ dup TYP_QH or r@ >hcqh-next le-l! - r> sync-qhqtds - enable-async + link-to-qh-ptr ( ) + + qh-ptr sync-qh ( ) + else ( ) + \ If there is no other qh, make it the head, link it to itself, + \ and start the asynch schedule. + + to qh-ptr ( ) + + qh-ptr >hcqh-endp-char dup le-l@ QH_HEAD or swap le-l! ( ) + + qh-ptr link-to-qh-ptr ( ) + + qh-ptr enable-async ( ) then ; : fix-wraparound-qh ( qh -- ) @@ -423,7 +423,6 @@ dup >qh-next l@ over = if \ If qh is the only qh in the system, disable-async and exit drop disable-async - 0 to qh-ptr else \ Otherwise, qh.prev points to qh.next, fix up reclamation bits. \ Ring doorbell, wait for answer. @@ -625,17 +624,20 @@ drop to dummy-qh TERMINATE dummy-qh >hcqh-overlay >hcqtd-next le-l! then + 0 to qh-ptr dummy-qh insert-qh ;
: free-dummy-qh ( -- ) - dummy-qh ?dup if free-qhqtds 0 to dummy-qh then + dummy-qh ?dup if free-qh 0 to dummy-qh then ;
: ?alloc-dummy-qh ( -- ) 0 my-w@ h# 1106 ( VIA ) = if alloc-dummy-qh then ;
+\ The words this calls are written so they can be called again +\ on resume from S3 state without causing redundant memory allocation. : (init-extra) ( -- ) ?alloc-dummy-qh init-intr