예제 #1
0
파일: ohci_hcd.c 프로젝트: InSoonPark/asf
/**
 * \brief Add a transfer descriptor to non-control endpoint.
 *
 * \param ep_number endpoint number.
 * \param buf Point to the data buffer.
 * \param buf_size Length of the data buffer.
 *
 * \return true for success.
 */
bool ohci_add_td_non_control(uint8_t ep_number, uint8_t *buf,
		uint32_t buf_size, struct ohci_td_general **td_general_header)
{
	struct ohci_ed *ed_header;
	uint32_t i;
	uint8_t ep_dir;

	if (ep_number & 0x80) {
		ep_dir = 2;
	} else {
		ep_dir = 1;
	}
	ep_number = ep_number & 0xF;

	/* Bulk endpoints. */
	i = 0;
	ed_header = (struct ohci_ed *)OHCI->HcBulkHeadED;
	while (ed_header != NULL) {
		if ((ed_header->ed_info.ed_info_s.bEndpointNumber == ep_number) &&
				(ed_header->ed_info.ed_info_s.bDirection == ep_dir)) {
			/* Wait for transfer done. */
			do {
				p_td_head = ((uint32_t)(ed_header->p_td_head)) & 0xFFFFFFF0;
				p_td_tail = ((uint32_t)(ed_header->p_td_tail)) & 0xFFFFFFF0;
			} while(p_td_head != p_td_tail);

			memset((void *)&bulk_td_head[i], 0, sizeof(bulk_td_head[i]));
			memset((void *)&bulk_td_tail[i], 0, sizeof(bulk_td_tail[i]));

			bulk_td_head[i].td_info.bBufferRounding = 1;
			bulk_td_head[i].td_info.bDirectionPID = 3;
			bulk_td_head[i].td_info.bDelayInterrupt = 0;
			bulk_td_head[i].td_info.bDataToggle = 0;
			bulk_td_head[i].td_info.bErrorCount = 0;
			bulk_td_head[i].td_info.bConditionCode = 0;
			bulk_td_head[i].pCurrentBufferPointer= buf;
			bulk_td_head[i].p_next_td = NULL;
			bulk_td_head[i].pBufferEnd = buf + buf_size - 1;

			/* Check the halt status. */
			if ((uint32_t)ed_header->p_td_head & 0x01) {
				return false;
			}

			p_td_head = (uint32_t)(&bulk_td_head[i]);
			p_td_head &= 0xFFFFFFF0;
			*td_general_header = (struct ohci_td_general *)p_td_head;
			p_td_tail = (uint32_t)(ed_header->p_td_head);
			p_td_tail &= 0x0000000F;
			p_td_head |= p_td_tail;

			ed_header->p_td_head = (void *)p_td_head;
			ed_header->p_td_tail = NULL;

			OHCI->HcCommandStatus = HC_COMMANDSTATUS_BLF;
			OHCI->HcControl |= HC_CONTROL_BLE;
				
			return true;
		} else {
			ed_header = ed_header->p_next_ed;
			i++;
		}
	}

	/* Int/ISO endpoints. */
	for (i = 0; i < 8; i++) {
		ed_header = (struct ohci_ed *)hcca.InterruptTable[i];
		if ((ed_header->ed_info.ed_info_s.bEndpointNumber == ep_number) &&
				(ed_header->ed_info.ed_info_s.bDirection == ep_dir)) {
			if (ed_header->ed_info.ed_info_s.bFormat == 0) {
				/* Wait for transfer done. */
				do {
					p_td_head = ((uint32_t)(ed_header->p_td_head)) & 0xFFFFFFF0;
					p_td_tail = ((uint32_t)(ed_header->p_td_tail)) & 0xFFFFFFF0;
				} while(p_td_head != p_td_tail);

				OHCI->HcControl &= ~HC_CONTROL_PLE;
				OHCI->HcControl &= ~HC_CONTROL_IE;
				
				memset((void *)&interrupt_td_head[i], 0, sizeof(interrupt_td_head[i]));
				memset((void *)&interrupt_td_tail[i], 0, sizeof(interrupt_td_tail[i]));

				interrupt_td_head[i].td_info.bBufferRounding = 1;
				interrupt_td_head[i].td_info.bDirectionPID = 3;
				interrupt_td_head[i].td_info.bDelayInterrupt = 0;
				interrupt_td_head[i].td_info.bDataToggle = 0;
				interrupt_td_head[i].td_info.bErrorCount = 0;
				interrupt_td_head[i].td_info.bConditionCode = 0;
				interrupt_td_head[i].pCurrentBufferPointer= buf;
				interrupt_td_head[i].p_next_td = NULL;
				interrupt_td_head[i].pBufferEnd = buf + buf_size - 1;

				/* Check the halt status. */
				if ((uint32_t)ed_header->p_td_head & 0x01) {
					return false;
				}

				p_td_head = (uint32_t)(&interrupt_td_head[i]);
				p_td_head &= 0xFFFFFFF0;
				*td_general_header = (struct ohci_td_general *)p_td_head;
				p_td_tail = (uint32_t)(ed_header->p_td_head);
				p_td_tail &= 0x0000000F;
				p_td_head |= p_td_tail;
				ed_header->p_td_head = (void *)p_td_head;
				ed_header->p_td_tail = NULL;

				OHCI->HcControl |= HC_CONTROL_PLE;
				OHCI->HcControl |= HC_CONTROL_IE;

				return true;
			} else {
				/* Wait for transfer done. */
				do {
					p_td_head = ((uint32_t)(ed_header->p_td_head)) & 0xFFFFFFF0;
					p_td_tail = ((uint32_t)(ed_header->p_td_tail)) & 0xFFFFFFF0;
				} while(p_td_head != p_td_tail);

				OHCI->HcControl &= ~HC_CONTROL_PLE;
				OHCI->HcControl &= ~HC_CONTROL_IE;
				
				memset((void *)&isochronous_td_head[i], 0, sizeof(isochronous_td_head[i]));
				memset((void *)&isochronous_td_tail[i], 0, sizeof(isochronous_td_tail[i]));

				/* Start after 3 frame. */
				isochronous_td_head[i].td_info.bStartingFrame = ohci_get_frame_number() + 3;
				isochronous_td_head[i].td_info.bDelayInterrupt = 0;
				isochronous_td_head[i].td_info.FrameCount = 0;				// one frame transaction
				isochronous_td_head[i].td_info.bConditionCode = 0;
				isochronous_td_head[i].pBufferPage0= buf;
				isochronous_td_head[i].p_next_td = NULL;
				isochronous_td_head[i].pBufferEnd = buf + buf_size - 1;
				isochronous_td_head[i].offset_psw[0] = 0;

				/* Check the halt status. */
//				if ((uint32_t)ed_header->p_td_head & 0x01) {
//					return false;
//				}

				// set the skip
//				ed_header->ed_info.ed_info_s.bSkip = 1;

				ed_header->p_td_head = (void *)&isochronous_td_head[i];
				ed_header->p_td_tail = NULL;

				// clear the skip
//				ed_header->ed_info.ed_info_s.bSkip = 0;

				OHCI->HcControl |= HC_CONTROL_PLE;
				OHCI->HcControl |= HC_CONTROL_IE;
					
				return true;
			}
		}
	}
	return false;
}
예제 #2
0
uint16_t uhd_get_frame_number(void)
{
	return ohci_get_frame_number();
}