Subversion Repositories Kolibri OS

Rev

Rev 5194 | Rev 5363 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2014. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;; i8255x (Intel eepro 100) driver for KolibriOS                   ;;
  7. ;;                                                                 ;;
  8. ;;    Written by hidnplayr@kolibrios.org                           ;;
  9. ;;                                                                 ;;
  10. ;;          GNU GENERAL PUBLIC LICENSE                             ;;
  11. ;;             Version 2, June 1991                                ;;
  12. ;;                                                                 ;;
  13. ;; Some parts of this driver are based on the code of eepro100.c   ;;
  14. ;;  from linux.                                                    ;;
  15. ;;                                                                 ;;
  16. ;; Intel's programming manual for i8255x:                          ;;
  17. ;; http://www.intel.com/design/network/manuals/8255x_opensdm.htm   ;;
  18. ;;                                                                 ;;
  19. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  20.  
  21. ; TODO: use separate descriptors in memory instead of placing them in front of packets!
  22.  
  23.  
  24. format PE DLL native
  25. entry START
  26.  
  27.         CURRENT_API             = 0x0200
  28.         COMPATIBLE_API          = 0x0100
  29.         API_VERSION             = (COMPATIBLE_API shl 16) + CURRENT_API
  30.  
  31.         MAX_DEVICES             = 16
  32.  
  33.         DEBUG                   = 1
  34.         __DEBUG__               = 1
  35.         __DEBUG_LEVEL__         = 2             ; 1 = verbose, 2 = errors only
  36.  
  37. section '.flat' readable writable executable
  38.  
  39. include '../proc32.inc'
  40. include '../struct.inc'
  41. include '../macros.inc'
  42. include '../fdo.inc'
  43. include '../netdrv.inc'
  44.  
  45. ; Serial EEPROM
  46.  
  47. EE_SK           = 1 shl 0      ; serial clock
  48. EE_CS           = 1 shl 1      ; chip select
  49. EE_DI           = 1 shl 2      ; data in
  50. EE_DO           = 1 shl 3      ; data out
  51. EE_MASK         = EE_SK + EE_CS + EE_DI + EE_DO
  52.  
  53. ; opcodes, first bit is start bit and must be 1
  54. EE_READ         = 110b
  55. EE_WRITE        = 101b
  56. EE_ERASE        = 111b
  57.  
  58. ; The SCB accepts the following controls for the Tx and Rx units:
  59.  
  60. CU_START        = 0x0010
  61. CU_RESUME       = 0x0020
  62. CU_STATSADDR    = 0x0040
  63. CU_SHOWSTATS    = 0x0050        ; Dump statistics counters.
  64. CU_CMD_BASE     = 0x0060        ; Base address to add CU commands.
  65. CU_DUMPSTATS    = 0x0070        ; Dump then reset stats counters.
  66.  
  67. RX_START        = 0x0001
  68. RX_RESUME       = 0x0002
  69. RX_ABORT        = 0x0004
  70. RX_ADDR_LOAD    = 0x0006
  71. RX_RESUMENR     = 0x0007
  72. INT_MASK        = 0x0100
  73. DRVR_INT        = 0x0200        ; Driver generated interrupt
  74.  
  75. CmdIASetup      = 0x0001
  76. CmdConfigure    = 0x0002
  77. CmdTx           = 0x0004
  78. CmdTxFlex       = 0x0008
  79. Cmdsuspend      = 0x4000
  80.  
  81. reg_scb_status  = 0
  82. reg_scb_cmd     = 2
  83. reg_scb_ptr     = 4
  84. reg_port        = 8
  85. reg_eeprom      = 14
  86. reg_mdi_ctrl    = 16
  87.  
  88. phy_100a        = 0x000003E0
  89. phy_100c        = 0x035002A8
  90. phy_82555_tx    = 0x015002A8
  91. phy_nsc_tx      = 0x5C002000
  92. phy_82562_et    = 0x033002A8
  93. phy_82562_em    = 0x032002A8
  94. phy_82562_ek    = 0x031002A8
  95. phy_82562_eh    = 0x017002A8
  96. phy_82552_v     = 0xd061004d
  97. phy_unknown     = 0xFFFFFFFF
  98.  
  99. mac_82557_D100_A        = 0
  100. mac_82557_D100_B        = 1    
  101. mac_82557_D100_C        = 2    
  102. mac_82558_D101_A4       = 4    
  103. mac_82558_D101_B0       = 5    
  104. mac_82559_D101M         = 8    
  105. mac_82559_D101S         = 9    
  106. mac_82550_D102          = 12    
  107. mac_82550_D102_C        = 13    
  108. mac_82551_E             = 14    
  109. mac_82551_F             = 15    
  110. mac_82551_10            = 16    
  111. mac_unknown             = 0xFF
  112.  
  113. struct  rxfd
  114.  
  115.         status          dw ?
  116.         command         dw ?
  117.         link            dd ?
  118.         rx_buf_addr     dd ?
  119.         count           dw ?
  120.         size            dw ?
  121.         packet          rb 1500
  122.  
  123. ends
  124.  
  125. struc   txfd {
  126.  
  127.         .status         dw ?
  128.         .command        dw ?
  129.         .link           dd ?
  130.         .desc_addr      dd ?
  131.         .count          dd ?
  132.  
  133.         .buf_addr0      dd ?
  134.         .buf_size0      dd ?
  135.  
  136. }
  137.  
  138. struc   confcmd {
  139.  
  140.         .status         dw ?
  141.         .command        dw ?
  142.         .link           dd ?
  143.         .data           rb 64
  144.  
  145. }
  146.  
  147. struc   lstats {
  148.  
  149.         .tx_good_frames         dd ?
  150.         .tx_coll16_errs         dd ?
  151.         .tx_late_colls          dd ?
  152.         .tx_underruns           dd ?
  153.         .tx_lost_carrier        dd ?
  154.         .tx_deferred            dd ?
  155.         .tx_one_colls           dd ?
  156.         .tx_multi_colls         dd ?
  157.         .tx_total_colls         dd ?
  158.  
  159.         .rx_good_frames         dd ?
  160.         .rx_crc_errs            dd ?
  161.         .rx_align_errs          dd ?
  162.         .rx_resource_errs       dd ?
  163.         .rx_overrun_errs        dd ?
  164.         .rx_colls_errs          dd ?
  165.         .rx_runt_errs           dd ?
  166.  
  167. }
  168.  
  169. struct  device          ETH_DEVICE
  170.  
  171.         io_addr         dd ?
  172.         pci_bus         dd ?
  173.         pci_dev         dd ?
  174.         rx_desc         dd ?
  175.         last_tx_buffer  dd ?
  176.         ee_bus_width    db ?
  177.         irq_line        db ?
  178.  
  179.         rb 0x100 - ($ and 0xff) ; align 256
  180.         txfd            txfd
  181.  
  182.         rb 0x100 - ($ and 0xff) ; align 256
  183.         confcmd         confcmd
  184.  
  185.         rb 0x100 - ($ and 0xff) ; align 256
  186.         lstats          lstats
  187.  
  188. ends
  189.  
  190. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  191. ;;                        ;;
  192. ;; proc START             ;;
  193. ;;                        ;;
  194. ;; (standard driver proc) ;;
  195. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  196.  
  197. proc START c, state:dword
  198.  
  199.         cmp [state], 1
  200.         jne .exit
  201.  
  202.   .entry:
  203.  
  204.         DEBUGF 1,"Loading driver\n"
  205.         invoke  RegService, my_service, service_proc
  206.         ret
  207.  
  208.   .fail:
  209.   .exit:
  210.         xor eax, eax
  211.         ret
  212.  
  213. endp
  214.  
  215.  
  216. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  217. ;;                        ;;
  218. ;; proc SERVICE_PROC      ;;
  219. ;;                        ;;
  220. ;; (standard driver proc) ;;
  221. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  222.  
  223. align 4
  224. proc service_proc stdcall, ioctl:dword
  225.  
  226.         mov     edx, [ioctl]
  227.         mov     eax, [edx + IOCTL.io_code]
  228.  
  229. ;------------------------------------------------------
  230.  
  231.         cmp     eax, 0 ;SRV_GETVERSION
  232.         jne     @F
  233.  
  234.         cmp     [edx + IOCTL.out_size], 4
  235.         jb      .fail
  236.         mov     eax, [edx + IOCTL.output]
  237.         mov     [eax], dword API_VERSION
  238.  
  239.         xor     eax, eax
  240.         ret
  241.  
  242. ;------------------------------------------------------
  243.   @@:
  244.         cmp     eax, 1 ;SRV_HOOK
  245.         jne     .fail
  246.  
  247.         cmp     [edx + IOCTL.inp_size], 3               ; Data input must be at least 3 bytes
  248.         jb      .fail
  249.  
  250.         mov     eax, [edx + IOCTL.input]
  251.         cmp     byte [eax], 1                           ; 1 means device number and bus number (pci) are given
  252.         jne     .fail                                   ; other types arent supported for this card yet
  253.  
  254. ; check if the device is already listed
  255.  
  256.         mov     esi, device_list
  257.         mov     ecx, [devices]
  258.         test    ecx, ecx
  259.         jz      .firstdevice
  260.  
  261. ;        mov     eax, [edx + IOCTL.input]                ; get the pci bus and device numbers
  262.         mov     ax , [eax+1]                            ;
  263.   .nextdevice:
  264.         mov     ebx, [esi]
  265.         cmp     al, byte[ebx + device.pci_bus]
  266.         jne     @f
  267.         cmp     ah, byte[ebx + device.pci_dev]
  268.         je      .find_devicenum                         ; Device is already loaded, let's find it's device number
  269.        @@:
  270.         add     esi, 4
  271.         loop    .nextdevice
  272.  
  273.  
  274. ; This device doesnt have its own eth_device structure yet, lets create one
  275.   .firstdevice:
  276.         cmp     [devices], MAX_DEVICES                  ; First check if the driver can handle one more card
  277.         jae     .fail
  278.  
  279.         allocate_and_clear ebx, sizeof.device, .fail      ; Allocate the buffer for device structure
  280.  
  281. ; Fill in the direct call addresses into the struct
  282.  
  283.         mov     [ebx + device.reset], reset
  284.         mov     [ebx + device.transmit], transmit
  285.         mov     [ebx + device.unload], unload
  286.         mov     [ebx + device.name], my_service
  287.  
  288. ; save the pci bus and device numbers
  289.  
  290.         mov     eax, [edx + IOCTL.input]
  291.         movzx   ecx, byte[eax+1]
  292.         mov     [ebx + device.pci_bus], ecx
  293.         movzx   ecx, byte[eax+2]
  294.         mov     [ebx + device.pci_dev], ecx
  295.  
  296. ; Now, it's time to find the base io addres of the PCI device
  297.  
  298.         stdcall PCI_find_io, [ebx + device.pci_bus], [ebx + device.pci_dev]
  299.         mov     [ebx + device.io_addr], eax
  300.  
  301. ; We've found the io address, find IRQ now
  302.  
  303.         invoke  PciRead8, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.interrupt_line
  304.         mov     [ebx + device.irq_line], al
  305.  
  306.         DEBUGF  1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\
  307.         [ebx + device.pci_dev]:1,[ebx + device.pci_bus]:1,[ebx + device.irq_line]:1,[ebx + device.io_addr]:4
  308.  
  309. ; Ok, the eth_device structure is ready, let's probe the device
  310.  
  311.         pushf
  312.         cli                     ; disable ints untilm initialisation is done
  313.  
  314.         call    probe                                                   ; this function will output in eax
  315.         test    eax, eax
  316.         jnz     .err                                                    ; If an error occured, exit
  317.  
  318.         mov     eax, [devices]                                          ; Add the device structure to our device list
  319.         mov     [device_list+4*eax], ebx                                ; (IRQ handler uses this list to find device)
  320.         inc     [devices]                                               ;
  321.  
  322.         popf
  323.  
  324.         mov     [ebx + device.type], NET_TYPE_ETH
  325.         invoke  NetRegDev
  326.  
  327.         cmp     eax, -1
  328.         je      .err
  329.  
  330.         ret
  331.  
  332. ; If the device was already loaded, find the device number and return it in eax
  333.  
  334.   .find_devicenum:
  335.         DEBUGF  2,"Trying to find device number of already registered device\n"
  336.         invoke  NetPtrToNum                                             ; This kernel procedure converts a pointer to device struct in ebx
  337.                                                                         ; into a device number in edi
  338.         mov     eax, edi                                                ; Application wants it in eax instead
  339.         DEBUGF  2,"Kernel says: %u\n", eax
  340.         ret
  341.  
  342. ; If an error occured, remove all allocated data and exit (returning -1 in eax)
  343.  
  344.   .err:
  345.         invoke  KernelFree, ebx
  346.  
  347.   .fail:
  348.         or      eax, -1
  349.         ret
  350.  
  351. ;------------------------------------------------------
  352. endp
  353.  
  354.  
  355.  
  356.  
  357.  
  358. ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
  359. ;;                                                                        ;;
  360. ;;        Actual Hardware dependent code starts here                      ;;
  361. ;;                                                                        ;;
  362. ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
  363.  
  364.  
  365. unload:
  366.         ; TODO: (in this particular order)
  367.         ;
  368.         ; - Stop the device
  369.         ; - Detach int handler
  370.         ; - Remove device from local list (device_list)
  371.         ; - call unregister function in kernel
  372.         ; - Remove all allocated structures and buffers the card used
  373.  
  374.         or      eax,-1
  375.  
  376. ret
  377.  
  378.  
  379. ;-------------
  380. ;
  381. ; Probe
  382. ;
  383. ;-------------
  384.  
  385. align 4
  386. probe:
  387.  
  388.         DEBUGF  1,"Probing\n"
  389.  
  390. ; Make the device a bus master
  391.         invoke  PciRead32, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.command
  392.         or      al, PCI_CMD_MASTER
  393.         invoke  PciWrite32, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.command, eax
  394.  
  395. ;---------------------------
  396. ; First, identify the device
  397.  
  398.         invoke  PciRead32, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header.vendor_id ; get device/vendor id
  399.  
  400.         DEBUGF  1,"Vendor_id=0x%x\n", ax
  401.  
  402.         cmp     ax, 0x8086
  403.         jne     .notfound
  404.         shr     eax, 16
  405.  
  406.         DEBUGF  1,"Device_id=0x%x\n", ax
  407.  
  408.         mov     ecx, DEVICE_IDs
  409.         mov     edi, device_id_list
  410.         repne   scasw
  411.         jne     .notfound
  412.         jmp     .found
  413.  
  414.   .notfound:
  415.         DEBUGF  2,"Unsupported device!\n"
  416.         or      eax, -1
  417.         ret
  418.  
  419.   .found:
  420.  
  421.         call    ee_get_width
  422.         call    MAC_read_eeprom
  423.  
  424.         ;;; TODO: detect phy
  425.  
  426.  
  427.  
  428. ;----------
  429. ;
  430. ;  Reset
  431. ;
  432. ;----------
  433.  
  434. align 4
  435. reset:
  436.  
  437.         movzx   eax, [ebx + device.irq_line]
  438.         DEBUGF  1,"Attaching int handler to irq %x\n", eax:1
  439.         invoke  AttachIntHandler, eax, int_handler, ebx
  440.         test    eax, eax
  441.         jnz     @f
  442.         DEBUGF  2,"Could not attach int handler!\n"
  443.         or      eax, -1
  444.         ret
  445.   @@:
  446.  
  447.         DEBUGF  1,"Resetting\n"
  448.  
  449. ;---------------
  450. ; reset the card
  451.  
  452.         set_io  [ebx + device.io_addr], 0
  453.         set_io  [ebx + device.io_addr], reg_port
  454.         xor     eax, eax        ; Software Reset
  455.         out     dx, eax
  456.  
  457.         mov     esi, 10
  458.         invoke  Sleep           ; Give the card time to warm up.
  459.  
  460. ;---------------------------------
  461. ; Tell device where to store stats
  462.  
  463.         lea     eax, [ebx + device.lstats.tx_good_frames]      ; lstats
  464.         invoke  GetPhysAddr
  465.         set_io  [ebx + device.io_addr], 0
  466.         set_io  [ebx + device.io_addr], reg_scb_ptr
  467.         out     dx, eax
  468.  
  469.         mov     ax, INT_MASK + CU_STATSADDR
  470.         set_io  [ebx + device.io_addr], reg_scb_cmd
  471.         out     dx, ax
  472.         call    cmd_wait
  473.  
  474. ;-----------------
  475. ; setup RX
  476.  
  477.         set_io  [ebx + device.io_addr], reg_scb_ptr
  478.         xor     eax, eax
  479.         out     dx, eax
  480.  
  481.         set_io  [ebx + device.io_addr], reg_scb_cmd
  482.         mov     ax, INT_MASK + RX_ADDR_LOAD
  483.         out     dx, ax
  484.         call    cmd_wait
  485.  
  486. ;-----------------------------
  487. ; Create RX and TX descriptors
  488.  
  489.         call    create_ring
  490.  
  491. ; RX start
  492.  
  493.         set_io  [ebx + device.io_addr], 0
  494.         set_io  [ebx + device.io_addr], reg_scb_ptr
  495.         mov     eax, [ebx + device.rx_desc]
  496.         invoke  GetPhysAddr
  497.         out     dx, eax
  498.  
  499.         mov     ax, INT_MASK + RX_START
  500.         set_io  [ebx + device.io_addr], reg_scb_cmd
  501.         out     dx, ax
  502.         call    cmd_wait
  503.  
  504. ; Set-up TX
  505.  
  506.         set_io  [ebx + device.io_addr], reg_scb_ptr
  507.         xor     eax, eax
  508.         out     dx, eax
  509.  
  510.         set_io  [ebx + device.io_addr], reg_scb_cmd
  511.         mov     ax, INT_MASK + CU_CMD_BASE
  512.         out     dx, ax
  513.         call    cmd_wait
  514.  
  515. ;  --------------------
  516.  
  517.         mov     [ebx + device.confcmd.command], CmdConfigure + Cmdsuspend
  518.         mov     [ebx + device.confcmd.status], 0
  519.         lea     eax, [ebx + device.txfd.status]
  520.         invoke  GetPhysAddr
  521.         mov     [ebx + device.confcmd.link], eax
  522.  
  523.         mov     esi, confcmd_data
  524.         lea     edi, [ebx + device.confcmd.data]
  525.         mov     ecx, 22
  526.         rep     movsb
  527.  
  528.         mov     byte[ebx + device.confcmd.data + 1], 0x88  ; fifo of 8 each
  529.         mov     byte[ebx + device.confcmd.data + 4], 0
  530.         mov     byte[ebx + device.confcmd.data + 5], 0x80
  531.         mov     byte[ebx + device.confcmd.data + 15], 0x48
  532.         mov     byte[ebx + device.confcmd.data + 19], 0x80
  533.         mov     byte[ebx + device.confcmd.data + 21], 0x05
  534.  
  535.         mov     [ebx + device.txfd.command], CmdIASetup
  536.         mov     [ebx + device.txfd.status], 0
  537.         lea     eax, [ebx + device.confcmd.status]
  538.         invoke  GetPhysAddr
  539.         mov     [ebx + device.txfd.link], eax
  540.  
  541. ;;; copy in our MAC
  542.  
  543.         lea     edi, [ebx + device.txfd.desc_addr]
  544.         lea     esi, [ebx + device.mac]
  545.         movsd
  546.         movsw
  547.  
  548.         set_io  [ebx + device.io_addr], reg_scb_ptr
  549.         lea     eax, [ebx + device.txfd.status]
  550.         invoke  GetPhysAddr
  551.         out     dx, eax
  552.  
  553. ; Start CU & enable ints
  554.  
  555.         set_io  [ebx + device.io_addr], reg_scb_cmd
  556.         mov     ax, CU_START
  557.         out     dx, ax
  558.         call    cmd_wait
  559.  
  560. ;-----------------------
  561. ; build txfd structure (again!)
  562.  
  563.         lea     eax, [ebx + device.txfd.status]
  564.         invoke  GetPhysAddr
  565.         mov     [ebx + device.txfd.link], eax
  566.         mov     [ebx + device.txfd.count], 0x02208000
  567.         lea     eax, [ebx + device.txfd.buf_addr0]
  568.         invoke  GetPhysAddr
  569.         mov     [ebx + device.txfd.desc_addr], eax
  570.  
  571. ; Indicate that we have successfully reset the card
  572.  
  573.         DEBUGF  1,"Reset complete\n"
  574.  
  575.         mov     [ebx + device.mtu], 1514
  576.  
  577. ; Set link state to unknown
  578.         mov     [ebx + device.state], ETH_LINK_UNKNOWN
  579.  
  580.         xor     eax, eax        ; indicate that we have successfully reset the card
  581.         ret
  582.  
  583.  
  584. align 4
  585. create_ring:
  586.  
  587.         DEBUGF  1,"Creating ring\n"
  588.  
  589. ;---------------------
  590. ; build rxfd structure
  591.  
  592.         invoke  KernelAlloc, 2000
  593.         mov     [ebx + device.rx_desc], eax
  594.         mov     esi, eax
  595.         invoke  GetPhysAddr
  596.         mov     [esi + rxfd.status], 0x0000
  597.         mov     [esi + rxfd.command], 0x0000
  598.         mov     [esi + rxfd.link], eax
  599.         mov     [esi + rxfd.count], 0
  600.         mov     [esi + rxfd.size], 1528
  601.  
  602. ;-----------------------
  603. ; build txfd structure
  604.  
  605.         lea     eax, [ebx + device.txfd.status]
  606.         invoke  GetPhysAddr
  607.         mov     [ebx + device.txfd.link], eax
  608.         mov     [ebx + device.txfd.count], 0x01208000
  609.         lea     eax, [ebx + device.txfd.buf_addr0]
  610.         invoke  GetPhysAddr
  611.         mov     [ebx + device.txfd.desc_addr], eax
  612.  
  613.         ret
  614.  
  615.  
  616.  
  617. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  618. ;;                                         ;;
  619. ;; Transmit                                ;;
  620. ;;                                         ;;
  621. ;; In: pointer to device structure in ebx  ;;
  622. ;;                                         ;;
  623. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  624.  
  625. proc transmit stdcall bufferptr, buffersize
  626.  
  627.         pushf
  628.         cli
  629.  
  630.         DEBUGF  1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [buffersize]
  631.         mov     eax, [bufferptr]
  632.         DEBUGF  1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\
  633.         [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\
  634.         [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\
  635.         [eax+13]:2,[eax+12]:2
  636.  
  637.         cmp     [buffersize], 1514
  638.         ja      .fail
  639.         cmp     [buffersize], 60
  640.         jb      .fail
  641.  
  642.         ;;; TODO: check if current descriptor is in use
  643.         ; fill in buffer address and size
  644.         mov     [ebx + device.last_tx_buffer], eax
  645.         invoke  GetPhysAddr
  646.         mov     [ebx + device.txfd.buf_addr0], eax
  647.         mov     ecx, [buffersize]
  648.         mov     [ebx + device.txfd.buf_size0], ecx
  649.  
  650.         mov     [ebx + device.txfd.status], 0
  651.         mov     [ebx + device.txfd.command], Cmdsuspend + CmdTx + CmdTxFlex + 1 shl 15 ;;; EL bit
  652.  ;       mov     [txfd.count], 0x02208000   ;;;;;;;;;;;
  653.  
  654.         ; Inform device of the new/updated transmit descriptor
  655.         lea     eax, [ebx + device.txfd.status]
  656.         invoke  GetPhysAddr
  657.         set_io  [ebx + device.io_addr], 0
  658.         set_io  [ebx + device.io_addr], reg_scb_ptr
  659.         out     dx, eax
  660.  
  661.         ; Start the transmit
  662.         mov     ax, CU_START
  663.         set_io  [ebx + device.io_addr], reg_scb_cmd
  664.         out     dx, ax
  665.         call    cmd_wait
  666.  
  667. ; Update stats
  668.         inc     [ebx + device.packets_tx]
  669.         mov     ecx, [buffersize]
  670.         add     dword[ebx + device.bytes_tx], ecx
  671.         adc     dword[ebx + device.bytes_tx + 4], 0
  672.  
  673.         DEBUGF  1,"Transmit OK\n"
  674.         popf
  675.         xor     eax, eax
  676.         ret
  677.  
  678.   .fail:
  679.         invoke  KernelFree, [bufferptr]
  680.         popf
  681.         or      eax, -1
  682.         ret
  683.  
  684. endp
  685.  
  686.  
  687. ;;;;;;;;;;;;;;;;;;;;;;;
  688. ;;                   ;;
  689. ;; Interrupt handler ;;
  690. ;;                   ;;
  691. ;;;;;;;;;;;;;;;;;;;;;;;
  692.  
  693. align 4
  694. int_handler:
  695.  
  696.         push    ebx esi edi
  697.  
  698.         DEBUGF  1,"INT\n"
  699.  
  700. ; find pointer of device wich made IRQ occur
  701.  
  702.         mov     ecx, [devices]
  703.         test    ecx, ecx
  704.         jz      .nothing
  705.         mov     esi, device_list
  706.   .nextdevice:
  707.         mov     ebx, [esi]
  708.  
  709. ;        set_io  [ebx + device.io_addr], 0              ; reg_scb_status = 0
  710.         set_io  [ebx + device.io_addr], reg_scb_status
  711.         in      ax, dx
  712.         out     dx, ax                              ; send it back to ACK
  713.         test    ax, ax
  714.         jnz     .got_it
  715.   .continue:
  716.         add     esi, 4
  717.         dec     ecx
  718.         jnz     .nextdevice
  719.   .nothing:
  720.         pop     edi esi ebx
  721.         xor     eax, eax
  722.  
  723.         ret                                         ; If no device was found, abort (The irq was probably for a device, not registered to this driver)
  724.  
  725.   .got_it:
  726.  
  727.         DEBUGF  1,"Device: %x Status: %x\n", ebx, ax
  728.  
  729.         test    ax, 1 shl 14    ; did we receive a frame?
  730.         jz      .no_rx
  731.  
  732.         push    ax
  733.  
  734.         DEBUGF  1,"Receiving\n"
  735.  
  736.         push    ebx
  737.   .rx_loop:
  738.         pop     ebx
  739.  
  740.         mov     esi, [ebx + device.rx_desc]
  741.         cmp     [esi + rxfd.status], 0        ; we could also check bits C and OK (bit 15 and 13)
  742.         je      .nodata
  743.  
  744.         DEBUGF  1,"rxfd status=0x%x\n", [esi + rxfd.status]:4
  745.  
  746.         movzx   ecx, [esi + rxfd.count]
  747.         and     ecx, 0x3fff
  748.  
  749.         push    ebx
  750.         push    .rx_loop
  751.         push    ecx
  752.         add     esi, rxfd.packet
  753.         push    esi
  754.  
  755. ; Update stats
  756.         add     dword [ebx + device.bytes_rx], ecx
  757.         adc     dword [ebx + device.bytes_rx + 4], 0
  758.         inc     dword [ebx + device.packets_rx]
  759.  
  760. ; allocate new descriptor
  761.  
  762.         invoke  KernelAlloc, 2000
  763.         mov     [ebx + device.rx_desc], eax
  764.         mov     esi, eax
  765.         invoke  GetPhysAddr
  766.         mov     [esi + rxfd.status], 0x0000
  767.         mov     [esi + rxfd.command], 0xc000    ; End of list + Suspend
  768.         mov     [esi + rxfd.link], eax
  769.         mov     [esi + rxfd.count], 0
  770.         mov     [esi + rxfd.size], 1528
  771.  
  772. ; restart RX
  773.  
  774.         set_io  [ebx + device.io_addr], 0
  775.         set_io  [ebx + device.io_addr], reg_scb_ptr
  776. ;        lea     eax, [ebx + device.rx_desc]
  777. ;        invoke  GetPhysAddr
  778.         out     dx, eax
  779.  
  780.         set_io  [ebx + device.io_addr], reg_scb_cmd
  781.         mov     ax, RX_START
  782.         out     dx, ax
  783.         call    cmd_wait
  784.  
  785. ; And give packet to kernel
  786.         jmp     [Eth_input]
  787.  
  788.   .nodata:
  789.         DEBUGF  1, "no more data\n"
  790.         pop     ax
  791.  
  792.   .no_rx:
  793.  
  794. ; Cleanup after TX
  795.         cmp     [ebx + device.txfd.status], 0
  796.         je      .done
  797.         cmp     [ebx + device.last_tx_buffer], 0
  798.         je      .done
  799.         push    ax
  800.         DEBUGF  1, "Removing packet 0x%x from RAM!\n", [ebx + device.last_tx_buffer]
  801.         invoke  KernelFree, [ebx + device.last_tx_buffer]
  802.         mov     [ebx + device.last_tx_buffer], 0
  803.         pop     ax
  804.  
  805.   .done:
  806.         and     ax, 00111100b
  807.         cmp     ax, 00001000b
  808.         jne     .fail
  809.  
  810.         DEBUGF  1, "out of resources!\n"
  811. ; Restart the RX
  812.  
  813. ; allocate new descriptor
  814.  
  815.         invoke  KernelAlloc, 2000
  816.         mov     [ebx + device.rx_desc], eax
  817.         mov     esi, eax
  818.         invoke  GetPhysAddr
  819.         mov     [esi + rxfd.status], 0x0000
  820.         mov     [esi + rxfd.command], 0xc000    ; End of list + Suspend
  821.         mov     [esi + rxfd.link], eax
  822.         mov     [esi + rxfd.count], 0
  823.         mov     [esi + rxfd.size], 1528
  824.  
  825. ; restart RX
  826.  
  827.         set_io  [ebx + device.io_addr], 0
  828.         set_io  [ebx + device.io_addr], reg_scb_ptr
  829. ;        lea     eax, [ebx + device.rx_desc]
  830. ;        invoke  GetPhysAddr
  831.         out     dx, eax
  832.  
  833.         set_io  [ebx + device.io_addr], reg_scb_cmd
  834.         mov     ax, RX_START
  835.         out     dx, ax
  836.         call    cmd_wait
  837.  
  838.   .fail:
  839.         pop     edi esi ebx
  840.         xor     eax, eax
  841.         inc     eax
  842.  
  843.         ret
  844.  
  845.  
  846.  
  847.  
  848. align 4
  849. cmd_wait:
  850.  
  851.         in      al, dx
  852.         test    al, al
  853.         jnz     cmd_wait
  854.  
  855.         ret
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862. align 4
  863. ee_read:        ; esi = address to read
  864.  
  865.         DEBUGF  1,"Eeprom read from 0x%x\n", esi
  866.  
  867.         set_io  [ebx + device.io_addr], 0
  868.         set_io  [ebx + device.io_addr], reg_eeprom
  869.  
  870. ;-----------------------------------------------------
  871. ; Prepend start bit + read opcode to the address field
  872. ; and shift it to the very left bits of esi
  873.  
  874.         mov     cl, 29
  875.         sub     cl, [ebx + device.ee_bus_width]
  876.         shl     esi, cl
  877.         or      esi, EE_READ shl 29
  878.  
  879.         movzx   ecx, [ebx + device.ee_bus_width]
  880.         add     ecx, 3
  881.  
  882.         mov     al, EE_CS
  883.         out     dx, al
  884.         call    udelay
  885.  
  886. ;-----------------------
  887. ; Write this to the chip
  888.  
  889.   .loop:
  890.         mov     al, EE_CS + EE_SK
  891.         shl     esi, 1
  892.         jnc     @f
  893.         or      al, EE_DI
  894.        @@:
  895.         out     dx, al
  896.         call    udelay
  897.  
  898.         and     al, not EE_SK
  899.         out     dx, al
  900.         call    udelay
  901.  
  902.         loop    .loop
  903.  
  904. ;------------------------------
  905. ; Now read the data from eeprom
  906.  
  907.         xor     esi, esi
  908.         mov     ecx, 16
  909.  
  910.   .loop2:
  911.         shl     esi, 1
  912.         mov     al, EE_CS + EE_SK
  913.         out     dx, al
  914.         call    udelay
  915.  
  916.         in      al, dx
  917.         test    al, EE_DO
  918.         jz      @f
  919.         inc     esi
  920.        @@:
  921.  
  922.         mov     al, EE_CS
  923.         out     dx, al
  924.         call    udelay
  925.  
  926.         loop    .loop2
  927.  
  928. ;-----------------------
  929. ; de-activate the eeprom
  930.  
  931.         xor     ax, ax
  932.         out     dx, ax
  933.  
  934.  
  935.         DEBUGF  1,"0x%x\n", esi:4
  936.         ret
  937.  
  938.  
  939.  
  940. align 4
  941. ee_write:       ; esi = address to write to, di = data
  942.  
  943.         DEBUGF  1,"Eeprom write 0x%x to 0x%x\n", di, esi
  944.  
  945.         set_io  [ebx + device.io_addr], 0
  946.         set_io  [ebx + device.io_addr], reg_eeprom
  947.  
  948. ;-----------------------------------------------------
  949. ; Prepend start bit + write opcode to the address field
  950. ; and shift it to the very left bits of esi
  951.  
  952.         mov     cl, 29
  953.         sub     cl, [ebx + device.ee_bus_width]
  954.         shl     esi, cl
  955.         or      esi, EE_WRITE shl 29
  956.  
  957.         movzx   ecx, [ebx + device.ee_bus_width]
  958.         add     ecx, 3
  959.  
  960.         mov     al, EE_CS       ; enable chip
  961.         out     dx, al
  962.  
  963. ;-----------------------
  964. ; Write this to the chip
  965.  
  966.   .loop:
  967.         mov     al, EE_CS + EE_SK
  968.         shl     esi, 1
  969.         jnc     @f
  970.         or      al, EE_DI
  971.        @@:
  972.         out     dx, al
  973.         call    udelay
  974.  
  975.         and     al, not EE_SK
  976.         out     dx, al
  977.         call    udelay
  978.  
  979.         loop    .loop
  980.  
  981. ;-----------------------------
  982. ; Now write the data to eeprom
  983.  
  984.         mov     ecx, 16
  985.  
  986.   .loop2:
  987.         mov     al, EE_CS + EE_SK
  988.         shl     di, 1
  989.         jnc     @f
  990.         or      al, EE_DI
  991.        @@:
  992.         out     dx, al
  993.         call    udelay
  994.  
  995.         and     al, not EE_SK
  996.         out     dx, al
  997.         call    udelay
  998.  
  999.         loop    .loop2
  1000.  
  1001. ;-----------------------
  1002. ; de-activate the eeprom
  1003.  
  1004.         xor     al, al
  1005.         out     dx, al
  1006.  
  1007.  
  1008.         ret
  1009.  
  1010.  
  1011.  
  1012. align 4
  1013. ee_get_width:
  1014.  
  1015.         set_io  [ebx + device.io_addr], 0
  1016.         set_io  [ebx + device.io_addr], reg_eeprom
  1017.  
  1018.         mov     al, EE_CS      ; activate eeprom
  1019.         out     dx, al
  1020.         call    udelay
  1021.  
  1022.         mov     si, EE_READ shl 13
  1023.         xor     ecx, ecx
  1024.   .loop:
  1025.         mov     al, EE_CS + EE_SK
  1026.         shl     si, 1
  1027.         jnc     @f
  1028.         or      al, EE_DI
  1029.        @@:
  1030.         out     dx, al
  1031.         call    udelay
  1032.  
  1033.         and     al, not EE_SK
  1034.         out     dx, al
  1035.         call    udelay
  1036.  
  1037.         inc     ecx
  1038.  
  1039.         cmp     ecx, 15
  1040.         jae     .give_up
  1041.  
  1042.         in      al, dx
  1043.         test    al, EE_DO
  1044.         jnz     .loop
  1045.  
  1046.         xor     al, al
  1047.         out     dx, al          ; de-activate eeprom
  1048.  
  1049.         sub     cl, 3           ; dont count the opcode bits
  1050.         mov     [ebx + device.ee_bus_width], cl
  1051.         DEBUGF  1, "Eeprom width=%u bit\n", ecx
  1052.  
  1053.         ret
  1054.  
  1055.   .give_up:
  1056.         DEBUGF  2, "Eeprom not found!\n"
  1057.  
  1058.         xor     al, al
  1059.         out     dx, al          ; de-activate eeprom
  1060.  
  1061.         ret
  1062.  
  1063.  
  1064. ; Wait a minimum of 2µs
  1065. udelay:
  1066.         pusha
  1067.         mov     esi, 1
  1068.         invoke  Sleep
  1069.         popa
  1070.  
  1071.         ret
  1072.  
  1073.  
  1074.  
  1075. ; cx = phy addr
  1076. ; dx = phy reg addr
  1077.  
  1078. ; ax = data
  1079.  
  1080. align 4
  1081. mdio_read:
  1082.  
  1083.         DEBUGF  1,"MDIO read\n"
  1084.  
  1085.         shl     ecx, 21                 ; PHY addr
  1086.         shl     edx, 16                 ; PHY reg addr
  1087.  
  1088.         mov     eax, ecx
  1089.         or      eax, edx
  1090.         or      eax, 10b shl 26         ; read opcode
  1091.  
  1092.         set_io  [ebx + device.io_addr], 0
  1093.         set_io  [ebx + device.io_addr], reg_mdi_ctrl
  1094.         out     dx, eax
  1095.  
  1096.   .wait:
  1097.         call    udelay
  1098.         in      eax, dx
  1099.         test    eax, 1 shl 28           ; ready bit
  1100.         jz      .wait
  1101.  
  1102.         ret
  1103.  
  1104. ; ax = data
  1105. ; cx = phy addr
  1106. ; dx = phy reg addr
  1107.  
  1108. ; ax = data
  1109.  
  1110. align 4
  1111. mdio_write:
  1112.  
  1113.         DEBUGF  1,"MDIO write\n"
  1114.  
  1115.         and     eax, 0xffff
  1116.  
  1117.         shl     ecx, 21                 ; PHY addr
  1118.         shl     edx, 16                 ; PHY reg addr
  1119.  
  1120.         or      eax, ecx
  1121.         or      eax, edx
  1122.         or      eax, 01b shl 26         ; write opcode
  1123.  
  1124.         set_io  [ebx + device.io_addr], 0
  1125.         set_io  [ebx + device.io_addr], reg_mdi_ctrl
  1126.         out     dx, eax
  1127.  
  1128.   .wait:
  1129.         call    udelay
  1130.         in      eax, dx
  1131.         test    eax, 1 shl 28           ; ready bit
  1132.         jz      .wait
  1133.  
  1134.         ret
  1135.  
  1136. read_mac:
  1137.  
  1138.         ret
  1139.  
  1140.  
  1141.  
  1142. align 4
  1143. MAC_read_eeprom:
  1144.  
  1145.         mov     esi, 0
  1146.         call    ee_read
  1147.         mov     word[ebx + device.mac], si
  1148.  
  1149.         mov     esi, 1
  1150.         call    ee_read
  1151.         mov     word[ebx + device.mac+2], si
  1152.  
  1153.         mov     esi, 2
  1154.         call    ee_read
  1155.         mov     word[ebx + device.mac+4], si
  1156.  
  1157.  
  1158.         ret
  1159.  
  1160.  
  1161. align 4
  1162. MAC_write:
  1163.  
  1164. ;;;;
  1165.  
  1166.         ret
  1167.  
  1168.  
  1169.  
  1170.  
  1171. ; End of code
  1172.  
  1173.  
  1174. data fixups
  1175. end data
  1176.  
  1177. include '../peimport.inc'
  1178.  
  1179. my_service      db 'I8255X', 0                    ; max 16 chars include zero
  1180. devicename      db 'Intel Etherexpress pro/100', 0
  1181.  
  1182. confcmd_data    db 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1
  1183.                 db 0, 0x2e, 0, 0x60, 0, 0xf2, 0x48, 0, 0x40, 0xf2
  1184.                 db 0x80, 0x3f, 0x05                                     ; 22 bytes total
  1185.  
  1186.  
  1187. device_id_list:
  1188.  
  1189.         dw 0x1029
  1190.         dw 0x1030
  1191.         dw 0x1031
  1192.         dw 0x1032
  1193.         dw 0x1033
  1194.         dw 0x1034
  1195.         dw 0x1038
  1196.         dw 0x1039
  1197.         dw 0x103A
  1198.         dw 0x103B
  1199.         dw 0x103C
  1200.         dw 0x103D
  1201.         dw 0x103E
  1202.         dw 0x1050
  1203.         dw 0x1051
  1204.         dw 0x1052
  1205.         dw 0x1053
  1206.         dw 0x1054
  1207.         dw 0x1055
  1208.         dw 0x1056
  1209.         dw 0x1057
  1210.         dw 0x1059
  1211.         dw 0x1064
  1212.         dw 0x1065
  1213.         dw 0x1066
  1214.         dw 0x1067
  1215.         dw 0x1068
  1216.         dw 0x1069
  1217.         dw 0x106A
  1218.         dw 0x106B
  1219.         dw 0x1091
  1220.         dw 0x1092
  1221.         dw 0x1093
  1222.         dw 0x1094
  1223.         dw 0x1095
  1224.         dw 0x10fe
  1225.         dw 0x1209
  1226.         dw 0x1229
  1227.         dw 0x2449
  1228.         dw 0x2459
  1229.         dw 0x245D
  1230.         dw 0x27DC
  1231.  
  1232. DEVICE_IDs = ($ - device_id_list) / 2
  1233.  
  1234. include_debug_strings                           ; All data wich FDO uses will be included here
  1235.  
  1236. align 4
  1237. devices         dd 0                              ; number of currently running devices
  1238. device_list     rd MAX_DEVICES                    ; This list contains all pointers to device structures the driver is handling
  1239.  
  1240.