Root/
| 1 | #pypp 0 |
| 2 | // vim: set filetype=cpp : // |
| 3 | // Iris: micro-kernel for a capability-based operating system. |
| 4 | // boot-programs/udc.ccp: USB device controller driver. |
| 5 | // Copyright 2009 Bas Wijnen <wijnen@debian.org> |
| 6 | // |
| 7 | // This program is free software: you can redistribute it and/or modify |
| 8 | // it under the terms of the GNU General Public License as published by |
| 9 | // the Free Software Foundation, either version 3 of the License, or |
| 10 | // (at your option) any later version. |
| 11 | // |
| 12 | // This program is distributed in the hope that it will be useful, |
| 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | // GNU General Public License for more details. |
| 16 | // |
| 17 | // You should have received a copy of the GNU General Public License |
| 18 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | |
| 20 | #include "iris.hh" |
| 21 | #include "devices.hh" |
| 22 | #define ARCH |
| 23 | #include "arch.hh" |
| 24 | |
| 25 | class Udc: |
| 26 | typedef unsigned char u8 |
| 27 | typedef unsigned short u16 |
| 28 | typedef unsigned int u32 |
| 29 | typedef u8 string |
| 30 | // The ugly stuff is because pypp doesn't support __attribute__. |
| 31 | /**/struct Setup { |
| 32 | u8 request_type; |
| 33 | u8 request; |
| 34 | u16 value; |
| 35 | u16 index; |
| 36 | u16 length; |
| 37 | } __attribute__ ((packed)) |
| 38 | /**/struct Device { |
| 39 | static u8 const Type = 1; |
| 40 | u8 length; |
| 41 | u8 type; |
| 42 | u16 usb_version; |
| 43 | u8 dev_class; |
| 44 | u8 subclass; |
| 45 | u8 protocol; |
| 46 | u8 max_packet_size0; |
| 47 | u16 vendor; |
| 48 | u16 product; |
| 49 | u16 dev_version; |
| 50 | string s_manufacturer; |
| 51 | string s_product; |
| 52 | string s_serial; |
| 53 | u8 num_configurations; |
| 54 | } __attribute__ ((packed)) |
| 55 | /**/struct Configuration { |
| 56 | static u8 const Type = 2; |
| 57 | u8 length; |
| 58 | u8 type; |
| 59 | u16 total_length; |
| 60 | u8 num_interfaces; |
| 61 | u8 configuration_value; |
| 62 | u8 configuration; |
| 63 | u8 attributes; |
| 64 | u8 max_power; |
| 65 | } __attribute__ ((packed)) |
| 66 | /**/struct Interface { |
| 67 | static u8 const Type = 4; |
| 68 | u8 length; |
| 69 | u8 type; |
| 70 | u8 interface; |
| 71 | u8 alternate; |
| 72 | u8 num_endpoints; |
| 73 | u8 iface_class; |
| 74 | u8 subclass; |
| 75 | u8 protocol; |
| 76 | string name; |
| 77 | } __attribute__ ((packed)) |
| 78 | /**/struct Endpoint { |
| 79 | static u8 const Type = 5; |
| 80 | u8 length; |
| 81 | u8 type; |
| 82 | u8 address; |
| 83 | u8 attributes; |
| 84 | u16 max_packet_size; |
| 85 | u8 interval; |
| 86 | } __attribute__ ((packed)) |
| 87 | /**/struct Device_Qualifier { |
| 88 | static u8 const Type = 6; |
| 89 | u8 length; |
| 90 | u8 type; |
| 91 | u16 version; |
| 92 | u8 dev_class; |
| 93 | u8 subclass; |
| 94 | u8 protocol; |
| 95 | u8 max_packet_size0; |
| 96 | u8 num_configurations; |
| 97 | u8 reserved; |
| 98 | } __attribute__ ((packed)) |
| 99 | /**/struct Langs { |
| 100 | static u8 const Type = 3; |
| 101 | u8 length; |
| 102 | u8 type; |
| 103 | u8 lang; |
| 104 | } __attribute__ ((packed)) |
| 105 | template <unsigned size> struct String { |
| 106 | static u8 const Type = 3; |
| 107 | u8 length; |
| 108 | u8 type; |
| 109 | u16 data[size]; |
| 110 | } __attribute__ ((packed)) |
| 111 | static unsigned const max_packet_size0 = 64 |
| 112 | static unsigned const max_packet_size_bulk = 64 |
| 113 | enum Requests: |
| 114 | GET_STATUS = 0 |
| 115 | CLEAR_FEATURE = 1 |
| 116 | SET_FEATURE = 3 |
| 117 | SET_ADDRESS = 5 |
| 118 | GET_DESCRIPTOR = 6 |
| 119 | SET_DESCRIPTOR = 7 |
| 120 | GET_CONFIGURATION = 8 |
| 121 | SET_CONFIGURATION = 9 |
| 122 | GET_INTERFACE = 10 |
| 123 | SET_INTERFACE = 11 |
| 124 | SYNCH_FRAME = 12 |
| 125 | enum Request_types: |
| 126 | STANDARD_TO_DEVICE = 0 |
| 127 | VENDOR_TO_DEVICE = 0x40 |
| 128 | STANDARD_FROM_DEVICE = 0x80 |
| 129 | VENDOR_FROM_DEVICE = 0xc0 |
| 130 | enum Endpoint_types: |
| 131 | CONTROL = 0 |
| 132 | ISOCHRONOUS = 1 |
| 133 | BULK = 2 |
| 134 | INTERRUPT = 3 |
| 135 | /**/struct my_config { |
| 136 | Configuration config; |
| 137 | Interface interface; |
| 138 | Endpoint endpoint[2]; |
| 139 | } __attribute__ ((packed)) |
| 140 | static Device device_descriptor |
| 141 | //static Device_Qualifier device_qualifier_descriptor |
| 142 | static my_config config_descriptor; //, other_config_descriptor |
| 143 | static String <1> s_langs |
| 144 | static String <6> s_manufacturer |
| 145 | static String <16> s_product |
| 146 | enum State: |
| 147 | IDLE |
| 148 | TX |
| 149 | RX |
| 150 | State state |
| 151 | char configuration |
| 152 | unsigned size |
| 153 | unsigned rx_request |
| 154 | char const *ptr |
| 155 | unsigned cmd_code, cmd_arg |
| 156 | bool rebooting |
| 157 | bool vendor (Setup *s, unsigned cmd) |
| 158 | bool get_descriptor (unsigned type, unsigned idx, unsigned len) |
| 159 | bool handle_setup (Setup *s, unsigned cmd) |
| 160 | void irq_usb (unsigned cmd) |
| 161 | void irq_in (unsigned cmd) |
| 162 | void irq_out (unsigned cmd) |
| 163 | char log_buffer[1000] |
| 164 | unsigned log_buffer_size |
| 165 | unsigned log_buffer_start |
| 166 | Iris::Cap caller, caller_arg |
| 167 | bool have_caller |
| 168 | unsigned *page |
| 169 | unsigned *p |
| 170 | Iris::Page buffer_page |
| 171 | public: |
| 172 | void init () |
| 173 | void log (unsigned c) |
| 174 | void interrupt (unsigned cmd) |
| 175 | void send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg) |
| 176 | |
| 177 | Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 } |
| 178 | Udc::my_config Udc::config_descriptor = { |
| 179 | (Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 }, |
| 180 | (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, { |
| 181 | (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 }, |
| 182 | (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 } |
| 183 | } |
| 184 | } |
| 185 | Udc::String <1> Udc::s_langs = { sizeof (String <1>), String <1>::Type, { 0x0409 } } |
| 186 | Udc::String <6> Udc::s_manufacturer = { sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } } |
| 187 | Udc::String <16> Udc::s_product = { sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } } |
| 188 | |
| 189 | //Udc::Device_Qualifier const Udc::device_qualifier_descriptor = { sizeof (Device_Qualifier), Device_Qualifier::Type, 0x200, 0, 0, 0, max_packet_size0, 1, 0 } |
| 190 | //Udc::my_config const Udc::other_config_descriptor = { |
| 191 | // (Configuration){ sizeof (Configuration), 7, sizeof (my_config), 1, 1, 0, 0xc0, 1 }, |
| 192 | // (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, { |
| 193 | // (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 }, |
| 194 | // (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 } |
| 195 | // } |
| 196 | // } |
| 197 | |
| 198 | void Udc::init (): |
| 199 | // Initialize the globals. My method of compiling doesn't do that properly. |
| 200 | device_descriptor = (Device){ sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 } |
| 201 | config_descriptor = (my_config){ |
| 202 | (Configuration){ sizeof (Configuration), Configuration::Type, sizeof (my_config), 1, 1, 0, 0xc0, 1 }, |
| 203 | (Interface){ sizeof (Interface), Interface::Type, 0, 0, 2, 0xff, 0, 0x80, 0 }, { |
| 204 | (Endpoint){ sizeof (Endpoint), Endpoint::Type, 1, BULK, max_packet_size_bulk, 0 }, |
| 205 | (Endpoint){ sizeof (Endpoint), Endpoint::Type, 0x81, BULK, max_packet_size_bulk, 0 } |
| 206 | } |
| 207 | } |
| 208 | s_langs = (String <1>){ sizeof (String <1>), String <1>::Type, { 0x0409 } } |
| 209 | s_manufacturer = (String <6>){ sizeof (String <6>), String <6>::Type, { 's', 'h', 'e', 'v', 'e', 'k' } } |
| 210 | s_product = (String <16>){ sizeof (String <16>), String <16>::Type, { 'I', 'r', 'i', 's', ' ', 'o', 'n', ' ', 'N', 'a', 'n', 'o', 'N', 'o', 't', 'e' } } |
| 211 | have_caller = false |
| 212 | log_buffer_size = 0 |
| 213 | log_buffer_start = 0 |
| 214 | cmd_code = ~0 |
| 215 | cmd_arg = 0 |
| 216 | |
| 217 | // Use the space which is reserved for the framebuffer, because it will not be in use. |
| 218 | // Normally a normal new page should be allocated here, but new isn't implemented at this point. |
| 219 | page = (unsigned *)LCD_FRAMEBUFFER_BASE |
| 220 | p = page |
| 221 | buffer_page = Iris::my_memory.create_page () |
| 222 | buffer_page.set_flags (Iris::Page::FRAME | Iris::Page::PAYING) |
| 223 | Iris::my_memory.map (buffer_page, (unsigned)page) |
| 224 | |
| 225 | // Disconnect from the bus and don't try to get high-speed. |
| 226 | UDC_POWER = 0 |
| 227 | UDC_TESTMODE = 0 |
| 228 | UDC_INDEX = 0 |
| 229 | state = IDLE |
| 230 | configuration = 0 |
| 231 | size = 0 |
| 232 | // exit suspend mode by reading the interrupt register. |
| 233 | cpm_start_udc () |
| 234 | // reset all pending endpoint interrupts. |
| 235 | unsigned i = UDC_INTRUSB |
| 236 | i = UDC_INTRIN |
| 237 | i = UDC_INTROUT |
| 238 | // enable interrupt on bus reset. |
| 239 | UDC_INTRUSBE = UDC_INTR_RESET |
| 240 | // enable interrupts on endpoint 0. |
| 241 | UDC_INTRINE = 1 << 0 |
| 242 | // and on out endpoint 1. |
| 243 | UDC_INTROUTE = 1 << 1 |
| 244 | // Wait a while. |
| 245 | for unsigned w = 0; w < 10000; ++w: |
| 246 | Iris::schedule () |
| 247 | // Connect to the host. |
| 248 | UDC_POWER = UDC_POWER_SOFTCONN |
| 249 | |
| 250 | bool Udc::vendor (Setup *s, unsigned cmd): |
| 251 | if !(s->request_type & 0x80): |
| 252 | kdebug ("data to device without size\n") |
| 253 | Iris::panic (0) |
| 254 | return true |
| 255 | if s->request == 10: |
| 256 | static unsigned b[2] |
| 257 | ptr = (char *)b |
| 258 | size = s->length < 8 ? s->length : 8 |
| 259 | if cmd_code != ~0: |
| 260 | b[0] = cmd_code |
| 261 | b[1] = cmd_arg |
| 262 | if cmd_code == Iris::Directory::LOCK_RO || cmd_code == Iris::Directory::UNLOCK_RO: |
| 263 | caller.invoke () |
| 264 | Iris::free_cap (caller) |
| 265 | Iris::free_cap (caller_arg) |
| 266 | have_caller = false |
| 267 | //kdebug ("(un)lock response\n") |
| 268 | cmd_code = ~0 |
| 269 | else: |
| 270 | if log_buffer_start == log_buffer_size: |
| 271 | b[0] = ~1 |
| 272 | b[1] = 0 |
| 273 | else: |
| 274 | b[0] = ~0 |
| 275 | b[1] = (log_buffer[log_buffer_start++] & 0xff) * 0x01010101 |
| 276 | if log_buffer_start == log_buffer_size: |
| 277 | log_buffer_start = 0 |
| 278 | log_buffer_size = 0 |
| 279 | else: |
| 280 | static char const *name = "Reboot" |
| 281 | ptr = name |
| 282 | size = s->length < 6 ? s->length : 6 |
| 283 | rebooting = true |
| 284 | state = TX |
| 285 | return true |
| 286 | |
| 287 | void Udc::send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg): |
| 288 | if cmd_code != ~0: |
| 289 | kdebug ("new code sent while old one wasn't finished.\n") |
| 290 | Iris::panic (0) |
| 291 | cmd_code = code |
| 292 | cmd_arg = narg |
| 293 | caller = reply |
| 294 | caller_arg = arg |
| 295 | have_caller = true |
| 296 | |
| 297 | bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len): |
| 298 | switch type: |
| 299 | case Configuration::Type: |
| 300 | if idx != 0: |
| 301 | return false |
| 302 | ptr = reinterpret_cast <char const *> (&config_descriptor) |
| 303 | size = (len < sizeof (config_descriptor) ? len : sizeof (config_descriptor)) |
| 304 | break |
| 305 | case Device::Type: |
| 306 | if idx != 0: |
| 307 | return false |
| 308 | ptr = reinterpret_cast <char const *> (&device_descriptor) |
| 309 | size = (len < sizeof (device_descriptor) ? len : sizeof (device_descriptor)) |
| 310 | break |
| 311 | case Device_Qualifier::Type: |
| 312 | //if idx != 0: |
| 313 | // return false |
| 314 | //ptr = reinterpret_cast <char const *> (&device_qualifier_descriptor) |
| 315 | //size = (len < sizeof (device_qualifier_descriptor) ? len : sizeof (device_qualifier_descriptor)) |
| 316 | //break |
| 317 | return false |
| 318 | // The 6 is an arbitrary number, except that String <6> is instantiated already. |
| 319 | case String <6>::Type: |
| 320 | switch idx: |
| 321 | case 0: |
| 322 | ptr = reinterpret_cast <char const *> (&s_langs) |
| 323 | size = (len < sizeof (s_langs) ? len : sizeof (s_langs)) |
| 324 | break |
| 325 | case 1: |
| 326 | ptr = reinterpret_cast <char const *> (&s_manufacturer) |
| 327 | size = (len < sizeof (s_manufacturer) ? len : sizeof (s_manufacturer)) |
| 328 | break |
| 329 | case 2: |
| 330 | ptr = reinterpret_cast <char const *> (&s_product) |
| 331 | size = (len < sizeof (s_product) ? len : sizeof (s_product)) |
| 332 | break |
| 333 | default: |
| 334 | return false |
| 335 | break |
| 336 | default: |
| 337 | return false |
| 338 | state = TX |
| 339 | return true |
| 340 | |
| 341 | bool Udc::handle_setup (Setup *s, unsigned cmd): |
| 342 | switch s->request_type: |
| 343 | case STANDARD_TO_DEVICE: |
| 344 | switch s->request: |
| 345 | case SET_ADDRESS: |
| 346 | UDC_FADDR = s->value |
| 347 | break |
| 348 | case SET_CONFIGURATION: |
| 349 | if s->value >= 2: |
| 350 | return false |
| 351 | configuration = s->value |
| 352 | break |
| 353 | case SET_INTERFACE: |
| 354 | if s->value != 0: |
| 355 | return false |
| 356 | break |
| 357 | default: |
| 358 | return false |
| 359 | UDC_OUTMAXP = 64 |
| 360 | UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF |
| 361 | UDC_OUTCSR = UDC_OUTCSR_CDT | UDC_OUTCSR_FF |
| 362 | break |
| 363 | case STANDARD_FROM_DEVICE: |
| 364 | switch s->request: |
| 365 | case GET_STATUS: |
| 366 | ptr = "\0\0" |
| 367 | size = (s->length < 2 ? s->length : 2) |
| 368 | state = TX |
| 369 | break |
| 370 | case GET_DESCRIPTOR: |
| 371 | return get_descriptor ((s->value >> 8) & 0xff, s->value & 0xff, s->length) |
| 372 | case GET_CONFIGURATION: |
| 373 | ptr = &configuration |
| 374 | size = (s->length < 1 ? s->length : 1) |
| 375 | state = TX |
| 376 | break |
| 377 | case GET_INTERFACE: |
| 378 | ptr = "\0" |
| 379 | size = (s->length < 1 ? s->length : 1) |
| 380 | state = TX |
| 381 | break |
| 382 | default: |
| 383 | return false |
| 384 | break |
| 385 | case VENDOR_TO_DEVICE: |
| 386 | case VENDOR_FROM_DEVICE: |
| 387 | return vendor (s, cmd) |
| 388 | default: |
| 389 | return false |
| 390 | return true |
| 391 | |
| 392 | void Udc::irq_usb (unsigned cmd): |
| 393 | // Reset. |
| 394 | //Iris::debug ("usb reset\n") |
| 395 | state = IDLE |
| 396 | |
| 397 | void Udc::irq_in (unsigned cmd): |
| 398 | // Interrupt on endpoint 0. |
| 399 | unsigned csr = UDC_CSR0 |
| 400 | if csr & UDC_CSR0_SENTSTALL: |
| 401 | csr &= ~(UDC_CSR0_SENTSTALL | UDC_CSR0_SENDSTALL) |
| 402 | state = IDLE |
| 403 | if csr & UDC_CSR0_SETUPEND: |
| 404 | csr |= UDC_CSR0_SVDSETUPEND |
| 405 | state = IDLE |
| 406 | switch state: |
| 407 | case IDLE: |
| 408 | if rebooting: |
| 409 | Iris::reboot () |
| 410 | if !(csr & UDC_CSR0_OUTPKTRDY): |
| 411 | return |
| 412 | union { unsigned d[2]; Setup s; } packet |
| 413 | packet.d[0] = UDC_FIFO (0) |
| 414 | packet.d[1] = UDC_FIFO (0) |
| 415 | if !(packet.s.request_type & 0x80) && packet.s.length > 0: |
| 416 | // More data will follow; delay handling of packet. |
| 417 | state = RX |
| 418 | UDC_CSR0 = csr | UDC_CSR0_SVDOUTPKTRDY |
| 419 | rx_request = packet.s.request |
| 420 | return |
| 421 | UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY |
| 422 | if !handle_setup (&packet.s, cmd): |
| 423 | csr |= UDC_CSR0_SENDSTALL |
| 424 | break |
| 425 | if size == 0: |
| 426 | return |
| 427 | // Fall through. |
| 428 | case TX: |
| 429 | unsigned i |
| 430 | for i = 0; (size & ~3) > 0 && i < max_packet_size0; i += 4, size -= 4: |
| 431 | UDC_FIFO (0) = *(unsigned *)ptr |
| 432 | ptr += 4 |
| 433 | for ; size > 0 && i < max_packet_size0; ++i, --size: |
| 434 | UDC_FIFO8 (0) = *ptr++ |
| 435 | if i == max_packet_size0: |
| 436 | csr |= UDC_CSR0_INPKTRDY |
| 437 | else: |
| 438 | state = IDLE |
| 439 | csr |= UDC_CSR0_INPKTRDY | UDC_CSR0_DATAEND |
| 440 | break |
| 441 | case RX: |
| 442 | // The protocol that is used doesn't allow large packets, so being here always means the entire packet is received. |
| 443 | switch rx_request & 0xff: |
| 444 | case Iris::Directory::GET_SIZE & 0xff: |
| 445 | if !have_caller: |
| 446 | kdebug ("received dir size from server without a caller waiting\n") |
| 447 | Iris::panic (0) |
| 448 | unsigned size_l = UDC_FIFO (0) |
| 449 | unsigned size_h = UDC_FIFO (0) |
| 450 | caller.invoke (Iris::Num (size_l, size_h)) |
| 451 | Iris::free_cap (caller) |
| 452 | Iris::free_cap (caller_arg) |
| 453 | have_caller = false |
| 454 | //kdebug ("get_size response\n") |
| 455 | break |
| 456 | case Iris::Directory::GET_NAME & 0xff: |
| 457 | if !have_caller: |
| 458 | kdebug ("received filename from server without a caller waiting\n") |
| 459 | Iris::panic (0) |
| 460 | unsigned n[4] |
| 461 | for unsigned i = 0; i < 4; ++i: |
| 462 | n[i] = UDC_FIFO (0) |
| 463 | caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3])) |
| 464 | Iris::free_cap (caller) |
| 465 | Iris::free_cap (caller_arg) |
| 466 | //kdebug ("get_name response\n") |
| 467 | have_caller = false |
| 468 | break |
| 469 | case Iris::String::GET_SIZE & 0xff: |
| 470 | if !have_caller: |
| 471 | kdebug ("received string size from server without a caller waiting\n") |
| 472 | Iris::panic (0) |
| 473 | unsigned size_l = UDC_FIFO (0) |
| 474 | unsigned size_h = UDC_FIFO (0) |
| 475 | caller.invoke (Iris::Num (size_l, size_h)) |
| 476 | Iris::free_cap (caller) |
| 477 | Iris::free_cap (caller_arg) |
| 478 | have_caller = false |
| 479 | //kdebug ("get_filesize response\n") |
| 480 | break |
| 481 | case Iris::String::GET_CHARS & 0xff: |
| 482 | if !have_caller: |
| 483 | kdebug ("received string char data from server without a caller waiting\n") |
| 484 | Iris::panic (0) |
| 485 | unsigned n[4] |
| 486 | for unsigned i = 0; i < 4; ++i: |
| 487 | n[i] = UDC_FIFO (0) |
| 488 | caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3])) |
| 489 | Iris::free_cap (caller) |
| 490 | Iris::free_cap (caller_arg) |
| 491 | have_caller = false |
| 492 | //kdebug ("get_chars response\n") |
| 493 | break |
| 494 | default: |
| 495 | kdebug ("invalid vendor request: ") |
| 496 | kdebug_num (rx_request) |
| 497 | kdebug ("\n") |
| 498 | Iris::panic (0) |
| 499 | UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY |
| 500 | state = IDLE |
| 501 | break |
| 502 | UDC_CSR0 = csr |
| 503 | |
| 504 | void Udc::irq_out (unsigned cmd): |
| 505 | // Interrupt on OUT endpoint 1. |
| 506 | UDC_INDEX = 1 |
| 507 | if !have_caller: |
| 508 | kdebug ("received bulk data from server without a caller waiting\n") |
| 509 | Iris::panic (0) |
| 510 | unsigned size = UDC_OUTCOUNT |
| 511 | unsigned csr = UDC_OUTCSR |
| 512 | //Iris::debug ("handling bulk interrupt for %x with %d bytes.\n", csr, size) |
| 513 | csr &= ~UDC_OUTCSR_OUTPKTRDY |
| 514 | for unsigned i = 0; i < size; i += 4: |
| 515 | *p++ = UDC_FIFO (1) |
| 516 | if p - page == PAGE_SIZE >> 2: |
| 517 | buffer_page.share (caller_arg, Iris::Page::FORGET) |
| 518 | buffer_page.set_flags (Iris::Page::FRAME) |
| 519 | caller.invoke () |
| 520 | Iris::free_cap (caller) |
| 521 | Iris::free_cap (caller_arg) |
| 522 | have_caller = false |
| 523 | //kdebug ("bulk response\n") |
| 524 | p = page |
| 525 | UDC_OUTCSR = csr |
| 526 | UDC_INDEX = 0 |
| 527 | |
| 528 | void Udc::interrupt (unsigned cmd): |
| 529 | while true: |
| 530 | unsigned usb = UDC_INTRUSB |
| 531 | unsigned in = UDC_INTRIN |
| 532 | unsigned out = UDC_INTROUT |
| 533 | if !(usb & 4) && !(in & 1) && !(out & 2): |
| 534 | break |
| 535 | //Iris::debug ("interrupt: %d/%d/%d\n", usb, in, out) |
| 536 | if usb & 4: |
| 537 | irq_usb (cmd) |
| 538 | if in & 1: |
| 539 | irq_in (cmd) |
| 540 | if out & 2: |
| 541 | irq_out (cmd) |
| 542 | |
| 543 | void Udc::log (unsigned c): |
| 544 | if log_buffer_size >= sizeof (log_buffer): |
| 545 | return |
| 546 | log_buffer[log_buffer_size++] = c |
| 547 | |
| 548 | enum pdata: |
| 549 | LOG = 1 |
| 550 | DIRECTORY |
| 551 | FILE |
| 552 | NAME |
| 553 | |
| 554 | Iris::Num start (): |
| 555 | map_udc () |
| 556 | map_gpio () |
| 557 | map_cpm () |
| 558 | Udc udc |
| 559 | |
| 560 | //Iris::Cap logcap = Iris::my_receiver.create_capability (LOG) |
| 561 | //__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1") |
| 562 | Iris::Directory dir = Iris::my_receiver.create_capability (DIRECTORY) |
| 563 | Iris::my_parent.provide_capability <Iris::Directory> (dir.copy ()) |
| 564 | Iris::free_cap (dir) |
| 565 | udc.init () |
| 566 | Iris::register_interrupt (IRQ_UDC) |
| 567 | // Don't call init_done, because this can be used as bootthread and without a parent this call will not be answered. |
| 568 | //Iris::my_parent.init_done () |
| 569 | unsigned state = 0 |
| 570 | while true: |
| 571 | Iris::wait () |
| 572 | Iris::Cap reply = Iris::get_reply () |
| 573 | Iris::Cap arg = Iris::get_arg () |
| 574 | //Iris::debug ("udc event, protected: %x\n", Iris::recv.protected_data.l) |
| 575 | switch Iris::recv.protected_data.l: |
| 576 | case 0: |
| 577 | udc.interrupt (state) |
| 578 | Iris::register_interrupt (IRQ_UDC) |
| 579 | break |
| 580 | case LOG: |
| 581 | udc.log (Iris::recv.data[0].l) |
| 582 | break |
| 583 | case DIRECTORY: |
| 584 | //Iris::debug ("dir request %d\n", Iris::recv.data[0].l) |
| 585 | switch Iris::recv.data[0].l: |
| 586 | case Iris::Directory::GET_NAME: |
| 587 | Iris::Cap name = Iris::my_receiver.create_capability (Iris::Num (NAME, Iris::recv.data[1].l)) |
| 588 | reply.invoke (0, 0, name.copy ()) |
| 589 | Iris::free_cap (name) |
| 590 | Iris::free_cap (reply) |
| 591 | Iris::free_cap (arg) |
| 592 | continue |
| 593 | case Iris::Directory::GET_SIZE: |
| 594 | case Iris::Directory::LOCK_RO: |
| 595 | case Iris::Directory::UNLOCK_RO: |
| 596 | state = Iris::recv.data[0].l |
| 597 | if Iris::recv.data[1].h != 0: |
| 598 | Iris::panic (0, "index out of supported range") |
| 599 | udc.send (Iris::recv.data[0].l, Iris::recv.data[1].l, reply, arg) |
| 600 | continue |
| 601 | case Iris::Directory::GET_FILE_RO: |
| 602 | if Iris::recv.data[1].h != 0: |
| 603 | kdebug ("index out of supported range\n") |
| 604 | Iris::panic (0) |
| 605 | //kdebug ("sending file\n") |
| 606 | Iris::Cap file = Iris::my_receiver.create_capability (Iris::Num (FILE, Iris::recv.data[1].l)) |
| 607 | reply.invoke (0, 0, file.copy ()) |
| 608 | Iris::free_cap (file) |
| 609 | Iris::free_cap (reply) |
| 610 | Iris::free_cap (arg) |
| 611 | continue |
| 612 | case Iris::Directory::GET_FILE_INFO: |
| 613 | default: |
| 614 | reply.invoke (Iris::ERR_INVALID_OPERATION) |
| 615 | Iris::free_cap (reply) |
| 616 | Iris::free_cap (arg) |
| 617 | continue |
| 618 | break |
| 619 | case FILE: |
| 620 | //Iris::debug ("file request %d\n", Iris::recv.data[0].l) |
| 621 | switch Iris::recv.data[0].l: |
| 622 | case Iris::Block::GET_BLOCK: |
| 623 | if Iris::recv.data[0].h != PAGE_SIZE << 16: |
| 624 | Iris::panic (0, "unsupported get_block arguments for boot usb device driver") |
| 625 | // Fall through. |
| 626 | case Iris::Block::GET_SIZE: |
| 627 | udc.send (Iris::recv.data[0].l | ((Iris::recv.data[1].l >> PAGE_BITS) << 16), Iris::recv.protected_data.h, reply, arg) |
| 628 | continue |
| 629 | default: |
| 630 | reply.invoke (Iris::ERR_INVALID_OPERATION) |
| 631 | Iris::free_cap (reply) |
| 632 | Iris::free_cap (arg) |
| 633 | continue |
| 634 | break |
| 635 | case NAME: |
| 636 | //Iris::debug ("name request %d\n", Iris::recv.data[0].l) |
| 637 | switch Iris::recv.data[0].l: |
| 638 | case Iris::String::GET_SIZE: |
| 639 | reply.invoke (16) |
| 640 | Iris::free_cap (reply) |
| 641 | Iris::free_cap (arg) |
| 642 | continue |
| 643 | case Iris::String::GET_CHARS: |
| 644 | state = Iris::recv.data[0].l |
| 645 | udc.send (Iris::Directory::GET_NAME, Iris::recv.protected_data.h, reply, arg) |
| 646 | continue |
| 647 | default: |
| 648 | reply.invoke (Iris::ERR_INVALID_OPERATION) |
| 649 | Iris::free_cap (reply) |
| 650 | Iris::free_cap (arg) |
| 651 | continue |
| 652 | default: |
| 653 | kdebug ("other request:") |
| 654 | kdebug_num (Iris::recv.protected_data.l) |
| 655 | kdebug ("\n") |
| 656 | udc.log ('~') |
| 657 | char digit[] = "0123456789abcdef" |
| 658 | for unsigned i = 0; i < 8; ++i: |
| 659 | udc.log (digit[(Iris::recv.protected_data.l >> (4 * (7 - i))) & 0xf]) |
| 660 | udc.log ('\n') |
| 661 | break |
| 662 | reply.invoke () |
| 663 | Iris::free_cap (reply) |
| 664 | Iris::free_cap (arg) |
| 665 |
Branches:
master
