USBpnext      dd 0ffff0000h
USBdevattr    dw 1000000000000100b 
USBstrategy   dw offset _USB_strategy
USBinterrupt  dw offset _USB_interrupt
USB_device    db 'USB4DOS ' ; Blank-padded device (or 10-byte block device sub-unit number)
; Jump table 
USBtable      db 9
              dw cs:USB_init    ; 0 - initialize driver
              dw cs:USB_err     ; 1 - media change check 
              dw cs:USB_err     ; 2 - build BPB
              dw cs:USB_err     ; 3 - IOCTL string output
              dw cs:USB_input   ; 4 - input
              dw cs:USB_input   ; 5 - nondestructive input
              dw cs:USB_err     ; 6 - input status
              dw cs:USB_input   ; 7 - input flush
              dw cs:USB_output  ; 8 - output
              dw cs:USB_output  ; 9 - output w/ verify
usblib        db 'USB_ASPI$',0
devfile       db 'devnums.bin',0
max_f_size     equ 16384      ; max size of 'devnums.bin' file
dn_line_s      equ 48         ; 48 bytes per line
LED_VENDOR_ID  EQU 0fc5h
LED_PRODUCT_ID EQU 1223h
dev_index     dw 00h
USB_IOAddr    dw ?           ; Address space of port  (32 bytes)
fram_l_ptr    dd 0           ; physical dword pointer to 1024 byte frame
fram_l_bse    dw ?          ; segment to 8192 byte frame base
VendorID      dw 00h        ; Vendor ID number
DeviceID      dw 00h        ; Device ID number
NO_USBFOUND   db 'No USB ports found.',0ffh,0
enableUSB     db 'Enabling USB...',0ffh,0
FoundUSBTS    db 'Found USB Controller:  ',0
BusNumberS    db '  Bus #/Dev #/Func #:  ',0
VendorIDS     db '           Vendor ID:  ',0
DeviceIDS     db '           Device ID:  ',0
CommandRS     db '    Command Register:  ',0
StatusRS      db '     Status Register:  ',0
RevisionS     db '       Revision Code:  ',0
ClassCodeS    db ' Class/Sub/Interface:  ',0
BusLatS       db '         Bus Latency:  ',0
HeaderS       db '         Header Type:  ',0
CacheS        db '     Cache Line Size:  ',0
SelfTestS     db '      Self Test Byte:  ',0
IOPortsS      db '       Address Space:  ',0
IRQNumS       db '          IRQ Number:  ',0
IntNumS       db '          INT Number:  ',0
status_str    db '     Status Register:  ',0
cmmnd_str     db '    Command Register:  ',0
frame_str     db '      Frame Register:  ',0
frameb_str    db ' Frame Base Register:  ',0
port0_str     db '     Root Hub port 1: (',0
port1_str     db '     Root Hub port 2: (',0
port_dis_s    db ') Port disabled',0ffh,0
port_susp_s   db ') Port suspened',0ffh,0
port_enbl_s   db ') Port enabled',0ffh,0
port_dev_p    db ' A device is present at ',0
port_dev_np   db ' No device present.',0ffh,0
port_low_s    db 'low speed',0
port_full_s   db 'full speed',0

USB4DOS_START:

; ===========================================================================
USB_finduhci proc far
; ===========================================================================
.386p
.387
    mov  si, dev_index
    mov  ax, 0B103h              ; find PCI CLASS
    mov  ecx,000C0300h           ; (USB = base=C, sub=3)
    int  1Ah                     ;
    jnc  short UFoundOne         ; on return: bh = bus
                                 ;            bl = dev num/func num
    stc
    mov  ax, 01
    jmp  umainx
UFoundOne:
    mov  bus_num,bh              ; save bus/dev/function
    mov  dev_func,bl             ;
    xor  di, di                   ; read word at 0000h (Vendor ID)
    call ReadPCIW                ; read it (returns in AX)
    mov  VendorID, ax             ; save it
    mov  di, 02h                  ; read word at 0002h (Device ID)
    call ReadPCIW                ; read it (returns in AX)
    mov  DeviceID, ax             ; save it

