China DOS Union

-- Unite DOS · Advance DOS · Grow DOS --

Union site: www.cn-dos.net Forum site: www.cn-dos.net/forum
DOS stands for freedom, openness and progress. Let us work hard, learn from the openness and GNU spirit of FreeDOS and Linux, and together build and grow a free GNU GPL world!

中国DOS联盟论坛
The time now is 2026-07-31 19:49
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » [Original] USB Series Part 1: List Your USB Devices DigestI View 2,008 Replies 1
Original Poster Posted 2008-07-21 20:40 ·  中国 北京 联通
初级用户
Credits 174
Posts 37
Joined 2006-09-28 03:38
19-year member
UID 63879
Status Offline
Original article address:
http://hengch.blog.163.com/blog/static/10780067200842383912698

USB has now become one of the indispensable interfaces on the PC. Almost all devices can be connected through USB: USB keyboards, mice, printers, cameras, and commonly used flash drives, etc. Starting from this article, I will spend a series of articles introducing methods for using USB devices in DOS. I can't say for sure how many articles there will be yet; I'll just write as far as it goes. There will always be at least three or four.
This article introduces how to use the knowledge covered in my earlier articles to find USB devices in your machine and determine their device types.
A USB system is generally composed of one USB host (HOST), one or more USB hubs (HUB, but not the kind of hub used in a LAN), and one or more USB device nodes (NODE). There is only one HOST in one system. The USB in our PCs is actually made up of the HOST and HUB parts. Your PC may have 4 USB ports, but in fact that is one HOST and one HUB, and the HUB provides you with 4 ports. The devices we plug into USB ports are generally USB devices, such as flash drives, USB printers, etc. Of course, we can also plug in a hub, expanding one USB port into several.
Actually, when we talk about using USB under DOS, what we are really doing is programming and managing the HOST in the USB system. According to the USB specification, the HOST will manage the HUBs and USB devices connected to it, so we don't need to worry about that. There are currently three specifications for HOST devices: OHCI(Open Host Controller Interface) and UHCI(Universal Host Controller Interface) support USB1.1, while EHCI(Enhanced Host Controller Interface) supports USB2.0. In later articles, we will focus on OHCI and EHCI.
To learn USB programming, reading the specifications is unavoidable. Below are some specification downloads that should be read:

OHCI specification: http://blog.hengch.com/specification/usb_ohci_r10a.pdf
EHCI specification: http://blog.hengch.com/specification/usb_ehci_r10.pdf
USB specification 1.1: http://blog.hengch.com/specification/usb_spec11.pdf
USB specification 2.0: http://blog.hengch.com/specification/usb_spec20.pdf

The content introduced in this article does not require studying the specifications.

Now let's get to the main topic: listing your USB devices. The USB HOST is attached to the PCI bus, so by enumerating PCI devices, we can find all the USB devices on your machine. When I previously introduced PCI configuration space, I mentioned that there is a three-byte class code field in the configuration space (if you don't know this, please refer to my earlier blog article "Enumerating PCI Devices"). The byte at offset 0x0B is called the base class code, the byte at offset 0x0A is called the subclass code, and the byte at offset 0x09 is called the programming interface code. For the USB device class, the base class code is 0x0C and the subclass code is 0x03. For HOST devices conforming to different specifications, the programming interface code is different: UHCI uses 0x00, OHCI uses 0x10, and EHCI uses 0x20. I think knowing this is enough.

Below is the source code for listing USB devices.

#include <stdio.h>
#include <stdlib.h>
#include <dpmi.h>

typedef unsigned long UDWORD;
typedef short int WORD;
typedef unsigned short int UWORD;
typedef unsigned char UBYTE;

