Date:2012-09-26 19:03:36 (11 years 6 months ago)
Author:Bas Wijnen
Commit:d9a12225ebc34be4837d027e31c17b022e8bef7b
Message:use automake

Files: Makefile (1 diff)
Makefile.am (1 diff)
Makefile.arch (1 diff)
configure.ac (1 diff)
courier-10+8+32.png (0 diffs)
courier.xcf (0 diffs)
devices.hhp (2 diffs)
init.config (3 diffs)
invoke.ccp (1 diff)
iris.hhp (4 diffs)
kernel.hhp (1 diff)
makefont (1 diff)
mips/arch.hhp (1 diff)
mips/boot.S (1 diff)
mips/entry.S (1 diff)
mips/init.ccp (2 diffs)
mips/interrupts.ccp (1 diff)
mips/nanonote/Makefile.arch (1 diff)
mips/nanonote/board.ccp (1 diff)
mips/nanonote/jz4740.hhp (1 diff)
mips/nanonote/nanonote-boot.ccp (1 diff)
mips/nanonote/sdram-setup.ccp (2 diffs)
mips/nanonote/sdram-setup.ld (1 diff)
mips/nanonote/server/usb-server.ccp (3 diffs)
mips/nanonote/threadlist.S (1 diff)
mips/nanonote/unbrick.ccp (1 diff)
mkthreadlist (1 diff)
source/alarm.ccp (1 diff)
source/bootinit.ccp (1 diff)
source/font.ccp (1 diff)
source/init.ccp (3 diffs)
source/lcd.ccp (2 diffs)
source/nanonote-gpio.ccp (5 diffs)
source/rtc.ccp (2 diffs)
source/sd+mmc.ccp (1 diff)
source/sdmmc.ccp (1 diff)
source/trendtac-gpio.ccp (2 diffs)
source/udc.ccp (9 diffs)
source/usb-mass-storage.ccp (1 diff)
source/usbmassstorage.ccp (1 diff)

Change Details