;    call dev_names               ; get vendor and device names
;    mov  si,offset VendorIDS     ;
;    call prtstring               ;
;    mov  si,offset Vendor_N      ; print vendor name
;    call prtstring               ;
;    mov  si,offset DeviceIDS     ; print device type
;    call prtstring               ;
;           mov  si,offset Device_N      ; print device name
;           call prtstring               ;
;
;           mov  si,offset BusNumberS    ; 
;           call prtstring               ;
;           mov  al,bus_num              ; bh = Bus Number
;           xor  ah,ah                   ;
;           call prthex                  ; print Bus Number
;           mov  dl,'/'                  ; print a slash
;           mov  ah,06                   ;
;           int  21h                     ;
;           mov  al,dev_func             ; bl = Dev Number
;           shr  al,03                   ;  (bits 7-3)
;           xor  ah,ah                   ;
;           call prthex                  ; print Dev Number
;           mov  dl,'/'                  ; print a slash
;           mov  ah,06                   ;
;           int  21h                     ;
;           mov  al,dev_func             ; bl = Func Number
;           and  al,00000111b            ;  (bits 2-0)
;           xor  ah,ah                   ;
;           call prthex                  ; print Func Number
;           mov  si,offset CommandRS
;           call prtstring
;           mov  di,04h                  ; read word at 0004h (Command Reg)
;           call ReadPCIW                ; read it (returns in AX)
;           call prthex                  ; 
;           mov  si,offset StatusRS
;           call prtstring
;           mov  di,06h                  ; read word at 0006h (Status Reg)
;           call ReadPCIW                ; read it (returns in AX)
;           call prthex                  ; 
;           mov  si,offset RevisionS
;           call prtstring
;           mov  di,08h                  ; read byte at 0008h (Revision Byte)
;           call ReadPCIB                ; read it (returns in AX)
;           call prthexn                 ;
;           mov  si,offset ClassCodeS
;           call prtstring
;           mov  di,0Bh                  ; read byte at 000Bh (Class)
;           call ReadPCIB                ; read it (returns in AX)
;           call prthexn                 ;
;           mov  dl,'/'                  ; print a slash
;           mov  ah,06                   ;
;           int  21h                     ;
;           dec  di                      ; read byte at 000Ah (Sub Class)
;           call ReadPCIB                ; read it (returns in AX)
;           call prthexn                 ;
;           mov  dl,'/'                  ; print a slash
;           mov  ah,06                   ;
;           int  21h                     ;
;           dec  di                      ; read byte at 0009h (Program Inter.)
;           call ReadPCIB                ; read it (returns in AX)
;           call prthexn                 ;
;           mov  si,offset CacheS        ;
;           call prtstring               ;
;           mov  di,0Ch                  ; read byte at 000Ch (Cache Line Size)
;           call ReadPCIB                ; read it (returns in AX)
;           call prthexn                 ; 
;           mov  si,offset BusLatS       ;
;           call prtstring               ;
;           mov  di,0Dh                  ; read byte at 000Dh (Bus Latency)
;           call ReadPCIB                ; read it (returns in AX)
;           call prthexn                 ; 
;           mov  si,offset HeaderS
;           call prtstring
;           mov  di,0Eh                  ; read byte at 000Eh (Header Type)
;           call ReadPCIB                ; read it (returns in AX)
;           call prthexn                 ; 
;           mov  si,offset SelfTestS
;           call prtstring
;           mov  di,0Fh                  ; read byte at 000Fh (Self Test)
;           call ReadPCIB                ; read it (returns in AX)
;           call prthexn                 ; 
;           mov  si,offset IOPortsS
;           call prtstring
;           ; don't do high word???
;           ;mov  di,22h                  ; read word at 0022h (base address 4)
;           ;call ReadPCIW                ; read it (returns in AX)
;           ;call prthex                  ; 
;           mov  di,20h                  ; read word at 0020h (base address 4)
;           call ReadPCIW                ; read it (returns in AX)
;           and  ax,0FFFEh               ; clear bit 0 ???
;           mov  IOAddr,ax               ; save if for testing the devices
;           call prthex                  ;
;           push ax                      ; save address space start
;           mov  dl,'-'                  ;
;           mov  ah,02                   ;
;           int  21h                     ;
;           pop  ax                      ;
;           add  ax,31                   ; print address space end
;           call prthex                  ;
;           mov  si,offset IRQNumS       ;
;           call prtstring               ;
;           mov  di,3Ch                  ; read byte at 000Fh (IRQ #)
;           call ReadPCIB                ; read it (returns in AX)
;           call prthexn                 ;
;           mov  si,offset IntNumS       ;
;           call prtstring               ;
;           mov  di,3Dh                  ; read byte at 000Fh (INT #)
;           call ReadPCIB                ; read it (returns in AX)
;           add  al,09h                  ; (A-D)
;           call prthexn                 ; 
    clc
    xor  ax, ax
Umainx:
.286p
.287
    ret
USB_finduhci endp

; ===========================================================================
usb_err  proc far
; ===========================================================================
         mov  ax, 3  ; invalid command
         ret
usb_err  endp

; ===========================================================================
usb_input proc far
; ===========================================================================

         ret
usb_input endp

; ===========================================================================
usb_output proc far
; ===========================================================================

         ret
usb_output endp

enable_USB proc far
         _print FoundUSBTS, 1    ; print found USB controller
         _print BusNumberS, 1
         xor  ax, ax 
         mov  al, cs:[bus_num]
         call put_hex
         _echo ' '
         mov  al, cs:[dev_func]
         call put_hex
         _newline
         _print enableUSB, 1
         mov  ax, VendorID             ;
         call put_hex                  ; print VendorID
         _echo ' '
         mov  ax, DeviceID             ;
         call put_hex                  ; print DeviceID

;for (usb_bus = usb_busses; usb_bus;
;     usb_bus = usb_bus->next) {
;     for (dev = usb_bus->devices; dev;
;         dev = dev->next) {
;         if ((dev->descriptor.idVendor == LED_VENDOR_ID) &&
;             (dev->descriptor.idProduct == LED_PRODUCT_ID))
;             return dev;
;         }
;     }
;return NULL;

;usb_control_msg(handle, 0xc8, 0x12, (0x02 * 0x100) + 0x0a,
;                (0c00 * 0x100) + color, buffer, 8, 5000)

;usb_handle = usb_open(usb_dev);
;if (usb_handle == NULL) {
;    fprintf(stderr,
;                "Not able to claim the USB device\n");
;                    goto exit;
;                    }
   ret
enable_USB endp

; ===========================================================================
USB_init proc far
; ===========================================================================
    call cs:In_V86Mode
    jc   usb_initx
    mov  al, cs:pcibus
    or   al, al
    jz   usb_initx
         call cs:usb_finduhci
         jc   enablingUSB
              _print NO_USBFOUND, 1
         jmp  usb_initx
enablingUSB:
         call enable_USB
usb_initx:
    ret
_USB_strategy:
        mov  word ptr [cs:reqpktptr], bx
        mov  word ptr [cs:reqpktptr+2], es
        retf
_USB_interrupt:
        push es
        push bx
        les  bx, [cs:reqpktptr]
        or   word ptr es:[bx+3], 100h  ; set done flag
        pop  bx
        pop  es
        retf
USB_init endp
