USB系列之一:列出你的USB设备

USB现在已经成为PC机必不可少的接口之一,几乎所有的设备都可以接在USB设备上,USB键盘、鼠标、打印机、摄像头,还有常用的U盘等等,从本篇文章开始,将集中篇幅介绍一下在DOS中使用USB设备的方法,具体会有几篇暂不好定,写到哪里算哪里吧,三、四篇总是少不了的。
    本文介绍如何使用我以前文章中介绍过的知识在你的机器中找到USB设备,并判定设备类型。
    一个USB系统一般由一个USB主机(HOST)、一个或多个USB集线器(HUB,但不是局域网里的集线器)和一个或多个USB设备节点(NODE)组成,一个系统中只有一个HOST,我们PC机里的USB实际上就是HOST和HUB两部分,你的PC机可能会有4个USB口,其实是一个HOST,一个HUB,HUB为你提供了4个端口,我们插在USB口上的器件,一般是USB设备,比如U盘,USB打印机等,当然我们也可以插一个集线器上去,使你的一个USB口扩展成多个。
    实际上我们说在DOS下使用USB,就是对USB系统中的HOST进行编程管理,根据USB的规范,HOST将对连接在上面的HUB和USB设备进行管理,不用我们操心。HOST器件目前有三个规范,OHCI(Open Host Controller Interface)、UHCI(Universal Host Controller Interface)支持USB1.1,EHCI(Enhanced Host Controller Interface)支持USB2.0,以后的文章中,我们将侧重介绍OHCI和EHCI。
    学习USB编程,读规范是少不了的,以下是一些应该阅读的规范下载:
    OHCI规范:http://blog.hengch.com/specification/usb_ohci_r10a.pdf
    EHCI规范:http://blog.hengch.com/specification/usb_ehci_r10.pdf
    USB规范1.1:http://blog.hengch.com/specification/usb_spec11.pdf
    USB规范2.0:http://blog.hengch.com/specification/usb_spec20.pdf
    本文介绍的内容不需要学习规范。

下面进入正题,列出你的USB设备,USB的HOST是挂接在PCI总线上的,所以通过PCI设备的遍历就可以找到你的机器上的所有USB设备,在以前介绍PCI的配置空间时,曾经介绍过在配置空间中有一个占三个字节的分类代码字段(如果不知道,请参阅我以前的博文《遍历PCI设备》),在偏移为0x0B的字节叫基本分类代码,在偏移为0x0A的字节叫子分类代码,在偏移为0x09的字节叫编程接口代码,对于USB设备类说,基本分类代码为0x0C,子分类代码为0x03,对于符合不同规范的HOST器件而言,编程接口代码是不同的,UHCI的编程接口代码是0x00,OHCI的编程接口代码是0x10,EHCI的编程接口代码是0x20,我想了解这些就足够了。
    下面列出USB设备的源程序。

#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[4];
    UBYTE esi[4];
    UBYTE ebp[4];
    UBYTE res[4];
    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);
}

程序非常简单,所有概念在以前的博文中均有过介绍,其中的子程序大多是以前程序范例中使用过的,所以在这里就不做更多的解释了,程序中,我们仅仅列出了设备的数量,但很显然,用这种方法,我们可以从配置空间里读出基地址等信息,这些在以后的文章中会用到。

时间: 2024-11-08 15:15:23

USB系列之一:列出你的USB设备的相关文章

USB系列之二:读取USB设备的描述符

在前面的文章中,我们已经给出了USB协议的链接地址,从这篇文章起,我们会涉及到许多USB 1.1的内容,我们的指导思想是先从熟悉USB 1.1协议入手,先使用现成的HCD和USBD,直接面对客户端驱动编程,尽快看到成果,使读者对USB的开发充满信心,进而去研究USBD和HCD的编程方法.请读者自行阅读协议,文章中有关协议的详细情况,由于会涉及非常多的文字,恕不能过多解释.1.USB系统主机端的软件结构    一般来说,教科书或者协议上都会把USB主机端的软件说成有三层,第一层叫主机控制器驱动程序

USB系列之六:基于DOSUSB的简单U盘驱动程序

首先要说明的是,该驱动程序仅实现了部分块设备的功能,如果作为成品软件使用,会感觉性能比较差,而且有些功能(比如FORMAT)是不能完成的,发表此驱动程序的目的旨在说明USB的编程原理以及DOS下驱动程序的工作原理:同时要说明的是,此驱动程序仅支持32M(包括32M)以下的U盘,当然这个问题解决起来并不困难,有兴趣的读者可以在阅读本文并理解的基础上加以改进使其支持32M以上2G以下的U盘.    前面的博文中提到由于DOSUSB是在命令行加载的,如果从config.sys中加载这个基于DOSUSB

