UHCI Counter in VMware?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
iocoder
Member
Member
Posts: 208
Joined: Sun Oct 18, 2009 5:47 pm
Libera.chat IRC: iocoder
Location: Alexandria, Egypt | Ottawa, Canada
Contact:

UHCI Counter in VMware?

Post by iocoder »

Hello All,
I was trying to implement a UHCI Driver. I have my initialization code that sets the frame list base address, frame list counter, and sets RUN/STOP to 1. Monitoring the counter, in QEMU, it works well and counts from 0 to 2047. but in VMWare, it counts slowly until it reach 300s, when it is increaded by one each second in a very slow way. Is there something wrong have been done? and I would be happy to know about the steps of initialization process of UHCI.
Regards,
Mostafa.
User avatar
osdnlo
Member
Member
Posts: 136
Joined: Thu Feb 25, 2010 5:39 pm

Re: UHCI Counter in VMware?

Post by osdnlo »

Hi mostafazizo: See http://forum.osdev.org/viewtopic.php?f=11&t=21679 for help with getting the USB debug info. Vmware is probably just a lot more demanding than QEMU (I don't know, I never used QEMU successfully) is, and from working with it (i.e., VMWARE), I think it expects perfection. As far as the steps for initialization go, you will need to read the USB specs. The UHCI specs don't really go over that, I think it is sort of implied (or I am continuously overlooking it). You can try to take a look at linux code too. Or, you can post what you have so far and I will take a look at it for you. Whatever floats your boat. :)
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
User avatar
iocoder
Member
Member
Posts: 208
Joined: Sun Oct 18, 2009 5:47 pm
Libera.chat IRC: iocoder
Location: Alexandria, Egypt | Ottawa, Canada
Contact:

Re: UHCI Counter in VMware?

Post by iocoder »

Dear osdnlo,
Thanks much for your answer, i have edited my vmx file, and now i run VMware in debug mode, but i don't know how to get debug info, or how to know about errors taking place in VMware.
I had read UHCI specs before trying to implement it, but i didn't find any about initialization. i also tried to look for it in USB Specification, but i failed. Do you know where i could find about this??? (notice that i want to initialize UHCI Host Controller only to get it work well on VMware).
Regards,
Mostafa.
User avatar
osdnlo
Member
Member
Posts: 136
Joined: Thu Feb 25, 2010 5:39 pm

Re: UHCI Counter in VMware?

Post by osdnlo »

Well, if you do, then please share with the rest of us. I have been trying to get vmware to play nice for about a month now and it's been pretty rough.

The log file is located in the same directory that your vmx is located when vmware starts. Probably. C:\DOCUME~1\MYVIRT~1\<name of your vmx>, you know, something like that. Inside your My Documents folder, nested in another folder named My Virtual Machines. The file you want to keep an eye is called vmware.log. What I do is I open that file in Firefox, and I have a plug-in that reloads the page every N seconds, and I just watch it fill up as the vm is running. Look for things like: USBGW, USBIO, UHCI, etc. Vmware even has a program they wrote to parse your log, but it doesn't work well on Windows, says the horses mouth.

I would suggest looking at linux code. I think it is some of the best example of code I have seen to date, in regards to UHCI. They have a real sophisticated way of initializing the controller that I too have been inspired by. You might also track down good ol' Geezer code. I know he wrote a nice example, but it is highly incomplete. However, it does demonstrate how to create the TDs and QH properly, so it's worth a look.

http://www.google.com/codesearch/p?hl=e ... temp/usb.c

I hope this helps. Post back if you run into any more trouble. ;)
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
User avatar
iocoder
Member
Member
Posts: 208
Joined: Sun Oct 18, 2009 5:47 pm
Libera.chat IRC: iocoder
Location: Alexandria, Egypt | Ottawa, Canada
Contact:

Re: UHCI Counter in VMware?

Post by iocoder »

thnxxxxxxxxxx a lot osdnlo, i had a look on the link, i've read the function of initializing uhci, but it seems really no difference!!!!!!
i found that he did something i didn't do, which is resetting PORT1 and PORT2, i tried to reset them, but absolutely no difference.
here is my uhci.cpp:

Code: Select all

