void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1, const _XpRefStr_ *p2, uint8_t n2) { uint8_t intr_state, total, avail; const prog_char *s2 = (const prog_char *)p2; total = n1 + n2; if (total > FLIGHTSIM_TX_SIZE) return; if (!enabled || !usb_configuration) return; intr_state = SREG; cli(); UENUM = FLIGHTSIM_TX_ENDPOINT; avail = FLIGHTSIM_TX_SIZE - UEBCLX; if ((UEINTX & (1<<RWAL)) && (avail >= total)) { goto send; } else { while (avail) { UEDATX = 0; avail--; } UEINTX = 0x3A; while (1) { if (UEINTX & (1<<RWAL)) break; SREG = intr_state; if (!enabled || !usb_configuration) return; intr_state = SREG; cli(); UENUM = FLIGHTSIM_TX_ENDPOINT; } } send: do { UEDATX = *p1++; } while (--n1 > 0); do { pgm_read_byte_postinc(UEDATX, s2); } while (--n2 > 0); if (UEBCLX == FLIGHTSIM_TX_SIZE) UEINTX = 0x3A; SREG = intr_state; }
static inline void endpoint0_isr(void) { uint8_t intbits; const uint8_t *list; const uint8_t *cfg; uint8_t i, n, len, en; uint8_t bmRequestType; uint8_t bRequest; uint16_t wValue; uint16_t wIndex; uint16_t wLength; uint16_t desc_val; const uint8_t *desc_addr; uint8_t desc_length; UENUM = 0; intbits = UEINTX; if (intbits & (1<<RXSTPI)) { bmRequestType = UEDATX; bRequest = UEDATX; read_word_lsbfirst(wValue, UEDATX); read_word_lsbfirst(wIndex, UEDATX); read_word_lsbfirst(wLength, UEDATX); UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI)); if (bRequest == GET_DESCRIPTOR) { list = (const uint8_t *)descriptor_list; for (i=0; ; i++) { if (i >= NUM_DESC_LIST) { UECONX = (1<<STALLRQ)|(1<<EPEN); //stall return; } pgm_read_word_postinc(desc_val, list); if (desc_val != wValue) { list += sizeof(struct descriptor_list_struct)-2; continue; } pgm_read_word_postinc(desc_val, list); if (desc_val != wIndex) { list += sizeof(struct descriptor_list_struct)-4; continue; } pgm_read_word_postinc(desc_addr, list); desc_length = pgm_read_byte(list); break; } len = (wLength < 256) ? wLength : 255; if (len > desc_length) len = desc_length; list = desc_addr; do { // wait for host ready for IN packet do { i = UEINTX; } while (!(i & ((1<<TXINI)|(1<<RXOUTI)))); if (i & (1<<RXOUTI)) return; // abort // send IN packet n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE; for (i = n; i; i--) { pgm_read_byte_postinc(UEDATX, list); } len -= n; usb_send_in(); } while (len || n == ENDPOINT0_SIZE); return; } if (bRequest == SET_ADDRESS) { usb_send_in(); usb_wait_in_ready(); UDADDR = wValue | (1<<ADDEN); return; } if (bRequest == SET_CONFIGURATION && bmRequestType == 0) { usb_configuration = wValue; debug_flush_timer = 0; usb_send_in(); cfg = endpoint_config_table; for (i=1; i<NUM_ENDPOINTS; i++) { UENUM = i; pgm_read_byte_postinc(en, cfg); UECONX = en; if (en) { pgm_read_byte_postinc(UECFG0X, cfg); pgm_read_byte_postinc(UECFG1X, cfg); } } UERST = 0x1E; UERST = 0; UENUM = DISK_RX_ENDPOINT; UEIENX = (1<<RXOUTE); return; } if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) { usb_wait_in_ready(); UEDATX = usb_configuration; usb_send_in(); return; } if (bRequest == GET_STATUS) { usb_wait_in_ready(); i = 0; if (bmRequestType == 0x82) { UENUM = wIndex; if (UECONX & (1<<STALLRQ)) i = 1; UENUM = 0; } UEDATX = i; UEDATX = 0; usb_send_in(); return; } if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE) && bmRequestType == 0x02 && wValue == 0) { i = wIndex & 0x7F; if (i >= 1 && i <= MAX_ENDPOINT) { usb_send_in(); UENUM = i; if (bRequest == SET_FEATURE) { UECONX = (1<<STALLRQ)|(1<<EPEN); } else { UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN); UERST = (1 << i); UERST = 0; if (i == DISK_TX_ENDPOINT) { UEIENX = (1<<TXINE); } } return; } } if (wIndex == KEYBOARD_INTERFACE) { if (bmRequestType == 0xA1) { if (bRequest == HID_GET_REPORT) { usb_wait_in_ready(); UEDATX = keyboard_modifier_keys; UEDATX = 0; for (i=0; i<6; i++) { UEDATX = keyboard_keys[i]; } usb_send_in(); return; } if (bRequest == HID_GET_IDLE) { usb_wait_in_ready(); UEDATX = keyboard_idle_config; usb_send_in(); return; } if (bRequest == HID_GET_PROTOCOL) { usb_wait_in_ready(); UEDATX = keyboard_protocol; usb_send_in(); return; } } if (bmRequestType == 0x21) { if (bRequest == HID_SET_REPORT) { usb_wait_receive_out(); keyboard_leds = UEDATX; usb_ack_out(); usb_send_in(); return; } if (bRequest == HID_SET_IDLE) { keyboard_idle_config = (wValue >> 8); keyboard_idle_count = 0; //usb_wait_in_ready(); usb_send_in(); return; } if (bRequest == HID_SET_PROTOCOL) { keyboard_protocol = wValue; //usb_wait_in_ready(); usb_send_in(); return; } } }
static inline uint8_t mass_storage_isr(uint8_t need_rx, uint8_t need_tx) { uint8_t n, state; const uint8_t *p; static uint32_t tag, xfer_len, lba; static uint8_t dir, cmd_len, status; static uint8_t scsi_sense, scsi_asense; static uint16_t sector_count; static uint8_t sector_chunk; static uint8_t previous_media_state, do_media_status; uint8_t cmd; if (need_rx) { UENUM = DISK_RX_ENDPOINT; if (!media_lock_isr()) { print("Media is locked, ISR exit\n"); // if the user program is busy with the media // then disable our interrupt and hope the user // program enables it again when finished. //UEIENX = 0; return 0; } //print("rx "); n = UEBCLX; state = ms_state; if (state == MS_STATE_IDLE) { print("CBW "); //phex(n); if (n != 31) goto error_stall; if (UEDATX != 0x55) goto error_stall; if (UEDATX != 0x53) goto error_stall; if (UEDATX != 0x42) goto error_stall; if (UEDATX != 0x43) goto error_stall; read_dword_lsbfirst(tag, UEDATX); read_dword_lsbfirst(xfer_len, UEDATX); dir = UEDATX & 0x80; UEDATX; // LUN cmd_len = UEDATX; //print(", len="); //phex(cmd_len); status = 0; cmd = UEDATX; print(", cmd="); phex(cmd); //print(", dir="); //phex(dir); //print(", xfer="); //phex32(xfer_len); print("\n"); do_media_status = 0; if (cmd == SCSI_CMD_REQUEST_SENSE) { // 0x03 print("REQUEST_SENSE "); phex(scsi_sense); phex(scsi_asense); print("\n"); if (media_state & MEDIA_STATE_CLAIMED) media_state |= MEDIA_STATE_CLAIMED_SENSE; UEINTX = 0x6B; UENUM = DISK_TX_ENDPOINT; UEDATX = 0x70; UEDATX = 0; UEDATX = scsi_sense; UEDATX = 0; UEDATX = 0; UEDATX = 0; UEDATX = 0; UEDATX = 10; UEDATX = 0; UEDATX = 0; UEDATX = 0; UEDATX = 0; UEDATX = scsi_asense; xfer_len -= 13; goto send_finishup; } scsi_sense = SCSI_SENSE_OK; scsi_asense = SCSI_ASENSE_NONE; if (cmd == SCSI_CMD_INQUIRY) { // 0x12 // http://en.wikipedia.org/wiki/SCSI_Inquiry_Command uint16_t len; UEDATX; // ignore request bits UEDATX; read_word_msbfirst(len, UEDATX); print("INQUIRY\n"); UEINTX = 0x6B; if (len > sizeof(scsi_inquiry_response)) len = sizeof(scsi_inquiry_response); p = scsi_inquiry_response; UENUM = DISK_TX_ENDPOINT; for (n=len; n > 0; n--) { pgm_read_byte_postinc(UEDATX, p); } xfer_len -= len; goto send_finishup; } previous_media_state = media_state; do_media_status = 1; // all commands below this point need media access if (cmd == SCSI_CMD_TEST_UNIT_READY) { // 0x00 print("TEST READY, ms="); phex(media_state); print("\n"); media_poll(); UEINTX = 0x3A; goto send_status; } // all commands below this point need the media // to be present if (!(previous_media_state & MEDIA_PRESENT_MASK)) { print("stall_in\n"); UEINTX = 0x6B; UENUM = DISK_TX_ENDPOINT; //UEIENX = 0; UECONX = (1<<STALLRQ) | (1<<EPEN); ms_state = MS_STATE_SEND_STATUS; return ENABLE_MORE_RX; } if (cmd == SCSI_CMD_MODE_SENSE_6 // 0x1A || cmd == SCSI_CMD_MODE_SENSE_10) { // 0x5A // 1A 00 1C 00 C0 00 - from disk.sys // 1A 00 3F 00 C0 00 - from classpnp.sys // 1A 00 3F 00 C0 00 - from linux kernel print("MODE SENSE 6 or 10\n"); // check allocation length... UEINTX = 0x6B; UENUM = DISK_TX_ENDPOINT; UEDATX = 0x03; UEDATX = 0x00; UEDATX = media_rdonly ? 0x80 : 0x00; // WP bit UEDATX = 0x00; xfer_len -= 4; goto send_finishup; } else if (cmd == SCSI_CMD_READ_CAPACITY) { // 0x25 uint32_t capacity; print("CAPACITY\n"); UEINTX = 0x6B; media_poll(); capacity = media_size(); UENUM = DISK_TX_ENDPOINT; write_dword_msbfirst(capacity - 1, UEDATX); UEDATX = 0x00; UEDATX = 0x00; UEDATX = 0x02; UEDATX = 0x00; xfer_len -= 8; goto send_finishup; } else if (cmd == SCSI_CMD_READ_FORMAT_CAPACITIES) { // 0x23 uint32_t capacity; print("READ_FORMAT_CAPACITIES\n"); UEINTX = 0x6B; media_poll(); capacity = media_size(); UENUM = DISK_TX_ENDPOINT; UEDATX = 0x00; UEDATX = 0x00; UEDATX = 0x00; UEDATX = 0x08; write_dword_msbfirst(capacity, UEDATX); UEDATX = 2 + status; // 2 = formatted, 3 = no media present UEDATX = 0x00; UEDATX = 0x02; // 512 byte blocks UEDATX = 0x00; xfer_len -= 12; goto send_finishup; } else if (cmd == SCSI_CMD_READ_10) { // 0x28 // http://en.wikipedia.org/wiki/SCSI_Read_Commands#Read_.2810.29 UEDATX; read_dword_msbfirst(lba, UEDATX); UEDATX; read_word_msbfirst(sector_count, UEDATX); print("READ_10: lba="); phex32(lba); print(", count="); phex16(sector_count); print("\n"); UEINTX = 0x6B; if (!(media_state & MEDIA_PRESENT_MASK)) { UENUM = DISK_TX_ENDPOINT; goto send_finishup; } media_send_begin(lba); sector_chunk = 0; ms_state = MS_STATE_SEND_DATA; goto send_data; } else if (cmd == SCSI_CMD_WRITE_10) { // 0x2A UEDATX; read_dword_msbfirst(lba, UEDATX); UEDATX; read_word_msbfirst(sector_count, UEDATX); print("WRITE_10: lba="); phex32(lba); print(", count="); phex16(sector_count); print("\n"); UEINTX = 0x6B; // TODO: how to handle write when media not ready //if (!(media_state & MEDIA_PRESENT_MASK)) goto send_finishup; sector_chunk = 0; media_receive_begin(lba); ms_state = MS_STATE_RECEIVE_DATA; n = UEBCLX; if (n > 0) goto receive_data; return ENABLE_MORE_RX; } else { print("Unimplemented, cmd="); phex(cmd); print("\n"); UEINTX = 0x6B; scsi_sense = SCSI_SENSE_ILLEGAL_REQUEST; scsi_asense = SCSI_ASENSE_INVALID_COMMAND; status = 1; goto send_finishup; //TODO: what is the proper way to handle this error?? //UENUM = DISK_TX_ENDPOINT; //UECONX = (1<<STALLRQ) | (1<<EPEN); //state = MS_STATE_SEND_STATUS; //UEIENX = (1<<TXINE); //return ENABLE_MORE_RX; } } else if (state == MS_STATE_RECEIVE_DATA) { receive_data: //print("receive, count="); //phex16(sector_count); //print (", lba="); //phex32(lba); //print(", chunk="); //phex(sector_chunk); //print("\n"); if (sector_count > 0) { media_receive_chunk(lba, sector_chunk); xfer_len -= 64; if (++sector_chunk >= 8) { sector_chunk = 0; lba++; //if (--sector_count == 0) ms_state = MS_STATE_SEND_STATUS; if (--sector_count == 0) { media_receive_end(); goto send_status; } } // if another interrupt already ending, do it now //if (UEINTX & (1<<RXOUTI)) goto receive_data; } else { UEINTX = 0x6B; } return ENABLE_MORE_RX; } else { //print("unexpected receive: n="); //phex(n); //print("\n"); UEINTX = 0x6B; return ENABLE_MORE_RX; } } if (need_tx) { UENUM = DISK_TX_ENDPOINT; //print("tx "); state = ms_state; if (state == MS_STATE_SEND_STATUS) goto send_status_force; if (state == MS_STATE_SEND_ZEROPAD) goto send_finishup; if (state == MS_STATE_SEND_DATA) goto send_data; print("unhandled tx interrupt "); phex(state); print("\n"); return 0; } return ENABLE_MORE_RX; // should never be called with both need_rx = 0 and need_tx = 0 send_data: //print("send, count="); //phex16(sector_count); //print (", lba="); //phex32(lba); //print(", chunk="); //phex(sector_chunk); //print("\n"); UENUM = DISK_TX_ENDPOINT; if (sector_count > 0 && (UEINTX & (1<<RWAL))) { media_send_chunk(lba, sector_chunk); xfer_len -= 64; if (++sector_chunk >= 8) { sector_chunk = 0; lba++; if (--sector_count == 0) { media_send_end(); ms_state = MS_STATE_SEND_STATUS; } } // if more buffers ready, don't wait for another interrupt if (UEINTX & (1<<RWAL)) goto send_data; } //UEIENX = (1<<TXINE); return ENABLE_MORE_TX; send_finishup: while (xfer_len > 0 && (UEINTX & (1<<RWAL))) { UEDATX = 0; xfer_len--; } UEINTX = 0x3A; if (xfer_len) { print("short reply\n"); ms_state = MS_STATE_SEND_ZEROPAD; //UEIENX = (1<<TXINE); return ENABLE_MORE_TX; } send_status: UENUM = DISK_TX_ENDPOINT; if (!(UEINTX & (1<<RWAL))) { print("wait tx\n"); ms_state = MS_STATE_SEND_STATUS; //UEIENX = (1<<TXINE); return ENABLE_MORE_TX; } send_status_force: if (do_media_status) { uint8_t current_media_state = media_state; if (current_media_state & MEDIA_STATE_CLAIMED) media_state = current_media_state | MEDIA_STATE_CLAIMED_STATUS; if (status == 0) { if (!(current_media_state & MEDIA_PRESENT_MASK)) { scsi_sense = SCSI_SENSE_NOT_READY; scsi_asense = SCSI_ASENSE_MEDIUM_NOT_PRESENT; status = 1; } else { if (!(previous_media_state & MEDIA_PRESENT_MASK)) { scsi_sense = SCSI_SENSE_UNIT_ATTENTION; scsi_asense = SCSI_ASENSE_NOT_READY_TO_READY; status = 1; } } } do_media_status = 0; } print("status "); phex(status); if (status) { phex(scsi_sense); phex(scsi_asense); } print("\n"); UEDATX = 0x55; UEDATX = 0x53; UEDATX = 0x42; UEDATX = 0x53; write_dword_lsbfirst(tag, UEDATX); write_dword_lsbfirst(xfer_len, UEDATX); UEDATX = status; UEINTX = 0x3A; //UEIENX = 0; ms_state = MS_STATE_IDLE; media_unlock_isr(); return ENABLE_MORE_RX; error_stall: print("\nStall\n"); ms_state = MS_STATE_STALLED; UENUM = DISK_RX_ENDPOINT; //UEIENX = 0; UECONX = (1<<STALLRQ) | (1<<EPEN); UENUM = DISK_TX_ENDPOINT; //UEIENX = 0; UECONX = (1<<STALLRQ) | (1<<EPEN); media_unlock_isr(); return ENABLE_MORE_RX | ENABLE_MORE_TX; }