Пример #1
0
static void usbIRQHandler(uint32_t token) {

	// we need to mask because GINTSTS is set for a particular interrupt even if it's masked in GINTMSK (GINTMSK just prevents an interrupt being generated)
	uint32_t status = GET_REG(USB + GINTSTS) & GET_REG(USB + GINTMSK);
	int process = FALSE;

	//uartPrintf("<begin interrupt: %x>\r\n", status);

	if(status) {
		process = TRUE;
	}

	while(process) {
		if((status & GINTMSK_OTG) == GINTMSK_OTG) {
			// acknowledge OTG interrupt (these bits are all R_SS_WC which means Write Clear, a write of 1 clears the bits)
			SET_REG(USB + GOTGINT, GET_REG(USB + GOTGINT));

			// acknowledge interrupt (this bit is actually RO, but should've been cleared when we cleared GOTGINT. Still, iBoot pokes it as if it was WC, so we will too)
			SET_REG(USB + GINTSTS, GINTMSK_OTG);

			process = TRUE;
		} else {
			// we only care about OTG
			process = FALSE;
		}

		if((status & GINTMSK_RESET) == GINTMSK_RESET) {
			if(usb_state < USBError) {
				bufferPrintf("usb: reset detected\r\n");
				change_state(USBPowered);
			}

			int retval = resetUSB();

			SET_REG(USB + GINTSTS, GINTMSK_RESET);

			if(retval) {
				bufferPrintf("usb: listening for further usb events\r\n");
				return;	
			}

			process = TRUE;
		}

		if(((status & GINTMSK_INEP) == GINTMSK_INEP) || ((status & GINTMSK_OEP) == GINTMSK_OEP)) {
			// aha, got something on one of the endpoints. Now the real fun begins

			// first, let's get the interrupt status of individual endpoints
			getEndpointInterruptStatuses();

			if(isSetupPhaseDone()) {
				// recall our earlier receiveControl calls. We now should have 8 bytes of goodness in controlRecvBuffer.
				USBSetupPacket* setupPacket = (USBSetupPacket*) controlRecvBuffer;

				uint16_t length;
				uint32_t totalLength;
				USBStringDescriptor* strDesc;
				if(USBSetupPacketRequestTypeType(setupPacket->bmRequestType) != USBSetupPacketVendor) {
					switch(setupPacket->bRequest) {
						case USB_GET_DESCRIPTOR:
							length = setupPacket->wLength;
							// descriptor type is high, descriptor index is low
							switch(setupPacket->wValue >> 8) {
								case USBDeviceDescriptorType:
									if(length > sizeof(USBDeviceDescriptor))
										length = sizeof(USBDeviceDescriptor);

									memcpy(controlSendBuffer, usb_get_device_descriptor(), length);
									break;
								case USBConfigurationDescriptorType:
									// hopefully SET_ADDRESS was received beforehand to set the speed
									totalLength = getConfigurationTree(setupPacket->wValue & 0xFF, usb_speed, controlSendBuffer);
									if(length > totalLength)
										length = totalLength;
									break;
								case USBStringDescriptorType:
									strDesc = usb_get_string_descriptor(setupPacket->wValue & 0xFF);
									if(length > strDesc->bLength)
										length = strDesc->bLength;
									memcpy(controlSendBuffer, strDesc, length);
									break;
								case USBDeviceQualifierDescriptorType:
									if(length > sizeof(USBDeviceQualifierDescriptor))
										length = sizeof(USBDeviceQualifierDescriptor);

									memcpy(controlSendBuffer, usb_get_device_qualifier_descriptor(), length);
									break;
								default:
									bufferPrintf("Unknown descriptor request: %d\r\n", setupPacket->wValue >> 8);
									if(usb_state < USBError) {
										change_state(USBUnknownDescriptorRequest);
									}
							}

							if(usb_state < USBError) {
								sendControl(controlSendBuffer, length);
							}

							break;

						case USB_SET_ADDRESS:
							usb_speed = DSTS_GET_SPEED(GET_REG(USB + DSTS));
							usb_max_packet_size = packetsizeFromSpeed(usb_speed);
							SET_REG(USB + DCFG, (GET_REG(USB + DCFG) & ~DCFG_DEVICEADDRMSK)
								| ((setupPacket->wValue & DCFG_DEVICEADDR_UNSHIFTED_MASK) << DCFG_DEVICEADDR_SHIFT));

							// send an acknowledgement
							sendControl(controlSendBuffer, 0);

							if(usb_state < USBError) {
								change_state(USBAddress);
							}
							break;

						case USB_SET_INTERFACE:
							// send an acknowledgement
							sendControl(controlSendBuffer, 0);
							break;

						case USB_GET_STATUS:
							// FIXME: iBoot doesn't really care about this status
							*((uint16_t*) controlSendBuffer) = 0;
							sendControl(controlSendBuffer, sizeof(uint16_t));
							break;

						case USB_GET_CONFIGURATION:
							// FIXME: iBoot just puts out a debug message on console for this request.
							break;

						case USB_SET_CONFIGURATION:
							setConfiguration(0);
							// send an acknowledgment
							sendControl(controlSendBuffer, 0);

							if(usb_state < USBError) {
								change_state(USBConfigured);
								startHandler();
							}
							break;
						default:
							if(usb_state < USBError) {
								change_state(USBUnknownRequest);
							}
					}

					// get the next SETUP packet
					receiveControl(controlRecvBuffer, sizeof(USBSetupPacket));
				}
			} else {
				//uartPrintf("\t<begin callEndpointHandlers>\r\n");
				callEndpointHandlers();
				//uartPrintf("\t<end callEndpointHandlers>\r\n");
			}

			process = TRUE;
		}
//! usb_get_descriptor.
//!
//! This function manages the GET DESCRIPTOR request. The device descriptor,
//! the configuration descriptor and the device qualifier are supported. All
//! other descriptors must be supported by the usb_user_get_descriptor
//! function.
//! Only 1 configuration is supported.
//!
//! @warning Code:xx bytes (function code length)
//!
void usb_get_descriptor(void)
{
	U8  LSBwLength, MSBwLength;
	U8  descriptor_type ;
	U8  string_type     ;
	U8  dummy;
	U8  byteswereread;

	zlp             = FALSE;                  /* no zero length packet */
	string_type     = Usb_read_byte();        /* read LSB of wValue    */
	descriptor_type = Usb_read_byte();        /* read MSB of wValue    */
	byteswereread   = 0;

	switch (descriptor_type)
	{
	case DEVICE_DESCRIPTOR:
	  data_to_transfer = Usb_get_dev_desc_length(); //!< sizeof (usb_user_device_descriptor);
	  pbuffer          = Usb_get_dev_desc_pointer();
	  break;
	case CONFIGURATION_DESCRIPTOR:
		data_to_transfer = Usb_get_conf_desc_length(string_type); //!< sizeof (usb_user_configuration_descriptor);
		pbuffer          = Usb_get_conf_desc_pointer(string_type);
	  break;
#if 1 
	case STRING_DESCRIPTOR:
	  if(string_type!=LANG_ID) {
		usb_get_string_descriptor(string_type);
		return;
	  }
#endif
	default:
		dummy = Usb_read_byte();
		dummy = Usb_read_byte();
		LSBwLength = Usb_read_byte();
		MSBwLength = Usb_read_byte();
		byteswereread=1;
		if( usb_user_get_descriptor(descriptor_type, string_type)==FALSE ) {
		    Usb_enable_stall_handshake(); //TODO:is this necessary, Win7 flaky without?
			Usb_ack_receive_setup();
			return;
		}
	  break;
	}
	if (byteswereread==0) {
		dummy = Usb_read_byte();                     //!< don't care of wIndex field
		dummy = Usb_read_byte();
		LSBwLength = Usb_read_byte();              //!< read wLength
		MSBwLength = Usb_read_byte();
	}

	Usb_ack_receive_setup() ;                  //!< clear the receive setup flag

	if ((LSBwLength > data_to_transfer) || (MSBwLength)) {
		if ((data_to_transfer % EP_CONTROL_LENGTH) == 0) { zlp = TRUE; }
		else { zlp = FALSE; }                   //!< no need of zero length packet

		LSBwLength = data_to_transfer;
		MSBwLength = 0x00;
	} else {
		data_to_transfer = LSBwLength;         //!< send only requested number of data
	}
	
	while((data_to_transfer != 0) && (!Is_usb_receive_out())) {
		U8  nb_byte = 0;
		if(usb_endpoint_wait_for_read_control_enabled()!=0) {
			Usb_enable_stall_handshake();
			break;
		}

        //! Send data until necessary
		while(data_to_transfer != 0) {
//			if(Is_usb_write_enabled()) //!< Check endpoint 0 size
			if(nb_byte++==EP_CONTROL_LENGTH) //!< Check endpoint 0 size
				break;

			Usb_write_byte(pgm_read_byte_near((unsigned int)pbuffer++));
			data_to_transfer --;

		}
		Usb_send_control_in();
	}

	if(Is_usb_receive_out()) {
		//! abort from Host
		Usb_ack_receive_out();
		return;
	}
	
	if(zlp == TRUE) {
		if(usb_endpoint_wait_for_read_control_enabled()!=0) {
			Usb_enable_stall_handshake();
			return;
		}
		Usb_send_control_in();
	}

	usb_endpoint_wait_for_receive_out();
	Usb_ack_receive_out();
}