#define UHCI	0x00	// Universal Host Controller Interface. Supports USB1 and USB1.1.

#define UHCI_REG_USBCMD		0x00
#define UHCI_REG_USBSTS		0x02
#define UHCI_REG_USBINTR	0x04
#define UHCI_REG_FRNUM		0x06
#define UHCI_REG_FRBASEADD	0x08
#define UHCI_REG_SOFMOD		0x0C
#define UHCI_REG_PORTSC1	0x10
#define UHCI_REG_PORTSC2	0x12

struct tdstr {
	unsigned char  T;	// Termination (1: Link is not valid, 0: Link is valid).
	unsigned char  QH;	// Queue Head (1: Link is to a QH, 0: Link is to a TD).
	unsigned char  Vf;	// Depth/Breadth Select (1: Depth First, 0: Breadth First).
	unsigned int   link;	// 32-Bit Memory Address of next descriptor.
	unsigned short ActLen;	// Actual Length.
	unsigned char  status;	// Status.
	unsigned char  IOC;	// Interrupt on Complete (1: Issue IOC after the current time frame).
	unsigned char  IOS;	// Isochronous Select (1: Isochronous TD, 0: Non-isochronous).
	unsigned char  LS;	// Low Speed Drive (1: Low Speed, 0: Full Speed).
	unsigned char  C_ERR;	// Counter Errot.
	unsigned char  SPD;	// Short Packet Detect (1: Enable, 0: Disable).
	unsigned char  PID;	// Packet Identification (0x69: IN, 0xE1: OUT, 0x2D: Setup).
	unsigned char  device;	// Device Address.
	unsigned char  EndPt;	// End Point.
	unsigned char  D;	// Data Toggle Synchronization.
	unsigned short MaxLen;	// Maximum Length.
	unsigned int   buffer;	// Buffer Pointer.
};

struct sixteenbytelen {
	unsigned int  lng[4];
};

struct eightbytelen {
	unsigned int  lng[2];
};

unsigned int    uhci_data[0x2000];	// 0x2000(Array size) * 4(int size) = 0x8000 byte (32KB).
unsigned int*   uhci_frlst;		// 4KB Frame List.
sixteenbytelen* uhci_tdlst;		// TD List.
eightbytelen*   uhci_qhlst;		// QH List.


void set_td(tdstr *td, unsigned int index) {
	uhci_tdlst[index].lng[0] =	(td[0].T	<<  0)|
					(td[0].QH	<<  1)|
					(td[0].Vf	<<  2)|
					(td[0].link	<<  0);
	uhci_tdlst[index].lng[1] =	(td[0].ActLen	<<  0)|
					(td[0].status	<< 16)|
					(td[0].IOC	<< 24)|
					(td[0].IOS	<< 25)|
					(td[0].LS	<< 26)|
					(td[0].C_ERR	<< 27)|
					(td[0].SPD	<< 29);
	uhci_tdlst[index].lng[2] =	(td[0].PID	<<  0)|
					(td[0].device	<<  8)|
					(td[0].EndPt	<< 15)|
					(td[0].D	<< 19)|
					(td[0].MaxLen	<< 21);
	uhci_tdlst[index].lng[3] =	(td[0].buffer	<<  0);
}

void uhci_init() {
	
	unsigned short ds; asm("movw %%ds, %%ax":"=a"(ds));
	unsigned int   i;
	printk(" Initializing UHCI USB Device Driver ...\n");
	
	// I: Initialize Pointers:
	uhci_frlst = (unsigned int	*) ((unsigned int) uhci_data & 0xFFFFF000); // 4KB Frame List.
	uhci_tdlst = (sixteenbytelen	*) ((unsigned int) &uhci_frlst[1024]); // 16KB TD List.
	uhci_qhlst = (eightbytelen	*) ((unsigned int) &uhci_tdlst[1024]); // 8KB QH List.
	
	// II: Resetting USB Host Controller:
	usbio.writeregw(0x04, UHCI_REG_USBCMD);
	sleep(10);	// 10ms delay is so enough.
	usbio.writeregw(0x00, UHCI_REG_USBCMD);
	sleep(100);	// 100ms delay is so enough.
	

	// III: Initialize Frame List:
		//1: Make Pointers:
		for (i = 0; i < 0x400; i++) {
			uhci_qhlst[i].lng[0] = uhci_qhlst[i].lng[1] = 0x00000001;
			uhci_frlst[i] = krnl_get_selector_base(ds) + (unsigned int) &uhci_qhlst[i] + 0x2;
		}
		
		// 2: Set the frame-list base in the Host Controller:
		usbio.writeregl(krnl_get_selector_base(ds) +
				(unsigned int) uhci_frlst, UHCI_REG_FRBASEADD);
		
		// 3: Set the time of frames:
		// For a 12MHz Motor, a value of 12000 makes each frame takes 1ms of time
		// (12000 vibration). the number of vibrations is calulated by adding the value of
		// first 7 bits of SOFMOD Register to 11936.
		usbio.writeregb(64,	UHCI_REG_SOFMOD); // 64+11936=12000. (1ms for each frame).
		
		// 4: Set Frame Number:
		usbio.writeregw(0x00,	UHCI_REG_FRNUM); // Start from first frame.
		
	
	// IV: Start the controller:
	usbio.writeregw(0x01,UHCI_REG_USBCMD);
	
	while (1) {
		printk(" Frame List Counter: %d.\n", usbio.readregw(UHCI_REG_FRNUM) & 0x3FF);
	}
	
}
User avatar
osdnlo
Member
Member
Posts: 136
Joined: Thu Feb 25, 2010 5:39 pm

Re: UHCI Counter in VMware?

Post by osdnlo »

Nice start. Your code looks real fine and clean. Good work thus far. :)

Some things that pop out at me right away is:

01. Now take a look at the LEGACY section of the USB UHCI spec. You need to make a check to see if it is on, if it is, turn it off.
02. You are not checking if the device is Low Speed or Full Speed. Make a check for that as you build the TDs. Don't just assume it is LS.
03. You should clear the CSC bit from all ports before you make your transaction, after you find a UHCI controller.
04. Make sure you also enable the port, then reset it before your first transaction. This causes the controller to force a port resume, which may not be necessary. You can check if the port is suspended first. b12.
05. Make sure the device you are testing is not High-Speed. If it is, then you will need to take ownership. See http://forum.osdev.org/viewtopic.php?f=1&t=21681
06. You may need to GRESUME if the controller is suspended. Make a check for that.

Other than that, you have a pretty good ideal of what needs to be done. And, like I said, take a look at linux code. You'll be glad you did. ;)

And, are you by chance using the Fat DS/nearptr hack? :)
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
User avatar
iocoder
Member
Member
Posts: 208
Joined: Sun Oct 18, 2009 5:47 pm
Libera.chat IRC: iocoder
Location: Alexandria, Egypt | Ottawa, Canada
Contact:

Re: UHCI Counter in VMware?

Post by iocoder »

osdnlo wrote:Nice start. Your code looks real fine and clean. Good work thus far. :)
:mrgreen:
osdnlo wrote:01. Now take a look at the LEGACY section of the USB UHCI spec. You need to make a check to see if it is on, if it is, turn it off.
DONE :D
osdnlo wrote:02. You are not checking if the device is Low Speed or Full Speed. Make a check for that as you build the TDs. Don't just assume it is LS.
I check a usb gamepad, but i'm still programming UHCI initialization. i don't assume that they are LS because there are no TDs already.
osdnlo wrote:03. You should clear the CSC bit from all ports before you make your transaction, after you find a UHCI controller.
DONE :D
osdnlo wrote:04. Make sure you also enable the port, then reset it before your first transaction. This causes the controller to force a port resume, which may not be necessary. You can check if the port is suspended first. b12..
DONE :D (but without checking)
osdnlo wrote:05. Make sure the device you are testing is not High-Speed. If it is, then you will need to take ownership. See http://forum.osdev.org/viewtopic.php?f=1&t=21681
I check a full-speed usb gamepad, but i'm still programming UHCI initialization.
osdnlo wrote:06. You may need to GRESUME if the controller is suspended. Make a check for that.
DONE :D

Despite all of that, i am still facing this strange behavior of VMware. here is my new code:

Code: Select all

#define UHCI	0x00	// Universal Host Controller Interface. Supports USB1 and USB1.1.