typedef union {
struct {
UDWORD edi;
UDWORD esi;
UDWORD ebp;
UDWORD res;
UDWORD ebx;
UDWORD edx;
UDWORD ecx;
UDWORD eax;
} d;
struct {
UWORD di, di_hi;
UWORD si, si_hi;
UWORD bp, bp_hi;
UWORD res, res_hi;
UWORD bx, bx_hi;
UWORD dx, dx_hi;
UWORD cx, cx_hi;
UWORD ax, ax_hi;
UWORD flags;
UWORD es;
UWORD ds;
UWORD fs;
UWORD gs;
UWORD ip;
UWORD cs;
UWORD sp;
UWORD ss;
} x;
struct {
UBYTE edi;
UBYTE esi;
UBYTE ebp;
UBYTE res;
UBYTE bl, bh, ebx_b2, ebx_b3;
UBYTE dl, dh, edx_b2, edx_b3;
UBYTE cl, ch, ecx_b2, ecx_b3;
UBYTE al, ah, eax_b2, eax_b3;
} h;
} X86_REGS;
/*************************************************************
* Excute soft interrupt in real mode
*************************************************************/
int x86_int(int int_num, X86_REGS *x86_reg) {
__dpmi_regs d_regs;
int return_value;

d_regs.d.edi = x86_reg->d.edi;
d_regs.d.esi = x86_reg->d.esi;
d_regs.d.ebp = x86_reg->d.ebp;
d_regs.d.res = x86_reg->d.res;
d_regs.d.ebx = x86_reg->d.ebx;
d_regs.d.ecx = x86_reg->d.ecx;
d_regs.d.edx = x86_reg->d.edx;
d_regs.d.eax = x86_reg->d.eax;
d_regs.x.flags = x86_reg->x.flags;
d_regs.x.es = x86_reg->x.es;
d_regs.x.ds = x86_reg->x.ds;
d_regs.x.fs = x86_reg->x.fs;
d_regs.x.gs = x86_reg->x.gs;
d_regs.x.ip = x86_reg->x.ip;
d_regs.x.cs = x86_reg->x.cs;
d_regs.x.sp = x86_reg->x.sp;
d_regs.x.ss = x86_reg->x.ss;

return_value = __dpmi_int(int_num, &d_regs);

x86_reg->d.edi = d_regs.d.edi;
x86_reg->d.esi = d_regs.d.esi;
x86_reg->d.ebp = d_regs.d.ebp;
x86_reg->d.res = d_regs.d.res;
x86_reg->d.ebx = d_regs.d.ebx;
x86_reg->d.ecx = d_regs.d.ecx;
x86_reg->d.edx = d_regs.d.edx;
x86_reg->d.eax = d_regs.d.eax;
x86_reg->x.flags = d_regs.x.flags;
x86_reg->x.es = d_regs.x.es;
x86_reg->x.ds = d_regs.x.ds;
x86_reg->x.fs = d_regs.x.fs;
x86_reg->x.gs = d_regs.x.gs;
x86_reg->x.ip = d_regs.x.ip;
x86_reg->x.cs = d_regs.x.cs;
x86_reg->x.sp = d_regs.x.sp;
x86_reg->x.ss = d_regs.x.ss;

return return_value;
}
/**********************************
* Read Configuration WORD if PCI
**********************************/
UWORD ReadConfigWORD(WORD pciAddr, int reg) {
X86_REGS inregs;

inregs.x.ax = 0xB109; // Read Configuration word
inregs.x.bx = pciAddr;
inregs.x.di = reg; // Register number
x86_int(0x1A, &inregs);

return inregs.d.ecx; // the value
}
// main program
int main(void) {
UWORD pciAddr;
UWORD subClass;
int ehciCount = 0, ohciCount = 0, uhciCount = 0;

for (pciAddr = 0; pciAddr < 0xffff; pciAddr++) {
if (ReadConfigWORD(pciAddr, 0) != 0xFFFF) {
// Read Class Code
if (ReadConfigWORD(pciAddr, 0x000a ) == 0x0c03) { // Usb Host Controller
// Read SubClass Code
subClass = ReadConfigWORD(pciAddr, 0x0008);
if ((subClass & 0xff00) == 0x2000) { // uhci
ehciCount++;
} else if ((subClass & 0xff00) == 0x1000) { // ohci
ohciCount++;
} else if ((subClass & 0xff00) == 0x00) { // uhci
uhciCount++;
}
}
}
}
printf("There are %d ohci device(s).\n", ohciCount);
printf("There are %d ehci device(s).\n", ehciCount);
printf("There are %d uhci device(s).\n", uhciCount);
}


The program is very simple. All the concepts in it have been introduced in earlier blog posts, and most of the subroutines have also been used in previous program examples, so I won't explain much more here. In the program, we only list the number of devices, but obviously, with this method we can also read information such as base addresses from configuration space, and that will be used in later articles.
Floor 2 Posted 2008-09-10 16:03 ·  中国 江苏 苏州 联通
新手上路
Credits 10
Posts 5
Joined 2008-09-10 13:48
17-year member
UID 125312
Gender Male
Status Offline
Learn a little something
Forum Jump: