Subversion Repositories Kolibri OS

Rev

Rev 5363 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2015. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;;  MTD80x driver for KolibriOS                                    ;;
  7. ;;                                                                 ;;
  8. ;;  Based on mtd80x.c from the etherboot project                   ;;
  9. ;;                                                                 ;;
  10. ;;  Written by hidnplayr@kolibrios.org                             ;;
  11. ;;                                                                 ;;
  12. ;;          GNU GENERAL PUBLIC LICENSE                             ;;
  13. ;;             Version 2, June 1991                                ;;
  14. ;;                                                                 ;;
  15. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  16.  
  17. format PE DLL native
  18. entry START
  19.  
  20.         CURRENT_API             = 0x0200
  21.         COMPATIBLE_API          = 0x0100
  22.         API_VERSION             = (COMPATIBLE_API shl 16) + CURRENT_API
  23.  
  24.         MAX_DEVICES             = 16
  25.  
  26.         __DEBUG__               = 1
  27.         __DEBUG_LEVEL__         = 2
  28.  
  29.         NUM_TX_DESC             = 6
  30.         NUM_RX_DESC             = 12
  31.  
  32. section '.flat' readable writable executable
  33.  
  34. include '../proc32.inc'
  35. include '../struct.inc'
  36. include '../macros.inc'
  37. include '../fdo.inc'
  38. include '../netdrv.inc'
  39.  
  40. ; for different PHY
  41.  
  42.     MysonPHY            = 1
  43.     AhdocPHY            = 2
  44.     SeeqPHY             = 3
  45.     MarvellPHY          = 4
  46.     Myson981            = 5
  47.     LevelOnePHY         = 6
  48.     OtherPHY            = 10
  49.  
  50. ; Offsets to the Command and Status Registers.
  51.  
  52.     PAR0                = 0x0           ; physical address 0-3
  53.     PAR1                = 0x04          ; physical address 4-5
  54.     MAR0                = 0x08          ; multicast address 0-3
  55.     MAR1                = 0x0C          ; multicast address 4-7
  56.     FAR0                = 0x10          ; flow-control address 0-3
  57.     FAR1                = 0x14          ; flow-control address 4-5
  58.     TCRRCR              = 0x18          ; receive & transmit configuration
  59.     BCR                 = 0x1C          ; bus command
  60.     TXPDR               = 0x20          ; transmit polling demand
  61.     RXPDR               = 0x24          ; receive polling demand
  62.     RXCWP               = 0x28          ; receive current word pointer
  63.     TXLBA               = 0x2C          ; transmit list base address
  64.     RXLBA               = 0x30          ; receive list base address
  65.     ISR                 = 0x34          ; interrupt status
  66.     IMR                 = 0x38          ; interrupt mask
  67.     FTH                 = 0x3C          ; flow control high/low threshold
  68.     MANAGEMENT          = 0x40          ; bootrom/eeprom and mii management
  69.     TALLY               = 0x44          ; tally counters for crc and mpa
  70.     TSR                 = 0x48          ; tally counter for transmit status
  71.     BMCRSR              = 0x4c          ; basic mode control and status
  72.     PHYIDENTIFIER       = 0x50          ; phy identifier
  73.     ANARANLPAR          = 0x54          ; auto-negotiation advertisement and link partner ability
  74.     ANEROCR             = 0x58          ; auto-negotiation expansion and pci conf.
  75.     BPREMRPSR           = 0x5c          ; bypass & receive error mask and phy status
  76.  
  77. ; Bits in the interrupt status/enable registers.
  78.  
  79.     RFCON               = 0x00020000    ; receive flow control xon packet
  80.     RFCOFF              = 0x00010000    ; receive flow control xoff packet
  81.     LSCStatus           = 0x00008000    ; link status change
  82.     ANCStatus           = 0x00004000    ; autonegotiation completed
  83.     FBE                 = 0x00002000    ; fatal bus error
  84.     FBEMask             = 0x00001800    ; mask bit12-11
  85.     ParityErr           = 0x00000000    ; parity error
  86.     TargetErr           = 0x00001000    ; target abort
  87.     MasterErr           = 0x00000800    ; master error
  88.     TUNF                = 0x00000400    ; transmit underflow
  89.     ROVF                = 0x00000200    ; receive overflow
  90.     ETI                 = 0x00000100    ; transmit early int
  91.     ERI                 = 0x00000080    ; receive early int
  92.     CNTOVF              = 0x00000040    ; counter overflow
  93.     RBU                 = 0x00000020    ; receive buffer unavailable
  94.     TBU                 = 0x00000010    ; transmit buffer unavilable
  95.     TI                  = 0x00000008    ; transmit interrupt
  96.     RI                  = 0x00000004    ; receive interrupt
  97.     RxErr               = 0x00000002    ; receive error
  98.  
  99. ; Bits in the NetworkConfig register.
  100.  
  101.     RxModeMask          = 0xe0
  102.     AcceptAllPhys       = 0x80          ; promiscuous mode
  103.     AcceptBroadcast     = 0x40          ; accept broadcast
  104.     AcceptMulticast     = 0x20          ; accept mutlicast
  105.     AcceptRunt          = 0x08          ; receive runt pkt
  106.     ALP                 = 0x04          ; receive long pkt
  107.     AcceptErr           = 0x02          ; receive error pkt
  108.  
  109.     AcceptMyPhys        = 0x00000000
  110.     RxEnable            = 0x00000001
  111.     RxFlowCtrl          = 0x00002000
  112.     TxEnable            = 0x00040000
  113.     TxModeFDX           = 0x00100000
  114.     TxThreshold         = 0x00e00000
  115.  
  116.     PS1000              = 0x00010000
  117.     PS10                = 0x00080000
  118.     FD                  = 0x00100000
  119.  
  120.  
  121. ; Bits in network_desc.status
  122.  
  123.     RXOWN               = 0x80000000    ; own bit
  124.     FLNGMASK            = 0x0fff0000    ; frame length
  125.     FLNGShift           = 16
  126.     MARSTATUS           = 0x00004000    ; multicast address received
  127.     BARSTATUS           = 0x00002000    ; broadcast address received
  128.     PHYSTATUS           = 0x00001000    ; physical address received
  129.     RXFSD               = 0x00000800    ; first descriptor
  130.     RXLSD               = 0x00000400    ; last descriptor
  131.     ErrorSummary        = 0x80          ; error summary
  132.     RUNT                = 0x40          ; runt packet received
  133.     LONG                = 0x20          ; long packet received
  134.     FAE                 = 0x10          ; frame align error
  135.     CRC                 = 0x08          ; crc error
  136.     RXER                = 0x04          ; receive error
  137.  
  138. ; rx_desc_control_bits
  139.  
  140.     RXIC                = 0x00800000    ; interrupt control
  141.     RBSShift            = 0
  142.  
  143. ; tx_desc_status_bits
  144.  
  145.     TXOWN               = 0x80000000    ; own bit
  146.     JABTO               = 0x00004000    ; jabber timeout
  147.     CSL                 = 0x00002000    ; carrier sense lost
  148.     LC                  = 0x00001000    ; late collision
  149.     EC                  = 0x00000800    ; excessive collision
  150.     UDF                 = 0x00000400    ; fifo underflow
  151.     DFR                 = 0x00000200    ; deferred
  152.     HF                  = 0x00000100    ; heartbeat fail
  153.     NCRMask             = 0x000000ff    ; collision retry count
  154.     NCRShift            = 0
  155.  
  156. ; tx_desc_control_bits
  157.  
  158.     TXIC                = 0x80000000    ; interrupt control
  159.     ETIControl          = 0x40000000    ; early transmit interrupt
  160.     TXLD                = 0x20000000    ; last descriptor
  161.     TXFD                = 0x10000000    ; first descriptor
  162.     CRCEnable           = 0x08000000    ; crc control
  163.     PADEnable           = 0x04000000    ; padding control
  164.     RetryTxLC           = 0x02000000    ; retry late collision
  165.     PKTSMask            = 0x3ff800      ; packet size bit21-11
  166.     PKTSShift           = 11
  167.     TBSMask             = 0x000007ff    ; transmit buffer bit 10-0
  168.     TBSShift            = 0
  169.  
  170. ; BootROM/EEPROM/MII Management Register
  171.  
  172.     MASK_MIIR_MII_READ  = 0x00000000
  173.     MASK_MIIR_MII_WRITE = 0x00000008
  174.     MASK_MIIR_MII_MDO   = 0x00000004
  175.     MASK_MIIR_MII_MDI   = 0x00000002
  176.     MASK_MIIR_MII_MDC   = 0x00000001
  177.  
  178. ; ST+OP+PHYAD+REGAD+TA
  179.  
  180.     OP_READ             = 0x6000        ; ST:01+OP:10+PHYAD+REGAD+TA:Z0
  181.     OP_WRITE            = 0x5002        ; ST:01+OP:01+PHYAD+REGAD+TA:10
  182.  
  183. ; -------------------------------------------------------------------------
  184. ;      Constants for Myson PHY
  185. ; -------------------------------------------------------------------------
  186.  
  187.     MysonPHYID          = 0xd0000302
  188.     MysonPHYID0         = 0x0302
  189.     StatusRegister      = 18
  190.     SPEED100            = 0x0400        ; bit10
  191.     FULLMODE            = 0x0800        ; bit11
  192.  
  193. ; -------------------------------------------------------------------------
  194. ;      Constants for Seeq 80225 PHY
  195. ; -------------------------------------------------------------------------
  196.  
  197.     SeeqPHYID0          = 0x0016
  198.     MIIRegister18       = 18
  199.     SPD_DET_100         = 0x80
  200.     DPLX_DET_FULL       = 0x40
  201.  
  202. ; -------------------------------------------------------------------------
  203. ;      Constants for Ahdoc 101 PHY
  204. ; -------------------------------------------------------------------------
  205.  
  206.     AhdocPHYID0         = 0x0022
  207.     DiagnosticReg       = 18
  208.     DPLX_FULL           = 0x0800
  209.     Speed_100           = 0x0400
  210.  
  211. ; --------------------------------------------------------------------------
  212. ;      Constants
  213. ; --------------------------------------------------------------------------
  214.  
  215.     MarvellPHYID0               = 0x0141
  216.     LevelOnePHYID0              = 0x0013
  217.  
  218.     MII1000BaseTControlReg      = 9
  219.     MII1000BaseTStatusReg       = 10
  220.     SpecificReg                 = 17
  221.  
  222. ; for 1000BaseT Control Register
  223.  
  224.     PHYAbletoPerform1000FullDuplex = 0x0200
  225.     PHYAbletoPerform1000HalfDuplex = 0x0100
  226.     PHY1000AbilityMask             = 0x300
  227.  
  228. ; for phy specific status register, marvell phy.
  229.  
  230.     SpeedMask      = 0x0c000
  231.     Speed_1000M    = 0x08000
  232.     Speed_100M     = 0x4000
  233.     Speed_10M      = 0
  234.     Full_Duplex    = 0x2000
  235.  
  236. ; for phy specific status register, levelone phy
  237.  
  238.     LXT1000_100M   = 0x08000
  239.     LXT1000_1000M  = 0x0c000
  240.     LXT1000_Full   = 0x200
  241.  
  242. ; for PHY
  243.  
  244.     LinkIsUp       = 0x0004
  245.     LinkIsUp2      = 0x00040000
  246.  
  247.  
  248.  
  249. struct  descriptor
  250.         status                  dd ?
  251.         control                 dd ?
  252.         buffer                  dd ?
  253.         next_desc               dd ?
  254.  
  255.         next_desc_logical       dd ?
  256.         skbuff                  dd ?
  257.         reserved1               dd ?
  258.         reserved2               dd ?
  259. ends
  260.  
  261.  
  262. struct  device          ETH_DEVICE
  263.  
  264.         io_addr         dd ?
  265.         pci_bus         dd ?
  266.         pci_dev         dd ?
  267.         irq_line        db ?
  268.         dev_id          dw ?
  269.         flags           dd ?
  270.         crvalue         dd ?
  271.         bcrvalue        dd ?
  272.         cur_rx          dd ?
  273.         cur_tx          dd ?
  274.         default_port    dd ?
  275.         PHYType         dd ?
  276.  
  277. ; MII transceiver section.
  278.         mii_cnt         dd ?    ; MII device addresses.
  279.         phys            db ?    ; MII device addresses.
  280.  
  281. ; descriptors
  282.         rb 0x100 - ($ and 0xff) ; align 256
  283.         tx_desc         rb NUM_TX_DESC*sizeof.descriptor
  284.         rx_desc         rb NUM_RX_DESC*sizeof.descriptor
  285.  
  286. ends
  287.  
  288.  
  289. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  290. ;;                        ;;
  291. ;; proc START             ;;
  292. ;;                        ;;
  293. ;; (standard driver proc) ;;
  294. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  295.  
  296. proc START c, reason:dword, cmdline:dword
  297.  
  298.         cmp     [reason], DRV_ENTRY
  299.         jne     .fail
  300.  
  301.         DEBUGF  1,"Loading driver\n"
  302.         invoke  RegService, my_service, service_proc
  303.         ret
  304.  
  305.   .fail:
  306.         xor     eax, eax
  307.         ret
  308.  
  309. endp
  310.  
  311.  
  312. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  313. ;;                        ;;
  314. ;; proc SERVICE_PROC      ;;
  315. ;;                        ;;
  316. ;; (standard driver proc) ;;
  317. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  318.  
  319. proc service_proc stdcall, ioctl:dword
  320.  
  321.         mov     edx, [ioctl]
  322.         mov     eax, [edx + IOCTL.io_code]
  323.  
  324. ;------------------------------------------------------
  325.  
  326.         cmp     eax, 0 ;SRV_GETVERSION
  327.         jne     @F
  328.  
  329.         cmp     [edx + IOCTL.out_size], 4
  330.         jb      .fail
  331.         mov     eax, [edx + IOCTL.output]
  332.         mov     [eax], dword API_VERSION
  333.  
  334.         xor     eax, eax
  335.         ret
  336.  
  337. ;------------------------------------------------------
  338.   @@:
  339.         cmp     eax, 1 ;SRV_HOOK
  340.         jne     .fail
  341.  
  342.         cmp     [edx + IOCTL.inp_size], 3               ; Data input must be at least 3 bytes
  343.         jb      .fail
  344.  
  345.         mov     eax, [edx + IOCTL.input]
  346.         cmp     byte [eax], 1                           ; 1 means device number and bus number (pci) are given
  347.         jne     .fail                                   ; other types arent supported for this card yet
  348.  
  349. ; check if the device is already listed
  350.  
  351.         mov     esi, device_list
  352.         mov     ecx, [devices]
  353.         test    ecx, ecx
  354.         jz      .firstdevice
  355.  
  356. ;        mov     eax, [edx + IOCTL.input]                ; get the pci bus and device numbers
  357.         mov     ax, [eax+1]                             ;
  358.   .nextdevice:
  359.         mov     ebx, [esi]
  360.         cmp     al, byte[ebx + device.pci_bus]
  361.         jne     @f
  362.         cmp     ah, byte[ebx + device.pci_dev]
  363.         je      .find_devicenum                         ; Device is already loaded, let's find it's device number
  364.        @@:
  365.         add     esi, 4
  366.         loop    .nextdevice
  367.  
  368.  
  369. ; This device doesnt have its own eth_device structure yet, lets create one
  370.   .firstdevice:
  371.         cmp     [devices], MAX_DEVICES                  ; First check if the driver can handle one more card
  372.         jae     .fail
  373.  
  374.         allocate_and_clear ebx, sizeof.device, .fail
  375.  
  376. ; Fill in the direct call addresses into the struct
  377.  
  378.         mov     [ebx + device.reset], reset
  379.         mov     [ebx + device.transmit], transmit
  380.         mov     [ebx + device.unload], unload
  381.         mov     [ebx + device.name], my_service
  382.  
  383. ; save the pci bus and device numbers
  384.  
  385.         mov     eax, [edx + IOCTL.input]
  386.         movzx   ecx, byte[eax+1]
  387.         mov     [ebx + device.pci_bus], ecx
  388.         movzx   ecx, byte[eax+2]
  389.         mov     [ebx + device.pci_dev], ecx
  390.  
  391. ; Now, it's time to find the base io addres of the PCI device
  392.  
  393.         stdcall PCI_find_io, [ebx + device.pci_bus], [ebx + device.pci_dev]
  394.         mov     [ebx + device.io_addr], eax
  395.  
  396. ; We've found the io address, find IRQ now
  397.  
  398.         invoke  PciRead8, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.interrupt_line
  399.         mov     [ebx + device.irq_line], al
  400.  
  401.         DEBUGF  1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\
  402.         [ebx + device.pci_dev]:1,[ebx + device.pci_bus]:1,[ebx + device.irq_line]:1,[ebx + device.io_addr]:8
  403.  
  404. ; Ok, the eth_device structure is ready, let's probe the device
  405. ; Because initialization fires IRQ, IRQ handler must be aware of this device
  406.         mov     eax, [devices]                                          ; Add the device structure to our device list
  407.         mov     [device_list+4*eax], ebx                                ; (IRQ handler uses this list to find device)
  408.         inc     [devices]                                               ;
  409.  
  410.         call    probe                                                   ; this function will output in eax
  411.         test    eax, eax
  412.         jnz     .err2                                                   ; If an error occured, exit
  413.  
  414.         mov     [ebx + device.type], NET_TYPE_ETH
  415.         invoke  NetRegDev
  416.  
  417.         cmp     eax, -1
  418.         je      .destroy
  419.  
  420.         ret
  421.  
  422. ; If the device was already loaded, find the device number and return it in eax
  423.  
  424.   .find_devicenum:
  425.         DEBUGF  2,"Trying to find device number of already registered device\n"
  426.         invoke  NetPtrToNum                                             ; This kernel procedure converts a pointer to device struct in ebx
  427.                                                                         ; into a device number in edi
  428.         mov     eax, edi                                                ; Application wants it in eax instead
  429.         DEBUGF  2,"Kernel says: %u\n", eax
  430.         ret
  431.  
  432. ; If an error occured, remove all allocated data and exit (returning -1 in eax)
  433.  
  434.   .destroy:
  435.         ; todo: reset device into virgin state
  436.  
  437.   .err2:
  438.         dec     [devices]
  439.   .err:
  440.         DEBUGF  2,"removing device structure\n"
  441.         invoke  KernelFree, ebx
  442.   .fail:
  443.         or      eax, -1
  444.         ret
  445.  
  446. ;------------------------------------------------------
  447. endp
  448.  
  449.  
  450. ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
  451. ;;                                                                        ;;
  452. ;;        Actual Hardware dependent code starts here                      ;;
  453. ;;                                                                        ;;
  454. ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
  455.  
  456.  
  457.  
  458. align 4
  459. unload:
  460.         ; TODO: (in this particular order)
  461.         ;
  462.         ; - Stop the device
  463.  
  464. ;    /* Disable Tx Rx*/
  465. ;    outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR );
  466. ;
  467. ;    /* Reset the chip to erase previous misconfiguration. */
  468. ;    mtd_reset(nic);
  469.  
  470.         ; - Detach int handler
  471.         ; - Remove device from local list (device_list)
  472.         ; - call unregister function in kernel
  473.         ; - Remove all allocated structures and buffers the card used
  474.  
  475.         or      eax, -1
  476.         ret
  477.  
  478.  
  479. ;-------
  480. ;
  481. ; PROBE
  482. ;
  483. ;-------
  484. align 4
  485. probe:
  486.  
  487.         DEBUGF  1,"Probing\n"
  488.  
  489. ; Make the device a bus master
  490.         invoke  PciRead32, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.command
  491.         or      al, PCI_CMD_MASTER
  492.         invoke  PciWrite32, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.command, eax
  493.  
  494. ; Check vendor/device id's
  495.         invoke  PciRead32, [ebx + device.pci_bus], [ebx + device.pci_dev], 0
  496.         cmp     ax, 0x1516
  497.         jne     .notfound
  498.         shr     eax, 16
  499.         mov     [ebx + device.dev_id], ax
  500.         cmp     ax, 0x0800
  501.         je      .mtd800
  502.         cmp     ax, 0x0803
  503.         je      .mtd803
  504.         cmp     ax, 0x0891
  505.         je      .mtd891
  506.  
  507.   .notfound:
  508.         DEBUGF  2,"Device not supported!\n"
  509.         xor     eax, eax
  510.         dec     eax
  511.         ret
  512.  
  513.   .mtd803:
  514.         mov     [ebx + device.name], sz_mtd803
  515.         DEBUGF  1,"Device has chip xcvr\n"
  516.         jmp     .xcvr_set
  517.  
  518.   .mtd800:
  519.         DEBUGF  1,"Device has mii xcvr\n"
  520.         mov     [ebx + device.name], sz_mtd800
  521.         jmp     .xcvr_set
  522.  
  523.   .mtd891:
  524.         DEBUGF  1,"Device has mii xcvr\n"
  525.         mov     [ebx + device.name], sz_mtd800
  526.  
  527.   .xcvr_set:
  528.         call    read_mac
  529.  
  530. ; Reset the chip to erase previous misconfiguration.
  531.         set_io  [ebx + device.io_addr], 0
  532.         set_io  [ebx + device.io_addr], BCR
  533.         xor     eax, eax
  534.         inc     eax
  535.         out     dx, eax
  536.  
  537. ; find the connected MII xcvrs
  538.         cmp     [ebx + device.dev_id], 0x0803
  539.         je      .is_803
  540.  
  541. ;        int     phy, phy_idx =   0;
  542. ;
  543. ;        for (phy =   1; phy < 32 && phy_idx < 1; phy++) {
  544. ;            int mii_status =   mdio_read(nic, phy, 1);
  545. ;
  546. ;            if (mii_status !=   0xffff && mii_status !=   0x0000) {
  547. ;                mtdx.phys[phy_idx] =   phy;
  548. ;
  549. ;                DBG ( "%s: MII PHY found at address %d, status "
  550. ;                      "0x%4.4x.\n", mtdx.nic_name, phy, mii_status );
  551. ;                /* get phy type */
  552. ;                {
  553. ;                    unsigned int data;
  554. ;
  555. ;                    data =   mdio_read(nic, mtdx.phys[phy_idx], 2);
  556. ;                    if (data equ=   SeeqPHYID0)
  557. ;                        mtdx.PHYType =   SeeqPHY;
  558. ;                    else if (data equ=   AhdocPHYID0)
  559. ;                        mtdx.PHYType =   AhdocPHY;
  560. ;                    else if (data equ=   MarvellPHYID0)
  561. ;                        mtdx.PHYType =   MarvellPHY;
  562. ;                    else if (data equ=   MysonPHYID0)
  563. ;                        mtdx.PHYType =   Myson981;
  564. ;                    else if (data equ=   LevelOnePHYID0)
  565. ;                        mtdx.PHYType =   LevelOnePHY;
  566. ;                    else
  567. ;                        mtdx.PHYType =   OtherPHY;
  568. ;                }
  569. ;                phy_idx++;
  570. ;            }
  571. ;        }
  572. ;
  573. ;        mtdx.mii_cnt =   phy_idx;
  574. ;        if (phy_idx equ=   0) {
  575. ;            printf("%s: MII PHY not found -- this device may "
  576. ;                   "not operate correctly.\n", mtdx.nic_name);
  577. ;        }
  578.  
  579.         jmp     .no_803
  580.  
  581.   .is_803:
  582.         mov     [ebx + device.phys], 32
  583.  
  584. ; get phy type
  585.         set_io  [ebx + device.io_addr], 0
  586.         set_io  [ebx + device.io_addr], PHYIDENTIFIER
  587.         in      eax, dx
  588.  
  589.         cmp     eax, MysonPHYID
  590.         jne     @f
  591.         mov     [ebx + device.PHYType], MysonPHY
  592.         DEBUGF  1,"Myson PHY\n"
  593.         jmp     .no_803
  594.        @@:
  595.  
  596.         mov     [ebx + device.PHYType], OtherPHY
  597.         DEBUGF  1,"Other PHY\n"
  598.   .no_803:
  599.  
  600. ;-------
  601. ;
  602. ; RESET
  603. ;
  604. ;-------
  605. align 4
  606. reset:
  607.  
  608.         DEBUGF  1,"Resetting\n"
  609.  
  610. ; attach irq handler
  611.         movzx   eax, [ebx + device.irq_line]
  612.         DEBUGF  1,"Attaching int handler to irq %x\n", eax:1
  613.         invoke  AttachIntHandler, eax, int_handler, ebx
  614.         test    eax, eax
  615.         jnz     @f
  616.         DEBUGF  2,"Could not attach int handler!\n"
  617.         or      eax, -1
  618.         ret
  619.   @@:
  620.  
  621. ; Reset the chip to erase previous misconfiguration.
  622.         set_io  [ebx + device.io_addr], 0
  623.         set_io  [ebx + device.io_addr], BCR
  624.         xor     eax, eax
  625.         inc     eax
  626.         out     dx, eax
  627.  
  628.         call    init_ring
  629.         test    eax, eax
  630.         jnz     .err
  631.  
  632. ; Initialize other registers.
  633. ; Configure the PCI bus bursts and FIFO thresholds.
  634.         mov     [ebx + device.bcrvalue], 0x10         ; little-endian, 8 burst length
  635.         mov     [ebx + device.crvalue], 0xa00         ; 128 burst length
  636.  
  637.         cmp     [ebx + device.dev_id], 0x891
  638.         jne     @f
  639.         or      [ebx + device.bcrvalue], 0x200       ; set PROG bit
  640.         or      [ebx + device.crvalue], 0x02000000   ; set enhanced bit
  641.   @@:
  642.         or      [ebx + device.crvalue], RxEnable + TxThreshold + TxEnable
  643.  
  644.         call    set_rx_mode
  645.  
  646.         set_io  [ebx + device.io_addr], 0
  647.         set_io  [ebx + device.io_addr], BCR
  648.         mov     eax, [ebx + device.bcrvalue]
  649.         out     dx, eax
  650.  
  651.         set_io  [ebx + device.io_addr], TCRRCR
  652.         mov     eax, [ebx + device.crvalue]
  653.         out     dx, eax
  654.  
  655.         call    getlinkstatus
  656.  
  657. ; Restart Rx engine if stopped.
  658.         set_io  [ebx + device.io_addr], 0
  659.         set_io  [ebx + device.io_addr], RXPDR
  660.         xor     eax, eax
  661.         out     dx, eax
  662.  
  663. ; Enable interrupts
  664.         set_io  [ebx + device.io_addr], ISR
  665.         mov     eax, FBE or TUNF or CNTOVF or RBU or TI or RI
  666.         out     dx, eax
  667.         set_io  [ebx + device.io_addr], IMR
  668.         out     dx, eax
  669.  
  670. ; clear packet/byte counters
  671.         xor     eax, eax
  672.         lea     edi, [ebx + device.bytes_tx]
  673.         mov     ecx, 6
  674.         rep     stosd
  675.  
  676.         mov     [ebx + device.mtu], 1514
  677.         xor     eax, eax
  678.         ret
  679.  
  680.   .err:
  681.         DEBUGF  2, "Error!\n"
  682.         or      eax, -1
  683.         ret
  684.  
  685.  
  686.  
  687.  
  688. align 4
  689. init_ring:
  690.  
  691.         DEBUGF  1, "initializing rx and tx ring\n"
  692.  
  693. ; Initialize all Rx descriptors
  694.         lea     esi, [ebx + device.rx_desc]
  695.         mov     [ebx + device.cur_rx], esi
  696.         mov     ecx, NUM_RX_DESC
  697.   .rx_desc_loop:
  698.         mov     [esi + descriptor.status], RXOWN
  699.         mov     [esi + descriptor.control], 1514 shl RBSShift
  700.  
  701.         lea     eax, [esi + sizeof.descriptor]
  702.         mov     [esi + descriptor.next_desc_logical], eax
  703.         push    ecx esi
  704.         invoke  GetPhysAddr
  705.         mov     [esi + descriptor.next_desc], eax
  706.  
  707.         invoke  NetAlloc, 1514+NET_BUFF.data
  708.         pop     esi ecx
  709.         test    eax, eax
  710.         jz      .out_of_mem
  711.         push    ecx esi
  712.         mov     [esi + descriptor.skbuff], eax
  713.         invoke  GetPgAddr
  714.         add     eax, NET_BUFF.data
  715.         pop     esi ecx
  716.         mov     [esi + descriptor.buffer], eax
  717.  
  718.         add     esi, sizeof.descriptor
  719.         loop    .rx_desc_loop
  720.  
  721. ; Mark the last entry as wrapping the ring.
  722.         lea     eax, [ebx + device.rx_desc]
  723.         mov     [esi - sizeof.descriptor + descriptor.next_desc_logical], eax
  724.         push    esi
  725.         invoke  GetPhysAddr
  726.         pop     esi
  727.         mov     [esi - sizeof.descriptor + descriptor.next_desc], eax
  728.  
  729.         set_io  [ebx + device.io_addr],   0
  730.         set_io  [ebx + device.io_addr],   RXLBA
  731.         out     dx, eax
  732.  
  733. ; Initialize all Tx descriptors
  734.         lea     esi, [ebx + device.tx_desc]
  735.         mov     [ebx + device.cur_tx], esi
  736.         mov     ecx, NUM_TX_DESC
  737.   .tx_desc_loop:
  738.         mov     [esi + descriptor.status], 0
  739.  
  740.         lea     eax, [esi + sizeof.descriptor]
  741.         mov     [esi + descriptor.next_desc_logical], eax
  742.         push    ecx esi
  743.         invoke  GetPhysAddr
  744.         pop     esi ecx
  745.         mov     [esi + descriptor.next_desc], eax
  746.         mov     [esi + descriptor.skbuff], 0
  747.         add     esi, sizeof.descriptor
  748.         loop    .tx_desc_loop
  749.  
  750. ; Mark the last entry as wrapping the ring.
  751.         lea     eax, [ebx + device.tx_desc]
  752.         mov     [esi - sizeof.descriptor + descriptor.next_desc_logical], eax
  753.         push    esi
  754.         invoke  GetPhysAddr
  755.         pop     esi
  756.         mov     [esi - sizeof.descriptor + descriptor.next_desc], eax
  757.  
  758.         set_io  [ebx + device.io_addr], 0
  759.         set_io  [ebx + device.io_addr], TXLBA
  760.         out     dx, eax
  761.  
  762.         xor     eax, eax
  763.         ret
  764.  
  765.   .out_of_mem:
  766.         or      eax, -1
  767.         ret
  768.  
  769.  
  770. align 4
  771. set_rx_mode:
  772.  
  773.         DEBUGF  1,"Setting RX mode\n"
  774.  
  775. ; Too many to match, or accept all multicasts.
  776.         set_io  [ebx + device.io_addr], 0
  777.         set_io  [ebx + device.io_addr], MAR0
  778.         xor     eax, eax
  779.         not     eax
  780.         out     dx, eax
  781.         set_io  [ebx + device.io_addr], MAR1
  782.         out     dx, eax
  783.  
  784.         and     [ebx + device.crvalue], not (RxModeMask)
  785.         or      [ebx + device.crvalue], AcceptBroadcast + AcceptMulticast + AcceptMyPhys
  786.  
  787.         ret
  788.  
  789.  
  790. align 4
  791. getlinkstatus:
  792.  
  793.         DEBUGF  1,"Getting link status\n"
  794.  
  795.         mov     [ebx + device.state], ETH_LINK_DOWN     ; assume link is dead
  796.  
  797.         cmp     [ebx + device.PHYType], MysonPHY
  798.         jne     .no_myson_phy
  799.         set_io  [ebx + device.io_addr], 0
  800.         set_io  [ebx + device.io_addr], BMCRSR
  801.         in      eax, dx
  802.         test    eax, LinkIsUp2
  803.         jnz     getlinktype
  804.         ret
  805.  
  806.   .no_myson_phy:
  807.         set_io  [ebx + device.io_addr], 0
  808.         set_io  [ebx + device.io_addr], BMCRSR
  809.         in      eax, dx
  810.         test    eax, LinkIsUp
  811.         jnz     getlinktype
  812.         ret
  813.  
  814. getlinktype:
  815.  
  816.         DEBUGF  1,"Getting link type\n"
  817.         cmp     [ebx + device.PHYType], MysonPHY
  818.         jne     .no_myson_phy
  819.  
  820.         DEBUGF  1,"myson PHY\n"
  821.         set_io  [ebx + device.io_addr], 0
  822.         set_io  [ebx + device.io_addr], TCRRCR
  823.         in      eax, dx
  824.         test    eax, FD
  825.         jz      @f
  826.         DEBUGF  1,"full duplex\n"
  827.         or      [ebx + device.state], ETH_LINK_FD
  828.        @@:
  829.         test    eax, PS10
  830.         jnz     @f
  831.         DEBUGF  1,"100mbit\n"
  832.         or      [ebx + device.state], ETH_LINK_100M
  833.         ret
  834.        @@:
  835.         DEBUGF  1,"10mbit\n"
  836.         or      [ebx + device.state], ETH_LINK_10M
  837.         ret
  838.  
  839.   .no_myson_phy:
  840.         DEBUGF  1,"not a myson PHY\n"
  841.         mov     [ebx + device.state], ETH_LINK_UNKNOWN
  842.  
  843. ;        if (mtdx.PHYType equ=   SeeqPHY) { /* this PHY is SEEQ 80225 */
  844. ;            unsigned int data;
  845. ;
  846. ;            data =   mdio_read(dev, mtdx.phys[0], MIIRegister18);
  847. ;            if (data & SPD_DET_100)
  848. ;                mtdx.line_speed =   2; /* 100M */
  849. ;            else
  850. ;                mtdx.line_speed =   1; /* 10M */
  851. ;            if (data & DPLX_DET_FULL)
  852. ;                mtdx.duplexmode =   2; /* full duplex mode */
  853. ;            else
  854. ;                mtdx.duplexmode =   1; /* half duplex mode */
  855. ;        } else if (mtdx.PHYType equ=   AhdocPHY) {
  856. ;            unsigned int data;
  857. ;
  858. ;            data =   mdio_read(dev, mtdx.phys[0], DiagnosticReg);
  859. ;            if (data & Speed_100)
  860. ;                mtdx.line_speed =   2; /* 100M */
  861. ;            else
  862. ;                mtdx.line_speed =   1; /* 10M */
  863. ;            if (data & DPLX_FULL)
  864. ;                mtdx.duplexmode =   2; /* full duplex mode */
  865. ;            else
  866. ;                mtdx.duplexmode =   1; /* half duplex mode */
  867. ;        }
  868. ;        else if (mtdx.PHYType equ=   MarvellPHY) {
  869. ;            unsigned int data;
  870. ;
  871. ;            data =   mdio_read(dev, mtdx.phys[0], SpecificReg);
  872. ;            if (data & Full_Duplex)
  873. ;                mtdx.duplexmode =   2; /* full duplex mode */
  874. ;            else
  875. ;                mtdx.duplexmode =   1; /* half duplex mode */
  876. ;            data &=   SpeedMask;
  877. ;            if (data equ=   Speed_1000M)
  878. ;                mtdx.line_speed =   3; /* 1000M */
  879. ;            else if (data equ=   Speed_100M)
  880. ;                mtdx.line_speed =   2; /* 100M */
  881. ;            else
  882. ;                mtdx.line_speed =   1; /* 10M */
  883. ;        }
  884. ;        else if (mtdx.PHYType equ=   Myson981) {
  885. ;            unsigned int data;
  886. ;
  887. ;            data =   mdio_read(dev, mtdx.phys[0], StatusRegister);
  888. ;
  889. ;            if (data & SPEED100)
  890. ;                mtdx.line_speed =   2;
  891. ;            else
  892. ;                mtdx.line_speed =   1;
  893. ;
  894. ;            if (data & FULLMODE)
  895. ;                mtdx.duplexmode =   2;
  896. ;            else
  897. ;                mtdx.duplexmode =   1;
  898. ;        }
  899. ;        else if (mtdx.PHYType equ=   LevelOnePHY) {
  900. ;            unsigned int data;
  901. ;
  902. ;            data =   mdio_read(dev, mtdx.phys[0], SpecificReg);
  903. ;            if (data & LXT1000_Full)
  904. ;                mtdx.duplexmode =   2; /* full duplex mode */
  905. ;            else
  906. ;                mtdx.duplexmode =   1; /* half duplex mode */
  907. ;            data &=   SpeedMask;
  908. ;            if (data equ=   LXT1000_1000M)
  909. ;                mtdx.line_speed =   3; /* 1000M */
  910. ;            else if (data equ=   LXT1000_100M)
  911. ;                mtdx.line_speed =   2; /* 100M */
  912. ;            else
  913.  ;               mtdx.line_speed =   1; /* 10M */
  914.   ;      }
  915.  
  916. ;        // chage crvalue
  917. ;        // mtdx.crvalue&equ(~PS10)&(~FD);
  918. ;        mtdx.crvalue &=   (~PS10) & (~FD) & (~PS1000);
  919. ;        if (mtdx.line_speed equ=   1)
  920. ;            mtdx.crvalue |=   PS10;
  921. ;        else if (mtdx.line_speed equ=   3)
  922. ;            mtdx.crvalue |=   PS1000;
  923. ;        if (mtdx.duplexmode equ=   2)
  924. ;            mtdx.crvalue |=   FD;
  925.  
  926.         ret
  927.  
  928.  
  929.  
  930.  
  931. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  932. ;;                                         ;;
  933. ;; Transmit                                ;;
  934. ;;                                         ;;
  935. ;; In: buffer pointer in [esp+4]           ;;
  936. ;;     size of buffer in [esp+8]           ;;
  937. ;;     pointer to device structure in ebx  ;;
  938. ;;                                         ;;
  939. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  940.  
  941. proc transmit stdcall bufferptr
  942.  
  943.         pushf
  944.         cli
  945.  
  946.         mov     esi, [bufferptr]
  947.         DEBUGF  1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [esi + NET_BUFF.length]
  948.         lea     eax, [esi + NET_BUFF.data]
  949.         DEBUGF  1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\
  950.         [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\
  951.         [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\
  952.         [eax+13]:2,[eax+12]:2
  953.  
  954.         cmp     [esi + NET_BUFF.length], 1514
  955.         ja      .fail
  956.         cmp     [esi + NET_BUFF.length], 60
  957.         jb      .fail
  958.  
  959.         mov     esi, [ebx + device.cur_tx]
  960.         test    [esi + descriptor.status], TXOWN
  961.         jnz     .fail
  962.  
  963.         push    [esi + descriptor.next_desc_logical]
  964.         pop     [ebx + device.cur_tx]
  965.  
  966.         mov     eax, [bufferptr]
  967.         mov     [esi + descriptor.skbuff], eax
  968.         add     eax, [eax + NET_BUFF.offset]
  969.         invoke  GetPhysAddr
  970.         mov     [esi + descriptor.buffer], eax
  971.  
  972.         mov     eax, [bufferptr]
  973.         mov     eax, [eax + NET_BUFF.length]
  974.         mov     ecx, eax
  975.         shl     eax, PKTSShift               ; packet size
  976.         shl     ecx, TBSShift
  977.         or      eax, ecx
  978.         or      eax, TXIC + TXLD + TXFD + CRCEnable + PADEnable
  979.         mov     [esi + descriptor.control], eax
  980.         mov     [esi + descriptor.status], TXOWN
  981.  
  982. ; Update stats
  983.         inc     [ebx + device.packets_tx]
  984.         mov     eax, [bufferptr]
  985.         mov     ecx, [eax + NET_BUFF.length]
  986.         add     dword[ebx + device.bytes_tx], ecx
  987.         adc     dword[ebx + device.bytes_tx + 4], 0
  988.  
  989. ; TX Poll
  990.         set_io  [ebx + device.io_addr], 0
  991.         set_io  [ebx + device.io_addr], TXPDR
  992.         xor     eax, eax
  993.         out     dx, eax
  994.  
  995.         DEBUGF  1,"Transmit OK\n"
  996.         popf
  997.         xor     eax, eax
  998.         ret
  999.  
  1000.   .fail:
  1001.         DEBUGF  2,"Transmit failed\n"
  1002.         invoke  NetFree, [bufferptr]
  1003.         popf
  1004.         or      eax, -1
  1005.         ret
  1006.  
  1007. endp
  1008.  
  1009.  
  1010.  
  1011. align 4
  1012. read_mac:
  1013.  
  1014.         set_io  [ebx + device.io_addr], 0
  1015.         set_io  [ebx + device.io_addr], PAR0
  1016.         lea     edi, [ebx + device.mac]
  1017.         insd
  1018.         set_io  [ebx + device.io_addr], PAR1
  1019.         insw
  1020.         DEBUGF  1,"MAC = %x-%x-%x-%x-%x-%x\n",\
  1021.         [ebx + device.mac+0]:2,[ebx + device.mac+1]:2,[ebx + device.mac+2]:2,[ebx + device.mac+3]:2,[ebx + device.mac+4]:2,[ebx + device.mac+5]:2
  1022.  
  1023.         ret
  1024.  
  1025. align 4
  1026. write_mac:
  1027.  
  1028.         ret
  1029.  
  1030.  
  1031.  
  1032. ;;;;;;;;;;;;;;;;;;;;;;;
  1033. ;;                   ;;
  1034. ;; Interrupt handler ;;
  1035. ;;                   ;;
  1036. ;;;;;;;;;;;;;;;;;;;;;;;
  1037.  
  1038. align 4
  1039. int_handler:
  1040.  
  1041.         push    ebx esi edi
  1042.  
  1043.         DEBUGF  1,"INT\n"
  1044.  
  1045. ; find pointer of device wich made IRQ occur
  1046.  
  1047.         mov     ecx, [devices]
  1048.         test    ecx, ecx
  1049.         jz      .nothing
  1050.         mov     esi, device_list
  1051.   .nextdevice:
  1052.         mov     ebx, [esi]
  1053.  
  1054.         set_io  [ebx + device.io_addr], 0
  1055.         set_io  [ebx + device.io_addr], ISR
  1056.         in      eax, dx
  1057.         out     dx, eax                                 ; send it back to ACK
  1058.         test    eax, eax
  1059.         jnz     .got_it
  1060.   .continue:
  1061.         add     esi, 4
  1062.         dec     ecx
  1063.         jnz     .nextdevice
  1064.   .nothing:
  1065.         pop     edi esi ebx
  1066.         xor     eax, eax
  1067.  
  1068.         ret                                             ; If no device was found, abort (The irq was probably for a device, not registered to this driver)
  1069.  
  1070.   .got_it:
  1071.  
  1072.         DEBUGF  1,"Device: %x Status: %x\n", ebx, ax
  1073.  
  1074.         test    ax, RI  ; receive interrupt
  1075.         jz      .no_rx
  1076.         push    ax
  1077.   .rx_loop:
  1078.         mov     esi, [ebx + device.cur_rx]
  1079.         test    [esi + descriptor.status], RXOWN
  1080.         jnz     .rx_done
  1081.  
  1082.         push    ebx
  1083.         push    .rx_complete
  1084.  
  1085.         mov     ecx, [esi + descriptor.status]
  1086.         shr     ecx, FLNGShift
  1087.         sub     ecx, 4                  ; we dont need CRC
  1088.         DEBUGF  1,"Received %u bytes\n", ecx
  1089.         mov     eax, [esi + descriptor.skbuff]
  1090.         push    eax
  1091.         mov     [eax + NET_BUFF.length], ecx
  1092.         mov     [eax + NET_BUFF.device], ebx
  1093.         mov     [eax + NET_BUFF.offset], NET_BUFF.data
  1094.  
  1095. ; Update stats
  1096.         add     dword[ebx + device.bytes_rx], ecx
  1097.         adc     dword[ebx + device.bytes_rx + 4], 0
  1098.         inc     [ebx + device.packets_rx]
  1099.  
  1100.         jmp     [EthInput]
  1101.  
  1102.   .rx_complete:
  1103.         pop     ebx
  1104.         mov     esi, [ebx + device.cur_rx]
  1105.         mov     [esi + descriptor.control], 1514 shl RBSShift
  1106.         push    esi
  1107.         invoke  NetAlloc, 1514+NET_BUFF.data
  1108.         pop     esi
  1109. ;        test    eax, eax
  1110. ;        jz      .rx_loop
  1111.         mov     [esi + descriptor.skbuff], eax
  1112.         invoke  GetPhysAddr
  1113.         add     eax, NET_BUFF.data
  1114.         mov     [esi + descriptor.buffer], eax
  1115.         mov     [esi + descriptor.status], RXOWN
  1116.  
  1117.         push    [esi + descriptor.next_desc_logical]
  1118.         pop     [ebx + device.cur_rx]
  1119.  
  1120.         jmp     .rx_loop
  1121.  
  1122.   .rx_done:
  1123.         DEBUGF  1,"RX done\n"
  1124.  
  1125. ; Restart Rx engine if stopped.
  1126.         set_io  [ebx + device.io_addr], 0
  1127.         set_io  [ebx + device.io_addr], RXPDR
  1128.         xor     eax, eax
  1129.         out     dx, eax
  1130.  
  1131.         pop     ax
  1132.   .no_rx:
  1133.  
  1134.         test    ax, TI ; transmit interrupt
  1135.         jz      .no_tx
  1136.         DEBUGF  1,"TX\n"
  1137.         push    ax
  1138.         lea     esi, [ebx + device.tx_desc]
  1139.         mov     ecx, NUM_TX_DESC
  1140.   .tx_loop:
  1141.         test    [esi + descriptor.status], TXOWN
  1142.         jnz     .skip_this_one
  1143.         mov     eax, [esi + descriptor.skbuff]
  1144.         test    eax, eax
  1145.         je      .skip_this_one
  1146.         mov     [esi + descriptor.skbuff], 0
  1147.         DEBUGF  1,"freeing buffer: 0x%x\n", eax
  1148.         invoke  NetFree, eax
  1149.   .skip_this_one:
  1150.         mov     esi, [esi + descriptor.next_desc_logical]
  1151.         loop    .tx_loop
  1152.         pop     ax
  1153.   .no_tx:
  1154.  
  1155.         test    ax, LSCStatus
  1156.         jz      .no_link_change
  1157.         push    ax
  1158.         call    getlinkstatus
  1159.         pop     ax
  1160.   .no_link_change:
  1161.  
  1162. ;        test    ax, TBU
  1163. ;        jz      .no_tbu
  1164. ;        DEBUGF  2,"Transmit buffer unavailable!\n"
  1165. ;  .no_tbu:
  1166.  
  1167.   .fail:
  1168.         pop     edi esi ebx
  1169.         xor     eax, eax
  1170.         inc     eax
  1171.  
  1172.         ret
  1173.  
  1174.  
  1175. ; End of code
  1176.  
  1177.  
  1178. data fixups
  1179. end data
  1180.  
  1181. include '../peimport.inc'
  1182.  
  1183. my_service      db 'MTD80X',0                   ; max 16 chars include zero
  1184.  
  1185. sz_mtd800       db "Myson MTD800", 0
  1186. sz_mtd803       db "Surecom EP-320X", 0
  1187. sz_mtd891       db "Myson MTD891", 0
  1188.  
  1189.  
  1190. include_debug_strings                           ; All data wich FDO uses will be included here
  1191.  
  1192. align 4
  1193. devices       dd 0
  1194. device_list   rd MAX_DEVICES                    ; This list contains all pointers to device structures the driver is handling
  1195.  
  1196.  
  1197.