USB系列之五:用汇编实现的一些USB功能

前面的USB系列一至四,实现了我们需要的一些USB功能,但都是用C语言的32位代码,之后我们插进了三篇关于DOS下设备驱动程序的文章,我们现在应该清楚,当我们要在DOS下写一个U盘的驱动时,最好使用汇编语言,而且不得不在实模式下编程. 基于这样一个原因,本文计划把<USB系列二>到<USB系列四>中的三段程序代码,用汇编语言再重新实现一遍,而且使用16位的8086模式编程,在下载下面的源代码之前,希望读者能够认真阅读USB系列以前所有的文章,最好能把其中的代码都看明白并亲自试一试,

USB系列之九:基于ASPI的U盘驱动程序

USB系列之七和之八介绍了ASPI,并通过一些实例说明了基于ASPI的编程方法,本文使用前两篇文章介绍的知识以及以前介绍的有关DOS驱动程序下驱动程序的内容实际完成一个简单的基于ASPI的U盘驱动程序,算是对ASPI应用的一个总结.    在<USB系列之六>中,我们完成了一个简单的基于DOSUSB的U盘驱动程序,实际上我们今天的程序是在那个程序的基础上改的,基本结构完全相同,思路也完全一样,只是由于有ASPI的支持,无需再读取各种描述符表,读盘.写盘的操作也显得简洁了很多,希望对本文有兴趣的

USB系列之三:从你的U盘里读出更多的内容

U盘是我们最常使用的一种USB设备,本文继续使用DOSUSB做驱动,试图以读取扇区的方式读取你的U盘.    本文可能涉及的协议可能会比较多.一.了解你的U盘    首先我们用上一篇文章介绍的程序usbview.exe去看一下你的U盘,我在本文中用于测试的U盘情况如下: Device Descriptor: (设备描述符) USB Address: 1 Length: 18 Descriptor Type: 1 USB Specification nr.: 0x0110 Calss Code:

USB系列之八:透过ASPI执行SCSI命令

在<USB系列之七>里我们介绍了ASPI的规范,并对一系列ASPI的命令做了测试,其中的02号命令是执行SCSI命令,我们专门在这篇文章中介绍,在<USB系列七>中,我们已经了解了调用ASPI的方法,主要是要填一个SRB(SCSI Request Block)的表,在以前的<USB系列之三:从你的U盘里读出更多的内容>文章中我们通过DOSUSB已经实现了许多SCSI命令,这些命令包括: SCSI INQUIRY Command SCSI READ CAPACITY (1

USB系列之七:ASPI介绍及命令测试

在以前的一篇博文<关于构建DOS下编程平台的总结>中曾经介绍了一种在DOS下驱动U盘的方法,我们大致回顾一下.在config.sys中加入两个驱动程序,就可以驱动U盘:    device = aspiohci.sys    device=di1000dd.sys    这两个驱动程序在上述博文中有下载.    如果大家仔细地阅读过我关于USB的文章的话,应该对OHCI这个东西不会陌生,在USB系列文章中,用大量的篇幅介绍了OHCI,这是因为OHCI这种符合USB1.1的控制器在使用上比UHC

Hyper-V 2016 系列教程28 Hyper-v平台USB 外设解决方案介绍

现在企业中,由于虚拟化技术的大力普及,企业的一般用户办公端都是以瘦客户端的形式存在,而瘦客户端一般是采用Linux或者Windows精简版本的系统,体积一般只有5寸平板大小,硬件接口有限,所以这样就带来一个问题,一般不能友好的支持USB接口的使用,不能使用USB存储,移动加密U盾等,另一方面由于虚拟计算机是从一个物理机上虚拟出来的,它自己并没有物理接口.当需要接入设备,如虚拟机上需要用到Ukey.加密狗等设备时,需要把物理机的接口切换给虚拟机才能使用,切换过程比较麻烦.加上物理机的接口是有限的,

USB逻辑设备是指各种各样的USB设备与主机连接

在编译之前要进行uClinux内核的配置工作,包括RAM.ROM的大小,地址空间的分配,外围设备的支持.除此以外,最关键的工作就是实现USB主机控制器的驱动程序,这也是研究工作的重点. 2. USB 主机控制器 在介绍USB主机控制器驱动程序之前,先让我们了解一下USB系统和USB主机控制器. 2.1 USB系统和USB主控制器的基本概念 在USB系统中,各种USB设备要与主机相连,就必须通过一个共同的接口接入主机.这个接口就是USB主机控制器(USB Host Controller).HC是软