Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
				}
			}
		}
Esempio n. 3
0
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;
}