mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-21 12:27:27 +03:00
split off nanonote code, try to make it boot
This commit is contained in:
@@ -84,6 +84,8 @@ Kernel::Num start ():
|
||||
if code & Keyboard::RELEASE:
|
||||
break
|
||||
kdebug_char (decode_kbd[code])
|
||||
if code == 0:
|
||||
Kernel::Caps ().print (~0)
|
||||
break
|
||||
case TP:
|
||||
unsigned leds = 0
|
||||
|
||||
@@ -32,7 +32,7 @@ struct Init : public Kernel::Cap:
|
||||
GPIO_LOCKLEDS
|
||||
GPIO_PWM
|
||||
LCD_SET_EOF_CB
|
||||
LCD_LOG
|
||||
LOG
|
||||
void register_gpio ():
|
||||
Kernel::Caps c = Kernel::my_memory.create_caps (4)
|
||||
unsigned slot = c.use ()
|
||||
|
||||
@@ -40,6 +40,7 @@ struct Descriptor:
|
||||
unsigned id
|
||||
unsigned cmd
|
||||
|
||||
#if defined (TRENDTAC)
|
||||
static void reset ():
|
||||
LCD_CTRL = LCD_CTRL_BPP_16 | LCD_CTRL_BST_16
|
||||
LCD_VSYNC = vs
|
||||
@@ -68,6 +69,12 @@ static void reset ():
|
||||
LCD_DA0 = physical_descriptor
|
||||
lcd_set_ena ()
|
||||
lcd_enable_eof_intr ()
|
||||
#elif defined (NANONOTE)
|
||||
static void reset ():
|
||||
// TODO
|
||||
#else
|
||||
#error unknown board
|
||||
#endif
|
||||
|
||||
static void putchar (unsigned x, unsigned y, unsigned ch, unsigned fg = 0xffff, unsigned bg = 0x0000):
|
||||
if ch < 32 || ch > 126:
|
||||
@@ -163,7 +170,6 @@ Kernel::Num start ():
|
||||
|
||||
((Init)Kernel::my_parent).register_lcd ()
|
||||
|
||||
unsigned slot = Kernel::alloc_slot ()
|
||||
Kernel::Cap eof_cb = Kernel::alloc_cap ()
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
|
||||
317
boot-programs/udc.ccp
Normal file
317
boot-programs/udc.ccp
Normal file
@@ -0,0 +1,317 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/udc.ccp: USB device controller driver.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "devices.hh"
|
||||
#include "init.hh"
|
||||
#define ARCH
|
||||
#include "arch.hh"
|
||||
|
||||
class Udc:
|
||||
typedef unsigned char u8
|
||||
typedef unsigned short u16
|
||||
typedef unsigned int u32
|
||||
typedef u8 string
|
||||
// The ugly stuff is because pypp doesn't support __attribute__.
|
||||
/**/struct Setup {
|
||||
u8 request_type;
|
||||
u8 request;
|
||||
u16 value;
|
||||
u16 index;
|
||||
u16 length;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Device {
|
||||
static u8 const Type = 1;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 usb_version;
|
||||
u8 dev_class;
|
||||
u8 subclass;
|
||||
u8 protocol;
|
||||
u8 max_packet_size0;
|
||||
u16 vendor;
|
||||
u16 product;
|
||||
u16 dev_version;
|
||||
string s_manufacturer;
|
||||
string s_product;
|
||||
string s_serial;
|
||||
u8 num_configurations;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Configuration {
|
||||
static u8 const Type = 2;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 total_length;
|
||||
u8 num_interfaces;
|
||||
u8 configuration_value;
|
||||
u8 configuration;
|
||||
u8 attributes;
|
||||
u8 max_power;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Interface {
|
||||
static u8 const Type = 4;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u8 interface;
|
||||
u8 alternate;
|
||||
u8 num_endpoints;
|
||||
u8 iface_class;
|
||||
u8 subclass;
|
||||
u8 protocol;
|
||||
string name;
|
||||
} __attribute__ ((packed))
|
||||
/**/struct Endpoint {
|
||||
static u8 const Type = 5;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u8 address;
|
||||
u8 attributes;
|
||||
u16 max_packet_size;
|
||||
u8 interval;
|
||||
} __attribute__ ((packed))
|
||||
template <unsigned size> struct String {
|
||||
static u8 const Type = 3;
|
||||
u8 length;
|
||||
u8 type;
|
||||
u16 data[size];
|
||||
} __attribute__ ((packed))
|
||||
static unsigned const max_packet_size0 = 64
|
||||
static unsigned const max_packet_size_bulk = 512
|
||||
enum Requests:
|
||||
GET_STATUS = 0
|
||||
CLEAR_FEATURE = 1
|
||||
SET_FEATURE = 3
|
||||
SET_ADDRESS = 5
|
||||
GET_DESCRIPTOR = 6
|
||||
SET_DESCRIPTOR = 7
|
||||
GET_CONFIGURATION = 8
|
||||
SET_CONFIGURATION = 9
|
||||
GET_INTERFACE = 10
|
||||
SET_INTERFACE = 11
|
||||
SYNCH_FRAME = 12
|
||||
enum Request_types:
|
||||
STANDARD_TO_DEVICE = 0
|
||||
VENDOR_TO_DEVICE = 0x40
|
||||
STANDARD_FROM_DEVICE = 0x80
|
||||
VENDOR_FROM_DEVICE = 0xc0
|
||||
enum Endpoint_types:
|
||||
CONTROL = 0
|
||||
ISOCHRONOUS = 1
|
||||
BULK = 2
|
||||
INTERRUPT = 3
|
||||
/**/struct my_config {
|
||||
Configuration config;
|
||||
Interface interface;
|
||||
Endpoint endpoint[2];
|
||||
} __attribute__ ((packed))
|
||||
static Device const device_descriptor
|
||||
static my_config const config_descriptor
|
||||
static String <7> const s_manufacturer
|
||||
static String <22> const s_product
|
||||
enum State:
|
||||
IDLE
|
||||
TX
|
||||
RX
|
||||
State state
|
||||
char configuration
|
||||
unsigned size
|
||||
char const *ptr
|
||||
unsigned send_next (unsigned old_csr)
|
||||
unsigned vendor (unsigned old_csr, Setup *s)
|
||||
unsigned get_descriptor (unsigned old_csr, unsigned type, unsigned idx, unsigned len)
|
||||
public:
|
||||
void init ()
|
||||
void log (unsigned c)
|
||||
void interrupt ()
|
||||
unsigned handle_setup (unsigned old_csr, Setup *s)
|
||||
|
||||
Udc::Device const Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0x601a, 0x4740, 0x100, 1, 2, 0, 1 }
|
||||
Udc::my_config const Udc::config_descriptor = {
|
||||
(Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 },
|
||||
(Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, {
|
||||
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 },
|
||||
(Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 }
|
||||
}
|
||||
}
|
||||
Udc::String <7> const Udc::s_manufacturer = { sizeof (String <7>), String <7>::Type, { 'I', 'n', 'g', 'e', 'n', 'i', 'c' } }
|
||||
Udc::String <22> const Udc::s_product = { sizeof (String <22>), String <22>::Type, { 'J', 'Z', '4', '7', '4', '0', ' ', 'U', 'S', 'B', ' ', 'B', 'o', 'o', 't', ' ', 'D', 'e', 'v', 'i', 'c', 'e'} }
|
||||
void Udc::init ():
|
||||
state = IDLE
|
||||
configuration = 0
|
||||
size = 0
|
||||
// exit suspend mode by reading the interrupt register.
|
||||
unsigned i = UDC_INTRUSB
|
||||
// reset all pending endpoint interrupts.
|
||||
i = UDC_INTRIN
|
||||
i = UDC_INTROUT
|
||||
// enable interrupt on bus reset.
|
||||
UDC_INTRUSB = UDC_INTR_RESET
|
||||
// enable interrupts on endpoint 0.
|
||||
UDC_INTRINE |= 1 << 0
|
||||
|
||||
unsigned Udc::send_next (unsigned old_csr):
|
||||
for unsigned i = 0; size > 0 && i < max_packet_size0; ++i, --size:
|
||||
// Use 8-bit transfers to avoid problems with alignment.
|
||||
REG8 (UDC_FIFO_EP0) = *ptr++
|
||||
if size:
|
||||
state = TX
|
||||
return (old_csr | UDC_CSR0_INPKTRDY) & ~UDC_CSR0_DATAEND
|
||||
else:
|
||||
state = IDLE
|
||||
return old_csr | UDC_CSR0_INPKTRDY
|
||||
|
||||
unsigned Udc::vendor (unsigned old_csr, Setup *s):
|
||||
if s->request_type & 0x80:
|
||||
ptr = "abcdefgh"
|
||||
size = 8
|
||||
return send_next (old_csr)
|
||||
return old_csr
|
||||
|
||||
unsigned Udc::get_descriptor (unsigned old_csr, unsigned type, unsigned idx, unsigned len):
|
||||
switch type:
|
||||
case Configuration::Type:
|
||||
if idx != 1:
|
||||
return old_csr | UDC_CSR0_SENDSTALL
|
||||
ptr = reinterpret_cast <char const *> (&config_descriptor)
|
||||
size = (len < sizeof (config_descriptor) ? len : sizeof (config_descriptor))
|
||||
break
|
||||
case Device::Type:
|
||||
if idx != 0:
|
||||
return old_csr | UDC_CSR0_SENDSTALL
|
||||
ptr = reinterpret_cast <char const *> (&device_descriptor)
|
||||
size = (len < sizeof (device_descriptor) ? len : sizeof (device_descriptor))
|
||||
break
|
||||
// The 7 is an arbitrary number.
|
||||
case String <7>::Type:
|
||||
switch idx:
|
||||
case 1:
|
||||
ptr = reinterpret_cast <char const *> (&s_manufacturer)
|
||||
size = (len < sizeof (s_manufacturer) ? len : sizeof (s_manufacturer))
|
||||
break
|
||||
case 2:
|
||||
ptr = reinterpret_cast <char const *> (&s_product)
|
||||
size = (len < sizeof (s_product) ? len : sizeof (s_product))
|
||||
break
|
||||
default:
|
||||
return old_csr | UDC_CSR0_SENDSTALL
|
||||
break
|
||||
default:
|
||||
return old_csr | UDC_CSR0_SENDSTALL
|
||||
return send_next (old_csr)
|
||||
|
||||
unsigned Udc::handle_setup (unsigned old_csr, Setup *s):
|
||||
switch s->request_type:
|
||||
case STANDARD_TO_DEVICE:
|
||||
switch s->request:
|
||||
case SET_ADDRESS:
|
||||
UDC_FADDR = s->value
|
||||
break
|
||||
case SET_CONFIGURATION:
|
||||
if s->value >= 2:
|
||||
return old_csr | UDC_CSR0_SENDSTALL
|
||||
configuration = s->value
|
||||
break
|
||||
case SET_INTERFACE:
|
||||
if s->value != 0:
|
||||
return old_csr | UDC_CSR0_SENDSTALL
|
||||
break
|
||||
default:
|
||||
return old_csr | UDC_CSR0_SENDSTALL
|
||||
break
|
||||
case STANDARD_FROM_DEVICE:
|
||||
switch s->request:
|
||||
case GET_STATUS:
|
||||
ptr = "\0\0"
|
||||
size = (s->length < 2 ? s->length : 2)
|
||||
return send_next (old_csr)
|
||||
case GET_DESCRIPTOR:
|
||||
return get_descriptor (old_csr, (s->value >> 8) & 0xff, s->value & 0xff, s->length)
|
||||
case GET_CONFIGURATION:
|
||||
ptr = &configuration
|
||||
size = (s->length < 1 ? s->length : 1)
|
||||
return send_next (old_csr)
|
||||
case GET_INTERFACE:
|
||||
ptr = "\0"
|
||||
size = (s->length < 1 ? s->length : 1)
|
||||
return send_next (old_csr)
|
||||
default:
|
||||
return old_csr | UDC_CSR0_SENDSTALL
|
||||
break
|
||||
case VENDOR_TO_DEVICE:
|
||||
case VENDOR_FROM_DEVICE:
|
||||
return vendor (old_csr, s)
|
||||
default:
|
||||
return old_csr | UDC_CSR0_SENDSTALL
|
||||
return old_csr
|
||||
|
||||
void Udc::interrupt ():
|
||||
unsigned i = UDC_INTRUSB
|
||||
if i & UDC_INTR_RESET:
|
||||
state = IDLE
|
||||
return
|
||||
i = UDC_INTRIN
|
||||
if i & (1 << 0):
|
||||
// Interrupt on endpoint 0.
|
||||
unsigned csr = UDC_CSR0
|
||||
if csr & UDC_CSR0_SENTSTALL:
|
||||
csr &= ~UDC_CSR0_SENTSTALL
|
||||
state = IDLE
|
||||
if csr & UDC_CSR0_SETUPEND:
|
||||
csr |= UDC_CSR0_SVDSETUPEND
|
||||
state = IDLE
|
||||
switch state:
|
||||
case IDLE:
|
||||
if !(csr & UDC_CSR0_OUTPKTRDY):
|
||||
break
|
||||
csr |= UDC_CSR0_SVDOUTPKTRDY | UDC_CSR0_DATAEND
|
||||
union { unsigned d[2]; Setup s; } packet
|
||||
packet.d[0] = UDC_FIFO_EP0
|
||||
packet.d[1] = UDC_FIFO_EP0
|
||||
csr = handle_setup (csr, &packet.s)
|
||||
UDC_CSR0 = csr
|
||||
break
|
||||
case TX:
|
||||
UDC_CSR0 = send_next (UDC_CSR0 | UDC_CSR0_DATAEND)
|
||||
break
|
||||
case RX:
|
||||
// Not supported.
|
||||
UDC_CSR0 |= UDC_CSR0_SENDSTALL
|
||||
state = IDLE
|
||||
break
|
||||
|
||||
void Udc::log (unsigned c):
|
||||
|
||||
Kernel::Num start ():
|
||||
map_udc ()
|
||||
Udc udc
|
||||
|
||||
udc.init ()
|
||||
Kernel::Cap logcap = Kernel::my_receiver.create_capability (Init::LOG)
|
||||
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
|
||||
Kernel::register_interrupt (IRQ_UDC)
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.l:
|
||||
case IRQ_UDC:
|
||||
udc.interrupt ()
|
||||
break
|
||||
case Init::LOG:
|
||||
udc.log (Kernel::recv.data[0].l)
|
||||
break
|
||||
default:
|
||||
udc.log ('~')
|
||||
break
|
||||
Reference in New Issue
Block a user