Makefile
1# Iris: micro-kernel for a capability-based operating system.
2# Makefile: build rules
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# Define some variables.
19SERIAL = /dev/ttyUSB0
20CXXFLAGS = -Wno-unused-parameter -fno-strict-aliasing -fno-builtin -nostdinc $(ARCH_CXXFLAGS) -ggdb3
21CPPFLAGS = -O5 -fno-inline $(ARCH_CPPFLAGS)
22CC = $(CROSS)gcc
23LD = $(CROSS)ld
24OBJCOPY = $(CROSS)objcopy
25
26headers = kernel.hh iris.hh devices.hh ui.hh keys.hh $(arch_headers)
27iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources)
28BUILT_SOURCES = $(iris_sources) $(boot_sources)
29
30STRIPFLAG = -S
31
32# Include arch-specific rules.
33include Makefile.arch
34
35# Disable implicit rules.
36%.o: %.S
37%.o: %.cc
38
39PYPP = /usr/bin/pypp
40%.cc: %.ccp
41    $(PYPP) --name $< < $< > $@
42%.hh: %.hhp
43    $(PYPP) --name $< < $< > $@
44
45%.o:%.cc Makefile Makefile.arch $(headers)
46    $(CC) $(CPPFLAGS) $(TARGET_FLAGS) $(CXXFLAGS) -c $< -o $@
47
48%.elf: boot-programs/crt0.o boot-programs/%.o
49    $(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
50    $(OBJCOPY) $(STRIPFLAG) $(OBJCOPYFLAGS) $@
51
52fs/%.elf: source/crt0.o source/%.o fs/init.config
53    $(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
54    $(OBJCOPY) $(STRIPFLAG) $(OBJCOPYFLAGS) $@
55
56fs/%: %
57    test -d fs || mkdir fs
58    ln -s ../$< $@
59
60clean:
61    rm -f *.o boot-programs/*.o $(BUILT_SOURCES) $(ARCH_CLEAN_FILES)
62    rm -rf fs/
63
64debug:
65    stty -F $(SERIAL) raw 57600
66    while : ; do cat $(SERIAL) ; done
67
68.PHONY: clean
69.PRECIOUS: $(headers) boot-programs/crt0.o source/crt0.o
Makefile.am
1# Iris: micro-kernel for a capability-based operating system.
2# Makefile.am: build rules
3# Copyright 2009-2012 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
18AUTOMAKE_OPTIONS = subdir-objects foreign
19
20# Define some variables.
21OBJCOPY = $(host_alias)-objcopy
22SERIAL = /dev/ttyUSB0
23junk = mdebug.abi32 reginfo comment pdr note.gnu.build-id
24objcopyflags = -S $(addprefix --remove-section=.,$(junk))
25
26start_load = 0x80400000
27load = 0x80000000
28
29noinst_DATA = iris.raw
30noinst_PROGRAMS = iris.elf
31
32%.raw: %.elf
33    $(OBJCOPY) $(objcopyflags) -Obinary $< $@
34
35# Define boot_threads depending on selected mode.
36if UDC
37boot_threads = bootinit udc
38else
39if UNBRICK
40boot_threads = nand sdmmc usbmassstorage
41else
42boot_threads = sdmmc partition fat
43endif
44endif
45
46# Threadlist must be the last file on the line below.
47iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc mips/interrupts.cc mips/arch.cc threadlist.S
48boot_sources = mips/init.cc mips/nanonote/board.cc
49headers = kernel.hh iris.hh devices.hh ui.hh keys.hh mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh mips/nand.hh
50iris_elf_CPPFLAGS = -O5 -fno-inline -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
51iris_elf_CXXFLAGS = -Wno-unused-parameter -fno-strict-aliasing -fno-builtin -ggdb3
52iris_elf_LDFLAGS = -Wl,--omagic -Wl,-Ttext -Wl,$(load) -nostdlib
53iris_elf_SOURCES = mips/entry.S ${iris_sources} mips/boot.S ${boot_sources} ${headers}
54
55program_sources = \
56    source/alarm.cc \
57    source/ball.cc \
58    source/boot.cc \
59    source/booter.cc \
60    source/bootinit.cc \
61    source/bsquare.cc \
62    source/buzzer.cc \
63    source/elfrun.cc \
64    source/fat.cc \
65    source/font.cc \
66    source/gpio.cc \
67    source/gui.cc \
68    source/init.cc \
69    source/lcd.cc \
70    source/metronome.cc \
71    source/nand.cc \
72    source/partition.cc \
73    source/rtc.cc \
74    source/sdmmc.cc \
75    source/test.cc \
76    source/udc.cc \
77    source/usbmassstorage.cc
78
79program_targets = \
80    fs/alarm.elf \
81    fs/ball.elf \
82    fs/boot.elf \
83    fs/booter.elf \
84    fs/bootinit.elf \
85    fs/bsquare.elf \
86    fs/buzzer.elf \
87    fs/elfrun.elf \
88    fs/fat.elf \
89    fs/font.elf \
90    fs/gpio.elf \
91    fs/gui.elf \
92    fs/init.elf \
93    fs/lcd.elf \
94    fs/metronome.elf \
95    fs/nand.elf \
96    fs/partition.elf \
97    fs/rtc.elf \
98    fs/sdmmc.elf \
99    fs/test.elf \
100    fs/udc.elf \
101    fs/usbmassstorage.elf
102
103noinst_PROGRAMS += $(program_targets)
104AM_CPPFLAGS = -O5 -fno-inline -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE
105AM_CXXFLAGS = -Wno-unused-parameter -fno-strict-aliasing -fno-builtin -ggdb3
106AM_LDFLAGS = -nostdlib
107
108BUILT_SOURCES = $(iris_sources) $(boot_sources) $(program_sources) $(headers) mips/nanonote/threadlist.S source/charset.data fs/font.dat fs/init.config
109
110threadlist.S: mkthreadlist Makefile $(addprefix fs/,$(addsuffix .elf,$(boot_threads)))
111    $(top_srcdir)/$< $(boot_threads) > $@
112
113PYPP = /usr/bin/pypp
114%.cc: %.ccp
115    $(PYPP) --name $< < $< > $@
116%.hh: %.hhp
117    $(PYPP) --name $< < $< > $@
118
119source/charset.data: source/charset
120    $< > $@
121fs/font.dat: courier-10+8+32.png makefont
122    ./makefont $< > $@
123fs/%: %
124    ln -s ../$< $@
125
126fs_alarm_elf_SOURCES = source/crt0.cc source/alarm.cc
127fs_ball_elf_SOURCES = source/crt0.cc source/ball.cc
128fs_boot_elf_SOURCES = source/crt0.cc source/boot.cc
129fs_booter_elf_SOURCES = source/crt0.cc source/booter.cc
130fs_bootinit_elf_SOURCES = source/crt0.cc source/bootinit.cc
131fs_bsquare_elf_SOURCES = source/crt0.cc source/bsquare.cc
132fs_buzzer_elf_SOURCES = source/crt0.cc source/buzzer.cc
133fs_elfrun_elf_SOURCES = source/crt0.cc source/elfrun.cc
134fs_fat_elf_SOURCES = source/crt0.cc source/fat.cc
135fs_font_elf_SOURCES = source/crt0.cc source/font.cc
136fs_gpio_elf_SOURCES = source/crt0.cc source/gpio.cc
137fs_gui_elf_SOURCES = source/crt0.cc source/gui.cc
138fs_init_elf_SOURCES = source/crt0.cc source/init.cc
139fs_lcd_elf_SOURCES = source/crt0.cc source/lcd.cc
140fs_metronome_elf_SOURCES = source/crt0.cc source/metronome.cc
141fs_nand_elf_SOURCES = source/crt0.cc source/nand.cc
142fs_partition_elf_SOURCES = source/crt0.cc source/partition.cc
143fs_rtc_elf_SOURCES = source/crt0.cc source/rtc.cc
144fs_sdmmc_elf_SOURCES = source/crt0.cc source/sdmmc.cc
145fs_test_elf_SOURCES = source/crt0.cc source/test.cc
146fs_udc_elf_SOURCES = source/crt0.cc source/udc.cc
147fs_usbmassstorage_elf_SOURCES = source/crt0.cc source/usbmassstorage.cc
148
149autoclean: maintainer-clean
150    rm -rf aclocal.m4 configure depcomp fs install-sh iris.raw iris-sd.tar Makefile.in missing
Makefile.arch
1mips/Makefile.arch
configure.ac
1AC_INIT([iris], [0.2], [wijnen@debian.org])
2AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
3AC_PROG_CXX
4AM_PROG_AS
5
6AC_ARG_ENABLE([udc-boot], AC_HELP_STRING([--enable-udc-boot], [Compile for booting over custom usb protocol]), AM_CONDITIONAL(UDC, true), AM_CONDITIONAL(UDC, false))
7AC_ARG_ENABLE([unbrick], AC_HELP_STRING([--enable-unbrick], [Compile for unbricking]), AM_CONDITIONAL(UNBRICK, true), AM_CONDITIONAL(UNBRICK, false))
8
9AC_CONFIG_FILES([Makefile])
10AC_OUTPUT
courier-10+8+32.png
courier.xcf
devices.hhp
300300            // TODO: Interface is to be designed.
301301            panic (0, "using undefined interface Display::get_info ()")
302302
303    // Font interface.
304    // This can be used to turn a Display into a tty
305    struct Font : public Cap:
306        Font (Cap c = Cap ()) : Cap (c):
307        enum request:
308            SET_DISPLAY = Display::ID
309            LOAD_FONT
310            SETUP
311            AT
312            WRITE
313            GET_POS
314            GET_SIZE
315            ID
316        // Connect this font to new Display.
317        void set_display (Display d):
318            ocall (d, CAP_MASTER_DIRECT | SET_DISPLAY)
319        // Load new glyphs.
320        void load_font (String font):
321            ocall (font, CAP_MASTER_DIRECT | LOAD_FONT)
322        // Set some things up, like colours.
323        void setup ():
324            // TODO: Interface is to be designed.
325            panic (0, "using undefined interface Font::setup ()")
326        // Set new cursor position.
327        void at (int x, int y, bool delta_x = false, bool delta_y = false):
328            call (Num (CAP_MASTER_DIRECT | AT, delta_x + 2 * delta_y), Num (x, y))
329        // Write one glyph to the display.
330        void write (char c):
331            call (CAP_MASTER_DIRECT | WRITE, c)
332        // Write some glyphs to the display.
333        void write (char const *text):
334            for char const *t = text; *t; ++t:
335                invoke (CAP_MASTER_DIRECT | WRITE, *t)
336        // Write some glyphs to the display.
337        void write (char const *text, unsigned size):
338            for unsigned t = 0; t < size; ++t:
339                invoke (CAP_MASTER_DIRECT | WRITE, text[t])
340        void get_pos (unsigned &x, unsigned &y):
341            call (CAP_MASTER_DIRECT | GET_POS)
342            x = recv.data[0].l
343            y = recv.data[1].l
344        // Determine the size of a character.
345        void get_size (unsigned c, unsigned &width, unsigned &height, unsigned &baseline):
346            Num ret = call (CAP_MASTER_DIRECT | GET_SIZE, c)
347            width = recv.data[1].l
348            height = ret.h
349            baseline = ret.l
350        void write (unsigned num, unsigned base = 10):
351            char const *encode = "0123456789abcdef"
352            unsigned digits = 1
353            unsigned power = 1
354            while power <= num / base:
355                power *= base
356                ++digits
357            for unsigned i = 0; i < digits; ++i:
358                unsigned d = num / power
359                write (encode[d])
360                num -= d * power
361                power /= base
362        void printf (char const *f, ...):
363            unsigned *last = (unsigned *)&f
364            while *f:
365                if *f == '\r':
366                    at (0, 0, false, true)
367                else if *f == '\n':
368                    at (0, 16, false, true)
369                else if *f == '%':
370                    ++f
371                    switch *f:
372                        case '%':
373                            write ('%')
374                            break
375                        case 'd':
376                            ++last
377                            write (*last)
378                            break
379                        case 'x':
380                            ++last
381                            write (*last, 0x10)
382                            break
383                        case 's':
384                            ++last
385                            write ((char *)*last)
386                            break
387                        case 'c':
388                            ++last
389                            write ((char)*last)
390                            break
391                        default:
392                            panic (*f, "invalid code character in dbg format string")
393                else:
394                    write (*f)
395                ++f
396
303397    // Numerical setting, such as a display backlight.
304398    struct Setting : public Device:
305399        Setting (Cap c = Cap ()) : Device (c):
306400        enum request:
307            SET = Display::ID
401            SET = Font::ID
308402            GET_RANGE
309403            ID
310404        // Set a new value.
...... 
393487            call (Num (CAP_MASTER_DIRECT | EVENT, code), value)
394488        void exit ():
395489            call (CAP_MASTER_DIRECT | EXIT)
490
491    struct RTC : public Cap:
492        RTC (Cap c = Cap ()) : Cap (c):
493        enum request:
494            SETUP = UI::ID
495            GET_TIME
496            SET_TIME
497            GET_ALARM
498            UNSET_ALARM
499            SET_ALARM
500            ID
501        void setup (unsigned hz, unsigned adjc):
502            call (CAP_MASTER_DIRECT | SETUP, Num (hz, adjc))
503        unsigned get_time ():
504            return call (CAP_MASTER_DIRECT | GET_TIME).l
505        unsigned set_time (unsigned time):
506            return call (CAP_MASTER_DIRECT | SET_TIME, time).l
507        unsigned get_alarm ():
508            return call (CAP_MASTER_DIRECT | GET_ALARM).l
509        unsigned unset_alarm ():
510            return call (CAP_MASTER_DIRECT | UNSET_ALARM).l
511        unsigned set_alarm (unsigned time, Cap cb):
512            return ocall (cb, CAP_MASTER_DIRECT | SET_ALARM, time).l
396513
397514// TODO.
398515// Sound interface.
init.config
11    # driver <name> = '<filename>' load a file into memory to be run priviledged.
22    # program <name> = '<filename>' load a file into memory to be run normally.
3    # file <name> = '<filename>' load a file into memory as a String.
3    # file <name> = '<filename>' load a file into memory as a Block.
44    # receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
55    # sysreq <cap> use a capability as the system request keyboard.
66    # give <name> / <type> [, <index>] = <cap> give this capability to this program when it requests it.
...... 
2424
2525    #file kernel = "kernel.raw"
2626    #program booter = "booter.elf"
27    #give booter / String = kernel
27    #give booter / Block = kernel
2828    #give booter / Boot = boot
2929
3030    driver driver_lcd = "lcd.elf"
...... 
3434    driver driver_buzzer = "buzzer.elf"
3535    receive driver_buzzer / Buzzer = buzzer
3636
37    program alarm = "alarm.elf"
38    receive alarm / UI = ui
37    #program alarm = "alarm.elf"
38    #receive alarm / UI = ui
3939
40    program gui = "gui.elf"
41    give gui / UI = ui
42    give gui / Display = display
43    give gui / Setting = display_bright
44    give gui / Buzzer = buzzer
45    give gui / Keyboard = keyboard
40    #program gui = "gui.elf"
41    #give gui / UI = ui
42    #give gui / Display = display
43    #give gui / Setting = display_bright
44    #give gui / Buzzer = buzzer
45    #give gui / Keyboard = keyboard
4646
4747    #driver sdmmc = "sd+mmc.elf"
48    #receive sdmmc / WString = sdmmc
48    #receive sdmmc / WBlock = sdmmc
4949    #give sdmmc / Event = sdmmc_gpio
5050
5151    #program partition = "partition.elf"
52    #receive partition / WString, 0 = p0
53    #receive partition / WString, 1 = p1
54    #receive partition / WString, 2 = p2
55    #receive partition / WString, 3 = p3
56    #give partition / WString = sdmmc
52    #receive partition / WBlock, 0 = p0
53    #receive partition / WBlock, 1 = p1
54    #receive partition / WBlock, 2 = p2
55    #receive partition / WBlock, 3 = p3
56    #give partition / WBlock = sdmmc
5757
5858    #program fat = "fat.elf"
5959    #receive fat / Directory = root
60    #give fat / WString = p0
60    #give fat / WBlock = p0
6161
6262    #program test = "test.elf"
6363    #give test / Directory = root
6464
65    #driver rtc = "rtc.elf"
65    file fontfile = "font.dat"
66    program font = "font.elf"
67    receive font / Font = font
68    give font / Block = fontfile
69    #give font / Display = display
70
71    driver driver_rtc = "rtc.elf"
72    receive driver_rtc / RTC = rtc
73
74    driver alarm = "alarm.elf"
75    give alarm / Keyboard = keyboard
76    give alarm / Display = display
77    give alarm / Buzzer = buzzer
78    give alarm / Font = font
79    give alarm / RTC = rtc
80    receive alarm / Event = alarm
invoke.ccp
574574                    arch_reboot ()
575575                case Iris::Thread::PRIV_POWEROFF & REQUEST_MASK:
576576                    arch_poweroff ()
577                case Iris::Thread::PRIV_SUSPEND & REQUEST_MASK:
578                    arch_suspend ()
579                    reply_num (~0)
580                    return
577581                case Iris::Thread::PRIV_BOOT & REQUEST_MASK:
578582                    arch_boot (c->data[1].l, c->data[1].h)
579583                case Iris::Thread::PRIV_PANIC & REQUEST_MASK:
iris.hhp
323323            DBG_SEND
324324            PRIV_REBOOT
325325            PRIV_POWEROFF
326            PRIV_SUSPEND
326327            PRIV_BOOT
327328            PRIV_PANIC
328329        // These get/set_info are not arch-specific.
...... 
578579        my_thread.ocall (my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
579580    inline void unregister_interrupt (unsigned num):
580581        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
581    inline void wait_for_interrupt (unsigned num):
582        my_receiver.set_reply_protected_data (num)
582    inline unsigned wait_for_interrupt ():
583        my_receiver.set_reply_protected_data (0)
583584        Cap ().call ()
585        unsigned ret = recv.data[0].l
584586        my_receiver.set_reply_protected_data (~0)
587        return ret
585588    inline Cap get_top_memory ():
586589        my_thread.icall (CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
587590        return get_arg ()
...... 
591594        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REBOOT)
592595    inline void poweroff ():
593596        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_POWEROFF)
597    inline void suspend ():
598        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_SUSPEND)
594599    inline void boot (unsigned address, unsigned arg):
595600        my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_BOOT, Iris::Num (address, arg))
596601
...... 
668673                        ++last
669674                        kdebug ((char *)*last)
670675                        break
676                    case 'c':
677                        ++last
678                        kdebug_char (*last)
679                        break
671680                    default:
672681                        panic (*f, "invalid character in dbg format string")
673682            else:
kernel.hhp
324324void arch_register_interrupt (unsigned num, kReceiverP r)
325325void arch_reboot ()
326326void arch_poweroff ()
327void arch_suspend ()
327328void arch_boot (unsigned address, unsigned arg)
328329void arch_uncache_page (unsigned page)
329330
makefont
1#!/usr/bin/env python
2import sys
3import os
4from PIL import Image
5
6def mknum (num):
7    return ''.join ([chr ((num >> (8 * i)) & 0xff) for i in range (4)])
8
9im = Image.open (sys.argv[1])
10height = im.size[1]
11width, baseline, skip = [int (x) for x in os.path.splitext (sys.argv[1])[0].split ('-')[-1].split ('+')]
12num_glyphs = im.size[0] / width
13sys.stdout.write (mknum (skip + num_glyphs))
14size1 = (3 + width * height) * 4
15base = (num_glyphs + skip) * 4
16for i in range (skip):
17    sys.stdout.write (mknum (base + (num_glyphs - 1) * size1))
18for i in range (skip, skip + num_glyphs):
19    sys.stdout.write (mknum (base + (i - skip) * size1))
20
21im = im.convert ('RGBA')
22pix = im.load ()
23#sys.stderr.write ('%d\n' % len (pix[0,0]))
24for g in range (skip, skip + num_glyphs):
25    sys.stdout.write (mknum (width))
26    sys.stdout.write (mknum (height))
27    sys.stdout.write (mknum (baseline))
28    for y in range (height):
29        for x in range (width):
30            sys.stdout.write (''.join ([chr (x) for x in (pix[x + (g - skip) * width, y])]))
mips/arch.hhp
138138
139139// These are "extern", not "EXTERN", because they really are defined elsewhere.
140140#ifdef INIT
141extern unsigned thread_start[NUM_THREADS + 1]
141extern unsigned *thread_start
142142#endif
143143// Fast pointer to page directory, for tlb miss events
144144extern Table **directory
mips/boot.S
1919    #define ARCH
2020    #include "arch.hh"
2121
22#define MEMORY_SIZE (32 << 20)
23#define KERNEL_STACK_SIZE 0x1000
2224    // The kernel stack.
2325    .lcomm kernel_stack, KERNEL_STACK_SIZE
2426
mips/entry.S
1515// You should have received a copy of the GNU General Public License
1616// along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
18#define KERNEL_STACK_SIZE 0x1000
1819    // The kernel stack.
1920    .lcomm kernel_stack, KERNEL_STACK_SIZE
2021
mips/init.ccp
118118    first_scheduled = NULL
119119    first_alarm = NULL
120120    kReceiver *init_receiver = NULL
121    for unsigned i = 0; i < NUM_THREADS; ++i:
121    unsigned i = 0
122    while thread_start[i] != 0:
122123        kMemory *mem = top_memory.alloc_memory ()
123124        assert (mem)
124125        kThread *thread = mem->alloc_thread (NUM_SLOTS)
...... 
269270        thread->schedule_prev = previous
270271        thread->schedule_next = NULL
271272        previous = thread
273        ++i
272274
273275// Initialize the kernel, finish by falling into the idle task.
274276void init (unsigned mem):
mips/interrupts.ccp
126126            // Send message to interrupt handler.
127127            if arch_interrupt_receiver[i]:
128128                kCapability::Context c
129                for unsigned j = 0; j < 2; ++j:
130                    c.data[j] = 0
131                arch_interrupt_receiver[i]->send_message (i, &c)
129                c.data[0] = i
130                c.data[1] = 0
131                arch_interrupt_receiver[i]->send_message (0, &c)
132132                arch_interrupt_receiver[i] = NULL
133133    if ipr & (1 << TIMER_INTERRUPT):
134134        #if defined (TRENDTAC)
mips/nanonote/Makefile.arch
3131standard_boot_programs = bootinit
3232
3333# use sort to remove duplicates.
34programs = $(sort 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))
34programs = $(sort init gpio font lcd bsquare ball buzzer metronome elfrun alarm rtc gui test boot booter $(udc_boot_programs) $(sd_boot_programs) $(unbrick_boot_programs) $(standard_boot_programs))
3535
3636ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
3737CROSS = mipsel-linux-gnu-
mips/nanonote/board.ccp
8484    while true:
8585
8686void arch_poweroff ():
87    sync_serial ()
8887    // Power off.
88    // First enable interrupts, so it can be awoken.
89    // Disable all interrupts which shouldn't wake it (only an issue while powering down, really).
90    INTC_IMSR = ~0
91    intc_unmask_irq (IRQ_RTC)
92    intc_unmask_irq (IRQ_GPIO3)
93    GPIO_PXIMS (3) = ~0
94    gpio_unmask_irq (3, 29)
95    // Clear interrupt flags.
96    gpio_ack_irq (3, 29)
97    intc_ack_irq (IRQ_GPIO3)
98    intc_ack_irq (IRQ_RTC)
99    // Clear pending interrupts and enable interrupts.
100    cp0_set (CP0_STATUS, 0x1000ff01)
101
89102    // Make sure the rtc is running.
90103    cpm_start_rtc ()
91104    while !rtc_write_ready ():
92105    rtc_enabled ()
93106    while !rtc_write_ready ():
107    kdebug ("Power down.\n")
108    sync_serial ()
94109    rtc_power_down ()
95110    // Wait for power down to work.
96    while !rtc_write_ready ():
97    // Delay a bit more.
98    for unsigned i = 0; i < 1000; ++i:
99        gpio_set (0, 0)
100    // Fall back to reboot.
101    kdebug ("Power down failed! Rebooting instead.\n")
102    arch_reboot ()
111    while true:
112        asm ("wait")
113
114void arch_suspend ():
115    sync_serial ()
116    // Suspend the system: go into SLEEP mode.
117    cpm_sleep_mode ()
118    asm ("wait")
119    cpm_idle_mode ()
103120
104121// Boot into another kernel.
105122void arch_boot (unsigned address, unsigned arg):
mips/nanonote/jz4740.hhp
35323532#define rtc_disabled() ( RTC_RCR &= ~RTC_RCR_RTCE )
35333533#define rtc_enable_alarm() ( RTC_RCR |= RTC_RCR_AE )
35343534#define rtc_disable_alarm() ( RTC_RCR &= ~RTC_RCR_AE )
3535#define rtc_alarm_is_enabled() ( RTC_RCR & RTC_RCR_AE )
35353536#define rtc_enable_alarm_irq() ( RTC_RCR |= RTC_RCR_AIE )
35363537#define rtc_disable_alarm_irq() ( RTC_RCR &= ~RTC_RCR_AIE )
35373538#define rtc_enable_1Hz_irq() ( RTC_RCR |= RTC_RCR_1HZIE )
mips/nanonote/nanonote-boot.ccp
3333extern char stage1[1]
3434extern char stage1_end[1]
3535
36unsigned const stage1_load = 0x80002000
37unsigned const stage1_start = 0x80002000
36unsigned const stage1_load = 0x80003000
37unsigned const stage1_start = 0x80003000
3838unsigned const stage1_size = stage1_end - stage1
3939
4040class nanonote:
mips/nanonote/sdram-setup.ccp
3030        ".globl __start\n"
3131        ".text\n"
3232        "__start:\n"
33        "\tnop\n"
34        "__hack_label:\n"
35        "\tmove $k0, $ra\n"
36        "\tbal 1f\n"
37        "\tnop\n"
38        "\t.word _gp\n"
33        "\tmove $t0, $ra\n" // 0
34        "\tnop\n" // 4
35        "\tbal 1f\n" // 8
36        "\tnop\n" // 12
37        "\t.word _gp\n" // 16
38        "\t.word 0\n" // 20: This is overwritten in software usbboot mode.
3939        "1:\n"
4040        "\tlw $gp, 0($ra)\n"
41        "\tla $sp, stack + 0x100\n"
41        "\tlb $a0, 4($ra)\n"
42        "\tla $sp, stack + 0x40\n"
4243        "\tla $t9, start_cpp\n"
43        "\tmove $ra, $k0\n"
44        "\tmove $ra, $t0\n"
4445        "\tjr $t9\n"
4546        "\tnop\n"
4647        ".set reorder")
...... 
5354    while !(UART0_LSR & UARTLSR_TEMT):
5455
5556extern "C":
56    void start_cpp ()
57    char stack[0x100]
57    void start_cpp (int skip_memsetup)
58    char stack[0x40]
5859
59void start_cpp ():
60void start_cpp (int skip_memsetup):
6061    setup_uart ()
6162    kdebug ('.')
62    setup_sdram ()
63    if !skip_memsetup:
64        setup_sdram ()
6365    kdebug ('!')
6466    // everything is ok now: return to boot loader to load stage 2.
mips/nanonote/sdram-setup.ld
22ENTRY(__start)
33MEMORY
44{
5    ram : ORIGIN = 0x80002000 , LENGTH = 0x2000
5    ram : ORIGIN = 0x80003000 , LENGTH = 0x800
66}
77
88SECTIONS
mips/nanonote/server/usb-server.ccp
4848        server->open (port)
4949
5050    private:
51    static unsigned const STAGE1_LOAD = 0x80002000
51    static unsigned const STAGE1_LOAD = 0x80003000
5252    static unsigned const STAGE1_ENTRY = STAGE1_LOAD
5353    enum requests:
5454        VR_GET_CPU_INFO = 0
...... 
245245            handle = NULL
246246            return
247247        ptr += ret
248    std::cerr << shevek::ostring ("sent %d bytes\n", size)
248249
249250void data::get_device (unsigned vendor, unsigned product, unsigned tries):
250251    for unsigned i = 0; i < tries; ++i:
...... 
314315
315316static void dump_devices ():
316317    std::cerr << std::hex << "String: " << Iris::String::ID
318    std::cerr << "\nBlock: " << Iris::Block::ID
317319    std::cerr << "\nWString: " << Iris::WString::ID
320    std::cerr << "\nWBlock: " << Iris::WBlock::ID
321    std::cerr << "\nBoot: " << Iris::Boot::ID
318322    std::cerr << "\nDevice: " << Iris::Device::ID
323    std::cerr << "\nEvent: " << Iris::Event::ID
324    std::cerr << "\nElfrun: " << Iris::Elfrun::ID
319325    std::cerr << "\nParent: " << Iris::Parent::ID
320326    std::cerr << "\nKeyboard: " << Iris::Keyboard::ID
321327    std::cerr << "\nBuzzer: " << Iris::Buzzer::ID
322328    std::cerr << "\nDisplay: " << Iris::Display::ID
329    std::cerr << "\nFont: " << Iris::Display::ID
323330    std::cerr << "\nSetting: " << Iris::Setting::ID
324331    std::cerr << "\nDirectory: " << Iris::Directory::ID
325332    std::cerr << "\nWDirectory: " << Iris::WDirectory::ID
326333    std::cerr << "\nStream: " << Iris::Stream::ID
334    std::cerr << "\nUI: " << Iris::UI::ID
327335    std::cerr << "\n"
328336
329337int main (int argc, char **argv):
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/sd+mmc.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
3535static int const run_product = 0x0002
3636static unsigned const timeout = 10000
3737void boot (std::string const &filename, unsigned load, unsigned entry)
38static unsigned const STAGE1_LOAD = 0x80002000
38static unsigned const STAGE1_LOAD = 0x80003000
3939static unsigned const STAGE1_ENTRY = STAGE1_LOAD
4040enum requests:
4141    VR_GET_CPU_INFO = 0
mkthreadlist
1#!/bin/sh
2cat << EOF
3    .globl init_start
4    .globl thread_start
5    .set noreorder
6    .balign 0x1000
7EOF
8
9for i in "$@" ; do
10    cat << EOF
11$i:
12    .incbin "fs/$i.elf"
13    .balign 0x1000
14EOF
15done
16
17cat << EOF
18end_threads:
19init_start:
20thread_start:
21EOF
22
23for i in "$@" ; do
24    cat << EOF
25    .word $i
26EOF
27done
28
29cat << EOF
30    .word 0
31EOF
source/alarm.ccp
11#pypp 0
22#include <iris.hh>
3#include <ui.hh>
3#include <devices.hh>
44
5enum Ins:
6    TOTAL_TIME
7    START
8    NUM_INS
9
10enum Outs:
11    CURRENT_TIME
12    ALARM
13    NUM_OUTS
14
15typedef UI <NUM_INS, NUM_OUTS> ui_t
16static ui_t ui
17static ui_t::in <unsigned> total_time
18static ui_t::in_event do_start
19static ui_t::out <unsigned> current_time
20static ui_t::out_event do_alarm
21
22static bool ticking
23
24static void event (unsigned code):
25    switch code:
26        case TOTAL_TIME:
27            break
28        case START:
29            current_time = total_time
30            if !ticking:
31                if !current_time:
32                    do_alarm ()
33                else:
34                    ticking = true
35                    Iris::my_receiver.set_alarm (HZ)
36            break
37        default:
38            Iris::panic (0, "invalid event for alarm clock")
5enum captypes:
6    CONTROL = 1
7    KBD
8    INTERRUPT
399
4010Iris::Num start ():
41    ticking = false;
42    Iris::Cap ui_cap = Iris::my_receiver.create_capability (0)
43    ui.init (ui_cap.copy ());
44    Iris::free_cap (ui_cap)
45    total_time.init ()
46    do_start.init ()
47    current_time.init ()
48    do_alarm.init ()
49    ui.add_in (&total_time, TOTAL_TIME);
50    ui.add_in (&do_start, START);
51    ui.add_out (&current_time, CURRENT_TIME);
52    ui.add_out (&do_alarm, ALARM);
11    unsigned *screen = (unsigned *)0x40000000
12    Iris::RTC rtc = Iris::my_parent.get_capability <Iris::RTC> ()
13    Iris::Display display = Iris::my_parent.get_capability <Iris::Display> ()
14    display.map_fb ((unsigned)screen)
15    Iris::Font font = Iris::my_parent.get_capability <Iris::Font> ()
16    font.set_display (display)
17    Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> ()
18    Iris::Cap cap = Iris::my_receiver.create_capability (KBD)
19    keyboard.set_cb (cap.copy ())
20    Iris::free_cap (cap)
21    Iris::Buzzer buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
22    Iris::Event self = Iris::my_receiver.create_capability (CONTROL)
23    Iris::my_parent.provide_capability <Iris::Event> (self)
24    cap = Iris::my_receiver.create_capability (INTERRUPT)
5325    Iris::my_parent.init_done ()
54
5526    while true:
5627        Iris::wait ()
5728        switch Iris::recv.protected_data.l:
58            case ~0:
59                // alarm.
60                if current_time:
61                    current_time = current_time - 1
62                if !current_time:
63                    do_alarm ()
64                    ticking = false
65                else:
66                    // TODO: use rtc for scheduling an event.
67                    Iris::my_receiver.set_alarm (HZ)
68                continue
69            case 0:
70                // ui event.
71                if !ui.event (&event):
72                    // Exit request.
73                    return 0
29            case INTERRUPT:
30                // Interrupt
31                if Iris::recv.data[0].l == ~0:
32                    // Not a real interrupt, just an abort notification.
33                    continue
34                font.printf ("alarm: interrupt\n")
35                break
36            case CONTROL:
37                // Store callback
38                font.printf ("alarm: control event\n")
39                break
40            case KBD:
41                // Key press
42                unsigned time = rtc.get_time ()
43                unsigned alarm = rtc.get_alarm ()
44                unsigned enabled = Iris::recv.data[1].l
45                font.printf ("%d %d %d", time, alarm, enabled)
46                rtc.set_alarm (time + 10, cap)
47                Iris::poweroff ()
48                break
49            default:
50                Iris::panic (Iris::recv.protected_data.l, "invalid request for alarm")
source/bootinit.ccp
320320    Iris::Memory top_memory = Iris::get_top_memory ()
321321    Iris::Directory root = receive_devices ()
322322    root.lock_ro ()
323    kdebug_line ()
323324    Iris::Block run_block = find (root, ELFRUN_NAME)
325    kdebug_line ()
324326    Iris::Cap parent_cap = Iris::my_receiver.create_capability (0)
327    kdebug_line ()
325328    run (run_block, top_memory, parent_cap)
329    kdebug_line ()
326330    Iris::wait ()
331    kdebug_line ()
327332    if Iris::recv.data[0].l != Iris::Parent::PROVIDE_CAPABILITY || Iris::recv.data[1].l != Iris::Elfrun::ID:
328333        Iris::panic (0, "elfrun doesn't provide correct capability")
329334    Iris::Cap reply = Iris::get_reply ()
source/font.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// source/font.ccp: Font manager.
4// Copyright 2012 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 "devices.hh"
20
21#define screenw 320
22#define screenh 240
23
24struct Glyph:
25    unsigned width, height, baseline
26    unsigned data[1]
27
28static Iris::Display display
29static Iris::Caps caps, display_caps
30static unsigned slot, num_glyphs
31static unsigned long pages, base
32static Glyph **glyphs
33static char *fb
34static unsigned x, y
35
36static unsigned read_int (unsigned addr):
37    return *reinterpret_cast <unsigned *> (addr)
38
39static void load_font (Iris::Block font):
40    unsigned long long size = font.get_size ().value ()
41    pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
42    caps = Iris::my_memory.create_caps (pages)
43    slot = caps.use ()
44    for unsigned i = 0; i < size; i += PAGE_SIZE:
45        Iris::Page page = Iris::Cap (slot, i >> PAGE_BITS)
46        Iris::set_recv_arg (page)
47        font.get_block (i)
48        Iris::my_memory.map (page, base + i)
49    num_glyphs = read_int (base)
50    glyphs = reinterpret_cast <Glyph **> (base + sizeof (int))
51    for unsigned i = 0; i < num_glyphs; ++i:
52        glyphs[i] = reinterpret_cast <Glyph *> (base + sizeof (int) + read_int (base + sizeof (int) + i * sizeof (int)))
53
54static void free_font ():
55    for unsigned i = 0; i < pages; ++i:
56        Iris::my_memory.destroy (Iris::Cap (slot, i))
57    Iris::my_memory.destroy (caps)
58    Iris::free_slot (slot)
59
60static unsigned draw_char (char c, unsigned &w, unsigned &h):
61    if c >= num_glyphs:
62        c = num_glyphs - 1
63    Glyph *g = glyphs[c]
64    w = g->width
65    h = g->height
66    for unsigned ty = 0; ty < h; ++ty:
67        unsigned py = ty + y - g->baseline
68        if py < 0 || py >= screenh:
69            continue
70        for unsigned tx = 0; tx < g->width; ++tx:
71            unsigned px = tx + x
72            if px < 0 || px >= screenw:
73                continue
74            unsigned p = g->data[ty * g->width + tx]
75            unsigned red = unsigned (p) & 0xff
76            unsigned green = unsigned (p >> 8) & 0xff
77            unsigned blue = unsigned (p >> 16) & 0xff
78            unsigned alpha = (unsigned (p >> 24) & 0xff) + 1
79            if alpha == 0x100:
80                fb[(py * 320 + px) * 4 + 2] = red
81                fb[(py * 320 + px) * 4 + 1] = green
82                fb[(py * 320 + px) * 4 + 0] = blue
83            else:
84                unsigned unalpha = 256 - alpha
85                fb[(py * 320 + px) * 4 + 2] = (fb[(py * 320 + px) * 4 + 2] * unalpha + red * alpha) >> 8
86                fb[(py * 320 + px) * 4 + 1] = (fb[(py * 320 + px) * 4 + 1] * unalpha + green * alpha) >> 8
87                fb[(py * 320 + px) * 4 + 0] = (fb[(py * 320 + px) * 4 + 0] * unalpha + blue * alpha) >> 8
88    return g->baseline
89
90static void get_size (char c, unsigned &w, unsigned &h, unsigned &b):
91    if c >= num_glyphs:
92        c = num_glyphs - 1
93    Glyph *g = glyphs[c]
94    w = g->width
95    h = g->height
96    b = g->baseline
97
98Iris::Num start ():
99    x = 0
100    y = 8
101    // Random address which is large enough to store a huge file.
102    base = 0x40000000
103    fb = reinterpret_cast <char *> (0x20000000)
104    Iris::Font self = Iris::my_receiver.create_capability (0)
105    Iris::my_parent.provide_capability <Iris::Font> (self.copy ())
106    Iris::free_cap (self)
107    //display = Iris::my_parent.get_capability <Iris::Display> ()
108    Iris::Block font = Iris::my_parent.get_capability <Iris::Block> ()
109    load_font (font)
110    Iris::free_cap (font)
111    Iris::my_parent.init_done ()
112    //display_caps = display.map_fb (reinterpret_cast <unsigned> (fb))
113    bool have_display = false
114    while true:
115        Iris::wait ()
116        switch Iris::recv.data[0].l:
117            case Iris::Font::SET_DISPLAY:
118                Iris::Cap reply = Iris::get_reply ()
119                if have_display:
120                    Iris::free_cap (display)
121                have_display = true
122                display = Iris::get_arg ()
123                display_caps = display.map_fb (reinterpret_cast <unsigned> (fb))
124                reply.invoke ()
125                Iris::free_cap (reply)
126                break
127            case Iris::Font::LOAD_FONT:
128                free_font ()
129                font = Iris::get_arg ()
130                load_font (font)
131                Iris::free_cap (font)
132                Iris::recv.reply.invoke ()
133                break
134            case Iris::Font::SETUP:
135                // TODO: interface needs to be defined.
136                Iris::recv.reply.invoke ()
137                break
138            case Iris::Font::AT:
139                if Iris::recv.data[0].h & 1:
140                    x += Iris::recv.data[1].l
141                    if x > screenw:
142                        x = 0
143                        y += 16
144                        if y + 16 > screenh + 8:
145                            y = 8
146                else:
147                    x = Iris::recv.data[1].l
148                if Iris::recv.data[0].h & 2:
149                    y += Iris::recv.data[1].h
150                    if y + 16 > screenh + 8:
151                        y = 8
152                else:
153                    y = Iris::recv.data[1].h
154                Iris::recv.reply.invoke ()
155                break
156            case Iris::Font::WRITE:
157                Iris::Cap reply = Iris::get_reply ()
158                unsigned w, h
159                unsigned b = draw_char (Iris::recv.data[1].l, w, h)
160                x += w
161                if x + w > screenw:
162                    x = 0
163                    y += h
164                    if y + h > screenh + b:
165                        y = b
166                reply.invoke ()
167                Iris::free_cap (reply)
168                break
169            case Iris::Font::GET_POS:
170                Iris::recv.reply.invoke (x, y)
171                break
172            case Iris::Font::GET_SIZE:
173                unsigned w, h, b
174                get_size (Iris::recv.data[1].l, w, h, b)
175                Iris::recv.reply.invoke (Iris::Num (b, h), w)
176                break
177            default:
178                Iris::panic (0, "invalid operation type for lcd")
179                break
source/init.ccp
295295    { "Keyboard", 8, Iris::Keyboard::ID },
296296    { "Buzzer", 6, Iris::Buzzer::ID },
297297    { "Display", 7, Iris::Display::ID },
298    { "Font", 4, Iris::Font::ID },
298299    { "Setting", 7, Iris::Setting::ID },
299300    { "Directory", 9, Iris::Directory::ID },
300301    { "WDirectory", 10, Iris::WDirectory::ID },
301302    { "Stream", 6, Iris::Stream::ID },
302303    { "UI", 2, Iris::UI::ID },
304    { "RTC", 3, Iris::RTC::ID },
303305    { NULL, 0, 0 }
304306    }
305307
...... 
514516        switch Iris::recv.protected_data.l:
515517            case SYSREQ:
516518                if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
517                    Iris::poweroff ()
519                    Iris::reboot ()
518520                    continue
519                kdebug ("sysreq event: powering device off at release\n")
521                kdebug ("sysreq event: rebooting device at release\n")
520522                continue
521523            case FILE:
522524                File *file = (File *)Iris::recv.protected_data.h
...... 
563565                            if (*d)->type == type && (*d)->index == index:
564566                                break
565567                        if !d:
568                            Iris::debug ("requested %x by %s\n", type, caller->name)
566569                            Iris::panic (type, "unregistered device requested")
567570                        Iris::recv.reply.invoke (0, 0, (*d)->dev->cap)
568571                        //kdebug ("given device ")
source/lcd.ccp
244244    log_char ('\n')
245245
246246enum captype:
247    LOG = 32
247    LOG = 1
248248    BACKLIGHT
249249    LCD
250250
...... 
359359        Iris::wait ()
360360        //log_msg ()
361361        switch Iris::recv.protected_data.l:
362            case IRQ_LCD:
362            case 0:
363363                have_eof = false
364364                eof_cb.invoke ()
365365                Iris::free_cap (eof_cb)
source/nanonote-gpio.ccp
2121#include "arch.hh"
2222#include "keys.hh"
2323
24//#define QI
24#define QI
2525#define SCAN_INTERVAL HZ / 50
2626
2727class DevKbd:
...... 
128128    { Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I },
129129    { Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K },
130130    { Key::ESCAPE, Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M },
131    { Key::TAB, Key::CAPS, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP },
132    { Key::O, Key::L, Key::EQUAL, Key::ARROW, Key::SPACE, Key::QI, Key::CTRL, Key::LEFT },
131    { Key::TAB, Key::CAPS_LOCK, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP },
132    { Key::O, Key::L, Key::EQUALS, Key::SPECIAL + 0, Key::SPACE, Key::RIGHT_LOGO, Key::RIGHT_CONTROL, Key::LEFT },
133133    { Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT },
134    { Key::SHIFT, Key::ALT, Key::FN, ~0, ~0, ~0, ~0, ~0 }
134    { Key::LEFT_SHIFT, Key::LEFT_ALT, Key::FN, ~0, ~0, ~0, ~0, ~0 }
135135    #else
136136    { Key::ESCAPE, Key::TAB, Key::F1, Key::F2, Key::F3, Key::F4, Key::SPECIAL + 0, ~0 },
137137    { Key::N1, Key::N2, Key::N3, Key::N4, Key::N5, Key::N6, Key::N7, Key::N8 },
...... 
149149    Key::Q, Key::W, Key::E, Key::R, Key::T, Key::Y, Key::U, Key::I,
150150    Key::A, Key::S, Key::D, Key::F, Key::G, Key::H, Key::J, Key::K,
151151    Key::ESCAPE, Key::Z, Key::X, Key::C, Key::V, Key::B, Key::N, Key::M,
152    Key::TAB, Key::CAPS, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP,
153    Key::O, Key::L, Key::EQUAL, Key::ARROW, Key::SPACE, Key::QI, Key::CTRL, Key::LEFT,
152    Key::TAB, Key::CAPS_LOCK, Key::BACKSLASH, Key::QUOTE, Key::COMMA, Key::PERIOD, Key::SLASH, Key::UP,
153    Key::O, Key::L, Key::EQUALS, Key::SPECIAL + 0, Key::SPACE, Key::RIGHT_LOGO, Key::RIGHT_CONTROL, Key::LEFT,
154154    Key::F8, Key::P, Key::BACKSPACE, Key::ENTER, Key::VOLUME_UP, Key::VOLUME_DOWN, Key::DOWN, Key::RIGHT,
155    Key::SHIFT, Key::ALT, Key::FN
155    Key::LEFT_SHIFT, Key::LEFT_ALT, Key::FN
156156    #else
157157    Key::ESCAPE, Key::TAB, Key::F1, Key::F2, Key::F3, Key::F4, Key::SPECIAL + 0,
158158    Key::N1, Key::N2, Key::N3, Key::N4, Key::N5, Key::N6, Key::N7, Key::N8,
...... 
195195        scan ()
196196
197197enum codes:
198    KBD_DEV = 32
198    KBD_DEV = 1
199199    PWR
200200    SDMMC
201201
...... 
228228                Iris::my_receiver.set_alarm (SCAN_INTERVAL)
229229            continue
230230        switch Iris::recv.protected_data.l:
231            case IRQ_GPIO3:
231            case 0:
232232                // Interrupt.
233233                pwr.scan ()
234234                kbd.scan ()
source/rtc.ccp
2020#define ARCH
2121#include "arch.hh"
2222
23static Iris::Font font
24
2325static void ready ():
2426    while !rtc_write_ready ():
2527        Iris::schedule ()
...... 
4244    cpm_start_rtc ()
4345    ready ()
4446    rtc_enabled ()
47    if rtc_get_scratch_pattern () != 0xbeefface:
48        ready ()
49        rtc_set_nc1Hz_val (RTC_CLOCK)
50        ready ()
51        rtc_set_adjc_val (0)
52        ready ()
53        rtc_set_second (0)
54    ready ()
55    rtc_disable_1Hz_irq ()
4556    ready ()
46    rtc_set_nc1Hz_val (RTC_CLOCK)
57    rtc_disable_alarm ()
4758    ready ()
48    rtc_enable_1Hz_irq ()
4959    rtc_clear_alarm_flag ()
60    ready ()
61    rtc_enable_alarm_irq ()
62    ready ()
5063    rtc_set_hwfcr_val (0)
64    ready ()
65    rtc_set_hrcr_val (0)
66    ready ()
67    rtc_enable_alarm_wakeup ()
68    ready ()
69    rtc_set_scratch_pattern (0xbeefface)
70    Iris::RTC self = Iris::my_receiver.create_capability (1)
71    Iris::my_parent.provide_capability <Iris::RTC> (self.copy ())
72    Iris::free_cap (self)
73    Iris::my_parent.init_done ()
74    bool have_interrupt = false
75    Iris::Cap interrupt
5176    while true:
52        ready ()
53        rtc_clear_1Hz_flag ()
54        ready ()
55        Iris::register_interrupt (IRQ_RTC)
5677        Iris::wait ()
57        kdebug ("tick\n")
78        if Iris::recv.protected_data.l == 0:
79            // Interrupt.
80            ready ()
81            rtc_disable_alarm ()
82            if have_interrupt:
83                interrupt.invoke (0)
84                Iris::free_cap (interrupt)
85                have_interrupt = false
86            continue
87        switch Iris::recv.data[0].l:
88            case Iris::RTC::SETUP:
89                ready ()
90                rtc_set_nc1Hz_val (Iris::recv.data[1].l)
91                ready ()
92                rtc_set_adjc_val (Iris::recv.data[1].h)
93                Iris::recv.reply.invoke ()
94                break
95            case Iris::RTC::GET_TIME:
96                ready ()
97                Iris::recv.reply.invoke (rtc_get_second ())
98                Iris::recv.reply.invoke (0)
99                break
100            case Iris::RTC::SET_TIME:
101                ready ()
102                rtc_set_second (Iris::recv.data[1].l)
103                Iris::recv.reply.invoke ()
104                break
105            case Iris::RTC::GET_ALARM:
106                ready ()
107                Iris::recv.reply.invoke (rtc_get_alarm_second (), rtc_alarm_is_enabled ())
108                Iris::recv.reply.invoke (0)
109                break
110            case Iris::RTC::UNSET_ALARM:
111                Iris::Cap reply = Iris::get_reply ()
112                if have_interrupt:
113                    have_interrupt = false
114                    interrupt.invoke (~0)
115                    Iris::free_cap (interrupt)
116                    Iris::unregister_interrupt (IRQ_RTC)
117                ready ()
118                rtc_disable_alarm ()
119                reply.invoke ()
120                Iris::free_cap (reply)
121            case Iris::RTC::SET_ALARM:
122                Iris::Cap reply = Iris::get_reply ()
123                Iris::Cap arg = Iris::get_arg ()
124                unsigned alarm = Iris::recv.data[1].l
125                ready ()
126                rtc_clear_alarm_flag ()
127                if have_interrupt:
128                    Iris::debug ("not registering irq\n")
129                    interrupt.invoke (~0)
130                    Iris::free_cap (interrupt)
131                else:
132                    Iris::debug ("registering irq\n")
133                    Iris::register_interrupt (IRQ_RTC)
134                interrupt = arg
135                have_interrupt = true
136                ready ()
137                rtc_set_alarm_second (alarm)
138                ready ()
139                rtc_clear_alarm_flag ()
140                ready ()
141                rtc_enable_alarm ()
142                reply.invoke ()
143                Iris::free_cap (reply)
144                break
145            default:
146                Iris::panic (Iris::recv.data[0].l, "invalid rtc request")
58147    return 0
source/sd+mmc.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// source/sd+mmc.ccp: sd+mmc driver.
4// Copyright 2009 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 "devices.hh"
20#define ARCH
21#include "arch.hh"
22
23class Mmc:
24    public:
25    enum Response_type:
26        NONE = MSC_CMDAT_RESPONSE_NONE
27        RD_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_READ
28        WR_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE
29        R1 = MSC_CMDAT_RESPONSE_R1
30        R1B = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_BUSY
31        R2 = MSC_CMDAT_RESPONSE_R2
32        R3 = MSC_CMDAT_RESPONSE_R3
33        R4 = MSC_CMDAT_RESPONSE_R4
34        R5 = MSC_CMDAT_RESPONSE_R5
35        R6 = MSC_CMDAT_RESPONSE_R6
36        R7 = MSC_CMDAT_RESPONSE_R7
37    static unsigned const POWER_PORT = 3
38    static unsigned const POWER_PIN = 2
39    struct CID:
40        unsigned mid
41        char oid[2]
42        char pnm[5]
43        unsigned prv
44        unsigned psn
45        unsigned year
46        unsigned month
47    struct CSD:
48        unsigned c_size
49        unsigned c_size_mult
50        unsigned read_bl_len, write_bl_len
51        bool copy
52        bool perm_write_protect
53        bool tmp_write_protect
54    bool send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response = NULL)
55    void check_sd ()
56    void check_sdmem ()
57    void check_mmc ()
58    public:
59    void reset ()
60    void detect ()
61    void release ()
62    void interrupt ()
63    CID const &get_cid ():
64        return cid
65    unsigned get_num_blocks ():
66        return num_blocks
67    unsigned get_read_block_size ():
68        return read_block_size
69    unsigned get_block_bits ():
70        return hc ? 9 : csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len
71    void write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
72    void read_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
73    void wait_write ()
74    void add_cb (Iris::Listitem item):
75        cb_list.add_item (item)
76    private:
77    void set_block (unsigned block)
78    unsigned current_block_num
79    bool dirty
80    unsigned *current_block
81    unsigned rca
82    bool have_sdmem, have_io
83    bool hc
84    CID cid
85    CSD csd
86    unsigned num_blocks, read_block_size
87    Iris::Page buffer_page
88    Iris::List cb_list
89    static unsigned const buffer = 0x15000
90
91bool Mmc::send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response):
92    MSC_CMD = cmd
93    MSC_ARG = arg
94    MSC_CMDAT = response_type
95    MSC_IMASK = ~MSC_IMASK_END_CMD_RES
96    Iris::register_interrupt (IRQ_MSC)
97    msc_start_op ()
98    Iris::wait_for_interrupt (IRQ_MSC)
99    MSC_IMASK = ~0
100    //kdebug ("cmd: ")
101    //kdebug_num (cmd)
102    unsigned stat = MSC_STAT
103    //kdebug (", stat: ")
104    //kdebug_num (stat)
105    //kdebug ("\n")
106    if stat & MSC_STAT_CRC_RES_ERR:
107        Iris::panic (0, "crc error in mmc response")
108        return false
109    if stat & MSC_STAT_TIME_OUT_RES:
110        kdebug ("time out waiting for mmc response\n")
111        MSC_IREG = MSC_IREG_END_CMD_RES
112        return false
113    if response_type == R2:
114        unsigned d = MSC_RES
115        if d >> 8 != 0x3f:
116            Iris::panic (d, "invalid r2 response")
117        if cmd == 3:
118            // Read out result.
119            cid.mid = d & 0xff
120            d = MSC_RES
121            cid.oid[0] = d >> 8
122            cid.oid[1] = d & 0xff
123            d = MSC_RES
124            cid.pnm[0] = d >> 8
125            cid.pnm[1] = d & 0xff
126            d = MSC_RES
127            cid.pnm[2] = d >> 8
128            cid.pnm[3] = d & 0xff
129            d = MSC_RES
130            cid.pnm[4] = d >> 8
131            cid.prv = d & 0xff
132            d = MSC_RES
133            cid.psn = d << 16
134            d = MSC_RES
135            cid.psn |= d
136            d = MSC_RES
137            cid.year = 2000 + (d >> 4 & 0xff)
138            cid.month = d & 0xf
139            #if 1
140            Iris::debug ("CID: mid=%x, oid=%x %x, pnm=%x %x %x %x %x, prv=%x, psn=%x, year=%x, month=%x\n", cid.mid, cid.oid[0], cid.oid[1], cid.pnm[0], cid.pnm[1], cid.pnm[2], cid.pnm[3], cid.pnm[4], cid.prv, cid.psn, cid.year, cid.month)
141            #endif
142        else:
143            // Header (8) 1.0 1.0
144            // Read out csd.
145            // Ignore csd_structure. 2 (+ 6) 1.0 2.0 ***
146            d = MSC_RES
147            // Ignore taac and nsac. 8 + 8 2.0 4.0 ***
148            d = MSC_RES
149            // Ignore tran_speed, ccc. 8 + 8/12 2.0 6.0 ***
150            d = MSC_RES
151            // Ignore rest of ccc. 4/12 0.4 6.4
152            // 4 0.4 7.0
153            csd.read_bl_len = (d >> 8) & 0xf
154            // Ignore read_bl_partial, write_blk_misalign, read_blk_misalign, dsr_imp. 1 + 1 + 1 + 1 (+ 2) 0.6 7.6
155            // 2/12 0.2 8.0 ***
156            csd.c_size = (d & 0x0003) << 10
157            d = MSC_RES
158            // 10/12 1.2 9.2
159            csd.c_size |= d >> 6
160            // Ignore vdd_r_cur_min, vdd_r_cur_max. 3 + 3 0.6 10.0 ***
161            d = MSC_RES
162            // Ignore vdd_w_cur_min, vdd_w_cur_max. 3 + 3 0.6 10.6
163            // 3 0.3 11.1
164            csd.c_size_mult = (d >> 7) & 0x7
165            // Ignore erase_blk_enable, sector_size. 1 + 6/7 0.7 12.0 ***
166            d = MSC_RES
167            // Ignore rest of sector_size, wp_grp_size, wp_grp_enable, r2w_factor. 1/7 + 7 + 1 (+ 2) + 3 1.6 13.6
168            // 2/4 0.4 14.0 ***
169            csd.write_bl_len = (d << 2) & 0xc
170            d = MSC_RES
171            // 2/4 0.2 14.2
172            csd.write_bl_len |= (d >> 14) & 0x3
173            // Ignore write_bl_partial, file_format_grp. 1 (+ 5) + 1 0.7 15.1
174            // 1 0.1 15.2
175            csd.copy = d & 0x40
176            // 1 0.1 15.3
177            csd.perm_write_protect = d & 0x20
178            // 1 0.1 15.4
179            csd.tmp_write_protect = d & 0x10
180            // Ignore file_format. 2 (+ 2) 0.4 16.0 ***
181            read_block_size = hc ? 512 : 1 << csd.read_bl_len
182            num_blocks = (csd.c_size + 1) << (csd.c_size_mult + 2)
183            if hc:
184                if csd.read_bl_len < 9:
185                    num_blocks >>= 9 - csd.read_bl_len
186                else:
187                    num_blocks <<= csd.read_bl_len - 9
188            #if 1
189            Iris::debug ("CSD: size=%x<<%x, r/w len=%x/%x, %s, %s, %s\n", csd.c_size, csd.c_size_mult, csd.read_bl_len, csd.write_bl_len, csd.copy ? "copy" : "no copy", csd.perm_write_protect ? "fixed write protect" : "no fixed write protect", csd.tmp_write_protect ? "write protect" : "no write protect")
190            #endif
191        unsigned c_size
192        unsigned c_size_mult
193        unsigned read_bl_len, write_bl_len
194        bool copy
195        bool perm_write_protect
196        bool tmp_write_protect
197    else if response_type != NONE:
198        unsigned r = MSC_RES
199        if response_type == R3:
200            if r >> 8 != 0x3f:
201                Iris::panic (r, "r3 response was not 3f")
202        else if r >> 8 != cmd:
203            kdebug ("stat: ")
204            kdebug_num (MSC_STAT)
205            kdebug ("; response: ")
206            kdebug_num (r)
207            kdebug ("; cmd: ")
208            kdebug_num (cmd)
209            Iris::panic (r, "response doesn't match command")
210        r <<= 24
211        r |= MSC_RES << 8
212        r |= MSC_RES & 0xff
213        if response:
214            *response = r
215    else:
216    //kdebug ("extra response fifo read: ")
217    //for unsigned i = 0; i < 9; ++i:
218        //kdebug (" ")
219        //kdebug_num (MSC_RES, 4)
220    //kdebug ("\n")
221    MSC_IREG = MSC_IREG_END_CMD_RES
222    return true
223
224void Mmc::reset ():
225    current_block_num = ~0
226    dirty = false
227    cb_list = Iris::my_memory.create_list ()
228    current_block = (unsigned *)(buffer + PAGE_SIZE)
229    // Create a buffer to use for data transfer.
230    buffer_page = Iris::my_memory.create_page ()
231    Iris::my_memory.map (buffer_page, buffer)
232    // Reset all state, by faking a release event.
233    release ()
234    // Enable 25 MHz clock to msc.
235    CPM_MSCCDR = 13
236    cpm_start_msc ()
237    // Enable msc pins.
238    gpio_as_msc ()
239    // Disable power to card.
240    gpio_as_gpio (POWER_PORT, 1 << POWER_PIN)
241    gpio_as_output (POWER_PORT, 1 << POWER_PIN)
242    gpio_disable_pull (POWER_PORT, 1 << POWER_PIN)
243    gpio_set (POWER_PORT, 1 << POWER_PIN)
244
245    // Stop the clock.
246    MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP
247    while MSC_STAT & MSC_STAT_CLK_EN:
248        //kdebug (",")
249        Iris::sleep (1)
250
251    // Reset controller and inserted devices.
252    MSC_STRPCL = MSC_STRPCL_RESET
253    while MSC_STAT & MSC_STAT_IS_RESETTING:
254        //kdebug (":")
255        Iris::sleep (1)
256
257    // Initialize registers.
258    MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_1
259    MSC_RESTO = 64
260    MSC_RDTO = ~0
261    MSC_BLKLEN = 0x200
262    MSC_NOB = 0
263    MSC_IREG = ~0
264    MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_RXFIFO_RD_REQ)
265    MSC_ARG = 0
266
267    // Start the clock.
268    MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START
269    // Set cards, if any, to idle.
270    send (0, 0, NONE)
271
272    // Reset SDIO device, if any. Don't do this, because it breaks for some reason.
273    //send (52, 0x88000c08, R5)
274
275void Mmc::check_mmc ():
276    //kdebug ("checking mmc\n")
277    // 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000).
278    // 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9.
279    // 3. IF THE INITIALIZATION HAS FINISHED, GO TO 5. (THE RESPONSE IS THE OCR REGISTER AND IT INCLUDES A STATUS INFORMATION BIT (BIT [31]). THIS STATUS BIT IS SET IF THE CARD POWER UP PROCEDURE HAS BEEN FINISHED. AS LONG AS THE CARD IS BUSY, THE CORRESPONDING BIT[31] IS SET TO LOW.)
280    // 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
281    // 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
282    // 6. If the response timeout occurs, goto 9.
283    // 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
284
285void Mmc::check_sdmem ():
286    kdebug ("checking sdmem\n")
287    // 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55.
288    // 3. If the response is correct (CMD55 has response), then continue, else go to check MMC.
289    unsigned code
290    hc = false
291    if send (8, 0x1aa, R7, &code) && (code & 0xff) == 0xaa:
292        kdebug ("hc\n")
293        hc = true
294    if !send (55, 0, R1, &code):
295        check_mmc ()
296        return
297    // 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
298    if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
299        check_mmc ()
300        return
301    // 5. If the initialization has finished, go to 7. (The response is the OCR register and it includes a status information bit (bit [31]). This status bit is set if the card power up procedure has been finished. As long as the card is busy, the corresponding bit[31] is set to LOW.)
302    // 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5.
303    unsigned retries = 100
304    while !(code & (1 << 31)) && --retries:
305        if !send (55, 0, R1, &code):
306            return
307        if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
308            return
309        Iris::sleep (1)
310    if !(code & (1 << 31)):
311        Iris::panic (code, "card fails to finish setting up")
312    // 7. Send CMD2 (ALL_SEND_CID) to get the card CID.
313    if !send (2, 0, R2):
314        Iris::panic (0, "card failed to send CID")
315    // 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response.
316    // 9. If do not accept the new RCA, go to 8, else record the new RCA.
317    rca = 0
318    while !rca:
319        if !send (3, 0, R6, &rca):
320            Iris::panic (0, "card failed to provide rca")
321        rca &= 0xffff0000
322    kdebug ("received rca ")
323    kdebug_num (rca >> 16, 4)
324    kdebug ("\n")
325    have_sdmem = true
326
327void Mmc::check_sd ():
328    //kdebug ("checking sdio\n")
329    if !send (0, 0, NONE):
330        Iris::panic (0, "unable to reset cards?")
331    // 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
332    // 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
333    unsigned code
334    if !send (5, 1 << 20, R4, &code) || !(code & (7 << 28)):
335        check_sdmem ()
336        return
337    // 4. If C-bit in the response is ready (the initialization has finished), go to 6.
338    // 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
339    while !(code & (1 << 31)):
340        if !send (5, 1 << 20, R4, &code):
341            Iris::panic (0, "invalid response to cmd 5")
342    // 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else it is only a SDIO card.
343    // 7. If it is a combo card, go to check SDMEM to initialize the memory part.
344    have_io = true
345    if code & (1 << 27):
346        check_sdmem ()
347        return
348    // 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned from the response.
349    // 9. If do not accept the new RCA, go to 8, else record the new RCA.
350    rca = 0
351    while rca == 0:
352        if !send (3, 0, R6, &rca):
353            Iris::panic (0, "unable to set rca")
354        rca &= 0xffff0000
355    check_mmc ()
356
357void Mmc::detect ():
358    kdebug ("mmc detect\n")
359    gpio_clear (POWER_PORT, 1 << POWER_PIN)
360    check_sd ()
361    check_mmc ()
362    if have_sdmem:
363        if !send (9, rca, R2):
364            Iris::panic (0, "unable to request csd")
365        if !send (7, rca, R1B):
366            Iris::panic (0, "unable to select sdmem")
367        kdebug ("found device; size = ")
368        kdebug_num (num_blocks)
369        kdebug (" * ")
370        kdebug_num (read_block_size)
371        kdebug (" = ")
372        kdebug_num (num_blocks * read_block_size)
373        kdebug ("\n")
374        // Set up buffer memory.
375        for unsigned i = 0; i < 1 << csd.write_bl_len; i += PAGE_SIZE:
376            Iris::Page p = Iris::my_memory.create_page ()
377            p.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
378            Iris::my_memory.map (p, (unsigned)current_block + i)
379            Iris::free_cap (p)
380        Iris::Listitem item = cb_list.get_next ()
381        while item.code != Iris::Cap ().code:
382            Iris::Cap c = cb_list.get_cap (item)
383            c.invoke (0, ~0)
384            Iris::free_cap (c)
385            Iris::Listitem nextitem = cb_list.get_next (item);
386            Iris::free_cap (item)
387            item = nextitem
388
389void Mmc::release ():
390    kdebug ("mmc release\n")
391    gpio_set (POWER_PORT, 1 << POWER_PIN)
392    have_sdmem = false
393    have_io = false
394    read_block_size = 0
395    if num_blocks != 0:
396        for unsigned i = 0; i < 1 << csd.write_bl_len; i += PAGE_SIZE:
397            Iris::Page p = Iris::my_memory.mapping ((void *)((unsigned)current_block + i))
398            Iris::my_memory.destroy (p)
399            Iris::free_cap (p)
400        if dirty:
401            Iris::debug ("Warning: sd/mmc card removed before data was written to it")
402        current_block_num = ~0
403        dirty = false
404    num_blocks = 0
405    Iris::Listitem item = cb_list.get_next ()
406    while item.code != Iris::Cap ().code:
407        Iris::Cap c = cb_list.get_cap (item)
408        c.invoke (0, ~0)
409        Iris::free_cap (c)
410        Iris::Listitem nextitem = cb_list.get_next (item);
411        Iris::free_cap (item)
412        item = nextitem
413
414void Mmc::interrupt ():
415    kdebug ("mmc interrupt\n")
416
417void Mmc::set_block (unsigned block):
418    if current_block_num == block:
419        return
420    if dirty && current_block_num != ~0:
421        MSC_NOB = 1
422        MSC_BLKLEN = 1 << csd.write_bl_len
423        if !send (24, (current_block_num << csd.write_bl_len), WR_DATA):
424            Iris::panic (0, "unable to send data")
425        MSC_IMASK = ~MSC_IMASK_TXFIFO_WR_REQ
426        for unsigned a = 0; a < 1 << csd.write_bl_len; a += 4:
427            while MSC_STAT & MSC_STAT_DATA_FIFO_FULL:
428                Iris::register_interrupt (IRQ_MSC)
429                Iris::wait_for_interrupt (IRQ_MSC)
430            MSC_TXFIFO = current_block[a >> 2]
431        MSC_IMASK = ~0
432        MSC_IREG = MSC_IREG_DATA_TRAN_DONE
433        //kdebug ("done writing page\n")
434    current_block_num = block
435    dirty = false
436    MSC_NOB = 1
437    MSC_BLKLEN = 1 << 9
438    for unsigned a = 0; a < 1 << csd.write_bl_len; a += 1 << 9:
439        if !send (17, (block << csd.write_bl_len) + a, RD_DATA):
440            Iris::panic (0, "unable to request data")
441        MSC_IMASK = ~MSC_IMASK_RXFIFO_RD_REQ
442        for unsigned aa = 0; aa < 1 << 9; aa += 4:
443            while MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY:
444                Iris::register_interrupt (IRQ_MSC)
445                Iris::wait_for_interrupt (IRQ_MSC)
446            current_block[(a + aa) >> 2] = MSC_RXFIFO
447        MSC_IMASK = ~0
448        MSC_IREG = MSC_IREG_DATA_TRAN_DONE
449    //kdebug ("done filling page\n")
450
451void Mmc::read_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
452    if address.value () >> (csd.write_bl_len + 32):
453        Iris::panic (address.h, "page too high: not supported")
454    unsigned block = address.value () >> csd.write_bl_len
455    unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1
456    set_block (block)
457    unsigned blockmask = ~((1 << 9) - 1)
458    size &= blockmask
459    offset &= ~PAGE_MASK & ~3
460    if size + offset > PAGE_SIZE:
461        size = PAGE_SIZE - offset
462    page.share (buffer_page)
463    buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
464    for unsigned i = 0; i < size; i += 4:
465        ((unsigned *)buffer)[(offset + i) >> 2] = current_block[(start_pos + i) >> 2]
466
467void Mmc::write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
468    if address.value () >> (csd.write_bl_len + 32):
469        Iris::panic (address.h, "page too high: not supported")
470    unsigned block = address.value () >> csd.write_bl_len
471    unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1
472    set_block (block)
473    unsigned blockmask = ~((1 << 9) - 1)
474    size &= blockmask
475    offset &= ~PAGE_MASK & ~3
476    if size + offset > PAGE_SIZE:
477        size = PAGE_SIZE - offset
478    page.share (buffer_page)
479    buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
480    for unsigned i = 0; i < size; i += 4:
481        current_block[(start_pos + i) >> 2] = ((unsigned *)buffer)[(offset + i) >> 2]
482    dirty = true
483
484void Mmc::wait_write ():
485    MSC_IMASK = ~MSC_IMASK_PRG_DONE
486    while !MSC_STAT & MSC_STAT_PRG_DONE:
487        Iris::register_interrupt (IRQ_MSC)
488        Iris::wait_for_interrupt (IRQ_MSC)
489    MSC_IREG = MSC_IREG_PRG_DONE
490
491static Mmc mmc
492
493enum types:
494    DETECT
495    REQUEST
496
497Iris::Num start ():
498    map_msc ()
499    map_gpio ()
500    map_cpm ()
501
502    mmc.reset ()
503
504    Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> ()
505    Iris::Cap cap = Iris::my_receiver.create_capability (DETECT)
506    detect.set_cb (cap.copy ())
507    cap.invoke (~0)
508    Iris::free_cap (cap)
509
510    // Get a message from the queue. This is either the "there is no card" message, or the message we just sent.
511    Iris::wait ()
512    if Iris::recv.data[0].l != ~0:
513        // If it was "there is no card", the message we sent is still in the queue.
514        Iris::wait ()
515    else:
516        // Otherwise, there is a card.
517        mmc.detect ()
518
519    cap = Iris::my_receiver.create_capability (REQUEST)
520    Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy ())
521    Iris::free_cap (cap)
522
523    Iris::my_parent.init_done ()
524
525    while true:
526        Iris::wait ()
527        switch Iris::recv.protected_data.l:
528            case DETECT:
529                if Iris::recv.data[0].l:
530                    mmc.detect ()
531                else:
532                    mmc.release ()
533                break
534            case IRQ_MSC:
535                mmc.interrupt ()
536                break
537            case REQUEST:
538                //kdebug ("sd+mmc request ")
539                //kdebug_num (Iris::recv.data[0].l)
540                //kdebug ("\n")
541                switch Iris::recv.data[0].l:
542                    case Iris::Block::GET_SIZE:
543                        Iris::debug ("get size\n")
544                        unsigned long long size = mmc.get_num_blocks () * mmc.get_read_block_size ()
545                        Iris::recv.reply.invoke (size)
546                        break
547                    case Iris::Block::GET_ALIGN_BITS:
548                        Iris::debug ("get align bits\n")
549                        Iris::recv.reply.invoke (9)
550                        break
551                    case Iris::Block::GET_BLOCK:
552                        //Iris::debug ("get block\n")
553                        Iris::Cap reply = Iris::get_reply ()
554                        Iris::Page page = Iris::get_arg ()
555                        mmc.read_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
556                        reply.invoke ()
557                        Iris::free_cap (page)
558                        Iris::free_cap (reply)
559                        break
560                    case Iris::WBlock::SET_BLOCK:
561                        Iris::debug ("set block\n")
562                        Iris::Cap reply = Iris::get_reply ()
563                        Iris::Page page = Iris::get_arg ()
564                        mmc.write_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
565                        reply.invoke ()
566                        Iris::free_cap (page)
567                        Iris::free_cap (reply)
568                        mmc.wait_write ()
569                        break
570                    case Iris::Block::SET_CHANGE_CB:
571                        Iris::debug ("set change cb\n")
572                        Iris::Listitem item = Iris::get_arg ()
573                        Iris::Cap reply = Iris::get_reply ()
574                        mmc.add_cb (item)
575                        reply.invoke ()
576                        Iris::free_cap (item)
577                        Iris::free_cap (reply)
578                        break
579                    case Iris::WBlock::TRUNCATE:
580                        Iris::debug ("truncate\n")
581                        // Fall through: don't support resizing.
582                    default:
583                        Iris::panic (0, "unexpected event for sd+mmc")
584                break
585            default:
586                Iris::panic (0, "unexpected request source for sd+mmc")
source/sdmmc.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// source/sd+mmc.ccp: sd+mmc driver.
4// Copyright 2009 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 "devices.hh"
20#define ARCH
21#include "arch.hh"
22
23class Mmc:
24    public:
25    enum Response_type:
26        NONE = MSC_CMDAT_RESPONSE_NONE
27        RD_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_READ
28        WR_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE
29        R1 = MSC_CMDAT_RESPONSE_R1
30        R1B = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_BUSY
31        R2 = MSC_CMDAT_RESPONSE_R2
32        R3 = MSC_CMDAT_RESPONSE_R3
33        R4 = MSC_CMDAT_RESPONSE_R4
34        R5 = MSC_CMDAT_RESPONSE_R5
35        R6 = MSC_CMDAT_RESPONSE_R6
36        R7 = MSC_CMDAT_RESPONSE_R7
37    static unsigned const POWER_PORT = 3
38    static unsigned const POWER_PIN = 2
39    struct CID:
40        unsigned mid
41        char oid[2]
42        char pnm[5]
43        unsigned prv
44        unsigned psn
45        unsigned year
46        unsigned month
47    struct CSD:
48        unsigned c_size
49        unsigned c_size_mult
50        unsigned read_bl_len, write_bl_len
51        bool copy
52        bool perm_write_protect
53        bool tmp_write_protect
54    bool send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response = NULL)
55    void check_sd ()
56    void check_sdmem ()
57    void check_mmc ()
58    public:
59    void reset ()
60    void detect ()
61    void release ()
62    void interrupt ()
63    CID const &get_cid ():
64        return cid
65    unsigned get_num_blocks ():
66        return num_blocks
67    unsigned get_read_block_size ():
68        return read_block_size
69    unsigned get_block_bits ():
70        return hc ? 9 : csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len
71    void write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
72    void read_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
73    void wait_write ()
74    void add_cb (Iris::Listitem item):
75        cb_list.add_item (item)
76    private:
77    void set_block (unsigned block)
78    unsigned current_block_num
79    bool dirty
80    unsigned *current_block
81    unsigned rca
82    bool have_sdmem, have_io
83    bool hc
84    CID cid
85    CSD csd
86    unsigned num_blocks, read_block_size
87    Iris::Page buffer_page
88    Iris::List cb_list
89    static unsigned const buffer = 0x15000
90
91bool Mmc::send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response):
92    MSC_CMD = cmd
93    MSC_ARG = arg
94    MSC_CMDAT = response_type
95    MSC_IMASK = ~MSC_IMASK_END_CMD_RES
96    Iris::register_interrupt (IRQ_MSC)
97    msc_start_op ()
98    Iris::wait_for_interrupt ()
99    MSC_IMASK = ~0
100    //kdebug ("cmd: ")
101    //kdebug_num (cmd)
102    unsigned stat = MSC_STAT
103    //kdebug (", stat: ")
104    //kdebug_num (stat)
105    //kdebug ("\n")
106    if stat & MSC_STAT_CRC_RES_ERR:
107        Iris::panic (0, "crc error in mmc response")
108        return false
109    if stat & MSC_STAT_TIME_OUT_RES:
110        kdebug ("time out waiting for mmc response\n")
111        MSC_IREG = MSC_IREG_END_CMD_RES
112        return false
113    if response_type == R2:
114        unsigned d = MSC_RES
115        if d >> 8 != 0x3f:
116            Iris::panic (d, "invalid r2 response")
117        if cmd == 3:
118            // Read out result.
119            cid.mid = d & 0xff
120            d = MSC_RES
121            cid.oid[0] = d >> 8
122            cid.oid[1] = d & 0xff
123            d = MSC_RES
124            cid.pnm[0] = d >> 8
125            cid.pnm[1] = d & 0xff
126            d = MSC_RES
127            cid.pnm[2] = d >> 8
128            cid.pnm[3] = d & 0xff
129            d = MSC_RES
130            cid.pnm[4] = d >> 8
131            cid.prv = d & 0xff
132            d = MSC_RES
133            cid.psn = d << 16
134            d = MSC_RES
135            cid.psn |= d
136            d = MSC_RES
137            cid.year = 2000 + (d >> 4 & 0xff)
138            cid.month = d & 0xf
139            #if 1
140            Iris::debug ("CID: mid=%x, oid=%x %x, pnm=%x %x %x %x %x, prv=%x, psn=%x, year=%x, month=%x\n", cid.mid, cid.oid[0], cid.oid[1], cid.pnm[0], cid.pnm[1], cid.pnm[2], cid.pnm[3], cid.pnm[4], cid.prv, cid.psn, cid.year, cid.month)
141            #endif
142        else:
143            // Header (8) 1.0 1.0
144            // Read out csd.
145            // Ignore csd_structure. 2 (+ 6) 1.0 2.0 ***
146            d = MSC_RES
147            // Ignore taac and nsac. 8 + 8 2.0 4.0 ***
148            d = MSC_RES
149            // Ignore tran_speed, ccc. 8 + 8/12 2.0 6.0 ***
150            d = MSC_RES
151            // Ignore rest of ccc. 4/12 0.4 6.4
152            // 4 0.4 7.0
153            csd.read_bl_len = (d >> 8) & 0xf
154            // Ignore read_bl_partial, write_blk_misalign, read_blk_misalign, dsr_imp. 1 + 1 + 1 + 1 (+ 2) 0.6 7.6
155            // 2/12 0.2 8.0 ***
156            csd.c_size = (d & 0x0003) << 10
157            d = MSC_RES
158            // 10/12 1.2 9.2
159            csd.c_size |= d >> 6
160            // Ignore vdd_r_cur_min, vdd_r_cur_max. 3 + 3 0.6 10.0 ***
161            d = MSC_RES
162            // Ignore vdd_w_cur_min, vdd_w_cur_max. 3 + 3 0.6 10.6
163            // 3 0.3 11.1
164            csd.c_size_mult = (d >> 7) & 0x7
165            // Ignore erase_blk_enable, sector_size. 1 + 6/7 0.7 12.0 ***
166            d = MSC_RES
167            // Ignore rest of sector_size, wp_grp_size, wp_grp_enable, r2w_factor. 1/7 + 7 + 1 (+ 2) + 3 1.6 13.6
168            // 2/4 0.4 14.0 ***
169            csd.write_bl_len = (d << 2) & 0xc
170            d = MSC_RES
171            // 2/4 0.2 14.2
172            csd.write_bl_len |= (d >> 14) & 0x3
173            // Ignore write_bl_partial, file_format_grp. 1 (+ 5) + 1 0.7 15.1
174            // 1 0.1 15.2
175            csd.copy = d & 0x40
176            // 1 0.1 15.3
177            csd.perm_write_protect = d & 0x20
178            // 1 0.1 15.4
179            csd.tmp_write_protect = d & 0x10
180            // Ignore file_format. 2 (+ 2) 0.4 16.0 ***
181            read_block_size = hc ? 512 : 1 << csd.read_bl_len
182            num_blocks = (csd.c_size + 1) << (csd.c_size_mult + 2)
183            if hc:
184                if csd.read_bl_len < 9:
185                    num_blocks >>= 9 - csd.read_bl_len
186                else:
187                    num_blocks <<= csd.read_bl_len - 9
188            #if 1
189            Iris::debug ("CSD: size=%x<<%x, r/w len=%x/%x, %s, %s, %s\n", csd.c_size, csd.c_size_mult, csd.read_bl_len, csd.write_bl_len, csd.copy ? "copy" : "no copy", csd.perm_write_protect ? "fixed write protect" : "no fixed write protect", csd.tmp_write_protect ? "write protect" : "no write protect")
190            #endif
191        unsigned c_size
192        unsigned c_size_mult
193        unsigned read_bl_len, write_bl_len
194        bool copy
195        bool perm_write_protect
196        bool tmp_write_protect
197    else if response_type != NONE:
198        unsigned r = MSC_RES
199        if response_type == R3:
200            if r >> 8 != 0x3f:
201                Iris::panic (r, "r3 response was not 3f")
202        else if r >> 8 != cmd:
203            kdebug ("stat: ")
204            kdebug_num (MSC_STAT)
205            kdebug ("; response: ")
206            kdebug_num (r)
207            kdebug ("; cmd: ")
208            kdebug_num (cmd)
209            Iris::panic (r, "response doesn't match command")
210        r <<= 24
211        r |= MSC_RES << 8
212        r |= MSC_RES & 0xff
213        if response:
214            *response = r
215    else:
216    //kdebug ("extra response fifo read: ")
217    //for unsigned i = 0; i < 9; ++i:
218        //kdebug (" ")
219        //kdebug_num (MSC_RES, 4)
220    //kdebug ("\n")
221    MSC_IREG = MSC_IREG_END_CMD_RES
222    return true
223
224void Mmc::reset ():
225    current_block_num = ~0
226    dirty = false
227    cb_list = Iris::my_memory.create_list ()
228    current_block = (unsigned *)(buffer + PAGE_SIZE)
229    // Create a buffer to use for data transfer.
230    buffer_page = Iris::my_memory.create_page ()
231    Iris::my_memory.map (buffer_page, buffer)
232    // Reset all state, by faking a release event.
233    release ()
234    // Enable 25 MHz clock to msc.
235    CPM_MSCCDR = 13
236    cpm_start_msc ()
237    // Enable msc pins.
238    gpio_as_msc ()
239    // Disable power to card.
240    gpio_as_gpio (POWER_PORT, 1 << POWER_PIN)
241    gpio_as_output (POWER_PORT, 1 << POWER_PIN)
242    gpio_disable_pull (POWER_PORT, 1 << POWER_PIN)
243    gpio_set (POWER_PORT, 1 << POWER_PIN)
244
245    // Stop the clock.
246    MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP
247    while MSC_STAT & MSC_STAT_CLK_EN:
248        //kdebug (",")
249        Iris::sleep (1)
250
251    // Reset controller and inserted devices.
252    MSC_STRPCL = MSC_STRPCL_RESET
253    while MSC_STAT & MSC_STAT_IS_RESETTING:
254        //kdebug (":")
255        Iris::sleep (1)
256
257    // Initialize registers.
258    MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_1
259    MSC_RESTO = 64
260    MSC_RDTO = ~0
261    MSC_BLKLEN = 0x200
262    MSC_NOB = 0
263    MSC_IREG = ~0
264    MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_RXFIFO_RD_REQ)
265    MSC_ARG = 0
266
267    // Start the clock.
268    MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START
269    // Set cards, if any, to idle.
270    send (0, 0, NONE)
271
272    // Reset SDIO device, if any. Don't do this, because it breaks for some reason.
273    //send (52, 0x88000c08, R5)
274
275void Mmc::check_mmc ():
276    //kdebug ("checking mmc\n")
277    // 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000).
278    // 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9.
279    // 3. IF THE INITIALIZATION HAS FINISHED, GO TO 5. (THE RESPONSE IS THE OCR REGISTER AND IT INCLUDES A STATUS INFORMATION BIT (BIT [31]). THIS STATUS BIT IS SET IF THE CARD POWER UP PROCEDURE HAS BEEN FINISHED. AS LONG AS THE CARD IS BUSY, THE CORRESPONDING BIT[31] IS SET TO LOW.)
280    // 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
281    // 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
282    // 6. If the response timeout occurs, goto 9.
283    // 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
284
285void Mmc::check_sdmem ():
286    kdebug ("checking sdmem\n")
287    // 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55.
288    // 3. If the response is correct (CMD55 has response), then continue, else go to check MMC.
289    unsigned code
290    hc = false
291    if send (8, 0x1aa, R7, &code) && (code & 0xff) == 0xaa:
292        kdebug ("hc\n")
293        hc = true
294    if !send (55, 0, R1, &code):
295        check_mmc ()
296        return
297    // 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
298    if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
299        check_mmc ()
300        return
301    // 5. If the initialization has finished, go to 7. (The response is the OCR register and it includes a status information bit (bit [31]). This status bit is set if the card power up procedure has been finished. As long as the card is busy, the corresponding bit[31] is set to LOW.)
302    // 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5.
303    unsigned retries = 100
304    while !(code & (1 << 31)) && --retries:
305        if !send (55, 0, R1, &code):
306            return
307        if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
308            return
309        Iris::sleep (1)
310    if !(code & (1 << 31)):
311        Iris::panic (code, "card fails to finish setting up")
312    // 7. Send CMD2 (ALL_SEND_CID) to get the card CID.
313    if !send (2, 0, R2):
314        Iris::panic (0, "card failed to send CID")
315    // 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response.
316    // 9. If do not accept the new RCA, go to 8, else record the new RCA.
317    rca = 0
318    while !rca:
319        if !send (3, 0, R6, &rca):
320            Iris::panic (0, "card failed to provide rca")
321        rca &= 0xffff0000
322    kdebug ("received rca ")
323    kdebug_num (rca >> 16, 4)
324    kdebug ("\n")
325    have_sdmem = true
326
327void Mmc::check_sd ():
328    //kdebug ("checking sdio\n")
329    if !send (0, 0, NONE):
330        Iris::panic (0, "unable to reset cards?")
331    // 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
332    // 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
333    unsigned code
334    if !send (5, 1 << 20, R4, &code) || !(code & (7 << 28)):
335        check_sdmem ()
336        return
337    // 4. If C-bit in the response is ready (the initialization has finished), go to 6.
338    // 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
339    while !(code & (1 << 31)):
340        if !send (5, 1 << 20, R4, &code):
341            Iris::panic (0, "invalid response to cmd 5")
342    // 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else it is only a SDIO card.
343    // 7. If it is a combo card, go to check SDMEM to initialize the memory part.
344    have_io = true
345    if code & (1 << 27):
346        check_sdmem ()
347        return
348    // 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned from the response.
349    // 9. If do not accept the new RCA, go to 8, else record the new RCA.
350    rca = 0
351    while rca == 0:
352        if !send (3, 0, R6, &rca):
353            Iris::panic (0, "unable to set rca")
354        rca &= 0xffff0000
355    check_mmc ()
356
357void Mmc::detect ():
358    kdebug ("mmc detect\n")
359    gpio_clear (POWER_PORT, 1 << POWER_PIN)
360    check_sd ()
361    check_mmc ()
362    if have_sdmem:
363        if !send (9, rca, R2):
364            Iris::panic (0, "unable to request csd")
365        if !send (7, rca, R1B):
366            Iris::panic (0, "unable to select sdmem")
367        kdebug ("found device; size = ")
368        kdebug_num (num_blocks)
369        kdebug (" * ")
370        kdebug_num (read_block_size)
371        kdebug (" = ")
372        kdebug_num (num_blocks * read_block_size)
373        kdebug ("\n")
374        // Set up buffer memory.
375        for unsigned i = 0; i < 1 << csd.write_bl_len; i += PAGE_SIZE:
376            Iris::Page p = Iris::my_memory.create_page ()
377            p.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
378            Iris::my_memory.map (p, (unsigned)current_block + i)
379            Iris::free_cap (p)
380        Iris::Listitem item = cb_list.get_next ()
381        while item.code != Iris::Cap ().code:
382            Iris::Cap c = cb_list.get_cap (item)
383            c.invoke (0, ~0)
384            Iris::free_cap (c)
385            Iris::Listitem nextitem = cb_list.get_next (item);
386            Iris::free_cap (item)
387            item = nextitem
388
389void Mmc::release ():
390    kdebug ("mmc release\n")
391    gpio_set (POWER_PORT, 1 << POWER_PIN)
392    have_sdmem = false
393    have_io = false
394    read_block_size = 0
395    if num_blocks != 0:
396        for unsigned i = 0; i < 1 << csd.write_bl_len; i += PAGE_SIZE:
397            Iris::Page p = Iris::my_memory.mapping ((void *)((unsigned)current_block + i))
398            Iris::my_memory.destroy (p)
399            Iris::free_cap (p)
400        if dirty:
401            Iris::debug ("Warning: sd/mmc card removed before data was written to it")
402        current_block_num = ~0
403        dirty = false
404    num_blocks = 0
405    Iris::Listitem item = cb_list.get_next ()
406    while item.code != Iris::Cap ().code:
407        Iris::Cap c = cb_list.get_cap (item)
408        c.invoke (0, ~0)
409        Iris::free_cap (c)
410        Iris::Listitem nextitem = cb_list.get_next (item);
411        Iris::free_cap (item)
412        item = nextitem
413
414void Mmc::interrupt ():
415    kdebug ("mmc interrupt\n")
416
417void Mmc::set_block (unsigned block):
418    if current_block_num == block:
419        return
420    if dirty && current_block_num != ~0:
421        MSC_NOB = 1
422        MSC_BLKLEN = 1 << csd.write_bl_len
423        if !send (24, (current_block_num << csd.write_bl_len), WR_DATA):
424            Iris::panic (0, "unable to send data")
425        MSC_IMASK = ~MSC_IMASK_TXFIFO_WR_REQ
426        for unsigned a = 0; a < 1 << csd.write_bl_len; a += 4:
427            while MSC_STAT & MSC_STAT_DATA_FIFO_FULL:
428                Iris::register_interrupt (IRQ_MSC)
429                Iris::wait_for_interrupt ()
430            MSC_TXFIFO = current_block[a >> 2]
431        MSC_IMASK = ~0
432        MSC_IREG = MSC_IREG_DATA_TRAN_DONE
433        //kdebug ("done writing page\n")
434    current_block_num = block
435    dirty = false
436    MSC_NOB = 1
437    MSC_BLKLEN = 1 << 9
438    for unsigned a = 0; a < 1 << csd.write_bl_len; a += 1 << 9:
439        if !send (17, (block << csd.write_bl_len) + a, RD_DATA):
440            Iris::panic (0, "unable to request data")
441        MSC_IMASK = ~MSC_IMASK_RXFIFO_RD_REQ
442        for unsigned aa = 0; aa < 1 << 9; aa += 4:
443            while MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY:
444                Iris::register_interrupt (IRQ_MSC)
445                Iris::wait_for_interrupt ()
446            current_block[(a + aa) >> 2] = MSC_RXFIFO
447        MSC_IMASK = ~0
448        MSC_IREG = MSC_IREG_DATA_TRAN_DONE
449    //kdebug ("done filling page\n")
450
451void Mmc::read_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
452    if address.value () >> (csd.write_bl_len + 32):
453        Iris::panic (address.h, "page too high: not supported")
454    unsigned block = address.value () >> csd.write_bl_len
455    unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1
456    set_block (block)
457    unsigned blockmask = ~((1 << 9) - 1)
458    size &= blockmask
459    offset &= ~PAGE_MASK & ~3
460    if size + offset > PAGE_SIZE:
461        size = PAGE_SIZE - offset
462    page.share (buffer_page)
463    buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
464    for unsigned i = 0; i < size; i += 4:
465        ((unsigned *)buffer)[(offset + i) >> 2] = current_block[(start_pos + i) >> 2]
466
467void Mmc::write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
468    if address.value () >> (csd.write_bl_len + 32):
469        Iris::panic (address.h, "page too high: not supported")
470    unsigned block = address.value () >> csd.write_bl_len
471    unsigned start_pos = address.l & (1 << csd.write_bl_len) - 1
472    set_block (block)
473    unsigned blockmask = ~((1 << 9) - 1)
474    size &= blockmask
475    offset &= ~PAGE_MASK & ~3
476    if size + offset > PAGE_SIZE:
477        size = PAGE_SIZE - offset
478    page.share (buffer_page)
479    buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
480    for unsigned i = 0; i < size; i += 4:
481        current_block[(start_pos + i) >> 2] = ((unsigned *)buffer)[(offset + i) >> 2]
482    dirty = true
483
484void Mmc::wait_write ():
485    MSC_IMASK = ~MSC_IMASK_PRG_DONE
486    while !MSC_STAT & MSC_STAT_PRG_DONE:
487        Iris::register_interrupt (IRQ_MSC)
488        Iris::wait_for_interrupt ()
489    MSC_IREG = MSC_IREG_PRG_DONE
490
491static Mmc mmc
492
493enum types:
494    DETECT = 1
495    REQUEST
496
497Iris::Num start ():
498    map_msc ()
499    map_gpio ()
500    map_cpm ()
501
502    mmc.reset ()
503
504    Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> ()
505    Iris::Cap cap = Iris::my_receiver.create_capability (DETECT)
506    detect.set_cb (cap.copy ())
507    cap.invoke (~0)
508    Iris::free_cap (cap)
509
510    // Get a message from the queue. This is either the "there is no card" message, or the message we just sent.
511    Iris::wait ()
512    if Iris::recv.data[0].l != ~0:
513        // If it was "there is no card", the message we sent is still in the queue.
514        Iris::wait ()
515    else:
516        // Otherwise, there is a card.
517        mmc.detect ()
518
519    cap = Iris::my_receiver.create_capability (REQUEST)
520    Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy ())
521    Iris::free_cap (cap)
522
523    Iris::my_parent.init_done ()
524
525    while true:
526        Iris::wait ()
527        switch Iris::recv.protected_data.l:
528            case 0:
529                mmc.interrupt ()
530                break
531            case DETECT:
532                if Iris::recv.data[0].l:
533                    mmc.detect ()
534                else:
535                    mmc.release ()
536                break
537            case REQUEST:
538                //kdebug ("sd+mmc request ")
539                //kdebug_num (Iris::recv.data[0].l)
540                //kdebug ("\n")
541                switch Iris::recv.data[0].l:
542                    case Iris::Block::GET_SIZE:
543                        Iris::debug ("get size\n")
544                        unsigned long long size = mmc.get_num_blocks () * mmc.get_read_block_size ()
545                        Iris::recv.reply.invoke (size)
546                        break
547                    case Iris::Block::GET_ALIGN_BITS:
548                        Iris::debug ("get align bits\n")
549                        Iris::recv.reply.invoke (9)
550                        break
551                    case Iris::Block::GET_BLOCK:
552                        //Iris::debug ("get block\n")
553                        Iris::Cap reply = Iris::get_reply ()
554                        Iris::Page page = Iris::get_arg ()
555                        mmc.read_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
556                        reply.invoke ()
557                        Iris::free_cap (page)
558                        Iris::free_cap (reply)
559                        break
560                    case Iris::WBlock::SET_BLOCK:
561                        Iris::debug ("set block\n")
562                        Iris::Cap reply = Iris::get_reply ()
563                        Iris::Page page = Iris::get_arg ()
564                        mmc.write_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
565                        reply.invoke ()
566                        Iris::free_cap (page)
567                        Iris::free_cap (reply)
568                        mmc.wait_write ()
569                        break
570                    case Iris::Block::SET_CHANGE_CB:
571                        Iris::debug ("set change cb\n")
572                        Iris::Listitem item = Iris::get_arg ()
573                        Iris::Cap reply = Iris::get_reply ()
574                        mmc.add_cb (item)
575                        reply.invoke ()
576                        Iris::free_cap (item)
577                        Iris::free_cap (reply)
578                        break
579                    case Iris::WBlock::TRUNCATE:
580                        Iris::debug ("truncate\n")
581                        // Fall through: don't support resizing.
582                    default:
583                        Iris::panic (0, "unexpected event for sd+mmc")
584                break
585            default:
586                Iris::panic (0, "unexpected request source for sd+mmc")
source/trendtac-gpio.ccp
247247    // TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything.
248248
249249enum codes:
250    KEYBOARD = 32
250    KEYBOARD = 1
251251    TOUCHPAD
252252    LOCKLEDS
253253    PWM
...... 
289289                if kbd.is_scanning ():
290290                    Iris::my_receiver.set_alarm (ALARM_INTERVAL)
291291                break
292            case IRQ_GPIO0:
292            case 0:
293293                // Always scan keyboard and touchpad on any interrupt.
294294                kbd.scan ()
295295                tp.check_events ()
source/udc.ccp
390390
391391void Udc::irq_usb (unsigned cmd):
392392    // Reset.
393    //Iris::debug ("usb reset\n")
393394    state = IDLE
394395
395396void Udc::irq_in (unsigned cmd):
...... 
507508        Iris::panic (0)
508509    unsigned size = UDC_OUTCOUNT
509510    unsigned csr = UDC_OUTCSR
510    //kdebug ("handling bulk interrupt for ")
511    //kdebug_num (csr)
512    //kdebug (" with ")
513    //kdebug_num (size)
514    //kdebug (" bytes.\n")
511    //Iris::debug ("handling bulk interrupt for %x with %d bytes.\n", csr, size)
515512    csr &= ~UDC_OUTCSR_OUTPKTRDY
516513    for unsigned i = 0; i < size; i += 4:
517514        *p++ = UDC_FIFO (1)
...... 
534531        unsigned out = UDC_INTROUT
535532        if !(usb & 4) && !(in & 1) && !(out & 2):
536533            break
537        //kdebug ("interrupt: ")
538        //kdebug_num (usb, 1)
539        //kdebug ("/")
540        //kdebug_num (in, 1)
541        //kdebug ("/")
542        //kdebug_num (out, 1)
543        //kdebug ("\n")
534        //Iris::debug ("interrupt: %d/%d/%d\n", usb, in, out)
544535        if usb & 4:
545536            irq_usb (cmd)
546537        if in & 1:
...... 
554545    log_buffer[log_buffer_size++] = c
555546
556547enum pdata:
557    LOG = 32
548    LOG = 1
558549    DIRECTORY
559550    FILE
560551    NAME
...... 
565556    map_cpm ()
566557    Udc udc
567558
568    Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
569    __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
570    udc.init ()
571    Iris::register_interrupt (IRQ_UDC)
559    //Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
560    //__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
572561    Iris::Directory dir = Iris::my_receiver.create_capability (DIRECTORY)
573562    Iris::my_parent.provide_capability <Iris::Directory> (dir.copy ())
574563    Iris::free_cap (dir)
564    udc.init ()
565    Iris::register_interrupt (IRQ_UDC)
566    // Don't call init_done, because this can be used as bootthread and without a parent this call will not be answered.
567    //Iris::my_parent.init_done ()
575568    unsigned state = 0
576569    while true:
577570        Iris::wait ()
578571        Iris::Cap reply = Iris::get_reply ()
579572        Iris::Cap arg = Iris::get_arg ()
573        //Iris::debug ("udc event, protected: %x\n", Iris::recv.protected_data.l)
580574        switch Iris::recv.protected_data.l:
581            case IRQ_UDC:
575            case 0:
582576                udc.interrupt (state)
583577                Iris::register_interrupt (IRQ_UDC)
584578                break
...... 
586580                udc.log (Iris::recv.data[0].l)
587581                break
588582            case DIRECTORY:
589                //kdebug ("dir request\n")
583                //Iris::debug ("dir request %d\n", Iris::recv.data[0].l)
590584                switch Iris::recv.data[0].l:
591585                    case Iris::Directory::GET_NAME:
592586                        Iris::Cap name = Iris::my_receiver.create_capability (Iris::Num (NAME, Iris::recv.data[1].l))
...... 
600594                    case Iris::Directory::UNLOCK_RO:
601595                        state = Iris::recv.data[0].l
602596                        if Iris::recv.data[1].h != 0:
603                            kdebug ("index out of supported range\n")
604                            Iris::panic (0)
597                            Iris::panic (0, "index out of supported range")
605598                        udc.send (Iris::recv.data[0].l, Iris::recv.data[1].l, reply, arg)
606599                        continue
607600                    case Iris::Directory::GET_FILE_RO:
...... 
623616                        continue
624617                break
625618            case FILE:
626                //kdebug ("file request\n")
619                //Iris::debug ("file request %d\n", Iris::recv.data[0].l)
627620                switch Iris::recv.data[0].l:
628621                    case Iris::Block::GET_BLOCK:
629622                        if Iris::recv.data[0].h != PAGE_SIZE << 16:
...... 
639632                        continue
640633                break
641634            case NAME:
642                //kdebug ("name request\n")
635                //Iris::debug ("name request %d\n", Iris::recv.data[0].l)
643636                switch Iris::recv.data[0].l:
644637                    case Iris::String::GET_SIZE:
645638                        reply.invoke (16)
source/usb-mass-storage.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// source/usb-mass-storage.ccp: USB mass storage device driver.
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 "iris.hh"
20#include "devices.hh"
21#define ARCH
22#include "arch.hh"
23
24#if 0
25States and expected interrupts:
26
27IDLE: after reset or csw.
28    IN interrupt: csw received, do nothing.
29    OUT interrupt: cbw; handle
30        -> IDLE (no data; csw sent)
31        -> TX (send)
32        -> RX (receive packets)
33TX: transmitting data.
34    IN interrupt: host received data; send more.
35        -> TX (more to send)
36RX: receiving data.
37    OUT interrupt: host sent data; handle.
38        -> RX (more to receive)
39        -> IDLE (done receiving; send csw)
40#endif
41
42extern "C":
43    void *memset (char *s, int c, unsigned long n):
44        Iris::debug ("memset called: %x %x->%x\n", s, n, c)
45        for unsigned i = 0; i < n; ++i:
46            s[i] = c
47        return s
48
49class Udc:
50    typedef unsigned char u8
51    typedef unsigned short u16
52    typedef unsigned int u32
53    typedef u8 string
54    // The ugly stuff is because pypp doesn't support __attribute__.
55    /**/struct Setup {
56        u8 request_type;
57        u8 request;
58        u16 value;
59        u16 index;
60        u16 length;
61     } __attribute__ ((packed))
62    /**/struct Device {
63        static u8 const Type = 1;
64        u8 length;
65        u8 type;
66        u16 usb_version;
67        u8 dev_class;
68        u8 subclass;
69        u8 protocol;
70        u8 max_packet_size0;
71        u16 vendor;
72        u16 product;
73        u16 dev_version;
74        string s_manufacturer;
75        string s_product;
76        string s_serial;
77        u8 num_configurations;
78     } __attribute__ ((packed))
79    /**/struct Configuration {
80        static u8 const Type = 2;
81        u8 length;
82        u8 type;
83        u16 total_length;
84        u8 num_interfaces;
85        u8 configuration_value;
86        u8 configuration;
87        u8 attributes;
88        u8 max_power;
89     } __attribute__ ((packed))
90    /**/struct Interface {
91        static u8 const Type = 4;
92        u8 length;
93        u8 type;
94        u8 interface;
95        u8 alternate;
96        u8 num_endpoints;
97        u8 iface_class;
98        u8 subclass;
99        u8 protocol;
100        string name;
101     } __attribute__ ((packed))
102    /**/struct Endpoint {
103        static u8 const Type = 5;
104        u8 length;
105        u8 type;
106        u8 address;
107        u8 attributes;
108        u16 max_packet_size;
109        u8 interval;
110     } __attribute__ ((packed))
111    /**/struct Device_Qualifier {
112        static u8 const Type = 6;
113        u8 length;
114        u8 type;
115        u16 version;
116        u8 dev_class;
117        u8 subclass;
118        u8 protocol;
119        u8 max_packet_size0;
120        u8 num_configurations;
121        u8 reserved;
122     } __attribute__ ((packed))
123    /**/struct Langs {
124        static u8 const Type = 3;
125        u8 length;
126        u8 type;
127        u8 lang;
128     } __attribute__ ((packed))
129    template <unsigned size> struct String {
130        static u8 const Type = 3;
131        u8 length;
132        u8 type;
133        u16 data[size];
134     } __attribute__ ((packed))
135    /**/struct CBW {
136        u32 sig;
137        u32 tag;
138        u32 length;
139        u8 flags;
140        u8 lun;
141        u8 size;
142        u8 data[16];
143        enum Code {
144            TEST_UNIT_READY = 0x00,
145            REQUEST_SENSE = 0x03,
146            FORMAT_UNIT = 0x04,
147            INQUIRY = 0x12,
148            RESERVE6 = 0x16,
149            RELEASE6 = 0x17,
150            SEND_DIAGNOSTIC = 0x1d,
151            READ_CAPACITY = 0x25,
152            READ10 = 0x28,
153            WRITE10 = 0x2a,
154            RESERVE10 = 0x56,
155            RELEASE10 = 0x57
156         };
157     } __attribute__ ((packed))
158    static unsigned const max_packet_size0 = 64
159    static unsigned const max_packet_size_bulk = 64
160    enum Requests:
161        GET_STATUS = 0
162        CLEAR_FEATURE = 1
163        SET_FEATURE = 3
164        SET_ADDRESS = 5
165        GET_DESCRIPTOR = 6
166        SET_DESCRIPTOR = 7
167        GET_CONFIGURATION = 8
168        SET_CONFIGURATION = 9
169        GET_INTERFACE = 10
170        SET_INTERFACE = 11
171        SYNCH_FRAME = 12
172    enum Storage_requests:
173        BULK_ONLY_RESET = 0xff
174        GET_MAX_LUN = 0xfe
175    enum Request_types:
176        STANDARD_TO_DEVICE = 0
177        CLASS_TO_DEVICE = 0x20
178        VENDOR_TO_DEVICE = 0x40
179        STANDARD_TO_INTERFACE = 1
180        CLASS_TO_INTERFACE = 0x21
181        VENDOR_TO_INTERFACE = 0x41
182        STANDARD_TO_ENDPOINT = 2
183        CLASS_TO_ENDPOINT = 0x22
184        VENDOR_TO_ENDPOINT = 0x42
185        STANDARD_FROM_DEVICE = 0x80
186        CLASS_FROM_DEVICE = 0xa0
187        VENDOR_FROM_DEVICE = 0xc0
188        STANDARD_FROM_INTERFACE = 0x81
189        CLASS_FROM_INTERFACE = 0xa1
190        VENDOR_FROM_INTERFACE = 0xc1
191        STANDARD_FROM_ENDPOINT = 0x82
192        CLASS_FROM_ENDPOINT = 0xa2
193        VENDOR_FROM_ENDPOINT = 0xc2
194    enum Endpoint_types:
195        CONTROL = 0
196        ISOCHRONOUS = 1
197        BULK = 2
198        INTERRUPT = 3
199    enum Endpoint_features:
200        ENDPOINT_HALT = 0
201    /**/struct my_config {
202        Configuration config;
203        Interface interface;
204        Endpoint endpoint[2];
205     } __attribute__ ((packed))
206    static Device device_descriptor
207    //static Device_Qualifier device_qualifier_descriptor
208    static my_config config_descriptor; //, other_config_descriptor
209    static String <1> s_langs
210    static String <6> s_manufacturer
211    static String <16> s_product
212    static String <12> s_serial
213    char configuration
214    unsigned get_descriptor (unsigned type, unsigned idx, unsigned len)
215    unsigned handle_setup (Setup *s)
216    void reset ()
217    void irq_in0 ()
218    void handle_rx ()
219    void handle_tx ()
220    void handle_cbw ()
221    void send_csw ()
222    unsigned big_endian (unsigned src)
223    bool handle_interrupt (bool usb, bool in)
224    void stall (unsigned error)
225    bool stalling
226    enum State:
227        IDLE
228        TX
229        RX
230        SENT_CSW
231        STALL
232    State state
233    unsigned residue
234    unsigned status
235    unsigned tag
236    unsigned data_done, lba, blocks
237    unsigned block_bits
238    Iris::WBlock block
239    Iris::Page buffer_page
240    // A random address to map the buffer.
241    static unsigned const buffer = 0x15000
242    public:
243    void init (Iris::WBlock b)
244    void log (unsigned c)
245    void interrupt ()
246    void send (unsigned ep, char const *data, unsigned length, unsigned maxlength)
247    void send_padded (char const *data, unsigned length, unsigned maxlength)
248
249Udc::Device Udc::device_descriptor
250Udc::my_config Udc::config_descriptor
251Udc::String <1> Udc::s_langs
252Udc::String <6> Udc::s_manufacturer
253Udc::String <16> Udc::s_product
254Udc::String <12> Udc::s_serial
255
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
285void Udc::init (Iris::WBlock b):
286    block = b
287    block_bits = block.get_align_bits ()
288    // Set up the buffer page.
289    buffer_page = Iris::my_memory.create_page ()
290    buffer_page.set_flags (Iris::Page::PAYING)
291    Iris::my_memory.map (buffer_page, buffer)
292    // Initialize the globals. My method of compiling doesn't handle global constructors.
293    device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 3, 1 }
294    config_descriptor = (my_config){
295        (Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 30 },
296        (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0x8, 0x6, 0x50, 0 }, {
297            (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
298            (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x82, BULK, max_packet_size_bulk, 0 }
299        }
300     }
301    s_langs = (String <1>){ sizeof (String <1>), String <1>::Type, { 0x0409 } }
302    s_manufacturer = (String <6>){ sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
303    s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
304    s_serial = (String <12>){ sizeof (String <12>), String <12>::Type, { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B' } }
305
306    cpm_start_udc ()
307    // Disconnect from the bus and don't try to get high-speed.
308    UDC_POWER = 0
309    reset ()
310    // Wait a while.
311    Iris::sleep (HZ / 10)
312    // Connect to the host.
313    UDC_POWER = UDC_POWER_SOFTCONN
314
315void Udc::send (unsigned ep, char const *data, unsigned length, unsigned maxlength):
316    if maxlength < length:
317        length = maxlength
318    unsigned i
319    for i = 0; (length - i & ~3) > 0 && i < length; i += 4:
320        UDC_FIFO (ep) = ((unsigned *)data)[i / 4]
321        //kdebug_num (((unsigned *)data)[i / 4], 8)
322        //kdebug (" ")
323    for ; i < length; ++i:
324        UDC_FIFO8 (ep) = data[i]
325        //kdebug_num (data[i], 2)
326        //kdebug (" ")
327
328void Udc::send_padded (char const *data, unsigned length, unsigned maxlength):
329    UDC_INDEX = 2
330    unsigned len = length < maxlength ? length : maxlength
331    residue = maxlength - len
332    len = (len + 3) & ~3
333    send (2, data, len, maxlength)
334    //Iris::debug ("sending %x, valid %x\n", maxlength, len)
335    while len + 3 < maxlength:
336        UDC_FIFO (2) = 0
337        len += 4
338        //kdebug_char ('-')
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
346
347unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
348    switch type:
349        case Configuration::Type:
350            if idx != 0:
351                return false
352            //Iris::debug ("get config descriptor\n")
353            send (0, reinterpret_cast <char const *> (&config_descriptor), sizeof (config_descriptor), len)
354            return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
355        case Device::Type:
356            if idx != 0:
357                return false
358            //Iris::debug ("get device descriptor\n")
359            send (0, reinterpret_cast <char const *> (&device_descriptor), sizeof (device_descriptor), len)
360            return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
361        case Device_Qualifier::Type:
362            //if idx != 0:
363            // return false
364            //send (0, reinterpret_cast <char const *> (&device_qualifier_descriptor), sizeof (device_qualifier_descriptor), len)
365            //return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
366            //break
367            return ~0
368        // The 6 is an arbitrary number, except that String <6> is instantiated already.
369        case String <6>::Type:
370            switch idx:
371                case 0:
372                    //Iris::debug ("get language descriptor\n")
373                    send (0, reinterpret_cast <char const *> (&s_langs), sizeof (s_langs), len)
374                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
375                case 1:
376                    //Iris::debug ("get manufacturer descriptor\n")
377                    send (0, reinterpret_cast <char const *> (&s_manufacturer), sizeof (s_manufacturer), len)
378                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
379                case 2:
380                    //Iris::debug ("get product descriptor\n")
381                    send (0, reinterpret_cast <char const *> (&s_product), sizeof (s_product), len)
382                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
383                case 3:
384                    //Iris::debug ("get serial descriptor\n")
385                    send (0, reinterpret_cast <char const *> (&s_serial), sizeof (s_serial), len)
386                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
387                default:
388                    return ~0
389        default:
390            return ~0
391
392unsigned Udc::handle_setup (Setup *s):
393    switch s->request_type:
394        case STANDARD_TO_DEVICE:
395            UDC_INDEX = 0
396            UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
397            switch s->request:
398                case SET_ADDRESS:
399                    UDC_FADDR = s->value
400                    Iris::debug ("set address %x\n", s->value)
401                    return 0
402                case SET_CONFIGURATION:
403                    if s->value >= 2:
404                        return ~0
405                    configuration = s->value
406                    Iris::debug ("set configuration %x\n", s->value)
407                    return 0
408                case SET_INTERFACE:
409                    if s->value != 0:
410                        return ~0
411                    Iris::debug ("set interface %x\n", s->value)
412                    return 0
413                default:
414                    return ~0
415        case STANDARD_FROM_DEVICE:
416            UDC_INDEX = 0
417            UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
418            switch s->request:
419                case GET_STATUS:
420                    Iris::debug ("get status\t")
421                    send (0, "\0\0", 2, s->length)
422                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
423                case GET_DESCRIPTOR:
424                    return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
425                case GET_CONFIGURATION:
426                    Iris::debug ("get configuration\t")
427                    send (0, &configuration, 1, s->length)
428                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
429                case GET_INTERFACE:
430                    Iris::debug ("get interface\t")
431                    send (0, "\0", 1, s->length)
432                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
433                default:
434                    return ~0
435        case STANDARD_TO_ENDPOINT:
436            switch s->request:
437                case CLEAR_FEATURE:
438                    switch s->value:
439                        case ENDPOINT_HALT:
440                            switch s->index:
441                                case 0x82:
442                                    //Iris::debug ("in ep halt reset\n")
443                                    UDC_INDEX = 2
444                                    UDC_INCSR = (UDC_INCSR & ~UDC_INCSR_SENDSTALL) | UDC_INCSR_CDT
445                                    stalling = false
446                                    send_csw ()
447                                    break
448                                case 1:
449                                    //Iris::panic (0, "halt reset on out endpoint")
450                                    UDC_INDEX = 1
451                                    UDC_OUTCSR |= UDC_OUTCSR_CDT
452                                    break
453                                default:
454                                    return ~0
455                            return UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
456                        default:
457                            return ~0
458                default:
459                    return ~0
460        case CLASS_FROM_INTERFACE:
461            UDC_INDEX = 0
462            UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
463            switch s->request:
464                case GET_MAX_LUN:
465                    //Iris::debug ("get max lun\t")
466                    send (0, "\0", 1, s->length)
467                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
468                default:
469                    return ~0
470        case CLASS_TO_INTERFACE:
471            UDC_INDEX = 0
472            UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
473            switch s->request:
474                case BULK_ONLY_RESET:
475                    Iris::debug ("bulk reset\n")
476                    state = IDLE
477                    return 0
478                default:
479                    return ~0
480        default:
481            Iris::debug ("request: %x %x %x %x %x\n", s->request_type, s->request, s->index, s->length, s->value)
482            return ~0
483
484void Udc::irq_in0 ():
485    // Interrupt on endpoint 0.
486    UDC_INDEX = 0
487    unsigned csr = UDC_CSR0
488    if csr & UDC_CSR0_SENTSTALL:
489        UDC_CSR0 = 0
490        //Iris::debug ("stall 0 done\t")
491    if csr & UDC_CSR0_SETUPEND:
492        UDC_CSR0 = UDC_CSR0_SVDSETUPEND
493        Iris::debug ("setup aborted\t")
494    if !(csr & UDC_CSR0_OUTPKTRDY):
495        //Iris::debug ("no packet 0: %x\n", csr)
496        return
497    UDC_INDEX = 0
498    union { unsigned d[2]; Setup s; } packet
499    packet.d[0] = UDC_FIFO (0)
500    packet.d[1] = UDC_FIFO (0)
501    if !(packet.s.request_type & 0x80) && packet.s.length > 0:
502        // More data will follow; unsupported.
503        Iris::debug ("packet on ep0 too long\n")
504        UDC_CSR0 = UDC_CSR0_SENDSTALL
505        return
506    unsigned ret = handle_setup (&packet.s)
507    UDC_INDEX = 0
508    if ret == ~0:
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)
510        UDC_CSR0 = UDC_CSR0_SENDSTALL
511        return
512    if ret:
513        UDC_CSR0 = ret
514    //kdebug ("done in0\n")
515
516void Udc::send_csw ():
517    UDC_INDEX = 2
518    UDC_FIFO (2) = 0x53425355
519    UDC_FIFO (2) = tag
520    UDC_FIFO (2) = residue
521    UDC_FIFO8 (2) = status
522    UDC_INCSR |= UDC_INCSR_INPKTRDY
523    state = SENT_CSW
524    status = 0
525    residue = 0
526    //kdebug ("sent csw\n")
527
528void Udc::stall (unsigned error):
529    if stalling:
530        Iris::debug ("already stalling!\n")
531    UDC_INCSR |= UDC_INCSR_SENDSTALL
532    stalling = true
533    state = STALL
534
535unsigned Udc::big_endian (unsigned src):
536    return src >> 24 | src >> 8 & 0xff00 | src << 8 & 0xff0000 | src << 24
537
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 ():
578    UDC_INDEX = 1
579    unsigned csr = UDC_OUTCSR
580    unsigned size = UDC_OUTCOUNT
581    if csr & UDC_OUTCSR_SENDSTALL:
582        // When stalling, do nothing else.
583        //kdebug ("not responding to out during stall\n")
584        UDC_OUTCSR = csr & ~UDC_OUTCSR_SENTSTALL
585        return
586    if !(csr & UDC_OUTCSR_OUTPKTRDY):
587        // No packet; this shouldn't happen.
588        Iris::panic (0, "no packet")
589        return
590    // expect a new cbw.
591    if size != 31:
592        Iris::debug ("count %d != 31\n", size)
593        stall (2)
594        return
595    union Cbw:
596        unsigned u[8]
597        char b[32]
598        CBW cbw
599    Cbw cbw
600    for unsigned i = 0; i < 7; ++i:
601        cbw.u[i] = UDC_FIFO (1)
602    for unsigned i = 28; i < 31; ++i:
603        cbw.b[i] = UDC_FIFO8 (1)
604    UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
605    tag = cbw.cbw.tag
606    if cbw.cbw.sig != 0x43425355 || cbw.cbw.lun != 0 || cbw.cbw.size == 0 || cbw.cbw.size > 16:
607        Iris::debug ("wrong cbw: sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
608        stall (2)
609        return
610    //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
618    UDC_INDEX = 2
619    bool to_host = cbw.cbw.flags & 0x80
620    switch cbw.cbw.data[0]:
621        case CBW::TEST_UNIT_READY:
622            if to_host || cbw.cbw.length != 0:
623                stall (2)
624                return
625            //Iris::debug ("sending ready response\t")
626            send_csw ()
627            break
628        case CBW::REQUEST_SENSE:
629            //Iris::debug ("sense requested\n")
630            send_padded ("\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length)
631            break
632        case CBW::FORMAT_UNIT:
633            Iris::panic (0, "FORMAT_UNIT isn't implemented")
634        case CBW::INQUIRY:
635            if !to_host:
636                stall (2)
637                return
638            //Iris::debug ("sending inquiry response\t")
639            // TODO: find out why these bytes are messed up.
640            send_padded ("\x00\x00\x04\x02\x1f\x00\x00\x00shevek iris usb stick \x00\x00\x04\x02", 36, cbw.cbw.length)
641            break
642        case CBW::RESERVE6:
643            Iris::panic (0, "RESERVE6 isn't implemented")
644        case CBW::RELEASE6:
645            Iris::panic (0, "RELEASE6 isn't implemented")
646        case CBW::SEND_DIAGNOSTIC:
647            Iris::panic (0, "SEND_DIAGNOSTIC isn't implemented")
648        case CBW::READ_CAPACITY:
649            if !to_host:
650                stall (2)
651                return
652            unsigned capacity[2]
653            capacity[0] = big_endian ((block.get_size ().value () >> block_bits) - 1)
654            capacity[1] = big_endian (1 << block_bits)
655            //Iris::debug ("sending capacity: %x * %x\t", capacity[0], capacity[1])
656            send_padded ((char *)capacity, 8, cbw.cbw.length)
657            break
658        case CBW::READ10:
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 ()
667            break
668        case CBW::WRITE10:
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)
680            break
681        case CBW::RESERVE10:
682            Iris::panic (0, "RESERVE10 isn't implemented")
683        case CBW::RELEASE10:
684            Iris::panic (0, "RELEASE10 isn't implemented")
685        default:
686            #if 0
687            Iris::debug ("unknown cbw:")
688            for unsigned i = 0; i < cbw.cbw.size; ++i:
689                kdebug_char (' ')
690                kdebug_num (cbw.cbw.data[i], 2)
691            Iris::debug ("\n")
692            #endif
693            residue = cbw.cbw.length
694            stall (1)
695            return
696
697void Udc::interrupt ():
698    //Iris::debug ("interrupt, state = %d\n", state)
699    while true:
700        bool action = false
701        unsigned usb = UDC_INTRUSB
702        unsigned in = UDC_INTRIN
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
716        if in & 4:
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
731            action = true
732        if out & 2:
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
745            action = true
746        if !action:
747            // No more interrupts to handle; this is normal, because we're looping until this happens.
748            //Iris::debug ("irq done\n")
749            return
750
751Iris::Num start ():
752    map_udc ()
753    map_gpio ()
754    map_cpm ()
755    Udc udc
756
757    Iris::WBlock nand = Iris::my_parent.get_capability <Iris::WBlock> ()
758    udc.init (nand)
759    while true:
760        Iris::register_interrupt (IRQ_UDC)
761        Iris::wait ()
762        udc.interrupt ()
source/usbmassstorage.ccp
1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// source/usb-mass-storage.ccp: USB mass storage device driver.
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 "iris.hh"
20#include "devices.hh"
21#define ARCH
22#include "arch.hh"
23
24#if 0
25States and expected interrupts:
26
27IDLE: after reset or csw.
28    IN interrupt: csw received, do nothing.
29    OUT interrupt: cbw; handle
30        -> IDLE (no data; csw sent)
31        -> TX (send)
32        -> RX (receive packets)
33TX: transmitting data.
34    IN interrupt: host received data; send more.
35        -> TX (more to send)
36RX: receiving data.
37    OUT interrupt: host sent data; handle.
38        -> RX (more to receive)
39        -> IDLE (done receiving; send csw)
40#endif
41
42extern "C":
43    void *memset (char *s, int c, unsigned long n):
44        Iris::debug ("memset called: %x %x->%x\n", s, n, c)
45        for unsigned i = 0; i < n; ++i:
46            s[i] = c
47        return s
48
49class Udc:
50    typedef unsigned char u8
51    typedef unsigned short u16
52    typedef unsigned int u32
53    typedef u8 string
54    // The ugly stuff is because pypp doesn't support __attribute__.
55    /**/struct Setup {
56        u8 request_type;
57        u8 request;
58        u16 value;
59        u16 index;
60        u16 length;
61     } __attribute__ ((packed))
62    /**/struct Device {
63        static u8 const Type = 1;
64        u8 length;
65        u8 type;
66        u16 usb_version;
67        u8 dev_class;
68        u8 subclass;
69        u8 protocol;
70        u8 max_packet_size0;
71        u16 vendor;
72        u16 product;
73        u16 dev_version;
74        string s_manufacturer;
75        string s_product;
76        string s_serial;
77        u8 num_configurations;
78     } __attribute__ ((packed))
79    /**/struct Configuration {
80        static u8 const Type = 2;
81        u8 length;
82        u8 type;
83        u16 total_length;
84        u8 num_interfaces;
85        u8 configuration_value;
86        u8 configuration;
87        u8 attributes;
88        u8 max_power;
89     } __attribute__ ((packed))
90    /**/struct Interface {
91        static u8 const Type = 4;
92        u8 length;
93        u8 type;
94        u8 interface;
95        u8 alternate;
96        u8 num_endpoints;
97        u8 iface_class;
98        u8 subclass;
99        u8 protocol;
100        string name;
101     } __attribute__ ((packed))
102    /**/struct Endpoint {
103        static u8 const Type = 5;
104        u8 length;
105        u8 type;
106        u8 address;
107        u8 attributes;
108        u16 max_packet_size;
109        u8 interval;
110     } __attribute__ ((packed))
111    /**/struct Device_Qualifier {
112        static u8 const Type = 6;
113        u8 length;
114        u8 type;
115        u16 version;
116        u8 dev_class;
117        u8 subclass;
118        u8 protocol;
119        u8 max_packet_size0;
120        u8 num_configurations;
121        u8 reserved;
122     } __attribute__ ((packed))
123    /**/struct Langs {
124        static u8 const Type = 3;
125        u8 length;
126        u8 type;
127        u8 lang;
128     } __attribute__ ((packed))
129    template <unsigned size> struct String {
130        static u8 const Type = 3;
131        u8 length;
132        u8 type;
133        u16 data[size];
134     } __attribute__ ((packed))
135    /**/struct CBW {
136        u32 sig;
137        u32 tag;
138        u32 length;
139        u8 flags;
140        u8 lun;
141        u8 size;
142        u8 data[16];
143        enum Code {
144            TEST_UNIT_READY = 0x00,
145            REQUEST_SENSE = 0x03,
146            FORMAT_UNIT = 0x04,
147            INQUIRY = 0x12,
148            RESERVE6 = 0x16,
149            RELEASE6 = 0x17,
150            SEND_DIAGNOSTIC = 0x1d,
151            READ_CAPACITY = 0x25,
152            READ10 = 0x28,
153            WRITE10 = 0x2a,
154            RESERVE10 = 0x56,
155            RELEASE10 = 0x57
156         };
157     } __attribute__ ((packed))
158    static unsigned const max_packet_size0 = 64
159    static unsigned const max_packet_size_bulk = 64
160    enum Requests:
161        GET_STATUS = 0
162        CLEAR_FEATURE = 1
163        SET_FEATURE = 3
164        SET_ADDRESS = 5
165        GET_DESCRIPTOR = 6
166        SET_DESCRIPTOR = 7
167        GET_CONFIGURATION = 8
168        SET_CONFIGURATION = 9
169        GET_INTERFACE = 10
170        SET_INTERFACE = 11
171        SYNCH_FRAME = 12
172    enum Storage_requests:
173        BULK_ONLY_RESET = 0xff
174        GET_MAX_LUN = 0xfe
175    enum Request_types:
176        STANDARD_TO_DEVICE = 0
177        CLASS_TO_DEVICE = 0x20
178        VENDOR_TO_DEVICE = 0x40
179        STANDARD_TO_INTERFACE = 1
180        CLASS_TO_INTERFACE = 0x21
181        VENDOR_TO_INTERFACE = 0x41
182        STANDARD_TO_ENDPOINT = 2
183        CLASS_TO_ENDPOINT = 0x22
184        VENDOR_TO_ENDPOINT = 0x42
185        STANDARD_FROM_DEVICE = 0x80
186        CLASS_FROM_DEVICE = 0xa0
187        VENDOR_FROM_DEVICE = 0xc0
188        STANDARD_FROM_INTERFACE = 0x81
189        CLASS_FROM_INTERFACE = 0xa1
190        VENDOR_FROM_INTERFACE = 0xc1
191        STANDARD_FROM_ENDPOINT = 0x82
192        CLASS_FROM_ENDPOINT = 0xa2
193        VENDOR_FROM_ENDPOINT = 0xc2
194    enum Endpoint_types:
195        CONTROL = 0
196        ISOCHRONOUS = 1
197        BULK = 2
198        INTERRUPT = 3
199    enum Endpoint_features:
200        ENDPOINT_HALT = 0
201    /**/struct my_config {
202        Configuration config;
203        Interface interface;
204        Endpoint endpoint[2];
205     } __attribute__ ((packed))
206    static Device device_descriptor
207    //static Device_Qualifier device_qualifier_descriptor
208    static my_config config_descriptor; //, other_config_descriptor
209    static String <1> s_langs
210    static String <6> s_manufacturer
211    static String <16> s_product
212    static String <12> s_serial
213    char configuration
214    unsigned get_descriptor (unsigned type, unsigned idx, unsigned len)
215    unsigned handle_setup (Setup *s)
216    void reset ()
217    void irq_in0 ()
218    void handle_rx ()
219    void handle_tx ()
220    void handle_cbw ()
221    void send_csw ()
222    unsigned big_endian (unsigned src)
223    bool handle_interrupt (bool usb, bool in)
224    void stall (unsigned error)
225    bool stalling
226    enum State:
227        IDLE
228        TX
229        RX
230        SENT_CSW
231        STALL
232    State state
233    unsigned residue
234    unsigned status
235    unsigned tag
236    unsigned data_done, lba, blocks
237    unsigned block_bits
238    Iris::WBlock block
239    Iris::Page buffer_page
240    // A random address to map the buffer.
241    static unsigned const buffer = 0x15000
242    public:
243    void init (Iris::WBlock b)
244    void log (unsigned c)
245    void interrupt ()
246    void send (unsigned ep, char const *data, unsigned length, unsigned maxlength)
247    void send_padded (char const *data, unsigned length, unsigned maxlength)
248
249Udc::Device Udc::device_descriptor
250Udc::my_config Udc::config_descriptor
251Udc::String <1> Udc::s_langs
252Udc::String <6> Udc::s_manufacturer
253Udc::String <16> Udc::s_product
254Udc::String <12> Udc::s_serial
255
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
285void Udc::init (Iris::WBlock b):
286    block = b
287    block_bits = block.get_align_bits ()
288    // Set up the buffer page.
289    buffer_page = Iris::my_memory.create_page ()
290    buffer_page.set_flags (Iris::Page::PAYING)
291    Iris::my_memory.map (buffer_page, buffer)
292    // Initialize the globals. My method of compiling doesn't handle global constructors.
293    device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 3, 1 }
294    config_descriptor = (my_config){
295        (Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 30 },
296        (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0x8, 0x6, 0x50, 0 }, {
297            (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
298            (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x82, BULK, max_packet_size_bulk, 0 }
299        }
300     }
301    s_langs = (String <1>){ sizeof (String <1>), String <1>::Type, { 0x0409 } }
302    s_manufacturer = (String <6>){ sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } }
303    s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } }
304    s_serial = (String <12>){ sizeof (String <12>), String <12>::Type, { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B' } }
305
306    cpm_start_udc ()
307    // Disconnect from the bus and don't try to get high-speed.
308    UDC_POWER = 0
309    reset ()
310    // Wait a while.
311    Iris::sleep (HZ / 10)
312    // Connect to the host.
313    UDC_POWER = UDC_POWER_SOFTCONN
314
315void Udc::send (unsigned ep, char const *data, unsigned length, unsigned maxlength):
316    if maxlength < length:
317        length = maxlength
318    unsigned i
319    for i = 0; (length - i & ~3) > 0 && i < length; i += 4:
320        UDC_FIFO (ep) = ((unsigned *)data)[i / 4]
321        //kdebug_num (((unsigned *)data)[i / 4], 8)
322        //kdebug (" ")
323    for ; i < length; ++i:
324        UDC_FIFO8 (ep) = data[i]
325        //kdebug_num (data[i], 2)
326        //kdebug (" ")
327
328void Udc::send_padded (char const *data, unsigned length, unsigned maxlength):
329    UDC_INDEX = 2
330    unsigned len = length < maxlength ? length : maxlength
331    residue = maxlength - len
332    len = (len + 3) & ~3
333    send (2, data, len, maxlength)
334    //Iris::debug ("sending %x, valid %x\n", maxlength, len)
335    while len + 3 < maxlength:
336        UDC_FIFO (2) = 0
337        len += 4
338        //kdebug_char ('-')
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
346
347unsigned Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
348    switch type:
349        case Configuration::Type:
350            if idx != 0:
351                return false
352            //Iris::debug ("get config descriptor\n")
353            send (0, reinterpret_cast <char const *> (&config_descriptor), sizeof (config_descriptor), len)
354            return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
355        case Device::Type:
356            if idx != 0:
357                return false
358            //Iris::debug ("get device descriptor\n")
359            send (0, reinterpret_cast <char const *> (&device_descriptor), sizeof (device_descriptor), len)
360            return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
361        case Device_Qualifier::Type:
362            //if idx != 0:
363            // return false
364            //send (0, reinterpret_cast <char const *> (&device_qualifier_descriptor), sizeof (device_qualifier_descriptor), len)
365            //return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
366            //break
367            return ~0
368        // The 6 is an arbitrary number, except that String <6> is instantiated already.
369        case String <6>::Type:
370            switch idx:
371                case 0:
372                    //Iris::debug ("get language descriptor\n")
373                    send (0, reinterpret_cast <char const *> (&s_langs), sizeof (s_langs), len)
374                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
375                case 1:
376                    //Iris::debug ("get manufacturer descriptor\n")
377                    send (0, reinterpret_cast <char const *> (&s_manufacturer), sizeof (s_manufacturer), len)
378                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
379                case 2:
380                    //Iris::debug ("get product descriptor\n")
381                    send (0, reinterpret_cast <char const *> (&s_product), sizeof (s_product), len)
382                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
383                case 3:
384                    //Iris::debug ("get serial descriptor\n")
385                    send (0, reinterpret_cast <char const *> (&s_serial), sizeof (s_serial), len)
386                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
387                default:
388                    return ~0
389        default:
390            return ~0
391
392unsigned Udc::handle_setup (Setup *s):
393    switch s->request_type:
394        case STANDARD_TO_DEVICE:
395            UDC_INDEX = 0
396            UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
397            switch s->request:
398                case SET_ADDRESS:
399                    UDC_FADDR = s->value
400                    Iris::debug ("set address %x\n", s->value)
401                    return 0
402                case SET_CONFIGURATION:
403                    if s->value >= 2:
404                        return ~0
405                    configuration = s->value
406                    Iris::debug ("set configuration %x\n", s->value)
407                    return 0
408                case SET_INTERFACE:
409                    if s->value != 0:
410                        return ~0
411                    Iris::debug ("set interface %x\n", s->value)
412                    return 0
413                default:
414                    return ~0
415        case STANDARD_FROM_DEVICE:
416            UDC_INDEX = 0
417            UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
418            switch s->request:
419                case GET_STATUS:
420                    Iris::debug ("get status\t")
421                    send (0, "\0\0", 2, s->length)
422                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
423                case GET_DESCRIPTOR:
424                    return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length)
425                case GET_CONFIGURATION:
426                    Iris::debug ("get configuration\t")
427                    send (0, &configuration, 1, s->length)
428                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
429                case GET_INTERFACE:
430                    Iris::debug ("get interface\t")
431                    send (0, "\0", 1, s->length)
432                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
433                default:
434                    return ~0
435        case STANDARD_TO_ENDPOINT:
436            switch s->request:
437                case CLEAR_FEATURE:
438                    switch s->value:
439                        case ENDPOINT_HALT:
440                            switch s->index:
441                                case 0x82:
442                                    //Iris::debug ("in ep halt reset\n")
443                                    UDC_INDEX = 2
444                                    UDC_INCSR = (UDC_INCSR & ~UDC_INCSR_SENDSTALL) | UDC_INCSR_CDT
445                                    stalling = false
446                                    send_csw ()
447                                    break
448                                case 1:
449                                    //Iris::panic (0, "halt reset on out endpoint")
450                                    UDC_INDEX = 1
451                                    UDC_OUTCSR |= UDC_OUTCSR_CDT
452                                    break
453                                default:
454                                    return ~0
455                            return UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
456                        default:
457                            return ~0
458                default:
459                    return ~0
460        case CLASS_FROM_INTERFACE:
461            UDC_INDEX = 0
462            UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
463            switch s->request:
464                case GET_MAX_LUN:
465                    //Iris::debug ("get max lun\t")
466                    send (0, "\0", 1, s->length)
467                    return UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND
468                default:
469                    return ~0
470        case CLASS_TO_INTERFACE:
471            UDC_INDEX = 0
472            UDC_CSR0 = UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
473            switch s->request:
474                case BULK_ONLY_RESET:
475                    Iris::debug ("bulk reset\n")
476                    state = IDLE
477                    return 0
478                default:
479                    return ~0
480        default:
481            Iris::debug ("request: %x %x %x %x %x\n", s->request_type, s->request, s->index, s->length, s->value)
482            return ~0
483
484void Udc::irq_in0 ():
485    // Interrupt on endpoint 0.
486    UDC_INDEX = 0
487    unsigned csr = UDC_CSR0
488    if csr & UDC_CSR0_SENTSTALL:
489        UDC_CSR0 = 0
490        //Iris::debug ("stall 0 done\t")
491    if csr & UDC_CSR0_SETUPEND:
492        UDC_CSR0 = UDC_CSR0_SVDSETUPEND
493        Iris::debug ("setup aborted\t")
494    if !(csr & UDC_CSR0_OUTPKTRDY):
495        //Iris::debug ("no packet 0: %x\n", csr)
496        return
497    UDC_INDEX = 0
498    union { unsigned d[2]; Setup s; } packet
499    packet.d[0] = UDC_FIFO (0)
500    packet.d[1] = UDC_FIFO (0)
501    if !(packet.s.request_type & 0x80) && packet.s.length > 0:
502        // More data will follow; unsupported.
503        Iris::debug ("packet on ep0 too long\n")
504        UDC_CSR0 = UDC_CSR0_SENDSTALL
505        return
506    unsigned ret = handle_setup (&packet.s)
507    UDC_INDEX = 0
508    if ret == ~0:
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)
510        UDC_CSR0 = UDC_CSR0_SENDSTALL
511        return
512    if ret:
513        UDC_CSR0 = ret
514    //kdebug ("done in0\n")
515
516void Udc::send_csw ():
517    UDC_INDEX = 2
518    UDC_FIFO (2) = 0x53425355
519    UDC_FIFO (2) = tag
520    UDC_FIFO (2) = residue
521    UDC_FIFO8 (2) = status
522    UDC_INCSR |= UDC_INCSR_INPKTRDY
523    state = SENT_CSW
524    status = 0
525    residue = 0
526    //kdebug ("sent csw\n")
527
528void Udc::stall (unsigned error):
529    if stalling:
530        Iris::debug ("already stalling!\n")
531    UDC_INCSR |= UDC_INCSR_SENDSTALL
532    stalling = true
533    state = STALL
534
535unsigned Udc::big_endian (unsigned src):
536    return src >> 24 | src >> 8 & 0xff00 | src << 8 & 0xff0000 | src << 24
537
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 ():
578    UDC_INDEX = 1
579    unsigned csr = UDC_OUTCSR
580    unsigned size = UDC_OUTCOUNT
581    if csr & UDC_OUTCSR_SENDSTALL:
582        // When stalling, do nothing else.
583        //kdebug ("not responding to out during stall\n")
584        UDC_OUTCSR = csr & ~UDC_OUTCSR_SENTSTALL
585        return
586    if !(csr & UDC_OUTCSR_OUTPKTRDY):
587        // No packet; this shouldn't happen.
588        Iris::panic (0, "no packet")
589        return
590    // expect a new cbw.
591    if size != 31:
592        Iris::debug ("count %d != 31\n", size)
593        stall (2)
594        return
595    union Cbw:
596        unsigned u[8]
597        char b[32]
598        CBW cbw
599    Cbw cbw
600    for unsigned i = 0; i < 7; ++i:
601        cbw.u[i] = UDC_FIFO (1)
602    for unsigned i = 28; i < 31; ++i:
603        cbw.b[i] = UDC_FIFO8 (1)
604    UDC_OUTCSR = csr & ~UDC_OUTCSR_OUTPKTRDY
605    tag = cbw.cbw.tag
606    if cbw.cbw.sig != 0x43425355 || cbw.cbw.lun != 0 || cbw.cbw.size == 0 || cbw.cbw.size > 16:
607        Iris::debug ("wrong cbw: sig %x lun %d size %d\n", cbw.cbw.sig, cbw.cbw.lun, cbw.cbw.size)
608        stall (2)
609        return
610    //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
618    UDC_INDEX = 2
619    bool to_host = cbw.cbw.flags & 0x80
620    switch cbw.cbw.data[0]:
621        case CBW::TEST_UNIT_READY:
622            if to_host || cbw.cbw.length != 0:
623                stall (2)
624                return
625            //Iris::debug ("sending ready response\t")
626            send_csw ()
627            break
628        case CBW::REQUEST_SENSE:
629            //Iris::debug ("sense requested\n")
630            send_padded ("\xf0\x00\x05\x00\x00\x00\x00\x00", 8, cbw.cbw.length)
631            break
632        case CBW::FORMAT_UNIT:
633            Iris::panic (0, "FORMAT_UNIT isn't implemented")
634        case CBW::INQUIRY:
635            if !to_host:
636                stall (2)
637                return
638            //Iris::debug ("sending inquiry response\t")
639            // TODO: find out why these bytes are messed up.
640            send_padded ("\x00\x00\x04\x02\x1f\x00\x00\x00shevek iris usb stick \x00\x00\x04\x02", 36, cbw.cbw.length)
641            break
642        case CBW::RESERVE6:
643            Iris::panic (0, "RESERVE6 isn't implemented")
644        case CBW::RELEASE6:
645            Iris::panic (0, "RELEASE6 isn't implemented")
646        case CBW::SEND_DIAGNOSTIC:
647            Iris::panic (0, "SEND_DIAGNOSTIC isn't implemented")
648        case CBW::READ_CAPACITY:
649            if !to_host:
650                stall (2)
651                return
652            unsigned capacity[2]
653            capacity[0] = big_endian ((block.get_size ().value () >> block_bits) - 1)
654            capacity[1] = big_endian (1 << block_bits)
655            //Iris::debug ("sending capacity: %x * %x\t", capacity[0], capacity[1])
656            send_padded ((char *)capacity, 8, cbw.cbw.length)
657            break
658        case CBW::READ10:
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 ()
667            break
668        case CBW::WRITE10:
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)
680            break
681        case CBW::RESERVE10:
682            Iris::panic (0, "RESERVE10 isn't implemented")
683        case CBW::RELEASE10:
684            Iris::panic (0, "RELEASE10 isn't implemented")
685        default:
686            #if 0
687            Iris::debug ("unknown cbw:")
688            for unsigned i = 0; i < cbw.cbw.size; ++i:
689                kdebug_char (' ')
690                kdebug_num (cbw.cbw.data[i], 2)
691            Iris::debug ("\n")
692            #endif
693            residue = cbw.cbw.length
694            stall (1)
695            return
696
697void Udc::interrupt ():
698    //Iris::debug ("interrupt, state = %d\n", state)
699    while true:
700        bool action = false
701        unsigned usb = UDC_INTRUSB
702        unsigned in = UDC_INTRIN
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
716        if in & 4:
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
731            action = true
732        if out & 2:
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
745            action = true
746        if !action:
747            // No more interrupts to handle; this is normal, because we're looping until this happens.
748            //Iris::debug ("irq done\n")
749            return
750
751Iris::Num start ():
752    map_udc ()
753    map_gpio ()
754    map_cpm ()
755    Udc udc
756
757    Iris::WBlock nand = Iris::my_parent.get_capability <Iris::WBlock> ()
758    udc.init (nand)
759    while true:
760        Iris::register_interrupt (IRQ_UDC)
761        Iris::wait ()
762        udc.interrupt ()

Archive Download the corresponding diff file

Branches:
master



interactive