#define UHCI_REG_USBCMD		0x00
#define UHCI_REG_USBSTS		0x02
#define UHCI_REG_USBINTR	0x04
#define UHCI_REG_FRNUM		0x06
#define UHCI_REG_FRBASEADD	0x08
#define UHCI_REG_SOFMOD		0x0C
#define UHCI_REG_PORTSC1	0x10
#define UHCI_REG_PORTSC2	0x12

struct tdstr {
	unsigned char  T;	// Termination (1: Link is not valid, 0: Link is valid).
	unsigned char  QH;	// Queue Head (1: Link is to a QH, 0: Link is to a TD).
	unsigned char  Vf;	// Depth/Breadth Select (1: Depth First, 0: Breadth First).
	unsigned int   link;	// 32-Bit Memory Address of next descriptor.
	unsigned short ActLen;	// Actual Length.
	unsigned char  status;	// Status.
	unsigned char  IOC;	// Interrupt on Complete (1: Issue IOC after the current time frame).
	unsigned char  IOS;	// Isochronous Select (1: Isochronous TD, 0: Non-isochronous).
	unsigned char  LS;	// Low Speed Drive (1: Low Speed, 0: Full Speed).
	unsigned char  C_ERR;	// Counter Errot.
	unsigned char  SPD;	// Short Packet Detect (1: Enable, 0: Disable).
	unsigned char  PID;	// Packet Identification (0x69: IN, 0xE1: OUT, 0x2D: Setup).
	unsigned char  device;	// Device Address.
	unsigned char  EndPt;	// End Point.
	unsigned char  D;	// Data Toggle Synchronization.
	unsigned short MaxLen;	// Maximum Length.
	unsigned int   buffer;	// Buffer Pointer.
};

struct sixteenbytelen {
	unsigned int  lng[4];
};

struct eightbytelen {
	unsigned int  lng[2];
};

unsigned int    uhci_data[0x2000];	// 0x2000(Array size) * 4(int size) = 0x8000 byte (32KB).
unsigned int*   uhci_frlst;		// 4KB Frame List.
sixteenbytelen* uhci_tdlst;		// TD List.
eightbytelen*   uhci_qhlst;		// QH List.


void set_td(tdstr *td, unsigned int index) {
	uhci_tdlst[index].lng[0] =	(td[0].T	<<  0)|
					(td[0].QH	<<  1)|
					(td[0].Vf	<<  2)|
					(td[0].link	<<  0);
	uhci_tdlst[index].lng[1] =	(td[0].ActLen	<<  0)|
					(td[0].status	<< 16)|
					(td[0].IOC	<< 24)|
					(td[0].IOS	<< 25)|
					(td[0].LS	<< 26)|
					(td[0].C_ERR	<< 27)|
					(td[0].SPD	<< 29);
	uhci_tdlst[index].lng[2] =	(td[0].PID	<<  0)|
					(td[0].device	<<  8)|
					(td[0].EndPt	<< 15)|
					(td[0].D	<< 19)|
					(td[0].MaxLen	<< 21);
	uhci_tdlst[index].lng[3] =	(td[0].buffer	<<  0);
}

