Date:2010-10-10 10:46:12 (13 years 5 months ago)
Author:Bas Wijnen
Commit:9aff93c300359af6070e64a8e4858bed8a9cbea1
Message:Add unbricking method

Files: .gitignore (1 diff)
mips/nand.hhp (1 diff)
mips/nanonote/Makefile.arch (4 diffs)
mips/nanonote/threadlist-sd.S (1 diff)
mips/nanonote/threadlist-udc.S (1 diff)
mips/nanonote/threadlist.S (1 diff)
mips/nanonote/unbrick.ccp (1 diff)
source/nand.ccp (1 diff)
source/usb-mass-storage.ccp (16 diffs)

Change Details

.gitignore
2323mips/nanonote/server/usb-server
2424fs/
2525iris-sd.tar
26unbrick
mips/nand.hhp
320320    addr (row >> 8)
321321    addr (row >> 16)
322322    cmd (CMD_ERASE2)
323    debug ("nand erase %d done\n", a)
323    //debug ("nand erase %d done\n", a)
mips/nanonote/Makefile.arch
1717
1818start_load = 0x80600000
1919load = 0x80000000
20UDC_BOOT = comment this out for sd boot
20# Uncomment one of these to select the boot method for the image.
21#UDC_BOOT = yes
22#SD_BOOT = yes
23UNBRICK = yes
2124
2225arch_iris_sources = mips/interrupts.cc mips/arch.cc
2326boot_sources = mips/init.cc mips/nanonote/board.cc
2427arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh mips/nand.hh
2528udc_boot_programs = udc
2629sd_boot_programs = sd+mmc partition fat
30unbrick_boot_programs = nand usb-mass-storage
2731standard_boot_programs = bootinit
2832
29programs = init usb-mass-storage gpio lcd bsquare ball buzzer metronome elfrun alarm rtc gui nand test boot booter $(udc_boot_programs) $(sd_boot_programs) $(standard_boot_programs)
33programs = init gpio lcd bsquare ball buzzer metronome elfrun alarm rtc gui test boot booter $(udc_boot_programs) $(sd_boot_programs) $(unbrick_boot_programs) $(standard_boot_programs)
3034
3135ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
3236CROSS = mipsel-linux-gnu-
...... 
3438junk = mdebug.abi32 reginfo comment pdr
3539OBJCOPYFLAGS = $(addprefix --remove-section=.,$(junk))
3640
37ifdef UDC_BOOT
41ifneq ($(UDC_BOOT),)
3842boot_threads = $(standard_boot_programs) $(udc_boot_programs)
39threadlist = mips/nanonote/threadlist-udc
4043ARCH_CXXFLAGS = -DNUM_THREADS=2
44BOOT_CPPFLAGS = -DUDCBOOT
4145all: mips/nanonote/nand-boot.raw test
4246mips/start.o: TARGET =
4347else
48ifneq ($(SD_BOOT),)
4449boot_threads = $(standard_boot_programs) $(sd_boot_programs)
45threadlist = mips/nanonote/threadlist-sd
4650ARCH_CXXFLAGS = -DNUM_THREADS=4
51BOOT_CPPFLAGS = -DSDBOOT
4752all: mips/nanonote/nand-boot.raw iris-sd.tar
4853mips/start.o: TARGET = -DWRAPPED
4954iris-sd.tar: $(addprefix fs/,$(addsuffix .elf,$(programs))) mips/start.raw.gz fs/init.config
5055    mkimage -A mips -T kernel -a $(start_load) -e $(shell /bin/sh -c '$(OBJDUMP) -t mips/start.elf | grep __start$$ | cut -b1-8') -n Iris -d mips/start.raw.gz fs/uimage | sed -e 's/:/;/g'
5156    cd fs && tar cvf ../$@ uimage init.config $(addsuffix .elf,$(programs)) --dereference
57else
58ifneq ($(UNBRICK),)
59boot_threads = $(standard_boot_programs) $(unbrick_boot_programs)
60ARCH_CXXFLAGS = -DNUM_THREADS=3
61BOOT_CPPFLAGS = -DUNBRICK
62all: mips/nanonote/nand-boot.raw iris.raw unbrick
63mips/start.o: TARGET =
64unbrick: mips/nanonote/unbrick.cc
65    g++ -Wall -Wextra -Werror `pkg-config --cflags --libs shevek` -lusb $< -o $@
66else
67error Please define your boot method.
68endif
69endif
5270endif
5371
5472iris.elf: LDFLAGS = --omagic -Ttext $(load)
...... 
83101
84102mips/nanonote/sdram-setup.elf: mips/nanonote/sdram-setup.ld
85103mips/nanonote/sdram-setup.elf: LDFLAGS = --omagic -T mips/nanonote/sdram-setup.ld
86$(threadlist).o: $(addprefix fs/,$(addsuffix .elf,$(boot_threads)))
104mips/nanonote/threadlist.o: $(addprefix fs/,$(addsuffix .elf,$(boot_threads)))
87105mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20"
88106mips/init.o: TARGET_FLAGS = -I/usr/include
89107source/bootinit.o: TARGET_FLAGS = -I/usr/include
...... 
99117    $< > $@
100118
101119%.o:%.S Makefile Makefile.arch mips/arch.hh
102    $(CC) $(CPPFLAGS) $(TARGET_FLAGS) -DKERNEL_STACK_SIZE=0x1000 -c $< -o $@
120    $(CC) $(CPPFLAGS) $(BOOT_CPPFLAGS) $(TARGET_FLAGS) -DKERNEL_STACK_SIZE=0x1000 -c $< -o $@
103121
104122# entry.o must be the first file. threadlist.o must be the first of the init objects (which can be freed after loading).
105iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) $(threadlist).o mips/boot.o $(subst .cc,.o,$(boot_sources))
123iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) mips/nanonote/threadlist.o mips/boot.o $(subst .cc,.o,$(boot_sources))
106124    $(LD) $(LDFLAGS) $^ -o $@
107125
108126mips/start.elf: mips/start.o
mips/nanonote/threadlist-sd.S
1// Iris: micro-kernel for a capability-based operating system.
2// mips/nanonote/threadlist.S: List of initial threads.
3// Copyright 2009 Bas Wijnen <wijnen@debian.org>
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18    .globl init_start
19    .globl thread_start
20    .set noreorder
21
22    .balign 0x1000
23thread0:
24    .incbin "fs/bootinit.elf"
25
26    .balign 0x1000
27thread1:
28    .incbin "fs/sd+mmc.elf"
29
30    .balign 0x1000
31thread2:
32    .incbin "fs/partition.elf"
33
34    .balign 0x1000
35thread3:
36    .incbin "fs/fat.elf"
37
38    .balign 0x1000
39thread4:
40
41// Everything from here may be freed after kernel initialization.
42init_start:
43
44thread_start:
45    .word thread0
46    .word thread1
47    .word thread2
48    .word thread3
49    .word thread4
mips/nanonote/threadlist-udc.S
1// Iris: micro-kernel for a capability-based operating system.
2// mips/nanonote/threadlist.S: List of initial threads.
3// Copyright 2009 Bas Wijnen <wijnen@debian.org>
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18    .globl init_start
19    .globl thread_start
20    .set noreorder
21
22    .balign 0x1000
23thread0:
24    .incbin "fs/bootinit.elf"
25
26    .balign 0x1000
27thread1:
28    .incbin "fs/udc.elf"
29
30    .balign 0x1000
31thread2:
32
33// Everything from here may be freed after kernel initialization.
34init_start:
35
36thread_start:
37    .word thread0
38    .word thread1
39    .word thread2
mips/nanonote/threadlist.S
1// Iris: micro-kernel for a capability-based operating system.
2// mips/nanonote/threadlist.S: List of initial threads.
3// Copyright 2009 Bas Wijnen <wijnen@debian.org>
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18    .globl init_start
19    .globl thread_start
20    .set noreorder
21
22#if defined (UDCBOOT)
23    .balign 0x1000
24thread0:
25    .incbin "fs/bootinit.elf"
26
27    .balign 0x1000
28thread1:
29    .incbin "fs/udc.elf"
30
31    .balign 0x1000
32thread2:
33
34// Everything from here may be freed after kernel initialization.
35init_start:
36
37thread_start:
38    .word thread0
39    .word thread1
40    .word thread2
41
42#elif defined (SDBOOT)
43    .balign 0x1000
44thread0:
45    .incbin "fs/bootinit.elf"
46
47    .balign 0x1000
48thread1:
49    .incbin "fs/sd+mmc.elf"
50
51    .balign 0x1000
52thread2:
53    .incbin "fs/partition.elf"
54
55    .balign 0x1000
56thread3:
57    .incbin "fs/fat.elf"
58
59    .balign 0x1000
60thread4:
61
62// Everything from here may be freed after kernel initialization.
63init_start:
64
65thread_start:
66    .word thread0
67    .word thread1
68    .word thread2
69    .word thread3
70#elif defined (UNBRICK)
71    .balign 0x1000
72thread0:
73    .incbin "fs/bootinit.elf"
74
75    .balign 0x1000
76thread1:
77    .incbin "fs/nand.elf"
78
79    .balign 0x1000
80thread2:
81    .incbin "fs/usb-mass-storage.elf"
82
83    .balign 0x1000
84thread3:
85
86// Everything from here may be freed after kernel initialization.
87init_start:
88
89thread_start:
90    .word thread0
91    .word thread1
92    .word thread2
93    .word thread3
94
95#else
96    #error "boot method not defined"
97#endif
mips/nanonote/unbrick.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// mips/nanonote/unbrick.ccp: Host-side helper for USB boot.
4// Copyright 2009-2010 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#include <unistd.h>
20#include <usb.h>
21#include <fstream>
22#include <sstream>
23#include <iostream>
24#include <iomanip>
25#include <cstring>
26#include <shevek/args.hh>
27#include <shevek/error.hh>
28
29#define STAGE1_FILE "stage1.raw"
30
31static usb_dev_handle *handle
32static int const boot_vendor = 0x601a
33static int const boot_product = 0x4740
34static int const run_vendor = 0xfffe
35static int const run_product = 0x0002
36static unsigned const timeout = 10000
37void boot (std::string const &filename, unsigned load, unsigned entry)
38static unsigned const STAGE1_LOAD = 0x80002000
39static unsigned const STAGE1_ENTRY = STAGE1_LOAD
40enum requests:
41    VR_GET_CPU_INFO = 0
42    VR_SET_DATA_ADDRESS = 1
43    VR_SET_DATA_LENGTH = 2
44    VR_FLUSH_CACHES = 3
45    VR_PROGRAM_START1 = 4
46    VR_PROGRAM_START2 = 5
47void request (requests num, unsigned data = 0)
48void get_device (unsigned vendor, unsigned product, unsigned tries)
49
50void request (requests r, unsigned data):
51    if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, r, (data >> 16) & 0xffff, data & 0xffff, NULL, 0, timeout) < 0:
52        std::cerr << "unable to send control message to NanoNote: " << usb_strerror () << ".\n"
53        usb_release_interface (handle, 0)
54        usb_close (handle)
55        handle = NULL
56
57void send_file (unsigned address, int size, char const *data):
58    request (VR_SET_DATA_ADDRESS, address)
59    char const *ptr = data
60    while ptr - data < size:
61        int ret = usb_bulk_write (handle, 1, ptr, size - (ptr - data), timeout)
62        if ret <= 0:
63            std::cerr << "failed to write to NanoNote.\n"
64            usb_release_interface (handle, 0)
65            usb_close (handle)
66            handle = NULL
67            return
68        ptr += ret
69
70void get_device (unsigned vendor, unsigned product, unsigned tries):
71    for unsigned i = 0; i < tries; ++i:
72        usb_find_busses ()
73        usb_find_devices ()
74        for struct usb_bus *bus = usb_busses; bus; bus = bus->next:
75            for struct usb_device *dev = bus->devices; dev; dev = dev->next:
76                if dev->descriptor.idProduct != product || dev->descriptor.idVendor != vendor:
77                    //std::cerr << shevek::ostring ("Not using %04x:%04x when looking for %04x:%04x\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product)
78                    continue
79                handle = usb_open (dev)
80                if usb_claim_interface (handle, 0) < 0:
81                    std::cerr << "unable to claim interface: " << usb_strerror () << "\n"
82                    usb_close (handle)
83                    handle = NULL
84                    continue
85                return
86        if i + 1 < tries:
87            //std::cerr << "failed to find device, still trying...\n"
88            sleep (1)
89    std::cerr << shevek::ostring ("giving up finding device %04x:%04x\n", vendor, product)
90
91void boot (std::string const &filename, unsigned load, unsigned entry):
92    std::cerr << "booting " << shevek::ostring ("%s from %x@%x", Glib::ustring (filename), load, entry) << "\n"
93    get_device (boot_vendor, boot_product, 1)
94    if !handle:
95        std::cerr << "unable to find device\n"
96        return
97    std::cerr << "sending stage 1\n"
98    std::ifstream file (STAGE1_FILE)
99    std::ostringstream stage1
100    stage1 << file.rdbuf ()
101    send_file (STAGE1_LOAD, stage1.str ().size (), stage1.str ().data ())
102    std::cerr << "running stage 1\n"
103    request (VR_PROGRAM_START1, STAGE1_ENTRY)
104    usleep (100)
105    std::ostringstream stage2
106    usb_release_interface (handle, 0)
107    file.close ()
108    file.open (filename.c_str ())
109    stage2 << file.rdbuf ()
110    std::cerr << shevek::ostring ("sending Iris (size 0x%x)\n", stage2.str ().size ())
111    send_file (load, stage2.str ().size (), stage2.str ().data ())
112    std::cerr << "flushing caches\n"
113    request (VR_FLUSH_CACHES)
114    std::cerr << "running Iris\n"
115    request (VR_PROGRAM_START2, entry)
116    usb_release_interface (handle, 0)
117    usb_close (handle)
118    handle = NULL
119    std::cerr << "done\n"
120
121int main (int argc, char **argv):
122    std::string filename ("iris.raw")
123    unsigned load (0x80000000), entry (0)
124    handle = NULL
125    usb_init ()
126    shevek::args::option opts[] = {
127        shevek::args::option ('f', "file", "image file", true, filename),
128        shevek::args::option ('l', "load", "load address", true, load),
129        shevek::args::option ('e', "entry", "entry point address", false, entry)
130     }
131    shevek::args args (argc, argv, opts, 0, 0, "unbrick program for NanoNote", "2009-2010")
132    if !entry:
133        shevek_error ("You must specify the entry point")
134    boot (filename, load, entry)
135    return 0
source/nand.ccp
3030static unsigned current_block
3131
3232static void sync ():
33    Iris::debug ("erasing %x\n", current_block << block_bits)
33    //Iris::debug ("erasing %x\n", current_block << block_bits)
3434    erase (current_block << block_bits)
3535    for unsigned p = 0; p < 1 << (block_bits - page_bits); ++p:
3636        write ((current_block << block_bits) + (p << page_bits), (char *)&cache[p << (page_bits - 2)])
source/usb-mass-storage.ccp
2828    IN interrupt: csw received, do nothing.
2929    OUT interrupt: cbw; handle
3030        -> IDLE (no data; csw sent)
31        -> CSW (data sent in one packet)
32        -> TX (more than one packet to send)
31        -> TX (send)
3332        -> RX (receive packets)
3433TX: transmitting data.
3534    IN interrupt: host received data; send more.
3635        -> TX (more to send)
37        -> CSW (last data has now been sent)
3836RX: receiving data.
3937    OUT interrupt: host sent data; handle.
4038        -> RX (more to receive)
4139        -> IDLE (done receiving; send csw)
42CSW: waiting to transmit csw.
43    IN interrupt: TX is done; send csw
44        -> IDLE
4540#endif
4641
4742extern "C":
...... 
218213    char configuration
219214    unsigned get_descriptor (unsigned type, unsigned idx, unsigned len)
220215    unsigned handle_setup (Setup *s)
221    void irq_usb ()
216    void reset ()
222217    void irq_in0 ()
223    void irq_out ()
218    void handle_rx ()
219    void handle_tx ()
220    void handle_cbw ()
224221    void send_csw ()
225222    unsigned big_endian (unsigned src)
226223    bool handle_interrupt (bool usb, bool in)
227224    void stall (unsigned error)
228    bool stalling[3]
225    bool stalling
226    enum State:
227        IDLE
228        TX
229        RX
230        SENT_CSW
231        STALL
232    State state
229233    unsigned residue
230234    unsigned status
231235    unsigned tag
236    unsigned data_done, lba, blocks
232237    unsigned block_bits
233238    Iris::WBlock block
234239    Iris::Page buffer_page
...... 
248253Udc::String <16> Udc::s_product
249254Udc::String <12> Udc::s_serial
250255
256void Udc::reset ():
257    // Reset.
258    UDC_TESTMODE = 0
259    configuration = 0
260    state = IDLE
261    status = 0
262    residue = 0
263    // enable interrupt on bus reset.
264    UDC_INTRUSBE = UDC_INTR_RESET
265    // enable interrupts on endpoint 0 and in endpoint 2
266    UDC_INTRINE = 1 << 0 | 1 << 2
267    // and on out endpoint 1.
268    UDC_INTROUTE = 1 << 1
269    // exit suspend mode by reading the interrupt register.
270    unsigned i = UDC_INTRUSB
271    // reset all pending endpoint interrupts.
272    i = UDC_INTRIN
273    i = UDC_INTROUT
274    UDC_INDEX = 1
275    UDC_OUTMAXP = max_packet_size_bulk
276    // Do this twice to flush a double-buffered fifo completely.
277    UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
278    UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
279    UDC_INDEX = 2
280    UDC_INMAXP = max_packet_size_bulk
281    UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF
282    UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF
283    //Iris::debug ("usb reset\n")
284
251285void Udc::init (Iris::WBlock b):
252286    block = b
253287    block_bits = block.get_align_bits ()
...... 
272306    cpm_start_udc ()
273307    // Disconnect from the bus and don't try to get high-speed.
274308    UDC_POWER = 0
275    UDC_TESTMODE = 0
276    configuration = 0
277    // Set max packet sizes.
278    UDC_INDEX = 1
279    UDC_OUTMAXP = max_packet_size_bulk
280    UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
281    UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF
282    UDC_INDEX = 2
283    UDC_INMAXP = max_packet_size_bulk
284    UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF
285    UDC_INCSR = (UDC_INCSRH_MODE << 8) | UDC_INCSR_CDT | UDC_INCSR_FF
286    // exit suspend mode by reading the interrupt register.
287    unsigned i = UDC_INTRUSB
288    // reset all pending endpoint interrupts.
289    i = UDC_INTRIN
290    i = UDC_INTROUT
291    // enable interrupt on bus reset.
292    UDC_INTRUSBE = UDC_INTR_RESET
293    // enable interrupts on endpoint 0 and in endpoint 2
294    UDC_INTRINE = 1 << 0 | 1 << 2
295    // and on out endpoint 1.
296    UDC_INTROUTE = 1 << 1
309    reset ()
297310    // Wait a while.
298311    Iris::sleep (HZ / 10)
299312    // Connect to the host.
300313    UDC_POWER = UDC_POWER_SOFTCONN
301314
302    // Initialize cbw state
303    status = 0
304    residue = 0
305
306315void Udc::send (unsigned ep, char const *data, unsigned length, unsigned maxlength):
307316    if maxlength < length:
308317        length = maxlength
...... 
318327
319328void Udc::send_padded (char const *data, unsigned length, unsigned maxlength):
320329    UDC_INDEX = 2
321    if UDC_INCSR & UDC_INCSR_INPKTRDY:
322        Iris::panic (0, "sending padded not possible because a packet is already waiting.\n")
323330    unsigned len = length < maxlength ? length : maxlength
324331    residue = maxlength - len
325332    len = (len + 3) & ~3
...... 
328335    while len + 3 < maxlength:
329336        UDC_FIFO (2) = 0
330337        len += 4
331        if len % max_packet_size_bulk == 0:
332            // This doesn't ever happen, because the largest packet we send is smaller than max_packet_size_bulk.
333            Iris::debug ("sending at len %x\n", len)
334            UDC_INCSR |= UDC_INCSR_INPKTRDY
335            while true:
336                Iris::register_interrupt (IRQ_UDC)
337                Iris::wait_for_interrupt (IRQ_UDC)
338                kdebug ("interrupt pad0\n")
339                unsigned usb = UDC_INTRUSB
340                unsigned in = UDC_INTRIN
341                if usb & 4 || in & 1:
342                    //kdebug ("general interrupt pad0\t")
343                    if !handle_interrupt (usb & 4, in & 1):
344                        return
345                unsigned out = UDC_INTROUT
346                if out & 2:
347                    Iris::panic (0, "out interrupt while waiting for in")
348                if in & 4:
349                    break
350338        //kdebug_char ('-')
351    if len % max_packet_size_bulk != 0 || len < maxlength:
352        while len < maxlength:
353            UDC_FIFO8 (2) = 0
354            ++len
355            //kdebug_char ('.')
356        UDC_INCSR |= UDC_INCSR_INPKTRDY
357        while true:
358            Iris::register_interrupt (IRQ_UDC)
359            Iris::wait_for_interrupt (IRQ_UDC)
360            kdebug ("interrupt pad\t")
361            unsigned usb = UDC_INTRUSB
362            unsigned in = UDC_INTRIN
363            if usb & 4 || in & 1:
364                //kdebug ("general interrupt pad\t")
365                if !handle_interrupt (usb & 4, in & 1):
366                    return
367            unsigned out = UDC_INTROUT
368            if out & 2:
369                Iris::panic (0, "out interrupt while waiting for in")
370            if in & 4:
371                break
372        //kdebug ("done interrupt pad\n")
339    while len < maxlength:
340        UDC_FIFO8 (2) = 0
341        ++len
342        //kdebug_char ('.')
343    UDC_INCSR |= UDC_INCSR_INPKTRDY
344    blocks = 0
345    state = TX
373346
374347unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
375348    switch type:
...... 
424397            switch s->request:
425398                case SET_ADDRESS:
426399                    UDC_FADDR = s->value
427                    //Iris::debug ("set address %x\n", s->value)
400                    Iris::debug ("set address %x\n", s->value)
428401                    return 0
429402                case SET_CONFIGURATION:
430403                    if s->value >= 2:
431404                        return ~0
432405                    configuration = s->value
433                    //Iris::debug ("set configuration %x\n", s->value)
406                    Iris::debug ("set configuration %x\n", s->value)
434407                    return 0
435408                case SET_INTERFACE:
436409                    if s->value != 0:
437410                        return ~0
438                    //Iris::debug ("set interface %x\n", s->value)
411                    Iris::debug ("set interface %x\n", s->value)
439412                    return 0
440413                default:
441414                    return ~0
...... 
444417            UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
445418            switch s->request:
446419                case GET_STATUS:
447                    //Iris::debug ("get status\t")
420                    Iris::debug ("get status\t")
448421                    send (0, "\0\0", 2, s->length)
449422                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
450423                case GET_DESCRIPTOR:
451424                    return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
452425                case GET_CONFIGURATION:
453                    //Iris::debug ("get configuration\t")
426                    Iris::debug ("get configuration\t")
454427                    send (0, &configuration, 1, s->length)
455428                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
456429                case GET_INTERFACE:
457                    //Iris::debug ("get interface\t")
430                    Iris::debug ("get interface\t")
458431                    send (0, "\0", 1, s->length)
459432                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
460433                default:
...... 
466439                        case ENDPOINT_HALT:
467440                            switch s->index:
468441                                case 0x82:
469                                    Iris::debug ("in ep halt reset\n")
442                                    //Iris::debug ("in ep halt reset\n")
470443                                    UDC_INDEX = 2
471                                    UDC_INCSR &= ~UDC_INCSR_SENDSTALL
472                                    stalling[2] = false
444                                    UDC_INCSR = (UDC_INCSR & ~UDC_INCSR_SENDSTALL) | UDC_INCSR_CDT
445                                    stalling = false
446                                    send_csw ()
473447                                    break
474448                                case 1:
475                                    Iris::debug ("out ep halt reset\n")
449                                    //Iris::panic (0, "halt reset on out endpoint")
476450                                    UDC_INDEX = 1
477                                    UDC_OUTCSR &= ~UDC_OUTCSR_SENDSTALL
478                                    stalling[1] = false
451                                    UDC_OUTCSR |= UDC_OUTCSR_CDT
479452                                    break
480453                                default:
481454                                    return ~0
...... 
499472            UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
500473            switch s->request:
501474                case BULK_ONLY_RESET:
502                    //Iris::debug ("bulk reset\n")
475                    Iris::debug ("bulk reset\n")
476                    state = IDLE
503477                    return 0
504478                default:
505479                    return ~0
...... 
507481            Iris::debug ("request: %x %x %x %x %x\n", s->request_type, s->request, s->index, s->length, s->value)
508482            return ~0
509483
510void Udc::irq_usb ():
511    // Reset.
512    // enable interrupts on endpoint 0 and in endpoint 2
513    UDC_INTRINE = 1 << 0 | 1 << 2
514    // and on out endpoint 1.
515    UDC_INTROUTE = 1 << 1
516    UDC_INDEX = 1
517    // Do this twice to flush a double-buffered fifo completely.
518    UDC_OUTMAXP = max_packet_size_bulk
519    UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
520    UDC_OUTCSR |= UDC_OUTCSR_CDT | UDC_OUTCSR_FF
521    UDC_INDEX = 2
522    UDC_INMAXP = max_packet_size_bulk
523    UDC_INCSR |= UDC_INCSR_CDT
524    //Iris::debug ("usb reset\n")
525
526484void Udc::irq_in0 ():
527485    // Interrupt on endpoint 0.
528486    UDC_INDEX = 0
529487    unsigned csr = UDC_CSR0
530488    if csr & UDC_CSR0_SENTSTALL:
531489        UDC_CSR0 = 0
532        //Iris::debug ("stall done\t")
490        //Iris::debug ("stall 0 done\t")
533491    if csr & UDC_CSR0_SETUPEND:
534492        UDC_CSR0 = UDC_CSR0_SVDSETUPEND
535        //Iris::debug ("setup aborted\t")
493        Iris::debug ("setup aborted\t")
536494    if !(csr & UDC_CSR0_OUTPKTRDY):
537495        //Iris::debug ("no packet 0: %x\n", csr)
538496        return
539    UDC_INDEX = 1
540    UDC_OUTCSR |= UDC_OUTCSR_CDT
541    UDC_INDEX = 2
542    UDC_INCSR |= UDC_INCSR_CDT
543497    UDC_INDEX = 0
544498    union { unsigned d[2]; Setup s; } packet
545499    packet.d[0] = UDC_FIFO (0)
546500    packet.d[1] = UDC_FIFO (0)
547501    if !(packet.s.request_type & 0x80) && packet.s.length > 0:
548502        // More data will follow; unsupported.
549        //Iris::debug ("packet on ep0 too long\n")
503        Iris::debug ("packet on ep0 too long\n")
550504        UDC_CSR0 = UDC_CSR0_SENDSTALL
551505        return
552506    unsigned ret = handle_setup (&packet.s)
553507    UDC_INDEX = 0
554508    if ret == ~0:
555        Iris::debug ("failed setup: %x %x %x %x %x\n", packet.s.request_type, packet.s.request, packet.s.index, packet.s.length, packet.s.value)
509        //Iris::debug ("failed setup: %x %x %x %x %x\n", packet.s.request_type, packet.s.request, packet.s.index, packet.s.length, packet.s.value)
556510        UDC_CSR0 = UDC_CSR0_SENDSTALL
557511        return
558512    if ret:
...... 
566520    UDC_FIFO (2) = residue
567521    UDC_FIFO8 (2) = status
568522    UDC_INCSR |= UDC_INCSR_INPKTRDY
523    state = SENT_CSW
569524    status = 0
570525    residue = 0
571    while true:
572        Iris::register_interrupt (IRQ_UDC)
573        Iris::wait_for_interrupt (IRQ_UDC)
574        kdebug ("interrupt csw\n")
575        unsigned usb = UDC_INTRUSB
576        unsigned in = UDC_INTRIN
577        if usb & 4 || in & 1:
578            if !handle_interrupt (usb & 4, in & 1):
579                return
580        if in & 4:
581            break
582        unsigned out = UDC_INTROUT
583        if out & 2:
584            Iris::panic (0, "out interrupt while waiting for in after csw")
585    kdebug ("sent csw\n")
526    //kdebug ("sent csw\n")
586527
587528void Udc::stall (unsigned error):
588    unsigned index = UDC_INDEX
589    if stalling[index]:
529    if stalling:
590530        Iris::debug ("already stalling!\n")
591    if index == 1:
592        UDC_OUTCSR |= UDC_OUTCSR_SENDSTALL
593    else:
594        UDC_INCSR |= UDC_INCSR_SENDSTALL
595    stalling[index] = true
596    while stalling[index]:
597        //Iris::debug ("stalling %d\n", index)
598        Iris::register_interrupt (IRQ_UDC)
599        Iris::wait_for_interrupt (IRQ_UDC)
600        kdebug ("stalling interrupt\n")
601        unsigned usb = UDC_INTRUSB
602        unsigned in = UDC_INTRIN
603        if in & 4:
604            if index != 2:
605                Iris::panic (0, "stalling on out, but in responds")
606            kdebug ("stall has been sent to in endpoint\n")
607            UDC_INDEX = 2
608            UDC_INCSR &= ~UDC_INCSR_SENTSTALL
609            //Iris::debug ("csr: %x\n", UDC_INCSR)
610        if usb & 4 || in & 1:
611            //kdebug ("stuff\n")
612            if !handle_interrupt (usb & 4, in & 1):
613                return
614        unsigned out = UDC_INTROUT
615        if out & 2:
616            if index != 1:
617                Iris::panic (0, "stalling on in, but out responds")
618            kdebug ("stall has been sent to out endpoint\n")
619            UDC_INDEX = 1
620            UDC_OUTCSR &= ~UDC_OUTCSR_SENTSTALL
621    //kdebug ("done stalling\n")
622    if index == 2:
623        status = error
624        send_csw ()
531    UDC_INCSR |= UDC_INCSR_SENDSTALL
532    stalling = true
533    state = STALL
625534
626535unsigned Udc::big_endian (unsigned src):
627536    return src >> 24 | src >> 8 & 0xff00 | src << 8 & 0xff0000 | src << 24
628537
629void Udc::irq_out ():
538void Udc::handle_rx ():
539    buffer_page.set_flags (Iris::Page::FRAME)
540    UDC_INDEX = 1
541    if !(UDC_OUTCSR & UDC_OUTCSR_OUTPKTRDY):
542        Iris::panic (0, "no packet ready after out interrupt during rx")
543    if UDC_OUTCOUNT != max_packet_size_bulk:
544        Iris::panic (UDC_OUTCOUNT, "invalid packet size during rx")
545    for unsigned t = 0; t < max_packet_size_bulk; t += 4:
546        ((unsigned *)buffer)[(t + data_done) >> 2] = UDC_FIFO (1)
547    UDC_OUTCSR &= ~UDC_OUTCSR_OUTPKTRDY
548    data_done += max_packet_size_bulk
549    if data_done == 1 << block_bits:
550        //Iris::debug ("writing block %x\n", lba)
551        block.set_block (lba << block_bits, buffer_page, 1 << block_bits)
552        data_done = 0
553        --blocks
554        ++lba
555        if blocks == 0:
556            send_csw ()
557            return
558
559void Udc::handle_tx ():
560    if blocks == 0:
561        send_csw ()
562        return
563    if data_done == 0:
564        // read block lba.
565        buffer_page.set_flags (Iris::Page::FRAME)
566        block.get_block (lba << block_bits, 1 << block_bits, 0, buffer_page)
567    UDC_INDEX = 2
568    for unsigned t = 0; t < max_packet_size_bulk; t += 4:
569        UDC_FIFO (2) = ((unsigned *)buffer)[(data_done + t) >> 2]
570    data_done += max_packet_size_bulk
571    if data_done == 1 << block_bits:
572        data_done = 0
573        ++lba
574        --blocks
575    UDC_INCSR |= UDC_INCSR_INPKTRDY
576
577void Udc::handle_cbw ():
630578    UDC_INDEX = 1
631579    unsigned csr = UDC_OUTCSR
632580    unsigned size = UDC_OUTCOUNT
633    if !(csr & UDC_OUTCSR_OUTPKTRDY):
634        // No packet, just a notification.
635        kdebug ("no packet\n")
636        return
637581    if csr & UDC_OUTCSR_SENDSTALL:
638582        // When stalling, do nothing else.
639583        //kdebug ("not responding to out during stall\n")
640584        UDC_OUTCSR = csr & ~UDC_OUTCSR_SENTSTALL
641585        return
586    if !(csr & UDC_OUTCSR_OUTPKTRDY):
587        // No packet; this shouldn't happen.
588        Iris::panic (0, "no packet")
589        return
642590    // expect a new cbw.
643591    if size != 31:
644592        Iris::debug ("count %d != 31\n", size)
...... 
656604    UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
657605    tag = cbw.cbw.tag
658606    if cbw.cbw.sig != 0x43425355 || cbw.cbw.lun != 0 || cbw.cbw.size == 0 || cbw.cbw.size > 16:
659        Iris::debug ("sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
607        Iris::debug ("wrong cbw: sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
660608        stall (2)
661609        return
662610    //kdebug ("bulk cbw\t")
611    #if 0
612    Iris::debug ("cbw:")
613    for unsigned i = 0; i < cbw.cbw.size; ++i:
614        kdebug_char (' ')
615        kdebug_num (cbw.cbw.data[i], 2)
616    Iris::debug ("\n")
617    #endif
663618    UDC_INDEX = 2
664619    bool to_host = cbw.cbw.flags & 0x80
665620    switch cbw.cbw.data[0]:
...... 
673628        case CBW::REQUEST_SENSE:
674629            //Iris::debug ("sense requested\n")
675630            send_padded ("\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length)
676            send_csw ()
677631            break
678632        case CBW::FORMAT_UNIT:
679633            Iris::panic (0, "FORMAT_UNIT isn't implemented")
...... 
682636                stall (2)
683637                return
684638            //Iris::debug ("sending inquiry response\t")
639            // TODO: find out why these bytes are messed up.
685640            send_padded ("\x00\x00\x04\x02\x1f\x00\x00\x00shevek iris usb stick \x00\x00\x04\x02", 36, cbw.cbw.length)
686            send_csw ()
687641            break
688642        case CBW::RESERVE6:
689643            Iris::panic (0, "RESERVE6 isn't implemented")
...... 
700654            capacity[1] = big_endian (1 << block_bits)
701655            //Iris::debug ("sending capacity: %x * %x\t", capacity[0], capacity[1])
702656            send_padded ((char *)capacity, 8, cbw.cbw.length)
703            send_csw ()
704657            break
705658        case CBW::READ10:
706            unsigned lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5]
707            unsigned blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8]
708            for unsigned i = 0; i < blocks; ++i:
709                //Iris::debug ("reading block %d\n", lba + i)
710                // read block lba + i.
711                buffer_page.set_flags (Iris::Page::FRAME)
712                block.get_block ((lba + i) << block_bits, 1 << block_bits, 0, buffer_page)
713                for unsigned p = 0; p < 1 << block_bits; p += max_packet_size_bulk:
714                    //Iris::debug (" %d", p)
715                    UDC_INDEX = 2
716                    for unsigned t = 0; t < max_packet_size_bulk; t += 4:
717                        UDC_FIFO (2) = ((unsigned *)buffer)[(p + t) >> 2]
718                    UDC_INCSR |= UDC_INCSR_INPKTRDY
719                    //Iris::debug ("\n")
720                    while true:
721                        Iris::register_interrupt (IRQ_UDC)
722                        Iris::wait_for_interrupt (IRQ_UDC)
723                        kdebug ("interrupt read10\n")
724                        unsigned usb = UDC_INTRUSB
725                        unsigned in = UDC_INTRIN
726                        unsigned out = UDC_INTROUT
727                        if usb & 4 || in & 1:
728                            //kdebug ("general interrupt read10\t")
729                            if !handle_interrupt (usb & 4, in & 1):
730                                return
731                        if out & 2:
732                            Iris::panic (0, "out interrupt while waiting for in")
733                        if in & 4:
734                            break
735            send_csw ()
659            if !to_host:
660                stall (2)
661                return
662            lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5]
663            blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8]
664            data_done = 0
665            state = TX
666            handle_tx ()
736667            break
737668        case CBW::WRITE10:
738            unsigned lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5]
739            unsigned blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8]
740            for unsigned i = 0; i < blocks; ++i:
741                //Iris::debug ("writing block %d\n", lba + i)
742                // write block lba + i.
743                buffer_page.set_flags (Iris::Page::FRAME)
744                //Iris::debug ("@%x:", (lba + i) << block_bits)
745                for unsigned p = 0; p < 1 << block_bits; p += max_packet_size_bulk:
746                    while true:
747                        Iris::register_interrupt (IRQ_UDC)
748                        Iris::wait_for_interrupt (IRQ_UDC)
749                        Iris::debug (".")
750                        unsigned usb = UDC_INTRUSB
751                        unsigned in = UDC_INTRIN
752                        unsigned out = UDC_INTROUT
753                        if usb & 4 || in & 1:
754                            if !handle_interrupt (usb & 4, in & 1):
755                                return
756                        if out & 2:
757                            break
758                        if in & 4:
759                            Iris::panic (0, "in interrupt while waiting for out")
760                    UDC_INDEX = 1
761                    if !(UDC_OUTCSR & UDC_OUTCSR_OUTPKTRDY):
762                        Iris::panic (0, "no packet ready after out interrupt in write10")
763                    if UDC_OUTCOUNT != max_packet_size_bulk:
764                        Iris::panic (UDC_OUTCOUNT, "invalid packet size in write10")
765                    for unsigned t = 0; t < max_packet_size_bulk; t += 4:
766                        ((unsigned *)buffer)[(p + t) >> 2] = UDC_FIFO (1)
767                        //kdebug (" ")
768                        //kdebug_num (((unsigned *)buffer)[(p + t) >> 2], 8)
769                    UDC_OUTCSR &= ~UDC_OUTCSR_OUTPKTRDY
770                //kdebug ("\n")
771                //Iris::debug ("setting block %x@%x+%x\n", lba + i << block_bits, 0, 1 << block_bits)
772                block.set_block ((lba + i) << block_bits, buffer_page, 1 << block_bits)
773            send_csw ()
669            if to_host:
670                stall (2)
671                return
672            lba = cbw.cbw.data[2] << 24 | cbw.cbw.data[3] << 16 | cbw.cbw.data[4] << 8 | cbw.cbw.data[5]
673            blocks = cbw.cbw.data[7] << 8 | cbw.cbw.data[8]
674            if blocks == 0:
675                send_csw ()
676                break
677            state = RX
678            data_done = 0
679            buffer_page.set_flags (Iris::Page::FRAME)
774680            break
775681        case CBW::RESERVE10:
776682            Iris::panic (0, "RESERVE10 isn't implemented")
777683        case CBW::RELEASE10:
778684            Iris::panic (0, "RELEASE10 isn't implemented")
779685        default:
780            Iris::debug ("cbw:")
686            #if 0
687            Iris::debug ("unknown cbw:")
781688            for unsigned i = 0; i < cbw.cbw.size; ++i:
782689                kdebug_char (' ')
783690                kdebug_num (cbw.cbw.data[i], 2)
784691            Iris::debug ("\n")
692            #endif
785693            residue = cbw.cbw.length
786694            stall (1)
787695            return
788696
789bool Udc::handle_interrupt (bool usb, bool in):
790    if usb:
791        //Iris::debug ("usb\t")
792        // reset.
793        irq_usb ()
794        return false
795    if in:
796        //Iris::debug ("control\t")
797        // control request
798        irq_in0 ()
799        return true
800
801697void Udc::interrupt ():
802    Iris::debug ("interrupt\n")
698    //Iris::debug ("interrupt, state = %d\n", state)
803699    while true:
700        bool action = false
804701        unsigned usb = UDC_INTRUSB
805702        unsigned in = UDC_INTRIN
806        bool action = false
703        unsigned out = UDC_INTROUT
704        if usb & 4:
705            //Iris::debug ("reset\n")
706            reset ()
707            action = true
708        if state == STALL && in & 4:
709            // This must be handled here, because the state can be changed by the control request.
710            //Iris::debug ("stalling\n")
711            in &= ~4
712        if in & 1:
713            //Iris::debug ("control request\n")
714            irq_in0 ()
715            action = true
807716        if in & 4:
808            Iris::panic (0, "data request during idle\n")
809        if usb & 4 || in & 1:
810            handle_interrupt (usb & 4, in & 1)
717            //Iris::debug ("in request\n")
718            // Notification of sent packet (or stall, but we don't do that on the in endpoint).
719            switch state:
720                case SENT_CSW:
721                    // csw received.
722                    state = IDLE
723                    break
724                case TX:
725                    handle_tx ()
726                    break
727                default:
728                    Iris::panic (state, "invalid state for data send")
729                    stall (2)
730                    break
811731            action = true
812        unsigned out = UDC_INTROUT
813732        if out & 2:
814            irq_out ()
733            //Iris::debug ("out request\n")
734            switch state:
735                case IDLE:
736                    handle_cbw ()
737                    break
738                case RX:
739                    handle_rx ()
740                    break
741                default:
742                    stall (2)
743                    Iris::panic (0, "invalid state for data receive")
744                    break
815745            action = true
816746        if !action:
817747            // No more interrupts to handle; this is normal, because we're looping until this happens.

Archive Download the corresponding diff file

Branches:
master



interactive