UHCI Counter in VMware?
Re: UHCI Counter in VMware?
You must be looking at Linux source now. And, it still isn't working? Do you at least notice the line UHCI: HCRESET in your vmware log now? Any differences yet? The way you do it is basically what I do. Except mine would timeout eventually. However, your code looks fine.
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
- iocoder
- 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?
This may be a vmware bug????
Re: UHCI Counter in VMware?
I don't think so. It works fine on my end with nearly the same logic. Try to let it run for a few seconds without the getch() thing. Make sure to while loop the frnum register to print each time the frnum changes by one unit, then check the log and observe the times there. See if you are receiving the same results.
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
Re: UHCI Counter in VMware?
My only other idea would be an error due to this part:
More specifically, this part:
You've essentially told the controller that the queue head is both invalid and a QH, which it must be at least one or the other, and if neither then at least a TD or just invalid (i.e. 0x00000001).
And, what's in here?
For your purposes, I think you should make at least one 'T'erminated TD.
My belief is that the vmware virtual uhci controller is retrying each frame multiple times until it times out and tries the next frame.
Code: Select all
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;
}
Code: Select all
uhci_qhlst[i].lng[0] = 0x00000003;
And, what's in here?
Code: Select all
uhci_qhlst[i].lng[1] = (krnl_get_selector_base(ds) + (int) &uhci_tdlst[i]);
My belief is that the vmware virtual uhci controller is retrying each frame multiple times until it times out and tries the next frame.
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
- iocoder
- 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?
Code: Select all
uhci_qhlst[i].lng[0] = 0x00000003;
This is very logical.My belief is that the vmware virtual uhci controller is retrying each frame multiple times until it times out and tries the next frame.
So, i shall make one QH that refers to one 'T'erminated TD, all frame pointers shall refer to the QH. is this right??? i am waiting for ur reply osdnlo and if this is right, i will do and post results.For your purposes, I think you should make at least one 'T'erminated TD.
Thanks and Regards.
Re: UHCI Counter in VMware?
That's right. Something like this:
There, that outta do it.
Let me know how it works.
Code: Select all
qh[0].h=0x00000001; //'T'erminate (2nd)
qh[0].v=td_head; //point to TD Head (1st)
td[0].link=0x00000001; //'T'erminate
framlist[0-1023]=qh_head | (1<<1); //point to QH Head
Let me know how it works.
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
- iocoder
- 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?
Code: Select all
qh[0].h=0x00000001; //'T'erminate (2nd)
qh[0].v=td_head; //point to TD Head (1st)
td[0].link=0x00000001; //'T'erminate
framlist[0-1023]=qh_head | (1<<1); //point to QH Head
but i think that the TD should be useful, like we should make it send a package to a specific device.
i uploaded Quafios to test it yourself once on VMware and another on QEMU:
http://www.mediafire.com/?twzyjmq3cnn
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_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");
sti();
// 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;
set_td(std, 0);
uhci_qhlst[0].lng[0] = 0x00000001;
uhci_qhlst[0].lng[1] = krnl_get_selector_base(ds) + (int) &uhci_tdlst[0];
for (i = 0; i < 0x400; i++) {
uhci_frlst[i] = (krnl_get_selector_base(ds) + (int) &uhci_qhlst[0]) | (1<<1);
}
// 3: Set the frame-list base in the Host Controller:
usbio.writeregl(krnl_get_selector_base(ds) + (int) uhci_frlst, UHCI_REG_FRBASEADD);
// V: Start the controller:
usbio.writeregw(0x01, UHCI_REG_USBCMD); // RUN
int x = 1024, y = 0;
while(1) {
if ((y = usbio.readregw(UHCI_REG_FRNUM) & 0x3FF) != x) {
x = y;
printk(" Frame List Counter: %d.\n", x & 0x3FF);
}
}
}
Re: UHCI Counter in VMware?
Are you now turning on legacy support? Go ahead and turn that off, then test again. Your code is looking better now. I think we are headed in the right direction.
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
- iocoder
- 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?
i turned it off, but the same.
why don't we make the TD useful?
my latest code:
why don't we make the TD useful?
my latest 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_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");
sti();
// 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 off PIRQ enable and SMI enable.
* This turns off legacy support for keyboard and mouse.
*/
pci_writew(UHCI_USBLEGSUP_RWC, 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;
set_td(std, 0);
uhci_qhlst[0].lng[0] = 0x00000001;
uhci_qhlst[0].lng[1] = krnl_get_selector_base(ds) + (int) &uhci_tdlst[0];
for (i = 0; i < 0x400; i++) {
uhci_frlst[i] = (krnl_get_selector_base(ds) + (int) &uhci_qhlst[0]) | (1<<1);
}
// 3: Set the frame-list base in the Host Controller:
usbio.writeregl(krnl_get_selector_base(ds) + (int) uhci_frlst, UHCI_REG_FRBASEADD);
// V: Start the controller:
usbio.writeregw(0x01, UHCI_REG_USBCMD); // RUN
int x = 1024, y = 0;
while(1) {
if ((y = usbio.readregw(UHCI_REG_FRNUM) & 0x3FF) != x) {
x = y;
printk(" Frame List Counter: %d.\n", x & 0x3FF);
}
}
}
Re: UHCI Counter in VMware?
I was going to mention that next. Make a control transfer and read in the status bits, maybe the error is in there?
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
- iocoder
- 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?
Dear osdlno,
am so sorry for being late. i learned how to make a TD and its parameters, then i have made it, but still the same!
am so sorry for being late. i learned how to make a TD and its parameters, then i have made it, but still the same!
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 ISO; // 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.
unsigned char uhci_buffer[10];
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.ISO << 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");
sti();
// 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 off PIRQ enable and SMI enable.
* This turns off legacy support for keyboard and mouse.
*/
pci_writew(UHCI_USBLEGSUP_RWC, 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.PID = 0x2D;
std.device = 1;
std.EndPt = 0;
std.MaxLen = 0;
std.buffer = krnl_get_selector_base(ds) + (int) uhci_buffer;
uhci_buffer[0] = 0x2; // Any Command.
set_td(std, 0);
uhci_qhlst[0].lng[0] = 0x00000001;
uhci_qhlst[0].lng[1] = krnl_get_selector_base(ds) + (int) &uhci_tdlst[0];
for (i = 0; i < 0x400; i++) {
uhci_frlst[i] = (krnl_get_selector_base(ds) + (int) &uhci_qhlst[0]) | (1<<1);
}
// 3: Set the frame-list base in the Host Controller:
usbio.writeregl(krnl_get_selector_base(ds) + (int) uhci_frlst, UHCI_REG_FRBASEADD);
// V: Start the controller:
usbio.writeregw(0x01, UHCI_REG_USBCMD); // RUN
int x = 1024, y = 0;
while(1) {
if ((y = usbio.readregw(UHCI_REG_FRNUM) & 0x3FF) != x) {
x = y;
printk(" Frame List Counter: %d.\n", x & 0x3FF);
}
}
}
- iocoder
- 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?
could i suggest something: lets first try to send a successful TD to a device, and then lets try with the problem again.
i try to send a SETUP Packet to my gamepad, but i can't recieve NAK. it is usb 1, but i don't know its address. i wrote this code:
and it always prints 0. is there somethins wrong??
i try to send a SETUP Packet to my gamepad, but i can't recieve NAK. it is usb 1, but i don't know its address. i wrote this code:
Code: Select all
for (i = 0; i < 128; i++) {
static tdstr std;
std.T = 1;
std.PID = 0x2D;
std.device = i;
std.EndPt = 0;
std.MaxLen = 9;
std.buffer = krnl_get_selector_base(ds) + (int) uhci_buffer;
uhci_buffer[0] = 0x80; // bmRequestType
uhci_buffer[1] = 0x00; // bRequest []
uhci_buffer[2] = 0x00; // wValue
uhci_buffer[3] = 0x00;
uhci_buffer[4] = 0x00; // wIndex
uhci_buffer[5] = 0x00;
uhci_buffer[6] = 0x02; // wLength
uhci_buffer[7] = 0x00;
set_td(std, 0);
usbio.writeregw(0x00, UHCI_REG_FRNUM); // Frame Number
usbio.writeregw(0x01, UHCI_REG_USBCMD); // RUN
getc();
printk(" Second INT: %x\n", uhci_tdlst[0].lng[1]);
usbio.writeregw(0x00, UHCI_REG_USBCMD); // Stop
}
Re: UHCI Counter in VMware?
Warning: VMware is brain damaged and will not give you accurate results, the log files are misleading, and tech. support is non-existent. That being said, you will need to make sure to also test your driver on a live machine.
OK, now on with the corrections:
01. While in the default state, address device 0.
02. A Control Transfer needs at least the following to be successful: [STATUS]->[DATA1 (at least one)]->[HANDSHAKE], so make two more.
03. You need to wait until the status bits change from 0x80 to something else. 0 = OK, !0 = BAD
04. Your max length should be maxlen-1 and while in the default state, use 8 as your maxlen.
05. You need to fill out your wValue and bRequest fields.
06. Your length field should be bigger than 2. Make it 8.
07. You should move the part where you set the frnum and start the controller somewhere before this code.
08. You start a transaction by making the queue valid. You initialize a queue by making it invalid. So, fix that.
09. No need to stop the HC after the transaction. Just let it keep running, and as a last step, make the queue invalid.
This outta keep you busy for a while.
OK, now on with the corrections:
01. While in the default state, address device 0.
02. A Control Transfer needs at least the following to be successful: [STATUS]->[DATA1 (at least one)]->[HANDSHAKE], so make two more.
03. You need to wait until the status bits change from 0x80 to something else. 0 = OK, !0 = BAD
04. Your max length should be maxlen-1 and while in the default state, use 8 as your maxlen.
05. You need to fill out your wValue and bRequest fields.
06. Your length field should be bigger than 2. Make it 8.
07. You should move the part where you set the frnum and start the controller somewhere before this code.
08. You start a transaction by making the queue valid. You initialize a queue by making it invalid. So, fix that.
09. No need to stop the HC after the transaction. Just let it keep running, and as a last step, make the queue invalid.
This outta keep you busy for a while.
Yes, I see that you have proven it, but my question was, 'How did you know that would work?'.
- iocoder
- 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?
Hi Again osdnlo!
I think it is really that VMware is brain damaged and not my code, which works well on QEMU and BOCHS, i am trying it on real machine soon, but now, i wonder if i could send 'GET STATUS' Request to a device that is connected to QEMU's uhci. i have re-wrote the following code depending on ur last advises:
and Status bits change to '0x84' which should mean 'Time Out Error!', i tried to send that to other devices rather that Device 0, but no change.
so i should make 3 TDs?
and if so, what will their buffers contain? notice that i wish to send data and receive data, so should i make 3 TDs for sending, and 3 for receiving?
Best Regards,
Mostafa.
I think it is really that VMware is brain damaged and not my code, which works well on QEMU and BOCHS, i am trying it on real machine soon, but now, i wonder if i could send 'GET STATUS' Request to a device that is connected to QEMU's uhci. i have re-wrote the following code depending on ur last advises:
Code: Select all
// V: Start the controller:
usbio.writeregw(0x00, UHCI_REG_FRNUM); // Frame Number
usbio.writeregw(0x01, UHCI_REG_USBCMD); // RUN
uhci_frlst[0] = krnl_get_selector_base(ds) + (int) &uhci_tdlst[0];
// Get Status from Device:
static tdstr std;
std.T = 1;
std.status = 0x80;
std.PID = 0x2D;
std.device = 0;
std.EndPt = 0;
std.MaxLen = 9;
std.buffer = krnl_get_selector_base(ds) + (int) uhci_buffer;
uhci_buffer[0] = 0x80; // bmRequestType
uhci_buffer[1] = 0x00; // bRequest
uhci_buffer[2] = 0x00; // wValue
uhci_buffer[3] = 0x00;
uhci_buffer[4] = 0x00; // wIndex
uhci_buffer[5] = 0x00;
uhci_buffer[6] = 0x02; // wLength
uhci_buffer[7] = 0x00;
set_td(std, 0);
while (uhci_tdlst[0].lng[1] == 0x00800000);
printk(" Status: %x\n", uhci_tdlst[0].lng[1]);
osdnlo wrote: 02. A Control Transfer needs at least the following to be successful: [STATUS]->[DATA1 (at least one)]->[HANDSHAKE], so make two more.
so i should make 3 TDs?
and if so, what will their buffers contain? notice that i wish to send data and receive data, so should i make 3 TDs for sending, and 3 for receiving?
Best Regards,
Mostafa.
Re: UHCI Counter in VMware?
Well, no. If the SETUP transfer got timeouted, that means there is no device on that address. There's a catch to this: qemu doesn't consider devices connected until they are reseted.mostafazizo wrote:Hi Again osdnlo!
I think it is really that VMware is brain damaged and not my code, which works well on QEMU and BOCHS, i am trying it on real machine soon, but now, i wonder if i could send 'GET STATUS' Request to a device that is connected to QEMU's uhci. i have re-wrote the following code depending on ur last advises:and Status bits change to '0x84' which should mean 'Time Out Error!', i tried to send that to other devices rather that Device 0, but no change.Code: Select all
// V: Start the controller: usbio.writeregw(0x00, UHCI_REG_FRNUM); // Frame Number usbio.writeregw(0x01, UHCI_REG_USBCMD); // RUN uhci_frlst[0] = krnl_get_selector_base(ds) + (int) &uhci_tdlst[0]; // Get Status from Device: static tdstr std; std.T = 1; std.status = 0x80; std.PID = 0x2D; std.device = 0; std.EndPt = 0; std.MaxLen = 9; std.buffer = krnl_get_selector_base(ds) + (int) uhci_buffer; uhci_buffer[0] = 0x80; // bmRequestType uhci_buffer[1] = 0x00; // bRequest uhci_buffer[2] = 0x00; // wValue uhci_buffer[3] = 0x00; uhci_buffer[4] = 0x00; // wIndex uhci_buffer[5] = 0x00; uhci_buffer[6] = 0x02; // wLength uhci_buffer[7] = 0x00; set_td(std, 0); while (uhci_tdlst[0].lng[1] == 0x00800000); printk(" Status: %x\n", uhci_tdlst[0].lng[1]);
osdnlo wrote: 02. A Control Transfer needs at least the following to be successful: [STATUS]->[DATA1 (at least one)]->[HANDSHAKE], so make two more.
so i should make 3 TDs?
and if so, what will their buffers contain? notice that i wish to send data and receive data, so should i make 3 TDs for sending, and 3 for receiving?
Best Regards,
Mostafa.
So, you have to also reset ports after you reset the UHCI.
As for the right way of doing control sequences: SETUP->IN/OUT. All you have to do is change the TD's pid and maxlen, set the status to 0x80 and wait for it . In case there is nothing to transfer, just set maxlen to 0, buffer to 0 and pid to IN .
PS: make functions on several levels, like uhci_do_in_transfer, uhci_do_out_transfer, uhci_do_setup_transfer, then when you get to upper layers, you can make a simple usb_get_device_status function .