void uhci_init() {
	
	unsigned short ds; asm("movw %%ds, %%ax":"=a"(ds));
	unsigned int   i;
	printk(" Initializing UHCI USB Device Driver ...\n");
	
	// I: Initialize Pointers:
	uhci_frlst = (unsigned int	*) ((unsigned int) uhci_data & 0xFFFFF000); // 4KB Frame List.
	uhci_tdlst = (sixteenbytelen	*) ((unsigned int) &uhci_frlst[1024]); // 16KB TD List.
	uhci_qhlst = (eightbytelen	*) ((unsigned int) &uhci_tdlst[1024]); // 8KB QH List.
	
	// II: Resetting USB Host Controller:
	usbio.writeregw(0x04, UHCI_REG_USBCMD);
	sleep(10);	// 10ms delay is so enough.
	usbio.writeregw(0x00, UHCI_REG_USBCMD);
	sleep(100);	// 100ms delay is so enough.
	
	// III: Rsetting Ports:
	usbio.writeregw(0x024E, UHCI_REG_PORTSC1); // Reset, Enable, Clear CSC
	sleep(10);	// 10ms delay is so enough.
	usbio.writeregw(0x004E, UHCI_REG_PORTSC1);
	usbio.writeregw(0x024E, UHCI_REG_PORTSC2);
	sleep(10);	// 10ms delay is so enough.
	usbio.writeregw(0x004E, UHCI_REG_PORTSC2);

	// IV: Enable Legacy Support for KB and Mouse:
	unsigned char bus = usb_pack[0x12];
	unsigned char device = usb_pack[0x13];
	unsigned char function = usb_pack[0x14];
	outl((1<<31) | (bus<<16) | (device<<11) | (function<<8) | 0xC0, 0xCF8);
	outw(0x20FF, 0xCFC);
	
	// V: Initialize Frame List:
		// 1: Set the time of frames:
		// For a 12MHz Motor, a value of 12000 makes each frame takes 1ms of time
		// (12000 vibration). the number of vibrations is calulated by adding the value of
		// first 7 bits of SOFMOD Register to 11936.
		usbio.writeregb(64,	UHCI_REG_SOFMOD); // 64+11936=12000. (1ms for each frame).
		
		// 2: Make Pointers:
		for (i = 0; i < 0x400; i++) {
			uhci_qhlst[i].lng[0] = uhci_qhlst[i].lng[1] = 0x00000001;
			uhci_frlst[i] = krnl_get_selector_base(ds) + (unsigned int) &uhci_qhlst[i] + 0x2;
		}
		
		// 3: Set the frame-list base in the Host Controller:
		usbio.writeregl(krnl_get_selector_base(ds) +
				(unsigned int) uhci_frlst, UHCI_REG_FRBASEADD);
		
		
	// VI: Start the controller:
	usbio.writeregw(0x01,UHCI_REG_USBCMD); // RUN
	
	while (1) {
		printk(" Frame List Counter: %d.\n", usbio.readregw(UHCI_REG_FRNUM) & 0x3FF);
	}
	
}
osdnlo wrote:Other than that, you have a pretty good ideal of what needs to be done. And, like I said, take a look at linux code. You'll be glad you did. ;)
Believe me, i have been checking Linux Source Code since your first post in this topic according to ur advice. :D
And, are you by chance using the Fat DS/nearptr hack? :)
???????????

Regards,
Mostafa
User avatar
osdnlo
Member
Member
Posts: 136
Joined: Thu Feb 25, 2010 5:39 pm

Re: UHCI Counter in VMware?

Post by osdnlo »

Well, it seems like you are doing everything correctly, so it may be a vmware thing. The best thing to do now would be to ask the horse itself. See http://communities.vmware.com/search.jspa. Post back if you find a solution. :)
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
User avatar
iocoder
Member
Member
Posts: 208
Joined: Sun Oct 18, 2009 5:47 pm
Libera.chat IRC: iocoder
Location: Alexandria, Egypt | Ottawa, Canada
Contact:

Re: UHCI Counter in VMware?

Post by iocoder »

hello again,
i tried the driver on Bochs, and it runs perfectly with no error, so the error might be from VMware 7 itself. but i tried to test the driver on VMware 6 simulation, and i found something strange:
The SOF frame time takes 1 second rather than 1ms.
i don't know the reason of that, may be the counter is 12 KHz and not 12MHz?
the strange is that i tested a variety of operating systems like Microsoft Windows XP, Linux Ubuntu and Linux Kubuntu on VMware (6, 7) and they control UHCI correctly and without reporting errors.
plz anyone have any idea????
Well, it seems like you are doing everything correctly, so it may be a vmware thing. The best thing to do now would be to ask the horse itself. See http://communities.vmware.com/search.jspa. Post back if you find a solution. :)
i searched for a topic that discusses this problem, but found nothing, i reported there for my error, but no reply till now!
Regards,
Mostafa
User avatar
osdnlo
Member
Member
Posts: 136
Joined: Thu Feb 25, 2010 5:39 pm

Re: UHCI Counter in VMware?

Post by osdnlo »

They are probably still trying to replicate your issue and haven't found an answer yet. Just give them some more time and I am sure they will address it soon. ;)

I am using the VMware Player 3.0.1 and I am not able to replicate your issue myself. The frames pass by really fast for me, as expected. Why not post your vmware log the next time you make a test and notice this issue. Perhaps the answer is in there. :)
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
User avatar
iocoder
Member
Member
Posts: 208
Joined: Sun Oct 18, 2009 5:47 pm
Libera.chat IRC: iocoder
Location: Alexandria, Egypt | Ottawa, Canada
Contact:

Re: UHCI Counter in VMware?

Post by iocoder »

Hi Again,
They are probably still trying to replicate your issue and haven't found an answer yet. Just give them some more time and I am sure they will address it soon. ;)
Waiting ... :D
Why not post your vmware log the next time you make a test and notice this issue. Perhaps the answer is in there. :)
I have attached my log file, notice that i am running VMware in debug mode.

UPDATE: I noticed something maddening in the log file:
Mar 21 06:54:43.253: mks| MKS: Base polling period is 1000000us
1000000us (micro-second) = 1000ms (millisecond) = 1s (second), may be this is relating to our problem?

Regards,
Mostafa.
Attachments
vmware.zip
(13.89 KiB) Downloaded 282 times
User avatar
osdnlo
Member
Member
Posts: 136
Joined: Thu Feb 25, 2010 5:39 pm

Re: UHCI Counter in VMware?

Post by osdnlo »

Hi, I took a look at your log and right away I see this:
Mar 21 06:54:35.285: vcpu-0| UHCI: HCReset
Mar 21 06:54:35.533: vcpu-0| VMSAMPLE32: cs=0x8, eip=0x1041d0
Mar 21 06:54:36.543: vcpu-0| VMSAMPLE32: cs=0x8, eip=0x104f62
Mar 21 06:54:37.543: vcpu-0| VMSAMPLE32: cs=0x38, eip=0x322
Mar 21 06:54:38.563: vcpu-0| VMSAMPLE32: cs=0x8, eip=0x104f61
Mar 21 06:54:39.615: vcpu-0| VMSAMPLE32: cs=0x8, eip=0x101dd2
Mar 21 06:54:40.623: vcpu-0| VMSAMPLE32: cs=0x8, eip=0x1051bc
Mar 21 06:54:40.674: mks| MKS lock releasing
Mar 21 06:54:41.632: vcpu-0| VMSAMPLE32: cs=0x8, eip=0x1041d0
Mar 21 06:54:42.651: vcpu-0| VMSAMPLE32: cs=0x8, eip=0x1050bc
Mar 21 06:54:43.194: vmx| VMXVmdbCbVmVmxExecState: Exec state change requested to state poweredOff without reset, hard.
Mar 21 06:54:43.194: vmx| Stopping VCPU threads...
What's going on here? Are you resetting the VM, is it resetting on you? I noticed right after this, your driver begins echoing output to the screen, but you did not allow it to run long enough to demonstrate that the FRNUM is changing too slowly, so I cannot verify what's wrong based on this log. I know you must be getting frustrated by now. Just hang in there, we'll figure it out. ;)
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
User avatar
iocoder
Member
Member
Posts: 208
Joined: Sun Oct 18, 2009 5:47 pm
Libera.chat IRC: iocoder
Location: Alexandria, Egypt | Ottawa, Canada
Contact:

Re: UHCI Counter in VMware?

Post by iocoder »

The Driver resets the HC, then it waits for me to press any key from keyboard, and then it prints the current frame number. and then it waits again to repeat the same process.
what happened is that i kept my finger pressing on 'Enter' and it the driver printed 4 many times for a second, then 5 for another second, then 6 for another second.... the log file captured a random screen that is full with '4'.
In QEMU and Bochs, when i do that, numbers change quickly, because it prints 4 in a millisecond, 5 in a millisecond ...

Code: Select all

 I know you must be getting frustrated by now. Just hang in there, we'll figure it out. 
No, i am not getting frustrated, because nothing is wrong till now, but when we find that this problem is a result of something wrong in my code, i will be frustrated in a way that will make me not programme again :lol:
User avatar
osdnlo
Member
Member
Posts: 136
Joined: Thu Feb 25, 2010 5:39 pm

Re: UHCI Counter in VMware?

Post by osdnlo »

Well, you're a better man than I am. I would have tossed my computer out the window and called it a day by now. Hmmm... I never saw where you performed an HCRESET. You know when you HCRESET you reset the internal counters and such, so you might try doing that (i.e. (1<<1)). ;)
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
User avatar
iocoder
Member
Member
Posts: 208
Joined: Sun Oct 18, 2009 5:47 pm
Libera.chat IRC: iocoder
Location: Alexandria, Egypt | Ottawa, Canada
Contact:

Re: UHCI Counter in VMware?

Post by iocoder »

I never saw where you performed an HCRESET.
how?

Code: Select all

#define UHCI	0x00	// Universal Host Controller Interface. Supports USB1 and USB1.1.

#define UHCI_REG_USBCMD		0x00
#define UHCI_REG_USBSTS		0x02
#define UHCI_REG_USBINTR	0x04
#define UHCI_REG_FRNUM		0x06
#define UHCI_REG_FRBASEADD	0x08
#define UHCI_REG_SOFMOD		0x0C
#define UHCI_REG_PORTBASE	0x10

#define UHCI_USBLEGSUP		0xc0		/* legacy support */
#define UHCI_USBLEGSUP_RWC	0x8f00		/* the R/WC bits */
#define UHCI_USBLEGSUP_RO	0x5040		/* R/O and reserved bits */
#define UHCI_USBCMD_RUN		0x0001		/* RUN/STOP bit */
#define UHCI_USBCMD_HCRESET	0x0002		/* Host Controller reset */
#define UHCI_USBCMD_GRESET	0x0004		/* Global Reset */
#define UHCI_USBCMD_EGSM	0x0008		/* Global Suspend Mode */
#define UHCI_USBCMD_CONFIGURE	0x0040		/* Config Flag */
#define UHCI_USBINTR_RESUME	0x0002		/* Resume interrupt enable */

#include <keypad.h>

struct tdstr {
	unsigned char  T;	// Termination (1: Link is not valid, 0: Link is valid).
	unsigned char  QH;	// Queue Head (1: Link is to a QH, 0: Link is to a TD).
	unsigned char  Vf;	// Depth/Breadth Select (1: Depth First, 0: Breadth First).
	unsigned int   link;	// 32-Bit Memory Address of next descriptor.
	unsigned short ActLen;	// Actual Length.
	unsigned char  status;	// Status.
	unsigned char  IOC;	// Interrupt on Complete (1: Issue IOC after the current time frame).
	unsigned char  IOS;	// Isochronous Select (1: Isochronous TD, 0: Non-isochronous).
	unsigned char  LS;	// Low Speed Drive (1: Low Speed, 0: Full Speed).
	unsigned char  C_ERR;	// Counter Errot.
	unsigned char  SPD;	// Short Packet Detect (1: Enable, 0: Disable).
	unsigned char  PID;	// Packet Identification (0x69: IN, 0xE1: OUT, 0x2D: Setup).
	unsigned char  device;	// Device Address.
	unsigned char  EndPt;	// End Point.
	unsigned char  D;	// Data Toggle Synchronization.
	unsigned short MaxLen;	// Maximum Length.
	unsigned int   buffer;	// Buffer Pointer.
};

struct sixteenbytelen {
	unsigned int  lng[4];
};

struct eightbytelen {
	unsigned int  lng[2];
};

unsigned int    uhci_data[0x2000];	// 0x2000(Array size) * 4(int size) = 0x8000 byte (32KB).
unsigned int*   uhci_frlst;		// 4KB Frame List.
sixteenbytelen* uhci_tdlst;		// TD List.
eightbytelen*   uhci_qhlst;		// QH List.
unsigned int    uhci_ports;		// Number of Ports.


void set_td(tdstr td, unsigned int index) {
	uhci_tdlst[index].lng[0] =	(td.T		<<  0)|
					(td.QH		<<  1)|
					(td.Vf		<<  2)|
					(td.link	<<  0);
	uhci_tdlst[index].lng[1] =	(td.ActLen	<<  0)|
					(td.status	<< 16)|
					(td.IOC		<< 24)|
					(td.IOS		<< 25)|
					(td.LS		<< 26)|
					(td.C_ERR	<< 27)|
					(td.SPD		<< 29);
	uhci_tdlst[index].lng[2] =	(td.PID		<<  0)|
					(td.device	<<  8)|
					(td.EndPt	<< 15)|
					(td.D		<< 19)|
					(td.MaxLen	<< 21);
	uhci_tdlst[index].lng[3] =	(td.buffer	<<  0);
}

void uhci_init() {
	
	unsigned short ds; asm("movw %%ds, %%ax":"=a"(ds));
	unsigned int   i;
	unsigned char bus  = usb_pack[0x12];
	unsigned char dev  = usb_pack[0x13];
	unsigned char func = usb_pack[0x14];
	unsigned char reset = 0;
	printk(" Initializing UHCI USB Device Driver ...\n");
	
	// I: Initialize Pointers:
	// ----------------------------
	uhci_frlst = (unsigned int	*) ((unsigned int) uhci_data & 0xFFFFF000); // 4KB Frame List.
	uhci_tdlst = (sixteenbytelen	*) ((unsigned int) &uhci_frlst[1024]); // 16KB TD List.
	uhci_qhlst = (eightbytelen	*) ((unsigned int) &uhci_tdlst[1024]); // 8KB QH List.
	
	// II: Get Number of Ports:
	// ----------------------------
	for (i = 0; i < 0x10; i+=2)
		if (!(usbio.readregw(UHCI_REG_PORTBASE + i) & 0x0080)
			|| usbio.readregw(UHCI_REG_PORTBASE + i) == 0xffff) break;
	if((uhci_ports = (i/2)) > 7) uhci_ports = 2;
	
	// III: Restart UHCI:
	// ----------------------------
	/* Turn on PIRQ enable and SMI enable.
	 * This turns on legacy support for keyboard and mouse.
	 */
	pci_writew(0xFFFF, bus, dev, func, UHCI_USBLEGSUP);

	/* Reset the HC - this will force us to get a
	 * new notification of any already connected
	 * ports due to the virtual disconnect that it
	 * implies.
	 */
	usbio.writeregw(UHCI_USBCMD_HCRESET, UHCI_REG_USBCMD);
	while (usbio.readregw(UHCI_REG_USBCMD) & UHCI_USBCMD_HCRESET); // Wait

	/* Just to be safe, disable interrupt requests and
	 * make sure the controller is stopped.
	 */
	usbio.writeregw(0, UHCI_REG_USBINTR);
	usbio.writeregw(0, UHCI_REG_USBCMD);
		
	/* HCRESET doesn't affect the Suspend, Reset, and Resume Detect
	 * bits in the port status and control registers.
	 * We have to clear them by hand.
	 */
	for (i = 0; i < 2; ++i)
		usbio.writeregw(0, UHCI_REG_PORTBASE + (i * 2));

	// IV: Initialize the HC:
	// ----------------------------
		// 1: Set the time of frames:
		// For a 12MHz Motor, a value of 12000 makes each frame takes 1ms of time
		// (12000 vibration). the number of vibrations is calulated by adding the value of
		// first 7 bits of SOFMOD Register to 11936.
		usbio.writeregb(64, UHCI_REG_SOFMOD); // 64+11936=12000. (1ms for each frame).
		
		// 2: Make Pointers:
		static tdstr std;
		std.T = 1;
		std.device = 0x7f;
		std.PID = 0x69; 
		
		for (i = 0; i < 0x400; i++) {
			set_td(std, i);
			uhci_qhlst[i].lng[0] = 0x00000003;
			uhci_qhlst[i].lng[1] = (krnl_get_selector_base(ds) + (int) &uhci_tdlst[i]);
			uhci_frlst[i] = 0x1;
		}
		
		// 3: Set the frame-list base in the Host Controller:
		usbio.writeregl(krnl_get_selector_base(ds) +
				(unsigned int) uhci_frlst, UHCI_REG_FRBASEADD);
		
	// V: Start the controller:
	usbio.writeregw(0x01, UHCI_REG_USBCMD); // RUN
	int x;
	while(1) {
		x = usbio.readregw(UHCI_REG_FRNUM);
		printk(" Frame List Counter: %d.\n", x & 0x3FF);
		printk(" Status: %x.\n", usbio.readregw(UHCI_REG_USBSTS));
		getc();
	}
}
Post Reply