Author: lwalter Date: Tue Aug 9 20:32:13 2011 New Revision: 2450 URL: http://tracker.coreboot.org/trac/openfirmware/changeset/2450
Log: USB webcam driver
Added: dev/usb2/device/webcam/ dev/usb2/device/webcam/build/ dev/usb2/device/webcam/desc.fth dev/usb2/device/webcam/webcam.bth dev/usb2/device/webcam/webcam.fth
Added: dev/usb2/device/webcam/desc.fth ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ dev/usb2/device/webcam/desc.fth Tue Aug 9 20:32:13 2011 (r2450) @@ -0,0 +1,126 @@ +purpose: USB video class descriptors parsing code +\ See license at end of file + +hex +headers + +1 value vs-interface \ Interface id of VS_VIDEO_STREAMING + +0 value desc-buf +0 value desc-buf-end +h# 800 value /desc-buf + +defer alt-array +defer frame-array + +\ Support uncompressed video format only + +1 value format-idx +2 value bytes/pixel \ # bytes per uncompressed pixel +d# 16 buffer: guid \ Uncompressed frame format + +d# 32 constant MAX_ALT_DESC \ Maximum number of alternate interface descriptors +d# 32 constant MAX_FRAME_DESC \ Maximum number of frame descriptors/format +0 value #fdesc \ Number of uncompressed frame descriptors +0 value #alt \ Number of alternate interface descriptors +MAX_FRAME_DESC /n* 2* buffer: farray \ Array of width and height per frame +MAX_ALT_DESC /n* buffer: iarray \ Array of /payload per alternate interface + +: #fdesc! ( idx -- ) #fdesc max to #fdesc ; +: #alt! ( idx -- ) #alt max to #alt ; +: alt-array! ( l idx -- ) /n* iarray + ! ; +: alt-array@ ( idx -- l ) /n* iarray + @ ; +: frame-array! ( w h idx -- ) /n* 2* farray + tuck na1+ ! ! ; +: frame-array@ ( idx -- width height ) /n* 2* frame-array + dup @ swap na1+ @ ; + +: process-vc ( idx -- ) + desc-buf swap find-intf-desc dup 0= if abort" Failed to find 1st Interface Descriptor" then + dup 5 + c@ e = over 6 + c@ 1 = and swap 7 + c@ 0= and + not if abort" Expect SC_VIDEO_CONTROL class" then +; + +: process-vs-desc ( adr -- adr' ) + farray MAX_FRAME_DESC /n* 2* erase + begin dup desc-buf-end <> while ( adr ) + dup 1+ c@ h# 24 <> if exit then \ CS_INTERFACE + dup 2 + c@ case + 4 of \ VS_FORMAT_UNCOMPRESSED + dup 5 + guid d# 16 move + dup d# 21 + c@ 3 >> to bytes/pixel + dup 3 + c@ to format-idx + endof + 5 of \ VS_FRAME_UNCOMPRESSED + dup 5 + le-w@ over 7 + le-w@ 2 pick 3 + c@ + dup #fdesc! frame-array! + endof + endcase + dup c@ + + repeat +; + +: process-alt-desc ( idx adr -- ) + iarray MAX_ALT_DESC /n* erase ( idx adr ) + begin dup desc-buf-end <> while ( idx adr ) + dup 1+ c@ 4 = if ( idx adr ) + 2dup 2 + c@ = if \ Alternate INTERFACE descriptor + dup 3 + c@ dup #alt! ( idx adr alt ) + swap c@ + ( idx alt adr' ) + dup 1+ c@ 5 = if \ Endpoint descriptor + tuck 4 + le-w@ swap alt-array! ( idx adr ) + dup 3 + c@ 1 and 0= if abort" Expect isochronous endpoint" then + dup 2 + c@ h# f and ( idx adr pipe ) + dup 6 + c@ ( idx adr pipe interval ) + 2 pick 2 + c@ h# 80 and + if to iso-in-interval to iso-in-pipe else to iso-out-interval to iso-out-pipe then + then + then + then + dup c@ + + repeat drop +; + +: process-vs ( idx -- ) + dup to vs-interface + desc-buf over find-intf-desc dup 0= if abort" Failed to find 2nd Interface Descriptor" then + dup >r ( idx adr ) ( R: adr ) + 5 + c@ e = r@ 6 + c@ 2 = and r@ 7 + c@ 0= and not if abort" Expect SC_VIDEO_STREAMING class" then + r> dup c@ + process-vs-desc ( idx adr ) ( R: adr ) + #fdesc 0= if abort" Failed to find VS_FRAME_UNCOMPRESSED descriptors" then + ( idx adr' ) process-alt-desc ( ) + #alt 0= if abort" Failed to find Alternate Interface descriptors" then +; + +: init-params ( -- ) + /desc-buf dma-alloc to desc-buf + desc-buf dup 0 get-cfg-desc dup 0= if abort" Failed to get-desc" then + + to desc-buf-end + desc-buf INTERFACE_ASSO find-desc dup 0= if abort" Failed to find Interface Association Descriptor" then + dup 3 + c@ 2 < if abort" Expect at least 2 associated interfaces" then + 2 + c@ dup process-vc \ Process Video Control Interface + 1+ process-vs \ Process Video Streaming Interface + desc-buf /desc-buf dma-free 0 to desc-buf +; + +\ LICENSE_BEGIN +\ Copyright (c) 20011 FirmWorks +\ +\ 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 AUTHORS OR 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. +\ +\ LICENSE_END
Added: dev/usb2/device/webcam/webcam.bth ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ dev/usb2/device/webcam/webcam.bth Tue Aug 9 20:32:13 2011 (r2450) @@ -0,0 +1,45 @@ +purpose: USB webcam driver loader +\ See license at end of file + +command: &tokenize &this +build-now + +silent on + +begin-tokenizing webcam.fc + +FCode-version2 + +fload ${BP}/dev/usb2/device/common.fth \ USB device driver common routines +fload ${BP}/dev/usb2/pkt-func.fth \ Some USB descriptor manipulation code +fload ${BP}/dev/usb2/device/webcam/desc.fth \ Webcam descriptor manipulation code +fload ${BP}/dev/usb2/device/webcam/webcam.fth \ USB webcam driver + +end0 + +end-tokenizing + + +\ LICENSE_BEGIN +\ Copyright (c) 20011 FirmWorks +\ +\ 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 AUTHORS OR 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. +\ +\ LICENSE_END
Added: dev/usb2/device/webcam/webcam.fth ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ dev/usb2/device/webcam/webcam.fth Tue Aug 9 20:32:13 2011 (r2450) @@ -0,0 +1,315 @@ +purpose: USB webcam driver +\ See license at end of file + +hex +headers + +" camera" device-name +" camera" device-type + +defer selftest-hook ['] noop to selftest-hook +true value verbose? + +0 value ctrl-buf +h# 400 value /ctrl-buf +0 value intr-buf + +h# c00 value /data-buf \ Buffer to store one microframe of data +/data-buf buffer: data-buf + +: alloc-bufs ( -- ) + ctrl-buf if exit then + /ctrl-buf dma-alloc to ctrl-buf + /intr-in-pipe dma-alloc to intr-buf +; +: free-bufs ( -- ) + ctrl-buf 0= if exit then + ctrl-buf /ctrl-buf dma-free 0 to ctrl-buf +; + +: init-iso-in ( #payload pipe interval -- ) " init-iso-in" $call-parent ; +: begin-iso-in ( -- ) " begin-iso-in" $call-parent ; +: restart-iso-in ( -- ) " restart-iso-in" $call-parent ; +: end-iso-in ( -- ) " end-iso-in" $call-parent ; +: get-iso-in ( adr len -- false | actual error? true ) " get-iso-in" $call-parent ; + +: begin-intr ( -- ) + intr-buf /intr-in-pipe intr-in-pipe intr-in-interval begin-intr-in +; +: end-intr ( -- ) end-intr-in ; + +: get-intr? ( adr len -- actual ) + intr-in? if nip nip restart-intr-in exit then \ USB error; restart + ?dup if ( adr len actual ) + min tuck intr-buf -rot move ( actual ) + verbose? if ." Interrupt: " intr-buf over " cdump" evaluate cr then + restart-intr-in ( actual ) + else + 2drop 0 ( actual ) + then +; + +create samsung-frame-array + 0 , 0 , \ width height + h# 280 , h# 1e0 , + h# a0 , h# 78 , + h# b0 , h# 90 , + h# 140 , h# f0 , + h# 160 , h# 120 , + h# 320 , h# 258 , + h# 500 , h# 2d0 , + +0 value hint +5 value frame-idx +h# 160 value width +h# 120 value height +width height * 2* value /frame \ 16-bit per pixel + +create samsung-alt-array + 0 , h# c0 , h# 180 , h# 200 , + h# 280 , h# 320 , h# 3b0 , h# a80 , + h# b20 , h# be0 , h# 1380 , h# 13fc , + +['] samsung-frame-array to frame-array \ Comment these 2 lines to use +['] samsung-alt-array to alt-array \ descriptor info + +\ Make sure the alt interface's endpoint and maxpayload matches +d# 5 value alt-interface +h# 320 value /payload +d# 256 value #payload +/payload dup h# 7ff and swap d# 11 >> 1+ * value /xlen + +external +: set-frame ( idx -- ) + dup to frame-idx + /n * 2* frame-array + dup @ to width na1+ @ to height + width height * 2* to /frame +; + +: set-alt ( idx -- ) + dup to alt-interface + alt-array swap na+ @ dup to /payload + dup h# 7ff and swap d# 11 >> 1+ * to /xlen +; + +: init-dev + configuration set-config if abort" Failed to set-config" then + vs-interface 0 set-interface if abort" Failed to set-interface to 0" then + ctrl-buf d# 26 vs-interface 100 a1 87 control-get nip if abort" Failed to VS_PROBE_CONTROL GET_DEF" then + hint ctrl-buf le-w! \ bmHint + format-idx ctrl-buf 2 + c! \ bFormatIndex + frame-idx ctrl-buf 3 + c! \ bFrameIndex + /frame ctrl-buf d# 18 + le-l! \ dwMaxVideoFrameSize + ctrl-buf d# 26 vs-interface 100 21 01 control-set if abort" Failed to VS_PROBE_CONTROL SET_CUR" then + ctrl-buf d# 26 vs-interface 100 a1 81 control-get nip if abort" Failed to VS_PROBE_CONTROL GET_CUR" then + begin-intr + ctrl-buf d# 26 vs-interface 200 21 01 control-set if abort" Failed to VS_COMMIT_CONTROL SET_CUR" then +; + +: init-stream + \ Make sure the alt interface's endpoint and maxpayload matches + 1 to iso-in-pipe \ Remove when init is properly done + 1 to iso-in-interval \ Remove when init is properly done + /payload iso-in-pipe set-pipe-maxpayload + #payload iso-in-pipe iso-in-interval init-iso-in + vs-interface alt-interface set-interface if abort" Failed to set alternate interface" then + d# 10 ms + begin-iso-in +; +headers + +\ Algorithm for selecting a particular alternate interface and the corresponding +\ uncompressed resolution: +\ +\ Empirically, when the webcam sends a video line of data out at a time, +\ ofw can process the video data reasonably well. +\ +\ Thus, choose the largest payload bandwidth without employing MULT. +\ Then, choose a best match video resolution. + +0 value twidth +0 value tidx +: select-alt ( -- idx ) + 0 to tidx + 0 to twidth + #alt 1 do + i alt-array@ dup h# f800 and if + drop + else + dup twidth > if to twidth i to tidx else drop then + then + loop tidx +; +: select-frame ( -- idx ) + 0 to twidth + 0 to tidx + #fdesc 1 do + i frame-array@ drop + dup bytes/pixel * h# c + /xlen <= if + dup twidth > if to twidth i to tidx else drop then + else + drop + then + loop tidx +; + +: set-params ( -- ) + ['] farray to frame-array + ['] iarray to alt-array + + select-alt set-alt + select-frame set-frame +; + +: get-next-payload ( -- len ) + data-buf /xlen get-iso-in if + drop + debug? if + dup if data-buf ca1+ c@ u. dup u. then + then + else + 0 + then +; + +0 value dptr \ Current address of data buffer to read and read-frame +0 value rlen \ Remaining # of bytes to read into the data buffer +: copy-payload ( len -- ) + ?dup 0= if exit then + h# c - data-buf h# c + ( len' src ) + dptr rot rlen min dup >r move ( ) ( R: len ) + dptr r@ + to dptr + rlen r> - to rlen +; + +4 constant MAX_RESTART_READ_FRAME +4 constant MAX_RESTART_ISO_IN +0 value #restart-read-frame +0 value #restart-iso-in +0 value dadr \ Original adress argument to read-frame +0 value dlen \ Original len argument to read-frame +: restart-read-frame ( -- ) + dadr to dptr dlen to rlen + #restart-read-frame 1+ dup to #restart-read-frame + MAX_RESTART_READ_FRAME = if + 0 to #restart-read-frame + #restart-iso-in 1+ dup to #restart-iso-in + MAX_RESTART_ISO_IN = if abort" Too many retries" else restart-iso-in then + then +; +: ?copy-payload ( len -- ) + ?dup 0= if exit then + data-buf ca1+ c@ 2 and 2 = if + rlen over h# c - <= if copy-payload else drop restart-read-frame then + else + copy-payload + then +; + +external +: read ( adr len -- actual ) + tuck to rlen to dptr ( actual ) + begin rlen while + get-next-payload ( actual len ) + copy-payload ( actual ) + repeat ( actual ) +; + +: read-frame ( adr len -- actual ) + /frame min \ Read no more than one frame worth of data + dup to dlen to dptr dup to dadr to rlen + 0 to #restart-iso-in 0 to #restart-read-frame + begin rlen while + get-next-payload ( len ) + ?copy-payload ( ) + repeat dlen +; + +: open ( -- flag ) + alloc-bufs + set-device? if false exit then + device set-target + true +; +: close ( -- ) free-bufs ; + +: init ( -- ) + init device set-target + ( init-params ) + ( set-params ) +; + +0 value selftest-adr +: selftest ( -- error? ) + open if + " cfg-vs-test" $find if + >r guid width height /frame r> execute + to selftest-adr to selftest-hook + else + ." Warning: need " type cr + then + + init-dev init-stream + begin + selftest-adr /frame read-frame drop + selftest-hook + key? until + + close + false + else + true + then +; + +headers + +init + +[ifndef] notdef +\ Debug aids +: .restart ( -- ) ." read-frame restart # = " #restart-read-frame .d cr + ." iso-in restart # = " #restart-iso-in .d cr ; + +: (.buf) ( i -- ) /xlen * data-buf + h# c " cdump" evaluate cr ; +: .buf ( -- ) /data-buf /xlen /mod swap if 1+ then 0 do i (.buf) loop ; + +: test ( -- ) + " load-base /frame read-frame drop" evaluate + " load-base dup /frame + /frame yuv2>rgb" evaluate + " load-base /frame + 0 0 width height" evaluate " draw-rectangle" " screen-ih $call-method" evaluate +; + +: testa ( -- ) + begin test key? until +; +: testb ( -- ) + begin restart-iso-in test key? until +; +[then] + +\ open u. init-dev init-stream testa + +\ LICENSE_BEGIN +\ Copyright (c) 20011 FirmWorks +\ +\ 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 AUTHORS OR 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. +\ +\ LICENSE_END