⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ohci.c

📁 newos is new operation system
💻 C
📖 第 1 页 / 共 2 页
字号:
				td0, td0->phys_addr, td0->flags, td0->curr_buf_ptr, td0->buf_end, td0->next_td);			// new tail			td1->ed = NULL;			td1->usb_transfer = NULL;			td1->transfer_head = td1->transfer_next = NULL;			SHOW_FLOW(6, "td1 %p (0x%lx) flags 0x%x, curr_buf_ptr 0x%x, buf_end 0x%x, next_td 0x%x",				td1, td1->phys_addr, td1->flags, td1->curr_buf_ptr, td1->buf_end, td1->next_td);			ed->tail_td = td1;			ed->tail = td1->phys_addr;			oi->regs->command_status = COMMAND_BLF;			mutex_unlock(&oi->hc_list_lock);			break;		}		default:			SHOW_ERROR(0, "unsupported transfer type %d", ed->usb_ed->attributes & 0x3);			return ERR_UNIMPLEMENTED;	}	return NO_ERROR;}#if 1static void ohci_test(ohci *oi){	static usb_endpoint_descriptor desc = {		sizeof(usb_endpoint_descriptor),		USB_DESCRIPTOR_ENDPOINT,		0, 0, 8, 0	};	static const usb_request GET_DESCRIPTOR = {		USB_REQTYPE_DEVICE_IN,		USB_REQUEST_GET_DESCRIPTOR,		USB_DESCRIPTOR_DEVICE << 8, 0, 8	};	static const usb_request SET_ADDR = {		USB_REQTYPE_DEVICE_OUT,		USB_REQUEST_SET_ADDRESS,		1, 0, 0	};	static uchar buf[512];	unsigned char *aligned_buf = (unsigned char *)((((addr_t)buf) & 0xffffffc0) + 0x40);	static usb_hc_transfer transfer;	ohci_ed *ed0, *ed1;	ed0 = create_endpoint(oi, &desc, 0, 0);	memcpy(aligned_buf, &GET_DESCRIPTOR, 8);	transfer.setup_buf = aligned_buf;	transfer.setup_len = 8;	transfer.data_buf = aligned_buf;	transfer.data_len = 8;	transfer.callback = NULL;	transfer.completion_sem = sem_create(0, "transaction sem");	ohci_enqueue_transfer(oi, ed0, &transfer);	sem_acquire_etc(transfer.completion_sem, 1, SEM_FLAG_TIMEOUT, 5000000, NULL);	SHOW_FLOW(5, "transaction completed with err 0x%x", transfer.status);	{		usb_device_descriptor *dev = (usb_device_descriptor *)aligned_buf;		SHOW_FLOW(5, "device: len %d class 0x%x subclass 0x%x protocol 0x%x",			dev->length, dev->device_class, dev->device_subclass, dev->device_protocol);	}	sem_delete(transfer.completion_sem);	memcpy(aligned_buf, &SET_ADDR, 8);	transfer.setup_buf = aligned_buf;	transfer.setup_len = 8;	transfer.data_buf = NULL;	transfer.data_len = 0;	transfer.callback = NULL;	transfer.completion_sem = sem_create(0, "transaction sem");	ohci_enqueue_transfer(oi, ed0, &transfer);	sem_acquire_etc(transfer.completion_sem, 1, SEM_FLAG_TIMEOUT, 5000000, NULL);	SHOW_FLOW(5, "transaction completed with err 0x%x", transfer.status);	sem_delete(transfer.completion_sem);	// new address	ed1 = create_endpoint(oi, &desc, 1, 0);	memcpy(aligned_buf, &GET_DESCRIPTOR, 8);	transfer.setup_buf = aligned_buf;	transfer.setup_len = 8;	transfer.data_buf = aligned_buf;	transfer.data_len = 8;	transfer.callback = NULL;	transfer.completion_sem = sem_create(0, "transaction sem");	ohci_enqueue_transfer(oi, ed1, &transfer);	sem_acquire_etc(transfer.completion_sem, 1, SEM_FLAG_TIMEOUT, 5000000, NULL);	SHOW_FLOW(5, "transaction completed with err 0x%x", transfer.status);	sem_delete(transfer.completion_sem);}#endifstatic ohci *ohci_init_hc(pci_info *pinfo){	int i;	ohci *oi;	ohci_ed *null_ed;	ohci_td *null_td;	uint32 saved_interval;	uint32 largest_packet;	oi = kmalloc(sizeof(ohci));	if(!oi)		goto err;	SHOW_INFO(0, "allocated structure at %p", oi);	memset(oi, 0, sizeof(*oi));	// find the irq	oi->irq = pinfo->u.h0.interrupt_line;	SHOW_INFO(0, "irq %d", oi->irq);	// XXX remove	if(oi->irq == 10)		goto err;	// map the controller's registers	oi->reg_region = vm_map_physical_memory(vm_get_kernel_aspace_id(), "ohci regs", (void **)&oi->regs,		REGION_ADDR_ANY_ADDRESS, pinfo->u.h0.base_register_sizes[0], LOCK_RW|LOCK_KERNEL,		pinfo->u.h0.base_registers[0]);	if(oi->reg_region < 0) {		SHOW_ERROR0(0, "ohci_init: error creating register region");		goto err;	}	SHOW_INFO(0, "regs at 0x%lx, mapped to %p, size 0x%lx", (addr_t)pinfo->u.h0.base_registers[0],		oi->regs, pinfo->u.h0.base_register_sizes[0]);	// print and check the hardware rev	SHOW_INFO(0, "hardware rev %d.%d%s", (oi->regs->revision >> 4) & 0xf, oi->regs->revision & 0xf,		oi->regs->revision & 0x100 ? " legacy support" : "");	if(((oi->regs->revision >> 4) & 0xf) != 1 || (oi->regs->revision & 0xf) != 0) {		SHOW_ERROR0(0, "hardware rev not supported, bailing...");		goto err1;	}	// create a region for the hcca memory	oi->hcca_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "ohci hcca", (void **)&oi->hcca,		REGION_ADDR_ANY_ADDRESS, OHCI_HCCA_SIZE, REGION_WIRING_WIRED_CONTIG, LOCK_RW|LOCK_KERNEL);	if(oi->hcca_region < 0) {		SHOW_ERROR0(0, "ohci_init: error creating hcca region");		goto err1;	}	vm_get_page_mapping(vm_get_kernel_aspace_id(), (addr_t)oi->hcca, &oi->hcca_phys);	SHOW_INFO(0, "hcca region at %p, physical address 0x%lx", oi->hcca, oi->hcca_phys);	// take the hardware back from SMM or anyone else that has had it before	if(oi->regs->control & CONTROL_IR) {		SHOW_INFO0(1, "SMM has control of the HC");		oi->regs->command_status = oi->regs->command_status | COMMAND_OCR;		// wait a total of 10ms for the host controller to come back to us		for(i = 0; i < 10; i++) {			if((oi->regs->control & CONTROL_IR) == 0) {				// it was released				break;			}			cpu_spin(1000); // 1ms		}		if(i >= 10) {			// SMM didn't release it			SHOW_ERROR0(0, "SMM will not release control of the HC");			goto err2;		}	}	// create a thread to process the done list for this hc	oi->done_list_sem = sem_create(0, "ohci done list sem");	oi->done_list_processor = thread_create_kernel_thread("ohci done list processor",		&ohci_done_list_processor, oi);	thread_set_priority(oi->done_list_processor, THREAD_RT_LOW_PRIORITY);	thread_resume_thread(oi->done_list_processor);	// set up some queues	oi->control_queue.head = NULL;	oi->control_queue.head_phys = &oi->regs->control_head_ed;	oi->bulk_queue.head = NULL;	oi->bulk_queue.head_phys = &oi->regs->bulk_head_ed;	mutex_init(&oi->hc_list_lock, "ohci list lock");	// create a pool of transfer descriptors out of the remainder of the hcca region	{		addr_t ptr;		ohci_td *td;		ptr = (addr_t)oi->hcca + sizeof(ohci_hcca);		oi->td_freelist = NULL;		mutex_init(&oi->td_freelist_lock, "ohci td freelist lock");		while(ptr < ((addr_t)oi->hcca + OHCI_HCCA_SIZE)) {			td = (ohci_td *)ptr;			td->phys_addr = oi->hcca_phys + ((addr_t)ptr - (addr_t)oi->hcca);			td->next = oi->td_freelist; // add it to the freelist			oi->td_freelist = td;			ptr += sizeof(ohci_td);		}	}	// allocate a null endpoint and transfer descriptor for the 63 interrupt queues we'll have	for(i = 0; i < 63; i++) {		// allocate a null transfer descriptor		null_td = allocate_td(oi);		// create a null endpoint descriptor		null_ed = create_ed();		null_ed->flags = 0;		null_ed->head = null_ed->tail = null_td->phys_addr;		null_ed->next = 0;		null_ed->next_ed = NULL;		oi->interrupt_queue[i].head = null_ed;		oi->interrupt_queue[i].head_phys = &null_ed->next;	}	// set up the interrupt 'tree' shown on page 10 of the OHCI spec 1.0a	for(i=0; i < 2; i++) {		oi->interrupt_queue[INT_Q_2MS + i].head->next_ed = oi->interrupt_queue[INT_Q_1MS].head;		oi->interrupt_queue[INT_Q_2MS + i].head->next = *oi->interrupt_queue[INT_Q_1MS].head_phys;	}	for(i=0; i < 4; i++) {		oi->interrupt_queue[INT_Q_4MS + i].head->next_ed = oi->interrupt_queue[INT_Q_2MS + i/2].head;		oi->interrupt_queue[INT_Q_4MS + i].head->next = *oi->interrupt_queue[INT_Q_2MS + i/2].head_phys;	}	for(i=0; i < 8; i++) {		oi->interrupt_queue[INT_Q_8MS + i].head->next_ed = oi->interrupt_queue[INT_Q_4MS + i/4].head;		oi->interrupt_queue[INT_Q_8MS + i].head->next = *oi->interrupt_queue[INT_Q_4MS + i/4].head_phys;	}	for(i=0; i < 16; i++) {		oi->interrupt_queue[INT_Q_16MS + i].head->next_ed = oi->interrupt_queue[INT_Q_8MS + i/8].head;		oi->interrupt_queue[INT_Q_16MS + i].head->next = *oi->interrupt_queue[INT_Q_8MS + i/8].head_phys;	}	for(i=0; i < 32; i++) {		oi->interrupt_queue[INT_Q_32MS + i].head->next_ed = oi->interrupt_queue[INT_Q_16MS + i/16].head;		oi->interrupt_queue[INT_Q_32MS + i].head->next = *oi->interrupt_queue[INT_Q_16MS + i/16].head_phys;		oi->hcca->interrupt_table[i] = oi->interrupt_queue[INT_Q_32MS + i].head->phys_addr;	}	// install the interrupt handler	int_set_io_interrupt_handler(oi->irq, &ohci_interrupt, oi, "ohci");	// save the frame interval from the card	saved_interval = oi->regs->frame_interval & 0x3fff;	// calculate the largest packet size	largest_packet = ((saved_interval - 210) * 6) / 7;	SHOW_FLOW(1, "largest packet %d", largest_packet);	// reset the controller	oi->regs->command_status = COMMAND_HCR;	for(i = 0; i < 100; i++) {		if((oi->regs->control & COMMAND_HCR) == 0) {			// it reset			break;		}		cpu_spin(10); // 1us	}	if(i >= 100) {		SHOW_ERROR0(0, "failed to reset the HC");		goto err3;	}	// restore the frame interval register	oi->regs->frame_interval = (largest_packet << 16) | saved_interval | 0x80000000;	oi->regs->periodic_start = (saved_interval * 9) / 10; // 90% of frame interval	oi->regs->ls_threshold = 8*8*8*7/6*2;	SHOW_FLOW(1, "ls threshold %d", oi->regs->ls_threshold);	oi->hcca->done_head = 0;	oi->regs->HCCA = oi->hcca_phys;	oi->regs->bulk_head_ed = 0;	oi->regs->bulk_current_ed = 0;	oi->regs->control_head_ed = 0;	oi->regs->control_current_ed = 0;	oi->regs->interrupt_disable = 0xffffffff;	oi->regs->interrupt_status = 0xffffffff;	// start it up	oi->regs->control = CONTROL_HCFS_OPERATIONAL | CONTROL_CLE | CONTROL_BLE | CONTROL_PLE;	thread_snooze(5000);	// reset a couple of the root ports	// XXX move this into root hub code	oi->rh_ports = (oi->regs->rh_descriptor_a & 0xff);	SHOW_FLOW(1, "%d root ports", oi->rh_ports);	oi->regs->rh_descriptor_a |= 0x0100;	oi->regs->rh_descriptor_b |= 0x60000;	for(i=0; i < oi->rh_ports; i++)		oi->regs->rh_port_status[i] = 0x100; // set port power	thread_snooze(1000);	for(i=0; i < oi->rh_ports; i++)		oi->regs->rh_port_status[i] = 0x10; // reset port	thread_snooze(10000);	for(i=0; i < oi->rh_ports; i++)		oi->regs->rh_port_status[i] = 0x2; // enable port	thread_snooze(10000);	// enable all interrupts except Start Of Frame	oi->regs->interrupt_enable = INT_MIE | INT_OC | /* INT_RHSC | */ INT_FNO | INT_UE | INT_RD | INT_WDH | INT_SO;//	thread_snooze(1000000);//	ohci_test(oi);	return oi;err3:	mutex_destroy(&oi->hc_list_lock);	mutex_destroy(&oi->td_freelist_lock);err2:	vm_delete_region(vm_get_kernel_aspace_id(), oi->hcca_region);err1:	vm_delete_region(vm_get_kernel_aspace_id(), oi->reg_region);err:	if(oi)		kfree(oi);	return NULL;}static int ohci_init(int (*hc_init_callback)(void *callback_cookie, void *cookie), void *callback_cookie){	int i;	pci_module_hooks *pci;	pci_info pinfo;	ohci *oi;	int count = 0;	if(module_get(PCI_BUS_MODULE_NAME, 0, (void **)&pci) < 0) {		SHOW_ERROR0(0, "ohci_detect: no pci bus found..");		return -1;	}	for(i = 0; pci->get_nth_pci_info(i, &pinfo) >= NO_ERROR; i++) {		if(pinfo.class_base == OHCI_BASE_CLASS &&		   pinfo.class_sub == OHCI_SUB_CLASS &&		   pinfo.class_api == OHCI_INTERFACE) {#if 0			{				int j;				for(j=0; j < 6; j++) {					dprintf(" %d: base 0x%x size 0x%x\n", j, pinfo.u.h0.base_registers[j], pinfo.u.h0.base_register_sizes[j]);				}			}#endif			oi = ohci_init_hc(&pinfo);			if(oi) {				// add it to our list of ohci hcfs				oi->next = oi_list;				oi_list = oi;				count++;				// register it with the bus				hc_init_callback(callback_cookie, oi);			}		}	}	module_put(PCI_BUS_MODULE_NAME);	return count;}static intohci_uninit(void *cookie){	// XXX finish	return ERR_UNIMPLEMENTED;}static intohci_module_init(void){	return NO_ERROR;}static intohci_module_uninit(void){	return NO_ERROR;}static struct usb_hc_module_hooks ohci_hooks = {	&ohci_init, // bus initialization	&ohci_uninit,	&ohci_create_endpoint,	&ohci_destroy_endpoint,	&ohci_enqueue_transfer,};static module_header ohci_module_header = {	USB_HC_MODULE_NAME_PREFIX "/ohci/v1",	MODULE_CURR_VERSION,	0, // dont keep loaded	&ohci_hooks,	&ohci_module_init,	&ohci_module_uninit};module_header *modules[]  = {	&ohci_module_header,	NULL};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -