diff --git a/data/eng/autorun.dat b/data/eng/autorun.dat index a53468d052..f24f781be3 100644 --- a/data/eng/autorun.dat +++ b/data/eng/autorun.dat @@ -6,7 +6,8 @@ #/RD/1/CROPFLAT "XS800 YS480" 1 # set limits of screen #/RD/1/COMMOUSE "" 1 # COM mice detector #/RD/1/DEVELOP/BOARD "" 1 # Load DEBUG board -#/RD/1/refrscrn "" 1 # Refresh screen +#/RD/1/refrscrn "" 1 # Refresh screen +/RD/1/NETWORK/NETCFG A 1 # /RD/1/NETWORK/ZEROCONF "" 1 # Network configuration /RD/1/MEDIA/PALITRA "H 007DCEDF 003C427F" 1 #SET BG /RD/1/@PANEL "" 1 # Start panel diff --git a/data/eng/docs/STACK.TXT b/data/eng/docs/STACK.TXT index 9b2f1c7184..645f6ef488 100644 --- a/data/eng/docs/STACK.TXT +++ b/data/eng/docs/STACK.TXT @@ -1,387 +1,203 @@ -What is implemented -=================== +eax = 74 - Work directly with network interface +ebx = -1 (Get number of active network devices) -The following features are present in the TCP/IP stack code: + out: + eax = number of active network devices - IP layer. - ICMP. - TCP layer. - UDP layer. - local loopback. - Realtek 8029 PCI ethernet interface. - Realtek 8139 PCI ethernet interface. - Intel i8255x PCI ethernet interface. - Dynamic ARP table. - PPP dialer - -And the following internet applcations are implemented +bh = device number, for all following functions ! - HTTP Server - Telnet - POP Client - DNS Name resolver - MP3 Server - TFTP Client - IRC Client - -There are also a number of experimental applications for streaming music -and performing interprocess communication via sockets. A Web broswer is in -development +bl = 0 (Get device type) + out: + eax = device type number -What is not implemented -======================= +bl = 1 (Get device name) -The IP layer does not process header options. -The IP layer does not support routing. -Packet fragmentation is not supported. + in: + ecx = pointer to 64 byte buffer + out: + name is copied into the buffer + eax = -1 on error +bl = 2 (Reset the device) -How to configure Kolibri for PPP -=============================== + in + none + out + eax = -1 on error -See ppp.txt +bl = 3 (Stop device) + in + none + out + eax = -1 on error -How to configure Kolibri for Ethernet -==================================== - -First, you need to have a supported ethernet card fitted, or present -on your motherboard. If you are uncertain what type of hardware you -have, try to configue the stack. If you have supported hardware it -will be found, and enabled. +TO BE FIGURED OUT -Setting Up the ARP Table ------------------------- - -Kolibri's ARP table is dynamically created and maintained; You can see what -hosts Kolibri has communicated with by running the ARPSTAT application. +eax = 75 - Work with Sockets -Enabling Ethernet ------------------ +These functions work like the ones found in UNIX (and windows) +for more info, please read http://beej.us/guide/bgnet/ -Boot Kolibri, then select STACKCFG from the NET menu. -Press the 'Read' Button, then select 'Packet Driver'. -Press 'Change' next to the IP address, and enter the IP address you want -to use. Make sure it is on the same sub-net as the LAN to which you are -connected. -Press 'Apply' to action the changes. -Close the program. +bl = 0 (Open Socket) + in: + ecx = domain + edx = type + esi = protocol + out: + eax = socket number, -1 on error -The stack is now running, which you can test by pinging Kolibri from a -remote host. +bl = 1 (Close Socket) + in: + ecx = socket number + out: + eax = -1 on error -The simplest way to connect two PC's together is using a 'Null Modem' -Ethernet cable. These simply cross certain wires over. They can be -purchased from PC stores, but are simple to make. Details can be found -on the web. Look on google for 'ethernet cross over cable' or similar. +bl = 2 (Bind) + in: + ecx = socket number + edx = pointer to sockaddr structure + esi = length of sockaddr structure + out: + eax = -1 on error -How to use TCP/IP locally, with no Network -========================================== +bl = 3 (Listen) -Kolibri supports a form of local loopback that means applications on the -same PC can communicate with each other via sockets as though they -were on separate hosts. To connect to an application on the same machine, -specify the local IP address as the destination address. You do not even -need to configure the stack for ethernet; local loopback will work without -any network hardware. It's great for development and testing. + in: + ecx = socket number + edx = backlog + out: + eax = -1 on error +bl = 4 (connect) -Application Programming Interface -================================= + in: + ecx = socket number + edx = pointer to sockaddr structure + esi = length of sockaddr structure + out: + eax = -1 on error -The developer can access the stack through interrupt 0x40, function 53. -The file TFTPC.ASM gives a good example of how to use the programming -interface ( at least, for UDP), but as network communication is complex -I'll give an overview. +bl = 5 (accept) + in: + ecx = socket number + edx = pointer to sockaddr structure + esi = length of sockaddr structure + out: + eax = socket number, -1 on error -Sockets -======= +bl = 6 (send) -Applications connect to each other and pass information between themselves -through a mechanism called a 'socket'. Sockets are end-points for -communication; You need one at each application to communicate. + in: + ecx = socket number + edx = pointer to buffer + esi = length of buffer + edi = flags + out: + eax = -1 on error -Using sockets is a little like using files on an OS; You open them, read -and write to them, then close them. The only thing that makes life slightly -more complicated is that unlike with a file, you have something intelligent -at the other end ( which for example may not want to close when you do! ) +bl = 7 (receive) -Lets deal with the terminology before we go any further. + in: + ecx = socket number + edx = pointer to buffer + esi = length of buffer + edi = flags + out: + eax = number of bytes copied, -1 on error -socket A unique identifier used by the application for communication. -local port A number that identifies this application on the local host. - Ports are a way to allow multiple applications to communicate - with other hosts without the data becoming mixed up. ( The - technical term is 'multiplex' ). Port numbers are 16 bit. -remote port A number that identifies the application on the remote host - to which we are communicating with. To the remote host, this is - it's 'local port'. Port numbers are 16 bit. -IP Address A 32 bit number that identifies the remote host PC that we are - communicating with. -Passive Refers to the mode by which a socket is opened; When opening in - passive mode, the local PC is awaiting an incoming connection. -Active Refers to the mode by which a socket is opened; When opening in - active mode, the local PC will attempt to connect to a remote - PC. +bl = 8 (set socket options) -When you connect to a socket on a remote PC, you need to specify more than -just the IP address, otherwise the remote stack will not know to which -application it should send your data. You must fully qualify the address, -which means you specify the IP address and the port number. This would be -written like this + in: + ecx = socket number + edx = level + esi = optionname + edi = ptr to buffer -192.168.1.10:80 ; Connect to port 80 on the machine 192.168.1.10 +The buffer's first dword is the length of the buffer, minus the first dword offcourse -Port numbers are important. Some are 'well known' and provide access to -common applications. For example port 80 is used by HTTP servers; That -way I can connect to a webserver on a host without having to find out -what port number the application is listening on. + out: + eax = -1 on error -This brings me to the way in which you open a socket; As I said earlier, -there are two modes, Passive and Active. A webserver would open a passive -socket, as it is waiting for incoming connection requests. A web browser -would open an active socket because it is attempting to connect to a -specified remote host. +bl = 9 (get socket options + in: + ecx = socket number + edx = level + esi = optionname + edi = ptr to buffer -Access to programming interface -=============================== -The developer accesses the stack functions through interrupt 0x40, -function 53. Some functions may be accessed through function 52, but these -are mainly for stack configuration. -Here is a summary of the functions that you may use and the parameter -definitions. +The buffer's first dword is the length of the buffer, minus the first dword offcourse + out: + eax = -1 on error, socket option otherwise -Get Local IP Address --------------------- -eax = 52 -ebx = 1 +TIP -IP address returned in eax ( in internet byte order ) +when you import 'network.inc' and 'macros.inc' into your source code, you can use the following syntax to work with sockets: -Write to stack input queue --------------------------- -eax = 52 -ebx = 6 -edx = number of bytes to write -esi = pointer to data ( in application space ) +for example, to open a socket -On return, eax holds 0 for OK, or 0xFFFFFFFF for error. -This interface is for slow network drivers only ( PPP, SLIP ) +mcall socket, AF_INET, SOCK_DGRAM,0 +mov [socketnum], eax +then to connect to a server -Read data from network output queue ------------------------------------ -eax = 52 -ebx = 8 -esi = pointer to data ( in application space ) +mcall connect, [socketnum], sockaddr, 18 -On return, eax holds number of bytes transferred. -This interface is for slow network drivers only ( PPP, SLIP ) +eax = 76 - Work with protocols -Open a UDP socket ------------------ -eax = 53 -ebx = 0 -ecx = local port -edx = remote port -esi = remote ip address ( in internet byte order ) +high half of ebx = protocol number (for all subfunctions!) +bh = device number (for all subfunctions!) +bl = subfunction number, depends on protocol type -The socket number allocated is returned in eax. -A return value of 0xFFFFFFFF means no socket could be opened. +For Ethernet protocol +0 - Read # Packets send +1 - Read # Packets received +2 - Read # Bytes send +3 - Read # Bytes received +4 - Read MAC +5 - Write MAC +6 - Read IN-QUEUE size +7 - Read OUT-QUEUE size +For IPv4 protocol -Open a TCP socket ------------------ -eax = 53 -ebx = 5 -ecx = local port -edx = remote port -esi = remote ip address ( in internet byte order ) -edi = mode : SOCKET_PASSIVE or SOCKET_ACTIVE ( defined in stack.inc ) +0 - Read # IP packets send +1 - Read # IP packets received +2 - Read IP +3 - Write IP +4 - Read DNS +5 - Write DNS +6 - Read subnet +7 - Write subnet +8 - Read gateway +9 - Write gateway +For ARP protocol -The socket number allocated is returned in eax. -A return value of 0xFFFFFFFF means no socket could be opened. +0 - Read # ARP packets send +1 - Read # ARP packets received +2 - Get # ARP entry's +3 - Read ARP entry +4 - Add static ARP entry +5 - Remove ARP entry (-1 = remove all) +For ICMP protocol +0 - Read # ICMP packets send +1 - Read # ICMP packets received +3 - enable/disable ICMP echo reply +For UDP protocol -Close a socket (UDP Only ) --------------------------- -eax = 53 -ebx = 1 -ecx = socket number +0 - Read # UDP packets send +1 - Read # UDP packets received +For TCP protocol -On return, eax holds 0 for OK, or 0xFFFFFFFF for error. - - -Close a socket (TCP Only ) --------------------------- -eax = 53 -ebx = 8 -ecx = socket number - -On return, eax holds 0 for OK, or 0xFFFFFFFF for error. - - -Poll socket ------------ -eax = 53 -ebx = 2 -ecx = socket number - -On return, eax holds the number of bytes in the receive buffer. - - -Read socket data ----------------- -eax = 53 -ebx = 3 -ecx = socket number - -On return, eax holds the number of bytes remaining, bl holds a data byte. - - -Write to socket ( UDP only ) ----------------------------- -eax = 53 -ebx = 4 -ecx = socket number -edx = number of bytes to write -esi = pointer to data ( in application space ) - -On return, eax holds 0 for OK, or 0xFFFFFFFF for error. - - -Return socket status ( TCP only ) ---------------------------------- -eax = 53 -ebx = 6 -ecx = socket number - -On return, eax holds the sockets TCP status. -This function can be used to determine when a socket has actually connected -to another socket - data cannot be written to a socket until the connection -is established (TCB_ESTABLISHED). The states a socket can be in are defined -in stack.inc as TCB_ - - -Write to socket ( TCP only ) ----------------------------- -eax = 53 -ebx = 7 -ecx = socket number -edx = number of bytes to write -esi = pointer to data ( in application space ) - -On return, eax holds 0 for OK, or 0xFFFFFFFF for error. - - -Check port number ------------------ -eax = 53 -ebx = 9 -ecx = port number - -This function is used to determine if a port number -is in use by any sockets as a local port number. Local -port numbers are normally unique. - -On return, eax is 1 for port number not in use, 0 otherwise. - - -Opening a TCP socket in Kolibri -=============================== - -There are two ways to open a socket - Passive or Active. - -In a Passive connection your application 'listens' for incoming -requests from remote applications. Typically this will be done when -you are implementing a server application that allows any other -application to connect to it. You would specify a 'known' local -port number, such as 80 for a web server. You would leave the -remote IP and remote port number as 0, which indicates any -remote application may connect. - -Once the socket has been opened you would wait for an incoming -connection before doing anything. This can be by either checking -the socket status for TCB_ESTABLISHED, or waiting for data in the -receive buffer. - -In an Active connection, you are making a connection to a specified -remote port. The remote IP and remote port parameters must be filled -in with non-zero values ( otherwise, what are you connecting to? ). -You also specify a unique local port number so the remote application -can uniquely identify you - after all, there may be several applications -on your machine connected to the same remote host. See below for finding -a unique port number. - - -How to find an unused local port number -======================================= - -Typically when you are creating an active connection to a remote -socket you will want to choose a unique local port number. Local -port numbers normally start from 1000; The following code may -be used to obtain an unused port number prior to making the -open socket call. - - mov ecx, 1000 ; local port starting at 1000 - -getlp: - inc ecx - push ecx - mov eax, 53 - mov ebx, 9 - int 0x40 - pop ecx - cmp eax, 0 ; is this local port in use? - jz getlp ; yes - so try next - - ; ecx contains a free local port number - - - -Writing data to a socket -======================== - -There are two functions available depending on whether the socket -was opened for TCP or UDP protocol; The call parameters are the -same however. When the socket is being opened for TCP, use the -status function to poll for a connection - data cannot be written -to a socket until another socket has connected to it, and the -state of the socket is TCB_ESTABLISHED. - -When you write data, the call results in a single IP packet being -created and transmitted. Thus the user application is responsible for -the size of transmitted packets. Keep the packet sizes under 768 bytes. -If you are writing a terminal program like telnet, you may want to send -a packet for each keystroke ( inefficient ) or use a timer to send data -periodically ( say, every second ). - - -Reading data from a socket -========================== - -There is one function to read data from a sockets receive buffer. This -function retrieves one byte at a time. You can use the poll function to -test the receive buffer for data. - - -Closing a socket -================ - -Simply call the appropriate function - there is one for TCP, and another -for UDP. When closing a TCP socket, don't forget that the other end -may continue to send data, so the socket may remain active for a -few seconds after your call. - - -If you have any questions or have suggestions for improving this -document please contact me at mikeh@oceanfree.net. +0 - Read # TCP packets send +1 - Read # TCP packets received \ No newline at end of file diff --git a/data/eng/menu.dat b/data/eng/menu.dat index 73416dd62d..88fbf9cb9e 100644 --- a/data/eng/menu.dat +++ b/data/eng/menu.dat @@ -128,27 +128,19 @@ Hex-Editor /rd/1/develop/heed #15 **** NET **** Servers > /@16 Clients > /@17 -Configuration /rd/1/network/stackcfg -Zero-Config /rd/1/network/zeroconf -Network status /rd/1/network/ethstat -ARP status /rd/1/network/arpstat +Zero-Config /sys/network/zeroconf +network Config /sys/network/netcfg +Network status /sys/network/netstat +ARP status /sys/network/arpcfg #16 **** SERVERS **** -SMTPS /rd/1/network/smtps -HTTPS /rd/1/network/https -FTPS /rd/1/network/ftps +FTP daemon /sys/network/ftpd #17 **** CLIENTS **** -TFTP client /rd/1/network/tftpc -Internet-chess /rd/1/network/chess -Internet downloader /rd/1/network/downloader -Text-based browser /rd/1/htmlv -NNTP-NewsGroups /rd/1/network/nntpc -TELNET /rd/1/network/telnet -POP - MAIL /rd/1/network/popc -IRC client /rd/1/network/airc -YAHOO messenger (demo) /rd/1/network/ym -JMail /rd/1/network/jmail -VNC client /rd/1/network/vncclient -DNS resolver /rd/1/network/nslookup +IRC client /sys/network/ircc +TFTP client /sys/network/tftpc +Ping /sys/network/ping +Telnet client /sys/network/telnet +Synergy client /sys/network/synergyc +DNS lookup /sys/network/nslookup #18 **** OTHER **** Analogue clock /rd/1/demos/aclock Binary clock /rd/1/demos/bcdclk diff --git a/data/eng/network.ini b/data/eng/network.ini new file mode 100644 index 0000000000..e37d2279f0 --- /dev/null +++ b/data/eng/network.ini @@ -0,0 +1,9 @@ +[ipconfig] +; type should be static or zeroconf +; zeroconf means the service first tries to contact a DHCP server +; If dhcp is not available, it switches to link-local +type = zeroconf +ip = 192.168.1.150 +gateway = 192.168.1.1 +dns = 192.168.1.1 +subnet = 255.255.255.0 \ No newline at end of file diff --git a/data/rus/autorun.dat b/data/rus/autorun.dat index a53468d052..c5914a45b8 100644 --- a/data/rus/autorun.dat +++ b/data/rus/autorun.dat @@ -7,6 +7,7 @@ #/RD/1/COMMOUSE "" 1 # COM mice detector #/RD/1/DEVELOP/BOARD "" 1 # Load DEBUG board #/RD/1/refrscrn "" 1 # Refresh screen +/RD/1/NETWORK/NETCFG A 1 # /RD/1/NETWORK/ZEROCONF "" 1 # Network configuration /RD/1/MEDIA/PALITRA "H 007DCEDF 003C427F" 1 #SET BG /RD/1/@PANEL "" 1 # Start panel diff --git a/data/rus/menu.dat b/data/rus/menu.dat index f906cdb39e..6c0177e340 100644 --- a/data/rus/menu.dat +++ b/data/rus/menu.dat @@ -133,27 +133,19 @@ HEX-। #15 **** NET **** ࢥ > /@16 > /@17 -䨣 /rd/1/network/stackcfg -Zero-Config /rd/1/network/zeroconf - /rd/1/network/ethstat - ARP /rd/1/network/arpstat +Zero-Config /sys/network/zeroconf +network Config /sys/network/netcfg +Network status /sys/network/netstat +ARP status /sys/network/arpcfg #16 **** SERVERS **** -SMTPS /rd/1/network/smtps -HTTPS /rd/1/network/https -FTPS /rd/1/network/ftps +FTP daemon /sys/network/ftpd #17 **** CLIENTS **** -TFTP- /rd/1/network/tftpc -୥-嬠 /rd/1/network/chess -୥ 稪 /rd/1/network/downloader -⮢ 㧥 /rd/1/htmlv -NNTP-㯯 ⥩ /rd/1/network/nntpc -TELNET /rd/1/network/telnet -POP- /rd/1/network/popc -IRC- /rd/1/network/airc -YAHOO IM () /rd/1/network/ym -JMail /rd/1/network/jmail -VNC- /rd/1/network/vncclient -DNS resolver /rd/1/network/nslookup +IRC client /sys/network/ircc +TFTP client /sys/network/tftpc +Ping /sys/network/ping +Telnet client /sys/network/telnet +Synergy client /sys/network/synergyc +DNS lookup /sys/network/nslookup #18 **** OTHER **** /rd/1/demos/aclock /rd/1/demos/bcdclk diff --git a/data/rus/network.ini b/data/rus/network.ini new file mode 100644 index 0000000000..e37d2279f0 --- /dev/null +++ b/data/rus/network.ini @@ -0,0 +1,9 @@ +[ipconfig] +; type should be static or zeroconf +; zeroconf means the service first tries to contact a DHCP server +; If dhcp is not available, it switches to link-local +type = zeroconf +ip = 192.168.1.150 +gateway = 192.168.1.1 +dns = 192.168.1.1 +subnet = 255.255.255.0 \ No newline at end of file diff --git a/drivers/ethernet/3c59x.asm b/drivers/ethernet/3c59x.asm new file mode 100644 index 0000000000..16f2e0cd69 --- /dev/null +++ b/drivers/ethernet/3c59x.asm @@ -0,0 +1,2954 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; 3Com network driver for KolibriOS ;; +;; ;; +;; Ported to KolibriOS net-branch by hidnplayr (28/05/10) ;; +;; ;; +;; Thanks to: scrap metal recyclers, whom provide me with ;; +;; loads of hardware ;; +;; diamond: who makes me understand KolibriOS ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; 3C59X.INC ;; +;; ;; +;; Ethernet driver for Menuet OS ;; +;; ;; +;; Driver for 3Com fast etherlink 3c59x and ;; +;; etherlink XL 3c900 and 3c905 cards ;; +;; References: ;; +;; www.3Com.com - data sheets ;; +;; DP83840A.pdf - ethernet physical layer ;; +;; 3c59x.c - linux driver ;; +;; ethernet driver template by Mike Hibbett ;; +;; ;; +;; Credits ;; +;; Mike Hibbett, ;; +;; who kindly supplied me with a 3Com905C-TX-M card ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Copyright (c) 2004, Endre Kozma +;; All rights reserved. +;; +;; Redistribution and use in source and binary forms, with or without +;; modification, are permitted provided that the following conditions are +;; met: +;; +;; 1. Redistributions of source code must retain the above copyright notice, +;; this list of conditions and the following disclaimer. +;; +;; 2. Redistributions in binary form must reproduce the above copyright +;; notice, this list of conditions and the following disclaimer in the +;; documentation and/or other materials provided with the distribution. +;; +;; 3. The name of the author may not be used to endorse or promote products +;; derived from this software without specific prior written permission. +;; +;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +;; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +;; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +;; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +;; +;; History +;; ======= +;; $Log: 3C59X.INC,v $ +;; Revision 1.3 2004/07/11 12:21:12 kozma +;; Support of vortex chips (3c59x) added. +;; Support of 3c920 and 3c982 added. +;; Corrections. +;; +;; Revision 1.2 2004/06/12 19:40:20 kozma +;; Function e3c59x_set_available_media added in order to set +;; the default media in case auto detection finds no valid link. +;; Incorrect mii check removed (3c900 Cyclone works now). +;; Cleanups. +;; +;; Revision 1.1 2004/06/12 18:27:15 kozma +;; Initial revision +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + FORCE_FD = 0 ; forcing full duplex mode makes sense at some cards and link types + PROMISCIOUS = 0 ; enables promiscous mode + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + +struc DPD { ; Download Packet Descriptor + + .next_ptr dd ? + .frame_start_hdr dd ? + .frag_addr dd ? ; for packet data + .frag_len dd ? ; for packet data + .realaddr dd ? + .size = 32 +} + +virtual at 0 + dpd DPD +end virtual + + +struc UPD { ; Upload Packet Descriptor + + .next_ptr dd ? + .pkt_status dd ? + .frag_addr dd ? + .frag_len dd ? ; for packet data + .realaddr dd ? + .size = 32 + +} + +virtual at 0 + upd UPD +end virtual + +; Registers + REG_POWER_MGMT_CTRL = 0x7c + REG_UP_LIST_PTR = 0x38 + REG_UP_PKT_STATUS = 0x30 + REG_TX_FREE_THRESH = 0x2f + REG_DN_LIST_PTR = 0x24 + REG_DMA_CTRL = 0x20 + REG_TX_STATUS = 0x1b + REG_RX_STATUS = 0x18 + REG_TX_DATA = 0x10 + +; Common window registers + REG_INT_STATUS = 0xe + REG_COMMAND = 0xe + +; Register window 7 + REG_MASTER_STATUS = 0xc + REG_POWER_MGMT_EVENT = 0xc + REG_MASTER_LEN = 0x6 + REG_VLAN_ETHER_TYPE = 0x4 + REG_VLAN_MASK = 0x0 + REG_MASTER_ADDRESS = 0x0 + +; Register window 6 + REG_BYTES_XMITTED_OK = 0xc + REG_BYTES_RCVD_OK = 0xa + REG_UPPER_FRAMES_OK = 0x9 + REG_FRAMES_DEFERRED = 0x8 + REG_FRAMES_RCVD_OK = 0x7 + REG_FRAMES_XMITTED_OK = 0x6 + REG_RX_OVERRUNS = 0x5 + REG_LATE_COLLISIONS = 0x4 + REG_SINGLE_COLLISIONS = 0x3 + REG_MULTIPLE_COLLISIONS = 0x2 + REG_SQE_ERRORS = 0x1 + REG_CARRIER_LOST = 0x0 + +; Register window 5 + REG_INDICATION_ENABLE = 0xc + REG_INTERRUPT_ENABLE = 0xa + REG_TX_RECLAIM_THRESH = 0x9 + REG_RX_FILTER = 0x8 + REG_RX_EARLY_THRESH = 0x6 + REG_TX_START_THRESH = 0x0 + +; Register window 4 + REG_UPPER_BYTES_OK = 0xe + REG_BAD_SSD = 0xc + REG_MEDIA_STATUS = 0xa + REG_PHYSICAL_MGMT = 0x8 + REG_NETWORK_DIAGNOSTIC = 0x6 + REG_FIFO_DIAGNOSTIC = 0x4 + REG_VCO_DIAGNOSTIC = 0x2 ; may not supported + +; Bits in register window 4 + BIT_AUTOSELECT = 24 + +; Register window 3 + REG_TX_FREE = 0xc + REG_RX_FREE = 0xa + REG_MEDIA_OPTIONS = 0x8 + REG_MAC_CONTROL = 0x6 + REG_MAX_PKT_SIZE = 0x4 + REG_INTERNAL_CONFIG = 0x0 + +; Register window 2 + REG_RESET_OPTIONS = 0xc + REG_STATION_MASK_HI = 0xa + REG_STATION_MASK_MID = 0x8 + REG_STATION_MASK_LO = 0x6 + REG_STATION_ADDRESS_HI = 0x4 + REG_STATION_ADDRESS_MID = 0x2 + REG_STATION_ADDRESS_LO = 0x0 + +; Register window 1 + REG_TRIGGER_BITS = 0xc + REG_SOS_BITS = 0xa + REG_WAKE_ON_TIMER = 0x8 + REG_SMB_RXBYTES = 0x7 + REG_SMB_DIAG = 0x5 + REG_SMB_ARB = 0x4 + REG_SMB_STATUS = 0x2 + REG_SMB_ADDRESS = 0x1 + REG_SMB_FIFO_DATA = 0x0 + +; Register window 0 + REG_EEPROM_DATA = 0xc + REG_EEPROM_COMMAND = 0xa + REG_BIOS_ROM_DATA = 0x8 + REG_BIOS_ROM_ADDR = 0x4 + +; Physical management bits + BIT_MGMT_DIR = 2 ; drive with the data written in mgmtData + BIT_MGMT_DATA = 1 ; MII management data bit + BIT_MGMT_CLK = 0 ; MII management clock + +; MII commands + MII_CMD_MASK = (1111b shl 10) + MII_CMD_READ = (0110b shl 10) + MII_CMD_WRITE = (0101b shl 10) + +; MII registers + REG_MII_BMCR = 0 ; basic mode control register + REG_MII_BMSR = 1 ; basic mode status register + REG_MII_ANAR = 4 ; auto negotiation advertisement register + REG_MII_ANLPAR = 5 ; auto negotiation link partner ability register + REG_MII_ANER = 6 ; auto negotiation expansion register + +; MII bits + BIT_MII_AUTONEG_COMPLETE = 5 ; auto-negotiation complete + BIT_MII_PREAMBLE_SUPPRESSION = 6 + +; eeprom bits and commands + EEPROM_CMD_READ = 0x80 + EEPROM_BIT_BUSY = 15 + +; eeprom registers + EEPROM_REG_OEM_NODE_ADDR= 0xa + EEPROM_REG_CAPABILITIES = 0x10 + +; Commands for command register + SELECT_REGISTER_WINDOW = (1 shl 11) + + IS_VORTEX = 0x1 + IS_BOOMERANG = 0x2 + IS_CYCLONE = 0x4 + IS_TORNADO = 0x8 + EEPROM_8BIT = 0x10 + HAS_PWR_CTRL = 0x20 + HAS_MII = 0x40 + HAS_NWAY = 0x80 + HAS_CB_FNS = 0x100 + INVERT_MII_PWR = 0x200 + INVERT_LED_PWR = 0x400 + MAX_COLLISION_RESET = 0x800 + EEPROM_OFFSET = 0x1000 + HAS_HWCKSM = 0x2000 + EXTRA_PREAMBLE = 0x4000 + +; Status + IntLatch = 0x0001 + HostError = 0x0002 + TxComplete = 0x0004 + TxAvailable = 0x0008 + RxComplete = 0x0010 + RxEarly = 0x0020 + IntReq = 0x0040 + StatsFull = 0x0080 + DMADone = 0x0100 + DownComplete = 0x0200 + UpComplete = 0x0400 + DMAInProgress = 0x0800 ; 1 shl 11 (DMA controller is still busy) + CmdInProgress = 0x1000 ; 1 shl 12 (EL3_CMD is still busy) + + S_5_INTS = HostError + RxEarly + UpComplete + DownComplete ;+ TxComplete + RxComplete + TxAvailable + +; Commands + TotalReset = 0 shl 11 + SelectWindow = 1 shl 11 + StartCoax = 2 shl 11 + RxDisable = 3 shl 11 + RxEnable = 4 shl 11 + RxReset = 5 shl 11 + UpStall = 6 shl 11 + UpUnstall = (6 shl 11)+1 + DownStall = (6 shl 11)+2 + DownUnstall = (6 shl 11)+3 + RxDiscard = 8 shl 11 + TxEnable = 9 shl 11 + TxDisable = 10 shl 11 + TxReset = 11 shl 11 + FakeIntr = 12 shl 11 + AckIntr = 13 shl 11 + SetIntrEnb = 14 shl 11 + SetStatusEnb = 15 shl 11 + SetRxFilter = 16 shl 11 + SetRxThreshold = 17 shl 11 + SetTxThreshold = 18 shl 11 + SetTxStart = 19 shl 11 + StartDMAUp = 20 shl 11 + StartDMADown = (20 shl 11)+1 + StatsEnable = 21 shl 11 + StatsDisable = 22 shl 11 + StopCoax = 23 shl 11 + SetFilterBit = 25 shl 11 + +; Rx mode bits + RxStation = 1 + RxMulticast = 2 + RxBroadcast = 4 + RxProm = 8 + +; RX/TX buffers sizes + MAX_ETH_PKT_SIZE = 1536 ; max packet size + NUM_RX_DESC = 4 ; a power of 2 number + NUM_TX_DESC = 4 ; a power of 2 number + MAX_ETH_FRAME_SIZE = 1520 ; size of ethernet frame + bytes alignment + +virtual at ebx + + device: + + ETH_DEVICE + + .dpd_buffer rd (dpd.size*NUM_TX_DESC)/4 + .upd_buffer rd (upd.size*NUM_RX_DESC)/4 + .curr_upd dd ? + .prev_dpd dd ? + + .io_addr dd ? + .pci_bus dd ? + .pci_dev dd ? + .irq_line db ? + rb 3 ; alignment + + .prev_tx_frame dd ? + .ver_id db ? + .full_bus_master db ? + .has_hwcksm db ? + .preamble db ? + .dn_list_ptr_cleared db ? + + .size = $ - device + +end virtual + +section '.flat' code readable align 16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 1,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types of this hardware dont exist + +; check if the device is already listed + + mov ecx, [VORTEX_DEVICES] + test ecx, ecx + jz .maybeboomerang + + mov esi, VORTEX_LIST + mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax , [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + + + .maybeboomerang: + mov ecx, [BOOMERANG_DEVICES] + test ecx, ecx + jz .firstdevice + + mov esi, BOOMERANG_LIST + mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax , [eax+1] ; + .nextdevice2: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice2 + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + mov ecx, [BOOMERANG_DEVICES] + add ecx, [VORTEX_DEVICES] + cmp ecx, MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], null_op + mov [device.unload], null_op + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base io addres of the PCI device + PCI_find_io + +; We've found the io address, find IRQ now + PCI_find_irq + + DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 + +; Ok, the eth_device structure is ready, let's probe the device + call probe ; this function will output in eax + test eax, eax + jnz .err ; If an error occured, exit + + + movzx ecx, [device.ver_id] + test word [hw_versions+2+ecx*4], IS_VORTEX + jz .not_vortex + + mov eax, [VORTEX_DEVICES] ; Add the device structure to our device list + mov [VORTEX_LIST+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [VORTEX_DEVICES] ; + + .register: + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + je .destroy + + call start_device + ret + + .not_vortex: + mov eax, [BOOMERANG_DEVICES] ; Add the device structure to our device list + mov [BOOMERANG_LIST+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [BOOMERANG_DEVICES] + + jmp .register + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 1,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 1,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + .err: + stdcall KernelFree, ebx + + + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + + + + +;*************************************************************************** +; Function +; probe +; Description +; Searches for an ethernet card, enables it and clears the rx buffer +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** + +align 4 +probe: + + DEBUGF 1,"Probing 3com card\n" + + PCI_make_bus_master + +; wake up the card + call wake_up + + stdcall PciRead32, [device.pci_bus], [device.pci_dev], 0 ; get device/vendor id + + DEBUGF 1,"Vendor id: 0x%x\n", ax + + cmp ax, 0x10B7 + jne .notfound + shr eax, 16 + + DEBUGF 1,"Vendor ok!, device id: 0x%x\n", ax + +; get chip version + mov ecx, HW_VERSIONS_SIZE/4-1 + .loop: + cmp ax, [hw_versions+ecx*4] + jz .found + loop .loop + .notfound: + DEBUGF 1,"Device id not found in list!\n" + or eax, -1 + ret + .found: + mov esi, [hw_str+ecx*4] + DEBUGF 1,"Hardware type: %s\n", esi + mov [device.name], esi + + mov [device.ver_id], cl + test word [hw_versions+2+ecx*4], HAS_HWCKSM + setnz [device.has_hwcksm] +; set pci latency for vortex cards + test word [hw_versions+2+ecx*4], IS_VORTEX + jz .not_vortex + + mov eax, 11111000b ; 248 = max latency + stdcall PciWrite32, [device.pci_bus], [device.pci_dev], PCI_REG_LATENCY, eax + + .not_vortex: +; set RX/TX functions + mov ax, EEPROM_REG_CAPABILITIES + call read_eeprom + test al, 100000b ; full bus master? + setnz [device.full_bus_master] + jnz .boomerang_func + mov [device.transmit], vortex_transmit + DEBUGF 1,"Device is a vortex type\n" + DEBUGF 1,"I'm sorry but vortex code hasnt been tested yet\n" + DEBUGF 1,"Please contact me on hidnplayr@kolibrios.org\n" + DEBUGF 1,"If you can help me finish it!\n" + or eax, -1 + ret + jmp @f + .boomerang_func: ; full bus master, so use boomerang functions + mov [device.transmit], boomerang_transmit + DEBUGF 1,"Device is a boomerang type\n" + @@: + call read_mac_eeprom + + test byte [device.full_bus_master], 0xff + jz .set_preamble +; switch to register window 2 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+2 + out dx, ax +; activate xcvr by setting some magic bits + set_io REG_RESET_OPTIONS + in ax, dx + and ax, not 0x4010 + movzx ecx, [device.ver_id] + test word [ecx*4+hw_versions+2], INVERT_LED_PWR + jz @f + or al, 0x10 + @@: + test word [ecx*4+hw_versions+2], INVERT_MII_PWR + jz @f + or ah, 0x40 + @@: + out dx, ax + .set_preamble: +; use preamble as default + mov byte [device.preamble], 1 ; enable preamble + + call global_reset + +;-------------------------- +; RESET + +align 4 +reset: + + movzx eax, [device.irq_line] + DEBUGF 1,"Attaching int handler to irq %x\n",eax:1 + + movzx ecx, [device.ver_id] + test word [hw_versions+2+ecx*4], IS_VORTEX + jz .not_vortex + + mov esi, int_vortex + jmp .reg_int + +.not_vortex: + mov esi, int_boomerang + +.reg_int: + stdcall AttachIntHandler, eax, esi, dword 0 + test eax, eax + jnz @f + DEBUGF 1,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW + 0 + out dx, ax + + mov ax, StopCoax + out dx, ax ; stop transceiver + + mov ax, SELECT_REGISTER_WINDOW + 4 + out dx, ax ; disable UTP + + set_io REG_MEDIA_STATUS + mov ax, 0x0 + + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW + 0 + out dx, ax + + set_io REG_FIFO_DIAGNOSTIC + mov ax, 0 + out dx, ax ; disable card + + mov ax, 1 + out dx, ax ; enable card + + call write_mac + + +;<<<<<<<<<<<<<< + + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW + 1 + out dx, ax + + mov ecx, 32 + set_io 0x0b + .loop: + in al, dx + loop .loop + +; Get rid of stray ints + set_io REG_COMMAND + mov ax, AckIntr + 0xff + out dx, ax + + mov ax, SetStatusEnb + S_5_INTS + out dx, ax + + mov ax, SetIntrEnb + S_5_INTS + out dx, ax + + call set_rx_mode + call set_active_port + +;>>>>>>>>>> + + call create_rx_ring + call rx_reset + call tx_reset + +;>>>>>>>>>>>>>>>>>> + + xor eax, eax +; clear packet/byte counters + + lea edi, [device.bytes_tx] + mov ecx, 6 + rep stosd + +; Set the mtu, kernel will be able to send now + mov [device.mtu], 1514 + + ret + + + + + +align 4 +start_device: + DEBUGF 1,"Starting the device\n" + + set_io 0 + set_io REG_COMMAND + mov ax, SetTxThreshold + 60 ;2047 ; recommended by the manual :) + out dx, ax + + call check_tx_status + + set_io 0 + set_io REG_COMMAND +; switch to register window 4 + mov ax, SELECT_REGISTER_WINDOW+4 + out dx, ax + +; wait for linkDetect + set_io REG_MEDIA_STATUS + mov ecx, 20 ; wait for max 2s + .link_detect_loop: + mov esi, 100 + call Sleep ; 100 ms + in ax, dx + test ah, 1000b ; linkDetect + jnz @f + loop .link_detect_loop + DEBUGF 1,"Link detect timed-out!\n" + @@: + +; print link type + xor eax, eax + bsr ax, word [device.state] + jz @f + sub ax, 4 + @@: + + mov esi, [link_str+eax*4] + DEBUGF 1,"Established Link type: %s\n", esi + +; enable interrupts + + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW + 1 + out dx, ax + + mov ax, AckIntr + 0xff + out dx, ax + + mov ax, SetStatusEnb + S_5_INTS + out dx, ax + + mov ax, SetIntrEnb + S_5_INTS + out dx, ax + +; Start RX/TX + + set_io 0 + set_io REG_COMMAND + mov ax, RxEnable + out dx, ax + + mov ax, TxEnable + out dx, ax + + set_io REG_COMMAND + mov ax, SetRxThreshold + 208 + out dx, ax + + mov ax, SetTxThreshold + 60 ;16 ; recommended by the manual :) + out dx, ax + + mov ax, SELECT_REGISTER_WINDOW + 1 + out dx, ax + + ret + + + + + + + +align 4 +set_rx_mode: + + DEBUGF 1,"Setting RX mode\n" + + set_io 0 + set_io REG_COMMAND + +if defined PROMISCIOUS + mov ax, SetRxFilter + RxStation + RxMulticast + RxBroadcast + RxProm +else if defined ALLMULTI + mov ax, SetRxFilter + RxStation + RxMulticast + RxBroadcast +else + mov ax, SetRxFilter + RxStation + RxBroadcast +end if + out dx, ax + + ret + + + + + +;*************************************************************************** +; Function +; global_reset +; Description +; resets the device +; Parameters: +; ebp - io_addr +; Return value: +; Destroyed registers +; ax, ecx, edx, esi +; +;***************************************************************************1 + +align 4 +global_reset: + + DEBUGF 1,"Global reset..\n" + +; GlobalReset + set_io 0 + set_io REG_COMMAND + xor eax, eax +; or al, 0x14 + out dx, ax +; wait for GlobalReset to complete + mov ecx, 64000 + .loop: + in ax , dx + test ah , 10000b ; check CmdInProgress + loopz .loop + + DEBUGF 1,"Waiting for nic to boot..\n" +; wait for 2 seconds for NIC to boot + mov esi, 2000 + call Sleep ; 2 seconds + + DEBUGF 1,"Ok!\n" + + ret + + + +;*************************************************************************** +; Function +; tx_reset +; Description +; resets and enables transmitter engine +; +;*************************************************************************** + +align 4 +tx_reset: + DEBUGF 1,"tx reset\n" + +; TxReset + set_io 0 + set_io REG_COMMAND + mov ax, TxReset + out dx, ax +; Wait for TxReset to complete + mov ecx, 200000 +.tx_reset_loop: + in ax, dx + test ah, 10000b ; check CmdInProgress + jz .tx_set_prev + dec ecx + jnz .tx_reset_loop +.tx_set_prev: +; init last_dpd + lea eax, [device.dpd_buffer + (NUM_TX_DESC-1)*dpd.size] + mov [device.prev_dpd], eax + +.tx_enable: + ret + + + +;*************************************************************************** +; Function +; rx_reset +; Description +; resets and enables receiver engine +; +;*************************************************************************** + +align 4 +rx_reset: + + DEBUGF 1,"rx reset\n" + + set_io 0 + set_io REG_COMMAND + mov ax, RxReset or 0x4 + out dx, ax + +; wait for RxReset to complete + mov ecx, 200000 + .loop: + in ax, dx + test ah, 10000b ; check CmdInProgress + jz .done + dec ecx + jnz .loop + .done: + + lea eax, [device.upd_buffer] + mov [device.curr_upd], eax + GetRealAddr + set_io 0 + set_io REG_UP_LIST_PTR + out dx, eax + + .rx_enable: + ret + + +align 4 +create_rx_ring: +; create upd ring + lea eax, [device.upd_buffer] + GetRealAddr + mov edi, eax ; real addr of first descr + + lea esi, [device.upd_buffer] ; ptr to first descr + lea edx, [device.upd_buffer + (NUM_RX_DESC-1)*upd.size] ; ptr to last descr + + mov ecx, NUM_RX_DESC + + .upd_loop: + mov [edx + upd.next_ptr], edi + + push ecx edx + stdcall KernelAlloc, MAX_ETH_FRAME_SIZE + pop edx ecx + mov [esi + upd.realaddr], eax + call GetPgAddr + mov [esi + upd.frag_addr], eax + and [esi + upd.pkt_status], 0 + mov [esi + upd.frag_len], MAX_ETH_FRAME_SIZE or (1 shl 31) + + DEBUGF 1,"UPD: lin=%x phys=%x len=%x next ptr=%x\n", [esi+upd.realaddr]:8, [esi+upd.frag_addr]:8, [esi+upd.frag_len]:8, edi + DEBUGF 1,"UPD: cur=%x prev=%x\n", esi, edx + + mov edx, esi + add esi, upd.size + add edi, upd.size + dec ecx + jnz .upd_loop + + ret + + + +;--------------------------------------------------------------------------- +; Function +; try_link_detect +; Description +; try_link_detect checks if link exists +; Parameters +; ebx = device structure +; Return value +; al - 0 ; no link detected +; al - 1 ; link detected +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;--------------------------------------------------------------------------- + +align 4 +try_link_detect: + + DEBUGF 1,"trying to detect link\n" + +; create self-directed packet + stdcall KernelAlloc, 20 ; create a buffer for the self-directed packet + test eax, eax + jz .fail + + pushd 20 ; Packet parameters for device.transmit + push eax ; + + mov edi, eax + + lea esi, [device.mac] + movsw + movsd + sub esi, 6 + movsw + movsd + mov ax , 0x0608 + stosw + +; download self-directed packet + call [device.transmit] + +; switch to register window 4 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+4 + out dx, ax + +; See if we have received the packet by now.. + cmp [device.packets_rx], 0 + jnz .link_detected + +; switch to register window 4 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+4 + out dx, ax + +; read linkbeatdetect + set_io REG_MEDIA_STATUS + in ax, dx + test ah, 1000b ; test linkBeatDetect + jnz .link_detected + xor al, al + jmp .finish + + .link_detected: + DEBUGF 1,"link detected!\n" + setb al + + .finish: + test al, al + jz @f + or byte [device.state+1], 100b + @@: + ret + + .fail: + ret + + + +;*************************************************************************** +; Function +; try_phy +; Description +; try_phy checks the auto-negotiation function +; in the PHY at PHY index. It can also be extended to +; include link detection for non-IEEE 802.3u +; auto-negotiation devices, for instance the BCM5000. ; TODO: BCM5000 +; Parameters +; ah - PHY index +; ebx - device stucture +; Return value +; al - 0 link is auto-negotiated +; al - 1 no link is auto-negotiated +; Destroyed registers +; eax, ebx, ecx, edx, esi +; +;*************************************************************************** + +align 4 +try_phy: + + DEBUGF 1,"PHY=%u\n", ah + DEBUGF 1,"Detecting if device is auto-negotiation capable\n" + + mov al, REG_MII_BMCR + push eax + call mdio_read ; returns with window #4 + or ah , 0x80 ; software reset + mov esi, eax + mov eax, dword [esp] + call mdio_write ; returns with window #4 + +; wait for reset to complete + mov esi, 2000 + stdcall Sleep ; 2s + mov eax, [esp] + call mdio_read ; returns with window #4 + test ah , 0x80 + jnz .fail1 + mov eax, [esp] + +; wait for a while after reset + mov esi, 20 + stdcall Sleep ; 20ms + mov eax, [esp] + mov al , REG_MII_BMSR + call mdio_read ; returns with window #4 + test al , 1 ; extended capability supported? + jz .fail2 + +; auto-neg capable? + test al , 1000b + jz .fail2 ; not auto-negotiation capable + + DEBUGF 1,"Device is auto-negotiation capable\n" + +; auto-neg complete? + test al , 100000b + jnz .auto_neg_ok + + DEBUGF 1,"Restarting auto-negotiation\n" + +; restart auto-negotiation + mov eax, [esp] + mov al , REG_MII_ANAR + push eax + call mdio_read ; returns with window #4 + or ax , 1111b shl 5; advertise only 10base-T and 100base-TX + mov esi, eax + pop eax + call mdio_write ; returns with window #4 + mov eax, [esp] + call mdio_read ; returns with window #4 + mov esi, eax + or bh , 10010b ; restart auto-negotiation + mov eax, [esp] + call mdio_write ; returns with window #4 + mov esi, 4000 + stdcall Sleep ; 4 seconds + mov eax, [esp] + mov al , REG_MII_BMSR + call mdio_read ; returns with window #4 + test al , 100000b ; auto-neg complete? + jnz .auto_neg_ok + jmp .fail3 + .auto_neg_ok: + + DEBUGF 1,"Auto-negotiation complete\n" + +; compare advertisement and link partner ability registers + mov eax, [esp] + mov al , REG_MII_ANAR + call mdio_read ; returns with window #4 + xchg eax, [esp] + mov al , REG_MII_ANLPAR + call mdio_read ; returns with window #4 + pop esi + and eax, esi + and eax, 1111100000b + push eax + + mov word[device.state+2], ax + +; switch to register window 3 + set_io 0 + set_io REG_COMMAND + mov ax , SELECT_REGISTER_WINDOW+3 + out dx , ax + +; set full-duplex mode + set_io REG_MAC_CONTROL + in ax , dx + and ax , not 0x120 ; clear full duplex and flow control + pop esi + test esi, 1010b shl 5; check for full-duplex + jz .half_duplex + or ax , 0x120 ; set full duplex and flow control + .half_duplex: + DEBUGF 1,"Using half-duplex\n" + out dx , ax + mov al , 1 + ret + + + .fail1: + DEBUGF 1,"reset failed!\n" + pop eax + xor al, al + ret + + .fail2: + DEBUGF 1,"This device is not auto-negotiation capable!\n" + pop eax + xor al, al + ret + + .fail3: + DEBUGF 1,"auto-negotiation reset failed!\n" + pop eax + xor al, al + ret + + + +;*************************************************************************** +; Function +; try_mii +; Description +; try_MII checks the on-chip auto-negotiation logic +; or an off-chip MII PHY, depending upon what is set in +; xcvrSelect by the caller. +; It exits when it finds the first device with a good link. +; Parameters +; ebp - io_addr +; Return value +; al - 0 +; al - 1 +; Destroyed registers +; eax, ebx, ecx, edx, esi +; +;*************************************************************************** + +align 4 +try_mii: + + DEBUGF 1,"trying to find MII PHY\n" + +; switch to register window 3 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+3 + out dx, ax + set_io REG_INTERNAL_CONFIG + in eax, dx + and eax, (1111b shl 20) + cmp eax, (1000b shl 20) ; is auto-negotiation set? + jne .mii_device + + DEBUGF 1,"auto-negotiation is set\n" +; switch to register window 4 + set_io REG_COMMAND + mov ax , SELECT_REGISTER_WINDOW+4 + out dx , ax + +; PHY==24 is the on-chip auto-negotiation logic +; it supports only 10base-T and 100base-TX + mov ah , 24 + call try_phy + test al , al + jz .fail_finish + + mov cl , 24 + jmp .check_preamble + + .mii_device: + cmp eax, (0110b shl 20) + jne .fail_finish + + set_io 0 + set_io REG_COMMAND + mov ax , SELECT_REGISTER_WINDOW+4 + out dx , ax + + set_io REG_PHYSICAL_MGMT + in ax , dx + and al , (1 shl BIT_MGMT_DIR) or (1 shl BIT_MGMT_DATA) + cmp al , (1 shl BIT_MGMT_DATA) + je .search_for_phy + + xor al , al + ret + + .search_for_phy: +; search for PHY + mov cx , 31 + .search_phy_loop: + DEBUGF 1,"Searching the PHY\n" + cmp cx , 24 + je .next_phy + mov ah , cl ; ah = phy + mov al , REG_MII_BMCR ; al = Basic Mode Status Register + push cx + call mdio_read + pop cx + test ax , ax + jz .next_phy + cmp ax , 0xffff + je .next_phy + mov ah , cl ; ah = phy + push cx + call try_phy + pop cx + test al , al + jnz .check_preamble + .next_phy: + loopw .search_phy_loop + + .fail_finish: + xor al, al + ret + +; epilog + .check_preamble: + DEBUGF 1,"Using PHY: %u\nChecking PreAmble\n", cl + push eax ; eax contains the return value of try_phy +; check hard coded preamble forcing + movzx eax, [device.ver_id] + test word [eax*4+hw_versions+2], EXTRA_PREAMBLE + setnz [device.preamble] ; force preamble + jnz .finish + +; check mii for preamble suppression + mov ah, cl + mov al, REG_MII_BMSR + call mdio_read + test al, 1000000b ; preamble suppression? + setz [device.preamble] ; no + + .finish: + pop eax + ret + + + +;*************************************************************************** +; Function +; test_packet +; Description +; try_loopback try a loopback packet for 10BASE2 or AUI port +; Parameters +; ebx = device structure +; +;*************************************************************************** + +align 4 +test_packet: + + DEBUGF 1,"sending test packet\n" + +; switch to register window 3 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+3 + out dx, ax + +; set fullDuplexEnable in MacControl register + set_io REG_MAC_CONTROL + in ax, dx + or ax, 0x120 + out dx, ax + +; switch to register window 5 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+5 + out dx, ax + +; set RxFilter to enable individual address matches + mov ax, (10000b shl 11) + set_io REG_RX_FILTER + in al, dx + or al, 1 + set_io REG_COMMAND + out dx, ax + +; issue RxEnable and TxEnable + call rx_reset + call tx_reset + +; create self-directed packet + stdcall KernelAlloc, 20 ; create a buffer for the self-directed packet + test eax, eax + jz .fail + + pushd 20 ; Packet parameters for device.transmit + push eax ; + + mov edi, eax + lea esi, [device.mac] + movsw + movsd + sub esi, 6 + movsw + movsd + mov ax , 0x0608 + stosw + +; download self-directed packet + call [device.transmit] + +; wait for 2s + mov esi, 2000 + call Sleep + +; check if self-directed packet is received + mov eax, [device.packets_rx] + test eax, eax + jnz .finish + +; switch to register window 3 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+3 + out dx, ax + +; clear fullDuplexEnable in MacControl register + set_io REG_MAC_CONTROL + in ax , dx + and ax , not 0x120 + out dx , ax + .fail: + xor eax, eax + + .finish: + ret + + + +;*************************************************************************** +; Function +; try_loopback +; Description +; tries a loopback packet for 10BASE2 or AUI port +; Parameters +; al - 0: 10Mbps AUI connector +; 1: 10BASE-2 +; ebp - io_addr +; Return value +; al - 0 +; al - 1 +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** + +align 4 +try_loopback: + + DEBUGF 1,"trying loopback\n" + + push eax +; switch to register window 3 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+3 + out dx, ax + mov eax, [esp] + + mov cl, al + inc cl + shl cl, 3 + or byte [device.state+1], cl + + test al, al ; aui or coax? + jz .complete_loopback +; enable 100BASE-2 DC-DC converter + mov ax, (10b shl 11) ; EnableDcConverter + out dx, ax + .complete_loopback: + + mov cx, 2 ; give a port 3 chances to complete a loopback + .next_try: + push ecx + call test_packet + pop ecx + test eax, eax + loopzw .next_try + + .finish: + xchg eax, [esp] + test al, al + jz .aui_finish + +; issue DisableDcConverter command + set_io 0 + set_io REG_COMMAND + mov ax, (10111b shl 11) + out dx, ax + .aui_finish: + pop eax ; al contains the result of operation + + test al, al + jnz @f + and byte [device.state+1], not 11000b + @@: + + ret + + +;*************************************************************************** +; Function +; set_active_port +; Description +; It selects the media port (transceiver) to be used +; Return value: +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** + +align 4 +set_active_port: + + DEBUGF 1,"Trying to find the active port\n" + +; switch to register window 3 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW + 3 + out dx, ax + + set_io REG_INTERNAL_CONFIG + in eax, dx + test eax, (1 shl 24) ; check if autoselect enable + jz .set_first_available_media + +; check 100BASE-TX and 10BASE-T + set_io REG_MEDIA_OPTIONS + in ax, dx + test al, 1010b ; check whether 100BASE-TX or 10BASE-T available + jz .mii_device ; they are not available + +; set auto-negotiation + set_io REG_INTERNAL_CONFIG + in eax, dx + and eax, not (1111b shl 20) + or eax, (1000b shl 20) + out dx, eax + call try_mii + test al, al + jz .mii_device + DEBUGF 1,"Using auto negotiation\n" + ret + + .mii_device: +; switch to register window 3 + set_io 0 +; check for off-chip mii device + set_io REG_MEDIA_OPTIONS + in ax, dx + test al, 1000000b ; check miiDevice + jz .base_fx + set_io REG_INTERNAL_CONFIG + in eax, dx + and eax, not (1111b shl 20) + or eax, (0110b shl 20) ; set MIIDevice + out dx, eax + call try_mii + test al, al + jz .base_fx + DEBUGF 1,"Using off-chip mii device\n" + ret + + .base_fx: +; switch to register window 3 + set_io 0 +; check for 100BASE-FX + set_io REG_MEDIA_OPTIONS + in ax, dx ; read media option register + test al, 100b ; check 100BASE-FX + jz .aui_enable + set_io REG_INTERNAL_CONFIG + in eax, dx + and eax, not (1111b shl 20) + or eax, (0101b shl 20) ; set 100base-FX + out dx, eax + call try_link_detect + test al, al + jz .aui_enable + DEBUGF 1,"Using 100Base-FX\n" + ret + + .aui_enable: +; switch to register window 3 + set_io 0 +; check for 10Mbps AUI connector + set_io REG_MEDIA_OPTIONS + in ax, dx ; read media option register + test al, 100000b ; check 10Mbps AUI connector + jz .coax_available + set_io REG_INTERNAL_CONFIG + in eax, dx + and eax, not (1111b shl 20) + or eax, (0001b shl 20) ; set 10Mbps AUI connector + out dx, eax + xor al, al ; try 10Mbps AUI connector + call try_loopback + test al, al + jz .coax_available + DEBUGF 1,"Using 10Mbps aui\n" + ret + + .coax_available: +; switch to register window 3 + set_io 0 +; check for coaxial 10BASE-2 port + set_io REG_MEDIA_OPTIONS + in ax, dx ; read media option register + test al, 10000b ; check 10BASE-2 + jz .set_first_available_media + + set_io REG_INTERNAL_CONFIG + in eax, dx + and eax, not (1111b shl 20) + or eax, (0011b shl 20) ; set 10BASE-2 + out dx, eax + mov al, 1 + call try_loopback + test al, al + jz .set_first_available_media + DEBUGF 1,"Using 10BASE-2 port\n" + ret + + .set_first_available_media: + DEBUGF 1,"Using the first available media\n" + +;*************************************************************************** +; Function +; set_available_media +; Description +; sets the first available media +; Parameters +; ebx - ptr to device struct +; Return value +; al - 0 +; al - 1 +; Destroyed registers +; eax, edx +; +;*************************************************************************** + +align 4 +set_available_media: + + DEBUGF 1,"Setting the available media\n" +; switch to register window 3 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+3 + out dx, ax + + set_io REG_MEDIA_OPTIONS + in ax, dx + DEBUGF 1,"available media:%x\n", al + mov cl, al + + set_io REG_INTERNAL_CONFIG + in eax, dx + and eax, not (1111b shl 20) ; these bits hold the 'transceiver select' value + + test cl, 10b ; baseTXAvailable + jz @f + + DEBUGF 1,"base TX is available\n" + or eax, (100b shl 20) +if defined FORCE_FD + mov word [device.state], (1 shl 8) +else + mov word [device.mode], (1 shl 7) +end if + jmp .set_media + @@: + + test cl, 100b ; baseFXAvailable + jz @f + + DEBUGF 1,"base FX is available\n" + or eax, (101b shl 20) + mov word [device.state], (1 shl 10) + jmp .set_media + @@: + + test cl, 1000000b ; miiDevice + jz @f + + DEBUGF 1,"mii-device is available\n" + or eax, (0110b shl 20) + mov word [device.state], (1 shl 13) + jmp .set_media + @@: + + test cl, 1000b ; 10bTAvailable + jz @f + + DEBUGF 1,"10base-T is available\n" + .set_default: +if FORCE_FD + mov word [device.state], (1 shl 6) +else + mov word [device.state], (1 shl 5) +end if + jmp .set_media + @@: + + test cl, 10000b ; coaxAvailable + jz @f + + DEBUGF 1,"coax is available\n" + push eax + set_io REG_COMMAND + mov ax, (10b shl 11) ; EnableDcConverter + out dx, ax + pop eax + + or eax, (11b shl 20) + mov word [device.state], (1 shl 12) + jmp .set_media + @@: + + test cl, 10000b ; auiAvailable + jz .set_default + + DEBUGF 1,"AUI is available\n" + or eax, (1 shl 20) + mov word [device.state], (1 shl 11) + + .set_media: + set_io 0 + set_io REG_INTERNAL_CONFIG + out dx, eax + +if FORCE_FD + DEBUGF 1,"Forcing full duplex\n" + set_io REG_MAC_CONTROL + in ax, dx + or ax, 0x120 + out dx, ax +end if + + mov al, 1 + ret + + + +;*************************************************************************** +; Function +; wake_up +; Description +; set the power state to D0 +; +;*************************************************************************** + +align 4 +wake_up: + + DEBUGF 1,"Waking up NIC: " + +; wake up - we directly do it by programming PCI +; check if the device is power management capable + stdcall PciRead32, [device.pci_bus], [device.pci_dev], PCI_REG_STATUS + + test al, 10000b ; is there "new capabilities" linked list? + jz .device_awake + +; search for power management register + stdcall PciRead16, [device.pci_bus], [device.pci_dev], PCI_REG_CAP_PTR + cmp al, 0x3f + jbe .device_awake + +; traverse the list + movzx esi, al + .pm_loop: + stdcall PciRead32, [device.pci_bus], [device.pci_dev], esi + + cmp al , 1 + je .set_pm_state + + movzx esi, ah + + test ah , ah + jnz .pm_loop + jmp .device_awake + +; waku up the device if necessary + .set_pm_state: + + add esi, PCI_REG_PM_CTRL + stdcall PciRead32, [device.pci_bus], [device.pci_dev], esi + test al, 3 + jz .device_awake + and al, not 11b ; set state to D0 + stdcall PciWrite32, [device.pci_bus], [device.pci_dev], esi, eax + + .device_awake: + DEBUGF 1,"Device is awake\n" + + ret + + + + +;*************************************************************************** +; Function +; write_eeprom +; Description +; reads eeprom +; Note : the caller must switch to the register window 0 +; before calling this function +; Parameters: +; ax - register to be read (only the first 63 words can be read) +; cx - value to be read into the register +; Return value: +; ax - word read +; Destroyed registers +; ax, ebx, edx +; +;*************************************************************************** +; align 4 +;write_eeprom: +; mov edx, [io_addr] +; add edx, REG_EEPROM_COMMAND +; cmp ah, 11b +; ja .finish ; address may have a value of maximal 1023 +; shl ax, 2 +; shr al, 2 +; push eax +;; wait for busy +; mov ebx, 0xffff +;@@: +; in ax, dx +; test ah, 0x80 +; jz .write_enable +; dec ebx +; jns @r +;; write enable +;.write_enable: +; xor eax, eax +; mov eax, (11b shl 4) +; out dx, ax +;; wait for busy +; mov ebx, 0xffff +;@@: +; in ax, dx +; test ah, 0x80 +; jz .erase_loop +; dec ebx +; jns @r +;.erase_loop: +; pop eax +; push eax +; or ax, (11b shl 6) ; erase register +; out dx, ax +; mov ebx, 0xffff +;@@: +; in ax, dx +; test ah, 0x80 +; jz .write_reg +; dec ebx +; jns @r +;.write_reg: +; add edx, REG_EEPROM_DATA-REG_EEPROM_COMMAND +; mov eax, ecx +; out dx, ax +;; write enable +; add edx, REG_EEPROM_COMMAND-REG_EEPROM_DATA +; xor eax, eax +; mov eax, (11b shl 4) +; out dx, ax +; wait for busy +; mov ebx, 0xffff +;@@: +; in ax, dx +; test ah, 0x80 +; jz .issue_write_reg +; dec ebx +; jns @r +;.issue_write_reg: +; pop eax +; or ax, 01b shl 6 +; out dx, ax +;.finish: +; ret + + +;*************************************************************************** +; Function +; read_eeprom +; Description +; reads eeprom +; Parameters: +; ax - register to be read (only the first 63 words can be read) +; ebx = driver structure +; Return value: +; ax - word read +; Destroyed registers +; ax, ebx, edx +; +;*************************************************************************** + +align 4 +read_eeprom: + + DEBUGF 1,"Reading from eeprom.. " + + push eax +; switch to register window 0 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+0 + out dx, ax + pop eax + and ax, 111111b ; take only the first 6 bits into account + movzx esi, [device.ver_id] + + test word [esi*4+hw_versions+2], EEPROM_8BIT + jz @f + add ax, 0x230 ; hardware constant + jmp .read +@@: + + add ax, EEPROM_CMD_READ + test word [esi*4+hw_versions+2], EEPROM_OFFSET + jz .read + add ax, 0x30 +.read: + + set_io REG_EEPROM_COMMAND + out dx, ax + mov ecx, 0xffff ; duration of about 162 us ;-) +.wait_for_reading: + in ax, dx + test ah, 0x80 ; check bit eepromBusy + jz .read_data + loop .wait_for_reading +.read_data: + set_io REG_EEPROM_DATA + in ax, dx + + DEBUGF 1,"ok!\n" + + ret + +;*************************************************************************** +; Function +; mdio_sync +; Description +; initial synchronization +; Parameters +; ebp - io_addr +; Return value +; Destroyed registers +; ax, edx, cl +; +;*************************************************************************** + +align 4 +mdio_sync: + + DEBUGF 1,"syncing mdio\n" + +; switch to register window 4 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+4 + out dx, ax + cmp [device.preamble], 0 + je .no_preamble +; send 32 logic ones + set_io REG_PHYSICAL_MGMT + mov ecx, 31 + .loop: + mov ax, (1 shl BIT_MGMT_DATA) or (1 shl BIT_MGMT_DIR) + out dx, ax + in ax, dx ; delay + mov ax, (1 shl BIT_MGMT_DATA) or (1 shl BIT_MGMT_DIR) or (1 shl BIT_MGMT_CLK) + out dx, ax + in ax, dx ; delay + loop .loop + .no_preamble: + + ret + +;*************************************************************************** +; Function +; mdio_read +; Description +; read MII register +; see page 16 in D83840A.pdf +; Parameters +; ah - PHY addr +; al - register addr +; ebx = device structure +; Return value +; ax - register read +; +;*************************************************************************** + +align 4 +mdio_read: + + DEBUGF 1,"Reading MII registers\n" + + push eax + call mdio_sync ; returns with window #4 + pop eax + set_io 0 + set_io REG_PHYSICAL_MGMT + shl al, 3 + shr ax, 3 + and ax, not MII_CMD_MASK + or ax, MII_CMD_READ + + mov esi, eax + mov ecx, 13 + .cmd_loop: + mov ax, (1 shl BIT_MGMT_DIR) ; write mii + bt esi, ecx + jnc .zero_bit + or al, (1 shl BIT_MGMT_DATA) + + .zero_bit: + out dx, ax + push ax + in ax, dx ; delay + pop ax + or al, (1 shl BIT_MGMT_CLK) ; write + out dx, ax + in ax, dx ; delay + loop .cmd_loop + +; read data (18 bits with the two transition bits) + mov ecx, 17 + xor esi, esi + .read_loop: + shl esi, 1 + xor eax, eax ; read comand + out dx, ax + in ax, dx ; delay + in ax, dx + test al, (1 shl BIT_MGMT_DATA) + jz .dont_set + inc esi + .dont_set: + mov ax, (1 shl BIT_MGMT_CLK) + out dx, ax + in ax, dx ; delay + loop .read_loop + mov eax, esi + + ret + + + +;*************************************************************************** +; Function +; mdio_write +; Description +; write MII register +; see page 16 in D83840A.pdf +; Parameters +; ah - PHY addr +; al - register addr +; si - word to be written +; Return value +; ax - register read +; +;*************************************************************************** + +align 4 +mdio_write: + + DEBUGF 1,"Writing MII registers\n" + + push eax + call mdio_sync + pop eax + set_io 0 + set_io REG_PHYSICAL_MGMT + shl al, 3 + shr ax, 3 + and ax, not MII_CMD_MASK + or ax, MII_CMD_WRITE + shl eax, 2 + or eax, 10b ; transition bits + shl eax, 16 + mov ax, si + mov esi, eax + mov ecx, 31 + + .cmd_loop: + mov ax, (1 shl BIT_MGMT_DIR) ; write mii + bt esi, ecx + jnc @f + or al, (1 shl BIT_MGMT_DATA) + @@: + out dx, ax + push eax + in ax, dx ; delay + pop eax + or al, (1 shl BIT_MGMT_CLK) ; write + out dx, ax + in ax, dx ; delay + loop .cmd_loop + + ret + + +;*************************************************************************** +; Function +; check_tx_status +; Description +; Checks TxStatus queue. +; Return value +; al - 0 no error was found +; al - 1 error was found TxReset was needed +; Destroyed registers +; eax, ecx, edx, ebp +; +;*************************************************************************** + +align 4 +check_tx_status: + + DEBUGF 1,"Checking TX status\n" + +; clear TxStatus queue + set_io 0 + set_io REG_TX_STATUS + mov ecx, 31 ; max number of queue entries + + .tx_status_loop: + in al, dx + test al, al + jz .finish ; no error + test al, 0x3f + jnz .error + .no_error_found: +; clear current TxStatus entry which advances the next one + xor al, al + out dx, al + loop .tx_status_loop + + .finish: + + ret + + .error: + call tx_reset + ret + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit (vortex) ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +vortex_transmit: + + DEBUGF 1,"Sending packet (vortex)\n" + + cmp dword [esp+8], MAX_ETH_FRAME_SIZE + ja .finish ; packet is too long + + call check_tx_status + +; switch to register window 7 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+7 + out dx, ax +; check for master operation in progress + set_io REG_MASTER_STATUS + in ax, dx + test ah, 0x80 + jnz .finish ; no DMA for sending +; program frame address to be sent + set_io REG_MASTER_ADDRESS + mov eax, [esp+4] + call GetPgAddr + out dx, eax +; program frame length + set_io REG_MASTER_LEN + mov eax, [esp+8] +;;; and eax, not 3 + out dx, ax +; start DMA Down + set_io REG_COMMAND + mov ax, (10100b shl 11) + 1 ; StartDMADown + out dx, ax +.finish: + call KernelFree + add esp, 4 + ret + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit (boomerang) ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +boomerang_transmit: + + DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8] + mov eax, [esp+4] + DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp+8], MAX_ETH_FRAME_SIZE + ja .fail + + call check_tx_status + +; calculate descriptor address + mov esi, [device.prev_dpd] + DEBUGF 1,"Previous DPD: %x\n", esi + add esi, dpd.size + lea ecx, [device.dpd_buffer + (NUM_TX_DESC)*dpd.size] + cmp esi, ecx + jb @f + lea esi, [device.dpd_buffer] ; Wrap if needed + @@: + DEBUGF 1,"Found a free DPD: %x\n", esi + +; check DnListPtr + set_io 0 + set_io REG_DN_LIST_PTR + in eax, dx +; mark if Dn_List_Ptr is cleared + test eax, eax + setz [device.dn_list_ptr_cleared] + +; finish if no more free descriptor is available - FIXME! +; cmp eax, esi +; jz .finish + +; update statistics + inc [device.packets_tx] + mov ecx, [esp+8] ; buffer size + add dword [device.bytes_tx], ecx + adc dword [device.bytes_tx + 4], 0 + +; program DPD + and [esi+dpd.next_ptr], 0 + mov eax, [esp+4] ; Tx buffer address + mov [esi+dpd.realaddr], eax + call GetPgAddr + mov [esi+dpd.frag_addr], eax + mov ecx, [esp+8] ; packet size + or ecx, 0x80000000 ; last fragment + mov [esi+dpd.frag_len], ecx + + mov ecx, [esp+8] ; packet size +; or ecx, 0x8000 ; transmission complete notification + + or ecx, 1 shl 31 + +; test byte [device.has_hwcksm], 0xff +; jz @f +; or ecx, (1 shl 26) ; set AddTcpChecksum +;@@: + mov [esi+dpd.frame_start_hdr], ecx + + DEBUGF 1,"DPD: lin=%x phys=%x len=%x start hdr=%x\n", [esi+dpd.realaddr]:8, [esi+dpd.frag_addr]:8, [esi+dpd.frag_len]:8, [esi+dpd.frame_start_hdr]:8 + +; calculate physical address of dpd + mov eax, esi + GetRealAddr + cmp [device.dn_list_ptr_cleared], 0 + jz .add_to_list + +; write Dn_List_Ptr + DEBUGF 1,"DPD phys addr=%x\n", eax + set_io 0 + set_io REG_DN_LIST_PTR + out dx, eax + jmp .finish + + .add_to_list: + DEBUGF 1,"Adding To list\n" + push eax +; DnStall + set_io 0 + set_io REG_COMMAND + mov ax, ((110b shl 11)+2) + out dx, ax + +; wait for DnStall to complete + DEBUGF 1,"Waiting for DnStall\n" + mov ecx, 6000 + .wait_for_stall: + in ax, dx ; read REG_INT_STATUS + test ah, 10000b + jz .dnstall_ok + dec ecx + jnz .wait_for_stall + + .dnstall_ok: + DEBUGF 1,"DnStall ok!\n" + mov ecx, [device.prev_dpd] + mov [ecx+dpd.next_ptr], eax + + set_io 0 + set_io REG_DN_LIST_PTR + in eax, dx + test eax, eax + pop eax + jnz .dnunstall + +; if Dn_List_Ptr has been cleared fill it up + DEBUGF 1,"DnList Ptr has been cleared\n" + out dx, eax + + .dnunstall: +; DnUnStall + set_io 0 + set_io REG_COMMAND + mov ax, ((110b shl 11)+3) + out dx, ax + + .finish: + mov [device.prev_dpd], esi + xor eax, eax + ret 8 + + .fail: + stdcall KernelFree, [esp+4] + or eax, -1 + ret 8 + + +;--------------------------------- +; Write MAC + +align 4 +write_mac: + + DEBUGF 1,"Writing mac\n" + + set_io 0 + set_io REG_COMMAND + +; switch to register window 2 + mov ax, SELECT_REGISTER_WINDOW+2 + out dx, ax + +; write MAC addres back into the station address registers + set_io REG_STATION_ADDRESS_LO + lea esi, [device.mac] + outsw + inc dx + inc dx + outsw + inc dx + inc dx + outsw + + +;---------------------------- +; Read MAC + +align 4 +read_mac: + + set_io 0 + set_io REG_COMMAND + +; switch to register window 2 + mov ax, SELECT_REGISTER_WINDOW+2 + out dx, ax + +; write MAC addres back into the station address registers + set_io REG_STATION_ADDRESS_LO + lea edi, [device.mac] + insw + inc dx + inc dx + insw + inc dx + inc dx + insw + + DEBUGF 1,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + + ret + + +;------------------------------------ +; Read MAC from eeprom + +align 4 +read_mac_eeprom: ; Tested - ok + + DEBUGF 1,"Reading mac from eeprom\n" + +; read MAC from eeprom + mov ecx, 3 + .mac_loop: + lea ax, [EEPROM_REG_OEM_NODE_ADDR+ecx-1] + push ecx + call read_eeprom + pop ecx + xchg ah, al ; htons + mov word [device.mac+ecx*2-2], ax + loop .mac_loop + + DEBUGF 1,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + + ret + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Vortex Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_vortex: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service + +; find pointer of device wich made IRQ occur + + mov esi, VORTEX_LIST + mov ecx, [VORTEX_DEVICES] + test ecx, ecx + jz .nothing + .nextdevice: + mov ebx, dword [esi] + + + set_io 0 + set_io REG_INT_STATUS + in ax, dx + and ax, S_5_INTS + jnz .nothing + + add esi, 4 + + test ax , ax + jnz .got_it + loop .nextdevice + + .nothing: + pop edi esi ebx + xor eax, eax + + ret + +.got_it: + + DEBUGF 1,"Device: %x Status: %x ",ebx,eax:4 + + test ax, RxComplete + jz .noRX + + set_io 0 + .rx_status_loop: +; examine RxStatus + set_io REG_RX_STATUS + in ax, dx + test ax, ax + jz .finish + + test ah, 0x80 ; rxIncomplete + jnz .finish + + test ah, 0x40 + jz .check_length + +; discard the top frame received advancing the next one + set_io REG_COMMAND + mov ax, (01000b shl 11) + out dx, ax + jmp .rx_status_loop + + .check_length: + and eax, 0x1fff + cmp eax, MAX_ETH_PKT_SIZE + ja .discard_frame ; frame is too long discard it + + .check_dma: + mov ecx, eax +; switch to register window 7 + set_io 0 + set_io REG_COMMAND + mov ax, SELECT_REGISTER_WINDOW+7 + out dx, ax +; check for master operation in progress + set_io REG_MASTER_STATUS + in ax, dx + + test ah, 0x80 + jnz .finish + + .read_frame: +; program buffer address to read in + push ecx + stdcall KernelAlloc, MAX_ETH_FRAME_SIZE + pop ecx + test eax, eax + jz .finish + + push .discard_frame + push ecx + push eax +; zero_to_dma eax + set_io REG_MASTER_ADDRESS + out dx, eax + +; program frame length + set_io REG_MASTER_LEN + mov ax, 1560 + out dx, ax + +; start DMA Up + set_io REG_COMMAND + mov ax, (10100b shl 11) ; StartDMAUp + out dx, ax + +; check for master operation in progress + set_io REG_MASTER_STATUS ; TODO: use timeout and reset after timeout expired + .dma_loop: + in ax, dx + test ah, 0x80 + jnz .dma_loop + +; registrate the received packet to kernel + jmp Eth_input + +; discard the top frame received + .discard_frame: + set_io 0 + set_io REG_COMMAND + mov ax, (01000b shl 11) + out dx, ax + + .finish: + + +.noRX: + + test ax, DMADone + jz .noDMA + + push ax + + set_io 0 + set_io 12 + in ax, dx + test ax, 0x1000 + jz .nodmaclear + + mov ax, 0x1000 + out dx, ax + + .nodmaclear: + + pop ax + + DEBUGF 1, "DMA Done!\n", cx + + + +.noDMA: + + + +.ACK: + set_io 0 + set_io REG_COMMAND + mov ax, AckIntr + IntReq + IntLatch + out dx, ax + + pop edi esi ebx + + ret + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Boomerang Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_boomerang: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service + +; find pointer of device wich made IRQ occur + + mov ecx, [BOOMERANG_DEVICES] + test ecx, ecx + jz .nothing + mov esi, BOOMERANG_LIST + .nextdevice: + mov ebx, [esi] + + set_io 0 + set_io REG_INT_STATUS + in ax, dx + test ax, ax + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret + + .got_it: + + DEBUGF 1,"Device: %x Status: %x ", ebx, ax + push ax + +; disable all INTS + + set_io REG_COMMAND + mov ax, SetIntrEnb + out dx, ax + +;-------------------------------------------------------------------------- + test word[esp], UpComplete + jz .noRX + + push ebx + + .receive: + DEBUGF 1,"UpComplete\n" + +; check if packet is uploaded + mov esi, [device.curr_upd] + test byte [esi+upd.pkt_status+1], 0x80 ; upPktComplete + jz .finish + DEBUGF 1, "Current upd: %x\n", esi +; packet is uploaded check for any error + .check_error: + test byte [esi+upd.pkt_status+1], 0x40 ; upError + jz .copy_packet_length + DEBUGF 1,"Error in packet\n" + and [esi+upd.pkt_status], 0 ; mark packet as read + jmp .finish + .copy_packet_length: + mov ecx, [esi+upd.pkt_status] + and ecx, 0x1fff + +; cmp ecx, MAX_ETH_PKT_SIZE +; jbe .copy_packet +; and [esi+upd.pkt_status], 0 +; jmp .finish +; .copy_packet: + + DEBUGF 1, "Received %u bytes in buffer %x\n", ecx, [esi+upd.realaddr]:8 + + push dword .loop ;.finish + push ecx + push [esi+upd.realaddr] + +; update statistics + inc [device.packets_rx] + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + +; update UPD (Alloc new buffer for next packet) + stdcall KernelAlloc, MAX_ETH_FRAME_SIZE + mov [esi + upd.realaddr], eax + GetRealAddr + mov [esi + upd.frag_addr], eax + and [esi + upd.pkt_status], 0 + mov [esi + upd.frag_len], MAX_ETH_FRAME_SIZE or (1 shl 31) + +; Update UPD pointer + add esi, upd.size + lea ecx, [device.upd_buffer+(NUM_RX_DESC)*upd.size] + cmp esi, ecx + jb @f + lea esi, [device.upd_buffer] + @@: + mov [device.curr_upd], esi + DEBUGF 1, "Next upd: %x\n", esi + + jmp Eth_input + .loop: + + mov ebx, [esp] + jmp .receive + + .finish: + pop ebx + +; check if the NIC is in the upStall state + set_io 0 + set_io REG_UP_PKT_STATUS + in eax, dx + test ah, 0x20 ; UpStalled + jz .noUpUnStall + + DEBUGF 1, "upUnStalling\n" +; issue upUnStall command + set_io REG_COMMAND + mov ax, ((11b shl 12)+1) ; upUnStall + out dx, ax + + ;;;; FIXME: make upunstall work + + .noUpUnStall: +.noRX: + test word[esp], DownComplete + jz .noTX + DEBUGF 1, "Downcomplete!\n" + + mov ecx, NUM_TX_DESC + lea esi, [device.dpd_buffer] + .txloop: + test [esi+dpd.frame_start_hdr], 1 shl 31 + jz .maybenext + + and [esi+dpd.frame_start_hdr], 0 + push ecx + stdcall KernelFree, [esi+dpd.realaddr] + pop ecx + + .maybenext: + add esi, dpd.size + dec ecx + jnz .txloop + +.noTX: + pop ax + + set_io 0 + set_io REG_COMMAND + or ax, AckIntr + out dx, ax + + set_io REG_INT_STATUS + in ax, dx + test ax, S_5_INTS + jnz .got_it + +;re-enable ints + set_io REG_COMMAND + mov ax, SetIntrEnb + S_5_INTS + out dx, ax + + pop edi esi ebx + + ret + + + + +; End of code +align 4 ; Place all initialised data here + +macro strtbl name, [string] +{ +common + label name dword +forward + local label + dd label +forward + label db string, 0 +} + +VORTEX_DEVICES dd 0 +BOOMERANG_DEVICES dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db '3C59X',0 ; max 16 chars include zero + + +strtbl link_str, \ + "No valid link type detected", \ + "10BASE-T half duplex", \ + "10BASE-T full-duplex", \ + "100BASE-TX half duplex", \ + "100BASE-TX full duplex", \ + "100BASE-T4", \ + "100BASE-FX", \ + "10Mbps AUI", \ + "10Mbps COAX (BNC)", \ + "miiDevice - not supported" + +strtbl hw_str, \ + "3c590 Vortex 10Mbps", \ + "3c592 EISA 10Mbps Demon/Vortex", \ + "3c597 EISA Fast Demon/Vortex", \ + "3c595 Vortex 100baseTx", \ + "3c595 Vortex 100baseT4", \ + "3c595 Vortex 100base-MII", \ + "3c900 Boomerang 10baseT", \ + "3c900 Boomerang 10Mbps Combo", \ + "3c900 Cyclone 10Mbps TPO", \ + "3c900 Cyclone 10Mbps Combo", \ + "3c900 Cyclone 10Mbps TPC", \ + "3c900B-FL Cyclone 10base-FL", \ + "3c905 Boomerang 100baseTx", \ + "3c905 Boomerang 100baseT4", \ + "3c905B Cyclone 100baseTx", \ + "3c905B Cyclone 10/100/BNC", \ + "3c905B-FX Cyclone 100baseFx", \ + "3c905C Tornado", \ + "3c980 Cyclone", \ + "3c982 Dual Port Server Cyclone", \ + "3cSOHO100-TX Hurricane", \ + "3c555 Laptop Hurricane", \ + "3c556 Laptop Tornado", \ + "3c556B Laptop Hurricane", \ + "3c575 [Megahertz] 10/100 LAN CardBus", \ + "3c575 Boomerang CardBus", \ + "3CCFE575BT Cyclone CardBus", \ + "3CCFE575CT Tornado CardBus", \ + "3CCFE656 Cyclone CardBus", \ + "3CCFEM656B Cyclone+Winmodem CardBus", \ + "3CXFEM656C Tornado+Winmodem CardBus", \ + "3c450 HomePNA Tornado", \ + "3c920 Tornado", \ + "3c982 Hydra Dual Port A", \ + "3c982 Hydra Dual Port B", \ + "3c905B-T4", \ + "3c920B-EMB-WNM Tornado" + + + +align 4 +hw_versions: +dw 0x5900, IS_VORTEX ; 3c590 Vortex 10Mbps +dw 0x5920, IS_VORTEX ; 3c592 EISA 10Mbps Demon/Vortex +dw 0x5970, IS_VORTEX ; 3c597 EISA Fast Demon/Vortex +dw 0x5950, IS_VORTEX ; 3c595 Vortex 100baseTx +dw 0x5951, IS_VORTEX ; 3c595 Vortex 100baseT4 +dw 0x5952, IS_VORTEX ; 3c595 Vortex 100base-MII +dw 0x9000, IS_BOOMERANG ; 3c900 Boomerang 10baseT +dw 0x9001, IS_BOOMERANG ; 3c900 Boomerang 10Mbps Combo +dw 0x9004, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c900 Cyclone 10Mbps TPO +dw 0x9005, IS_CYCLONE or HAS_HWCKSM ; 3c900 Cyclone 10Mbps Combo +dw 0x9006, IS_CYCLONE or HAS_HWCKSM ; 3c900 Cyclone 10Mbps TPC +dw 0x900A, IS_CYCLONE or HAS_HWCKSM ; 3c900B-FL Cyclone 10base-FL +dw 0x9050, IS_BOOMERANG or HAS_MII ; 3c905 Boomerang 100baseTx +dw 0x9051, IS_BOOMERANG or HAS_MII ; 3c905 Boomerang 100baseT4 +dw 0x9055, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE ; 3c905B Cyclone 100baseTx +dw 0x9058, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c905B Cyclone 10/100/BNC +dw 0x905A, IS_CYCLONE or HAS_HWCKSM ; 3c905B-FX Cyclone 100baseFx +dw 0x9200, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c905C Tornado +dw 0x9800, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c980 Cyclone +dw 0x9805, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c982 Dual Port Server Cyclone +dw 0x7646, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3cSOHO100-TX Hurricane +dw 0x5055, IS_CYCLONE or EEPROM_8BIT or HAS_HWCKSM ; 3c555 Laptop Hurricane +dw 0x6055, IS_TORNADO or HAS_NWAY or EEPROM_8BIT or HAS_CB_FNS or INVERT_MII_PWR or HAS_HWCKSM ; 3c556 Laptop Tornado +dw 0x6056, IS_TORNADO or HAS_NWAY or EEPROM_OFFSET or HAS_CB_FNS or INVERT_MII_PWR or HAS_HWCKSM ; 3c556B Laptop Hurricane +dw 0x5b57, IS_BOOMERANG or HAS_MII or EEPROM_8BIT ; 3c575 [Megahertz] 10/100 LAN CardBus +dw 0x5057, IS_BOOMERANG or HAS_MII or EEPROM_8BIT ; 3c575 Boomerang CardBus +dw 0x5157, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFE575BT Cyclone CardBus +dw 0x5257, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or MAX_COLLISION_RESET or HAS_HWCKSM ; 3CCFE575CT Tornado CardBus +dw 0x6560, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFE656 Cyclone CardBus +dw 0x6562, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFEM656B Cyclone+Winmodem CardBus +dw 0x6564, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or MAX_COLLISION_RESET or HAS_HWCKSM ; 3CXFEM656C Tornado+Winmodem CardBus +dw 0x4500, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c450 HomePNA Tornado +dw 0x9201, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c920 Tornado +dw 0x1201, IS_TORNADO or HAS_HWCKSM or HAS_NWAY ; 3c982 Hydra Dual Port A +dw 0x1202, IS_TORNADO or HAS_HWCKSM or HAS_NWAY ; 3c982 Hydra Dual Port B +dw 0x9056, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE ; 3c905B-T4 +dw 0x9210, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c920B-EMB-WNM Tornado +HW_VERSIONS_SIZE = $ - hw_versions + +include_debug_strings ; All data wich FDO uses will be included here + +section '.data' data readable writable align 16 ; place all uninitialized data place here + +VORTEX_LIST rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling +BOOMERANG_LIST rd MAX_DEVICES + + + + diff --git a/drivers/ethernet/R6040.asm b/drivers/ethernet/R6040.asm new file mode 100644 index 0000000000..7debf9ef8b --- /dev/null +++ b/drivers/ethernet/R6040.asm @@ -0,0 +1,1120 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; R6040 driver for KolibriOS ;; +;; ;; +;; based on R6040.c from linux ;; +;; ;; +;; Written by Asper (asper.85@mail.ru) ;; +;; and hidnplayr (hidnplayr@gmail.com) ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + + W_MAX_TIMEOUT = 0x0FFF ; max time out delay time + + TX_TIMEOUT = 6000 ; Time before concluding the transmitter is hung, in ms + + TX_RING_SIZE = 4 ; RING sizes must be a power of 2 + RX_RING_SIZE = 4 + + RX_BUF_LEN_IDX = 3 ; 0==8K, 1==16K, 2==32K, 3==64K + +; Threshold is bytes transferred to chip before transmission starts. + + TX_FIFO_THRESH = 256 ; In bytes, rounded down to 32 byte units. + +; The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. + + RX_FIFO_THRESH = 4 ; Rx buffer level before first PCI xfer. + RX_DMA_BURST = 4 ; Maximum PCI burst, '4' is 256 bytes + TX_DMA_BURST = 4 + + + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + +; Operational parameters that usually are not changed. + +PHY1_ADDR = 1 ;For MAC1 +PHY2_ADDR = 3 ;For MAC2 +PHY_MODE = 0x3100 ;PHY CHIP Register 0 +PHY_CAP = 0x01E1 ;PHY CHIP Register 4 + +;************************************************************************** +; RDC R6040 Register Definitions +;************************************************************************** +MCR0 = 0x00 ;Control register 0 +MCR1 = 0x01 ;Control register 1 +MAC_RST = 0x0001 ;Reset the MAC +MBCR = 0x08 ;Bus control +MT_ICR = 0x0C ;TX interrupt control +MR_ICR = 0x10 ;RX interrupt control +MTPR = 0x14 ;TX poll command register +MR_BSR = 0x18 ;RX buffer size +MR_DCR = 0x1A ;RX descriptor control +MLSR = 0x1C ;Last status +MMDIO = 0x20 ;MDIO control register +MDIO_WRITE = 0x4000 ;MDIO write +MDIO_READ = 0x2000 ;MDIO read +MMRD = 0x24 ;MDIO read data register +MMWD = 0x28 ;MDIO write data register +MTD_SA0 = 0x2C ;TX descriptor start address 0 +MTD_SA1 = 0x30 ;TX descriptor start address 1 +MRD_SA0 = 0x34 ;RX descriptor start address 0 +MRD_SA1 = 0x38 ;RX descriptor start address 1 +MISR = 0x3C ;Status register +MIER = 0x40 ;INT enable register +MSK_INT = 0x0000 ;Mask off interrupts +RX_FINISH = 0x0001 ;RX finished +RX_NO_DESC = 0x0002 ;No RX descriptor available +RX_FIFO_FULL = 0x0004 ;RX FIFO full +RX_EARLY = 0x0008 ;RX early +TX_FINISH = 0x0010 ;TX finished +TX_EARLY = 0x0080 ;TX early +EVENT_OVRFL = 0x0100 ;Event counter overflow +LINK_CHANGED = 0x0200 ;PHY link changed +ME_CISR = 0x44 ;Event counter INT status +ME_CIER = 0x48 ;Event counter INT enable +MR_CNT = 0x50 ;Successfully received packet counter +ME_CNT0 = 0x52 ;Event counter 0 +ME_CNT1 = 0x54 ;Event counter 1 +ME_CNT2 = 0x56 ;Event counter 2 +ME_CNT3 = 0x58 ;Event counter 3 +MT_CNT = 0x5A ;Successfully transmit packet counter +ME_CNT4 = 0x5C ;Event counter 4 +MP_CNT = 0x5E ;Pause frame counter register +MAR0 = 0x60 ;Hash table 0 +MAR1 = 0x62 ;Hash table 1 +MAR2 = 0x64 ;Hash table 2 +MAR3 = 0x66 ;Hash table 3 +MID_0L = 0x68 ;Multicast address MID0 Low +MID_0M = 0x6A ;Multicast address MID0 Medium +MID_0H = 0x6C ;Multicast address MID0 High +MID_1L = 0x70 ;MID1 Low +MID_1M = 0x72 ;MID1 Medium +MID_1H = 0x74 ;MID1 High +MID_2L = 0x78 ;MID2 Low +MID_2M = 0x7A ;MID2 Medium +MID_2H = 0x7C ;MID2 High +MID_3L = 0x80 ;MID3 Low +MID_3M = 0x82 ;MID3 Medium +MID_3H = 0x84 ;MID3 High +PHY_CC = 0x88 ;PHY status change configuration register +PHY_ST = 0x8A ;PHY status register +MAC_SM = 0xAC ;MAC status machine +MAC_ID = 0xBE ;Identifier register + +MAX_BUF_SIZE = 0x600 ;1536 + +MBCR_DEFAULT = 0x012A ;MAC Bus Control Register +MCAST_MAX = 3 ;Max number multicast addresses to filter + +;Descriptor status +DSC_OWNER_MAC = 0x8000 ;MAC is the owner of this descriptor +DSC_RX_OK = 0x4000 ;RX was successfull +DSC_RX_ERR = 0x0800 ;RX PHY error +DSC_RX_ERR_DRI = 0x0400 ;RX dribble packet +DSC_RX_ERR_BUF = 0x0200 ;RX length exceeds buffer size +DSC_RX_ERR_LONG = 0x0100 ;RX length > maximum packet length +DSC_RX_ERR_RUNT = 0x0080 ;RX packet length < 64 byte +DSC_RX_ERR_CRC = 0x0040 ;RX CRC error +DSC_RX_BCAST = 0x0020 ;RX broadcast (no error) +DSC_RX_MCAST = 0x0010 ;RX multicast (no error) +DSC_RX_MCH_HIT = 0x0008 ;RX multicast hit in hash table (no error) +DSC_RX_MIDH_HIT = 0x0004 ;RX MID table hit (no error) +DSC_RX_IDX_MID_MASK = 3 ;RX mask for the index of matched MIDx + +;PHY settings +ICPLUS_PHY_ID = 0x0243 + +RX_INTS = RX_FIFO_FULL or RX_NO_DESC or RX_FINISH +TX_INTS = TX_FINISH +INT_MASK = RX_INTS or TX_INTS + +RX_BUF_LEN equ (8192 << RX_BUF_LEN_IDX) ; Size of the in-memory receive ring. + +IO_SIZE = 256 ; RDC MAC I/O Size +MAX_MAC = 2 ; MAX RDC MAC + + +virtual at 0 +x_head: + .status dw ? ;0-1 + .len dw ? ;2-3 + .buf dd ? ;4-7 + .ndesc dd ? ;8-B + .rev1 dd ? ;C-F + .vbufp dd ? ;10-13 + .vndescp dd ? ;14-17 + .skb_ptr dd ? ;18-1B + .rev2 dd ? ;1C-1F + .sizeof: +end virtual + + +virtual at ebx + + device: + + ETH_DEVICE + + .io_addr dd ? + + .cur_rx dw ? + .cur_tx dw ? + .last_tx dw ? + .phy_addr dw ? + .phy_mode dw ? + .mcr0 dw ? + .mcr1 dw ? + .switch_sig dw ? + + .pci_bus dd ? + .pci_dev dd ? + .irq_line db ? + + rb 3 ; dword alignment + + .tx_ring: rb (((x_head.sizeof*TX_RING_SIZE)+32) and 0xfffffff0) + .rx_ring: rb (((x_head.sizeof*RX_RING_SIZE)+32) and 0xfffffff0) + + .size = $ - device + +end virtual + + + +section '.flat' code readable align 16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 2,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax , [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base io addres of the PCI device + + PCI_find_io + +; We've found the io address, find IRQ now + + PCI_find_irq + + DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 + +; Ok, the eth_device structure is ready, let's probe the device + cli + + call probe ; this function will output in eax + test eax, eax + jnz .err_sti ; If an error occured, exit + + mov eax, [devices] ; Add the device structure to our device list + mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + mov [device.type], NET_TYPE_ETH + call NetRegDev + sti + + cmp eax, -1 + je .destroy + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 1,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 1,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + .err_sti: + sti + + .err: + stdcall KernelFree, ebx + + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + +macro mdio_write reg, val { + stdcall phy_read, [device.io_addr], [device.phy_addr], reg +} + +macro mdio_write reg, val { + stdcall phy_write, [device.io_addr], [devce.phy_addr], reg, val +} + + +align 4 +unload: + ; TODO: (in this particular order) + ; + ; - Stop the device + ; - Detach int handler + ; - Remove device from local list (RTL8139_LIST) + ; - call unregister function in kernel + ; - Remove all allocated structures and buffers the card used + + or eax,-1 + +ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; probe: enables the device (if it really is RTL8139) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +probe: + DEBUGF 2,"Probing R6040 device\n" + + PCI_make_bus_master + + ; If PHY status change register is still set to zero + ; it means the bootloader didn't initialize it + + set_io 0 + set_io PHY_CC + in ax, dx + test ax, ax + jnz @f + mov ax, 0x9F07 + out dx, ax + @@: + + call read_mac + + ; Some bootloaders/BIOSes do not initialize MAC address, warn about that + and eax, 0xFF + or eax, dword [device.mac] + test eax, eax + jnz @f + DEBUGF 2, "ERROR: MAC address not initialized!\n" + + @@: + ; Init RDC private data + mov [device.mcr0], 0x1002 + ;mov [private.phy_addr], 1 ; Asper: Only one network card is supported now. + mov [device.switch_sig], 0 + + ; Check the vendor ID on the PHY, if 0xFFFF assume none attached + stdcall phy_read, 1, 2 + cmp ax, 0xFFFF + jne @f + DEBUGF 2, "Failed to detect an attached PHY\n" ;, generating random" + mov eax, -1 + ret + @@: + + ; Set MAC address + call init_mac_regs + + ; Initialize and alloc RX/TX buffers + call init_txbufs + call init_rxbufs + + ; Read the PHY ID + mov [device.phy_mode], 0x8000 + stdcall phy_read, 0, 2 + mov [device.switch_sig], ax + cmp ax, ICPLUS_PHY_ID + jne @f + stdcall phy_write, 29, 31, 0x175C ; Enable registers + jmp .phy_readen + @@: + + ; PHY Mode Check + movzx eax, [device.phy_addr] + stdcall phy_write, eax, 4, PHY_CAP + stdcall phy_write, eax, 0, PHY_MODE + + if PHY_MODE = 0x3100 + call phy_mode_chk + mov [device.phy_mode], ax + jmp .phy_readen + end if + + if not (PHY_MODE and 0x0100) + mov [device.phy_mode], 0 + end if + + .phy_readen: + + ; Set duplex mode + mov ax, [device.phy_mode] + or [device.mcr0], ax + + ; improve performance (by RDC guys) + stdcall phy_read, 30, 17 + or ax, 0x4000 + stdcall phy_write, 30, 17, eax + + stdcall phy_read, 30, 17 + and ax, not 0x2000 + stdcall phy_write, 30, 17, eax + + stdcall phy_write, 0, 19, 0x0000 + stdcall phy_write, 0, 30, 0x01F0 + + ; Initialize all Mac registers + call init_mac_regs + + + +align 4 +reset: + + DEBUGF 2,"Resetting R6040\n" + + ; Mask off Interrupt + xor ax, ax + set_io 0 + set_io MIER + out dx, ax + + +; attach int handler + + movzx eax, [device.irq_line] + DEBUGF 2,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 2,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + + + ;Reset RDC MAC + mov eax, MAC_RST + set_io 0 + set_io MCR1 + out dx, ax + + mov ecx, 2048 ;limit + .read: + in ax, dx + test ax, 0x1 + jnz @f + dec ecx + test ecx, ecx + jnz .read + @@: + ;Reset internal state machine + mov ax, 2 + set_io MAC_SM + out dx, ax + + xor ax, ax + out dx, ax + + mov esi, 5 + stdcall Sleep + + ;MAC Bus Control Register + mov ax, MBCR_DEFAULT + set_io 0 + set_io MBCR + out dx, ax + + ;Buffer Size Register + mov ax, MAX_BUF_SIZE + set_io MR_BSR + out dx, ax + + ;Write TX ring start address + lea eax, [device.tx_ring] + GetRealAddr + set_io MTD_SA0 + out dx, ax + shr eax, 16 + set_io MTD_SA1 + out dx, ax + + ;Write RX ring start address + lea eax, [device.rx_ring] + GetRealAddr + set_io MRD_SA0 + out dx, ax + shr eax, 16 + set_io MRD_SA1 + out dx, ax + + ;Set interrupt waiting time and packet numbers + xor ax, ax + set_io MT_ICR + out dx, ax + + ;Enable interrupts + mov ax, INT_MASK + set_io MIER + out dx, ax + + ;Enable TX and RX + mov ax, [device.mcr0] + or ax, 0x0002 + set_io 0 + out dx, ax + + ;Let TX poll the descriptors + ;we may got called by tx_timeout which has left + ;some unset tx buffers + xor ax, ax + inc ax + set_io 0 + set_io MTPR + out dx, ax + +; Set the mtu, kernel will be able to send now + mov [device.mtu], 1514 + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + + DEBUGF 1,"Reset ok\n" + xor eax, eax + ret + + + +align 4 +init_txbufs: + + DEBUGF 1,"Init TxBufs\n" + + lea esi, [device.tx_ring] + lea eax, [device.tx_ring + x_head.sizeof] + GetRealAddr + mov ecx, TX_RING_SIZE + + .next_desc: + mov [esi + x_head.ndesc], eax + mov [esi + x_head.skb_ptr], 0 + mov [esi + x_head.status], DSC_OWNER_MAC + + add eax, x_head.sizeof + add esi, x_head.sizeof + + dec ecx + jnz .next_desc + + lea eax, [device.tx_ring] + GetRealAddr + mov [device.tx_ring + x_head.sizeof*(TX_RING_SIZE - 1) + x_head.ndesc], eax + + ret + + + +align 4 +init_rxbufs: + + DEBUGF 1,"Init RxBufs\n" + + lea esi, [device.rx_ring] + lea eax, [device.rx_ring + x_head.sizeof] + GetRealAddr + mov edx, eax + mov ecx, RX_RING_SIZE + + .next_desc: + mov [esi + x_head.ndesc], edx + + push esi ecx + stdcall KernelAlloc, MAX_BUF_SIZE + pop ecx esi + + mov [esi + x_head.skb_ptr], eax + GetRealAddr + mov [esi + x_head.buf], eax + mov [esi + x_head.status], DSC_OWNER_MAC + + add edx, x_head.sizeof + add esi, x_head.sizeof + + dec ecx + jnz .next_desc + + ; complete the ring by linking the last to the first + + lea eax, [device.rx_ring] + GetRealAddr + mov [device.rx_ring + x_head.sizeof*(RX_RING_SIZE - 1) + x_head.ndesc], eax + + ret + + + +align 4 +phy_mode_chk: + + DEBUGF 1,"Checking PHY mode\n" + + ; PHY Link Status Check + movzx eax, [device.phy_addr] + stdcall phy_read, eax, 1 + test eax, 0x4 + jz .ret_0x8000 + + ; PHY Chip Auto-Negotiation Status + movzx eax, [device.phy_addr] + stdcall phy_read, eax, 1 + test eax, 0x0020 + jnz .auto_nego + + ; Force Mode + movzx eax, [device.phy_addr] + stdcall phy_read, eax, 0 + test eax, 0x100 + jnz .ret_0x8000 + + .auto_nego: + ; Auto Negotiation Mode + movzx eax, [device.phy_addr] + stdcall phy_read, eax, 5 + mov ecx, eax + movzx eax, [device.phy_addr] + stdcall phy_read, eax, 4 + and eax, ecx + test eax, 0x140 + jnz .ret_0x8000 + + xor eax, eax + ret + + .ret_0x8000: + mov eax, 0x8000 + ret + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +align 4 +transmit: + DEBUGF 2,"\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] + mov eax, [esp+4] + DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp+8], 1514 + ja .fail + cmp dword [esp+8], 60 + jb .fail + + movzx edi, [device.cur_tx] + shl edi, 5 + add edi, ebx + add edi, device.tx_ring - ebx + + DEBUGF 2,"TX buffer status: 0x%x\n", [edi + x_head.status]:4 + + test [edi + x_head.status], DSC_OWNER_MAC ; check if buffer is available + jnz .wait_to_send + + .do_send: + + DEBUGF 2,"Sending now\n" + + mov eax, [esp+4] + mov [edi + x_head.skb_ptr], eax + GetRealAddr + mov [edi + x_head.buf], eax + mov ecx, [esp+8] + mov [edi + x_head.len], cx + mov [edi + x_head.status], DSC_OWNER_MAC + + ; Trigger the MAC to check the TX descriptor + mov ax, 0x01 + set_io 0 + set_io MTPR + out dx, ax + + inc [device.cur_tx] + and [device.cur_tx], TX_RING_SIZE - 1 + xor eax, eax + +; Update stats + inc [device.packets_tx] + mov eax, [esp+8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + + ret 8 + + .wait_to_send: + + DEBUGF 2,"Waiting for TX buffer\n" + + call GetTimerTicks ; returns in eax + lea edx, [eax + 100] + .l2: + test [edi + x_head.status], DSC_OWNER_MAC + jz .do_send + mov esi, 10 + call Sleep + call GetTimerTicks + cmp edx, eax + jb .l2 + + DEBUGF 1,"Send timeout\n" + xor eax, eax + dec eax + .fail: + DEBUGF 1,"Send failed\n" + ret 8 + + + + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service + +; Find pointer of device wich made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + + set_io 0 + set_io MISR + in ax, dx + out dx, ax ; send it back to ACK + test ax, ax + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) + + +; At this point, test for all possible reasons, and handle accordingly + + .got_it: + + DEBUGF 1,"Device: %x Status: %x ", ebx, ax + + push ax + + test word [esp], RX_FINISH + jz .no_RX + + push ebx + .more_RX: + pop ebx + + ; Find the current RX descriptor + + movzx edx, [device.cur_rx] + shl edx, 5 + lea edx, [device.rx_ring + edx] + + ; Check the descriptor status + + mov cx, [edx + x_head.status] + test cx, DSC_OWNER_MAC + jnz .no_RX + + DEBUGF 2,"packet status=0x%x\n", cx + + test cx, DSC_RX_ERR ; Global error status set + jnz .no_RX + + ; Packet successfully received + + movzx ecx, [edx + x_head.len] + and ecx, 0xFFF + sub ecx, 4 ; Do not count the CRC + +; Update stats + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + inc dword [device.packets_rx] + + ; Push packet size and pointer, kernel will need it.. + + push ebx + push .more_RX + + push ecx + push [edx + x_head.skb_ptr] + + DEBUGF 2,"packet ptr=0x%x\n", [edx + x_head.skb_ptr] + + ; reset the RX descriptor + + push edx + stdcall KernelAlloc, MAX_BUF_SIZE + pop edx + mov [edx + x_head.skb_ptr], eax + GetRealAddr + mov [edx + x_head.buf], eax + mov [edx + x_head.status], DSC_OWNER_MAC + + ; Use next descriptor next time + + inc [device.cur_rx] + and [device.cur_rx], RX_RING_SIZE - 1 + + ; At last, send packet to kernel + + jmp Eth_input + + + .no_RX: + + test word [esp], TX_FINISH + jz .no_TX + + .loop_tx: + movzx edi, [device.last_tx] + shl edi, 5 + lea edi, [device.tx_ring + edi] + + test [edi + x_head.status], DSC_OWNER_MAC + jnz .no_TX + + cmp [edi + x_head.skb_ptr], 0 + je .no_TX + + DEBUGF 2,"Freeing buffer 0x%x\n", [edi + x_head.skb_ptr] + + push [edi + x_head.skb_ptr] + mov [edi + x_head.skb_ptr], 0 + call KernelFree + + inc [device.last_tx] + and [device.last_tx], TX_RING_SIZE - 1 + + jmp .loop_tx + + .no_TX: + pop ax + + pop edi esi ebx + + ret + + + + +align 4 +init_mac_regs: + + DEBUGF 2,"initializing MAC regs\n" + + ; MAC operation register + mov ax, 1 + set_io 0 + set_io MCR1 + out dx, ax + ; Reset MAC + mov ax, 2 + set_io MAC_SM + out dx, ax + ; Reset internal state machine + xor ax, ax + out dx, ax + mov esi, 5 + stdcall Sleep + + call read_mac + + ret + + + + +; Read a word data from PHY Chip + +align 4 +proc phy_read stdcall, phy_addr:dword, reg:dword + + DEBUGF 2,"PHY read, addr=0x%x reg=0x%x\n", [phy_addr]:8, [reg]:8 + + mov eax, [phy_addr] + shl eax, 8 + add eax, [reg] + add eax, MDIO_READ + set_io 0 + set_io MMDIO + out dx, ax + + ;Wait for the read bit to be cleared. + mov ecx, 2048 ;limit + .read: + in ax, dx + test ax, MDIO_READ + jz @f + dec ecx + jnz .read + @@: + + set_io MMRD + in ax, dx + and eax, 0xFFFF + + DEBUGF 2,"PHY read, val=0x%x\n", eax:4 + + ret + +endp + + + + +; Write a word data to PHY Chip + +align 4 +proc phy_write stdcall, phy_addr:dword, reg:dword, val:dword + + DEBUGF 2,"PHY write, addr=0x%x reg=0x%x val=0x%x\n", [phy_addr]:8, [reg]:8, [val]:8 + + mov eax, [val] + set_io 0 + set_io MMWD + out dx, ax + + ;Write the command to the MDIO bus + + mov eax, [phy_addr] + shl eax, 8 + add eax, [reg] + add eax, MDIO_WRITE + set_io MMDIO + out dx, ax + + ;Wait for the write bit to be cleared. + mov ecx, 2048 ;limit + .write: + in ax, dx + test ax, MDIO_WRITE + jz @f + dec ecx + jnz .write + @@: + + DEBUGF 2,"PHY write ok\n" + + ret +endp + + + +align 4 +read_mac: + + DEBUGF 2,"Reading MAC: " + + mov cx, 3 + lea edi, [device.mac] + set_io 0 + set_io MID_0L + .mac: + in ax, dx + stosw + inc dx + inc dx + dec cx + jnz .mac + + DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[edi-6]:2, [edi-5]:2, [edi-4]:2, [edi-3]:2, [edi-2]:2, [edi-1]:2 + + ret + + + + +; End of code + +section '.data' data readable writable align 16 ; place all uninitialized data place here +align 4 ; Place all initialised data here + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'R6040',0 ; max 16 chars include zero + +include_debug_strings ; All data wich FDO uses will be included here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + diff --git a/drivers/ethernet/RTL8029.asm b/drivers/ethernet/RTL8029.asm new file mode 100644 index 0000000000..e52b9650da --- /dev/null +++ b/drivers/ethernet/RTL8029.asm @@ -0,0 +1,1203 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; RTL8029/ne2000 driver for KolibriOS ;; +;; ;; +;; based on RTL8029.asm driver for menuetos ;; +;; and realtek8029.asm for SolarOS by Eugen Brasoveanu ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; with help from CleverMouse ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +virtual at ebx + + device: + + ETH_DEVICE + + .io_addr dd ? + .irq_line db ? + .pci_bus dd ? + .pci_dev dd ? + + .flags db ? + .vendor db ? + + .memsize db ? + .rx_start db ? + .tx_start db ? + .bmem dd ? + .rmem dd ? + + .size = $ - device + +end virtual + + +public START +public service_proc +public version + + P0_COMMAND = 0x00 + P0_PSTART = 0x01 + P0_PSTOP = 0x02 + P0_BOUND = 0x03 + P0_TSR = 0x04 + P0_TPSR = 0x04 + P0_TBCR0 = 0x05 + P0_TBCR1 = 0x06 + P0_ISR = 0x07 + P0_RSAR0 = 0x08 + P0_RSAR1 = 0x09 + P0_RBCR0 = 0x0A + P0_RBCR1 = 0x0B + P0_RSR = 0x0C + P0_RCR = 0x0C + P0_TCR = 0x0D + P0_DCR = 0x0E + P0_IMR = 0x0F + + P1_COMMAND = 0x00 + P1_PAR0 = 0x01 + P1_PAR1 = 0x02 + P1_PAR2 = 0x03 + P1_PAR3 = 0x04 + P1_PAR4 = 0x05 + P1_PAR5 = 0x06 + P1_CURR = 0x07 + P1_MAR0 = 0x08 + + CMD_PS0 = 0x00 ; Page 0 select + CMD_PS1 = 0x40 ; Page 1 select + CMD_PS2 = 0x80 ; Page 2 select + CMD_RD2 = 0x20 ; Remote DMA control + CMD_RD1 = 0x10 + CMD_RD0 = 0x08 + CMD_TXP = 0x04 ; transmit packet + CMD_STA = 0x02 ; start + CMD_STP = 0x01 ; stop + + CMD_RDMA_READ = 001b shl 3 + CMD_RDMA_WRITE = 010b shl 3 + CMD_RDMA_SEND_PACKET = 011b shl 3 + CMD_RDMA_ABORT = 100b shl 3 ; really is 1xx, Abort/Complete Remote DMA +; RDMA_MASK = 111b shl 3 ; internal, mask + + RCR_MON = 0x20 ; monitor mode + + DCR_FT1 = 0x40 + DCR_LS = 0x08 ; Loopback select + DCR_WTS = 0x01 ; Word transfer select + + ISR_PRX = 0x01 ; successful recv + ISR_PTX = 0x02 ; successful xmit + ISR_RXE = 0x04 ; receive error + ISR_TXE = 0x08 ; transmit error + ISR_OVW = 0x10 ; Overflow + ISR_CNT = 0x20 ; Counter overflow + ISR_RDC = 0x40 ; Remote DMA complete + ISR_RST = 0x80 ; reset + + IRQ_MASK = ISR_PRX ;+ ISR_PTX ;+ ISR_RDC + ISR_PTX + ISR_TXE + + RSTAT_PRX = 1 shl 0 ; successful recv + RSTAT_CRC = 1 shl 1 ; CRC error + RSTAT_FAE = 1 shl 2 ; Frame alignment error + RSTAT_OVER = 1 shl 3 ; FIFO overrun + + TXBUF_SIZE = 6 + RXBUF_END = 32 + PAGE_SIZE = 256 + + ETH_ZLEN = 60 + ETH_FRAME_LEN = 1514 + + FLAG_PIO = 1 shl 0 + FLAG_16BIT = 1 shl 1 + + VENDOR_NONE = 0 + VENDOR_WD = 1 + VENDOR_NOVELL = 2 + VENDOR_3COM = 3 + + NE_ASIC = 0x10 + NE_RESET = 0x0F ; Used to reset card + NE_DATA = 0x00 ; Used to read/write NIC mem + + MEM_8k = 32 + MEM_16k = 64 + MEM_32k = 128 + + ISA_MAX_ADDR = 0x400 + + + +section '.flat' code readable align 16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; proc START +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + .entry: + DEBUGF 2,"Registering %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + .fail: + .exit: + xor eax, eax + ret + +endp + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; proc SERVICE_PROC +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + ;--------------- + cmp eax, 0 ;SRV_GETVERSION + jne @F ;--------------- + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: ;--------- + cmp eax, 1 ;SRV_HOOK + jne @F ;--------- + + DEBUGF 2,"Checking if device is already listed..\n" + + mov eax, [IOCTL.input] + + cmp [IOCTL.inp_size], 3 + jb .fail + cmp byte [eax], 1 + je .pci + + cmp [IOCTL.inp_size], 4 + jb .fail + cmp byte [eax], 0 + je .isa + + jmp .fail + + .pci: + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice_pci + + mov ax, [eax+1] ; get the pci bus and device numbers + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + + .firstdevice_pci: + call create_new_struct + + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base io addres of the PCI device + + PCI_find_io + +; We've found the io address, find IRQ now + + PCI_find_irq + + jmp .hook + + .isa: + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice_isa + mov al, [eax+3] + movzx edi, word [eax+1] + .nextdevice_isa: + mov ebx, [esi] + cmp edi, [device.io_addr] + jne .maybenext + cmp al, [device.irq_line] + je find_device_num + .maybenext: + add esi, 4 + loop .nextdevice_isa + + + + .firstdevice_isa: + call create_new_struct + + mov eax, [IOCTL.input] + movzx ecx, word [eax+1] + mov [device.io_addr], ecx + mov cl, [eax+3] + mov [device.irq_line], cl + + .hook: + + DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 + + call probe ; this function will output in eax + test eax, eax + jnz .err ; If an error occured, exit + + mov eax, [devices] + mov [device_list+4*eax], ebx + inc [devices] + + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + jz .err + ret + + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 1,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 1,"Kernel says: %u\n", eax + ret + + .err: + DEBUGF 1,"Failed, removing device structure\n" + stdcall KernelFree, ebx + + jmp .fail + +;------------------------------------------------------ + @@: +.fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +create_new_struct: + + cmp [devices], MAX_DEVICES + jae .fail + + allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + + ret + + .fail: + add esp, 4 ; return to caller of 'hook' + or eax, -1 + ret + +find_device_num: + + DEBUGF 1,"Trying to find device number of already registered device\n" + mov ebx, eax + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 1,"Kernel says: %u\n", eax + ret + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + +unload: ; TODO + or eax, -1 + ret + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; probe: enables the device and clears the rx buffer +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +probe: + mov [device.vendor], VENDOR_NONE + mov [device.bmem], 0 + + DEBUGF 2,"Trying 16-bit mode\n" + + mov [device.flags], FLAG_16BIT + FLAG_PIO + mov [device.memsize], MEM_32k + mov [device.tx_start], 64 + mov [device.rx_start], TXBUF_SIZE + 64 + + set_io 0 + set_io P0_DCR + mov al, DCR_WTS + DCR_FT1 + DCR_LS ; word transfer select + + out dx, al + + set_io P0_PSTART + mov al, MEM_16k + out dx, al + + set_io P0_PSTOP + mov al, MEM_32k + out dx, al + + mov esi, my_service + mov di, 16384 + mov cx, 14 + call PIO_write + + mov si, 16384 + mov cx, 14 + sub esp, 16 + mov edi, esp + call PIO_read + + mov esi, esp + add esp, 16 + mov edi, my_service + mov ecx, 13 + repe cmpsb + je ep_set_vendor + + DEBUGF 2,"16-bit mode failed\n" + DEBUGF 2,"Trying 8-bit mode\n" + + mov [device.flags], FLAG_PIO + mov [device.memsize], MEM_16k + mov [device.tx_start], 32 + mov [device.rx_start], TXBUF_SIZE + 32 + + set_io NE_ASIC + NE_RESET + in al, dx + out dx, al + + in al, 0x84 + + set_io P0_COMMAND + mov al, CMD_RD2 + CMD_STP + out dx, al + + set_io P0_RCR + mov al, RCR_MON + out dx, al + + set_io P0_DCR + mov al, DCR_FT1 + DCR_LS + out dx, al + + set_io P0_PSTART + mov al, MEM_8k + out dx, al + + set_io P0_PSTOP + mov al, MEM_16k + out dx, al + + mov esi, my_service + mov di, 8192 + mov cx, 14 + call PIO_write + + mov si, 8192 + mov cx, 14 + sub esp, 16 + mov edi, esp + call PIO_read + + mov esi, my_service + mov edi, esp + add esp, 16 + mov ecx, 13 + repe cmpsb + je ep_set_vendor + + DEBUGF 2,"This is not a valid ne2000 device!\n" + or eax, -1 + ret + + +ep_set_vendor: + + DEBUGF 2,"Mode ok\n" + + cmp [device.io_addr], ISA_MAX_ADDR + jbe .isa + + DEBUGF 2,"Card is using PCI bus\n" + + mov [device.vendor], VENDOR_NOVELL ;;; FIXME + jmp ep_check_have_vendor + + .isa: + DEBUGF 2,"Card is using ISA bus\n" + + mov [device.vendor], VENDOR_NOVELL + +ep_check_have_vendor: + + + mov al, [device.vendor] + cmp al, VENDOR_NONE +; je exit + + cmp al, VENDOR_3COM + je reset + + mov eax, [device.bmem] + mov [device.rmem], eax + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; reset: Place the chip into a virgin state +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +reset: + DEBUGF 2,"Resetting device\n" + +; attach int handler + movzx eax, [device.irq_line] + DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + +; Stop card + DMA + set_io 0 +; set_io P0_COMMAND + mov al, CMD_PS0 + CMD_RDMA_ABORT + CMD_STP + out dx, al + +; initialize DCR + set_io P0_DCR + mov al, DCR_FT1 + DCR_LS + test [device.flags], FLAG_16BIT + jz @f + or al, DCR_WTS ; word transfer select + @@: + out dx, al + +; clear remote bytes count + set_io P0_RBCR0 + xor al, al + out dx, al + + set_io P0_RBCR1 + out dx, al + +; initialize Receive configuration register (until all init is done) + set_io P0_RCR + mov al, 0x20 ; monitor mode + out dx, al + +; transmit configuration register to monitor mode (until all ini is done) + set_io P0_TCR + mov al, 2 ; internal loopback + out dx, al + +; clear interupt status + set_io P0_ISR + mov al, 0xff + out dx, al + +; clear IRQ mask ;;;;; CHECKME ;;;;; + set_io P0_IMR + xor al, al + out dx, al + +; set transmit pointer + set_io P0_TPSR + mov al, [device.tx_start] + out dx, al + +; set pagestart pointer + set_io P0_PSTART + mov al, [device.rx_start] + out dx, al + +; set pagestop pointer + set_io P0_PSTOP + mov al, [device.memsize] + out dx, al + +; set boundary pointer + set_io P0_BOUND + mov al, [device.memsize] + dec al + out dx, al + +; set curr pointer + set_io P0_COMMAND + mov al, CMD_PS1 ;+ CMD_RD2 + CMD_STP ; page 1, stop mode + out dx, al + + set_io P1_CURR + mov al, [device.rx_start] + out dx, al + + set_io P0_COMMAND + mov al, CMD_PS0 ;+ CMD_RD2 + CMD_STA ; go to page 0, start mode + out dx, al + +; Read MAC address and set it to registers + call read_mac + push .macret + sub esp, 6 + lea esi, [device.mac] + mov edi, esp + movsd + movsw + jmp write_mac + .macret: + +; set IRQ mask + set_io 0 + set_io P0_IMR + mov al, IRQ_MASK + out dx, al + +; start mode + set_io P0_COMMAND + mov al, CMD_STA + out dx, al + +; clear transmit control register + set_io P0_TCR + xor al, al ; no loopback + out dx, al + +; set receive control register ;;;; + set_io P0_RCR + mov al, 4 ; accept broadcast + out dx, al + +; clear packet/byte counters + xor eax, eax + lea edi, [device.bytes_tx] + mov ecx, 6 + rep stosd + +; Set the mtu, kernel will be able to send now + mov [device.mtu], ETH_FRAME_LEN + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + +; Indicate that we have successfully reset the card + xor eax, eax + DEBUGF 2,"Done!\n" + + ret + + + +;*************************************************************************** +; Function +; transmit +; buffer in [esp+4], size in [esp+8], pointer to device struct in ebx +;*************************************************************************** + +align 4 +transmit: + + mov esi, [esp + 4] + mov ecx, [esp + 8] + DEBUGF 2,"Transmitting packet, buffer:%x, size:%u\n",esi, ecx + DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [esi+0]:2,[esi+1]:2,[esi+2]:2,[esi+3]:2,[esi+4]:2,[esi+5]:2,[esi+6]:2,[esi+7]:2,[esi+8]:2,[esi+9]:2,[esi+10]:2,[esi+11]:2,[esi+13]:2,[esi+12]:2 + + cmp ecx, ETH_FRAME_LEN + ja .err ; packet is too long + cmp ecx, ETH_ZLEN + jb .err ; packet is too short + + movzx edi, [device.tx_start] + shl edi, 8 + push cx + call PIO_write + pop cx + + set_io 0 +; set_io P0_COMMAND + mov al, CMD_PS0 + CMD_RD2 + CMD_STA + out dx, al + + set_io P0_TPSR + mov al, [device.tx_start] + out dx, al + + set_io P0_TBCR0 + mov al, cl + out dx, al + + set_io P0_TBCR1 + mov al, ch + out dx, al + + set_io P0_COMMAND + mov al, CMD_PS0 + CMD_TXP + CMD_RD2 + CMD_STA + out dx, al + + DEBUGF 2," - Packet Sent!\n" + + inc [device.packets_tx] + mov eax, [esp + 8] ; Get packet size in eax + + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + + stdcall KernelFree, [esp+4] + xor eax, eax + ret 8 + +.err: + DEBUGF 2," - Error!\n" + + or eax, -1 + stdcall KernelFree, [esp+4] + ret 8 + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; Interrupt handler +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service + +; find pointer of device wich made INT occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + + set_io 0 +; set_io P0_COMMAND + mov al, CMD_PS0 + out dx, al + + set_io P0_ISR + in al, dx + test al, al + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret + + .got_it: + + DEBUGF 1,"Device=%x status=%x\n", ebx, eax:2 + + push ebx + + test al, ISR_PRX ; packet received ok ? + jz .no_rx + + test [device.flags], FLAG_PIO + jz .no_rx ; FIXME: Only PIO mode supported for now + +; + + pushd .no_rx + +; allocate a buffer + + stdcall KernelAlloc, ETH_FRAME_LEN + test eax, eax + jz .fail_2 + pushd 0 + push eax + +; read offset for current packet from device + + set_io 0 + set_io P0_BOUND ; boundary ptr is offset to next packet we need to read. + in al, dx + inc al + + cmp al, [device.memsize] + jb @f + mov al, [device.rx_start] + @@: + mov ch, al + + set_io P0_COMMAND + mov al, CMD_PS1 + out dx, al + + set_io P1_CURR + in al, dx ; get current page in cl + mov cl, al + + set_io P1_COMMAND + mov al, CMD_PS0 + out dx, al + + cmp cl, [device.memsize] + jb @f + mov cl, [device.rx_start] + @@: + + cmp cl, ch + je .fail + + movzx esi, ch ; we are using 256 byte pages + shl esi, 8 ; esi now holds the offset for current packet + +; Get packet header in eax + + sub esp, 4 ; reserve 4 bytes on stack to put packet header in + mov edi, esp + mov cx, 4 + call PIO_read + + mov ecx, [esp] ; ecx now contains packet header + +; check if packet is ok + + test ecx, RSTAT_PRX + jz .fail_3 + +; calculate packet length in ecx + + shr ecx, 16 + sub ecx, 4 ; CRC doesnt count as data byte + mov [esp + 4 + 4], ecx + +; check if packet size is ok + + cmp ecx, ETH_ZLEN + jb .fail_3 + cmp ecx, ETH_FRAME_LEN + ja .fail_3 + +; update stats + + DEBUGF 2,"Received %u bytes\n", ecx + + add dword[device.bytes_rx], ecx + adc dword[device.bytes_rx + 4], 0 + inc [device.packets_rx] + +; update read and write pointers + + add esi, 4 + mov edi, [esp + 4] + +; now check if we can read all data at once (if we cross the end boundary, we need to wrap back to the beginning) + + xor eax, eax + mov ah, [device.memsize] + sub eax, esi + cmp ecx, eax ; eax = number of bytes till end of buffer, ecx = bytes we need to read + jbe .no_wrap + + DEBUGF 2,"WRAP!\n" + +; Read first part + + sub ecx, eax + push ecx + mov ecx, eax + + call PIO_read ; Read the data + +; update pointers + + add edi, ecx + pop ecx + + movzx esi, [device.rx_start] + shl esi, 8 + +; now read second part (or only part) + + .no_wrap: + call PIO_read ; Read the data + +; update boundary pointer + + pop eax + mov al, ah + cmp al, [device.rx_start] + jne @f + mov al, [device.memsize] + @@: + + set_io 0 + set_io P0_BOUND + dec al + out dx, al + +; now send the data to the kernel + + jmp Eth_input + + .fail_3: + add esp, 4 + .fail: + add esp, 8 + .fail_2: + + + .no_rx: + pop ebx + DEBUGF 2,"done\n" + + set_io 0 + set_io P0_ISR + mov al, 0xff + out dx, al + + pop edi esi ebx + + ret + + + + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Write MAC address ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +write_mac: ; in: mac on stack (6 bytes) + + DEBUGF 1,"Writing MAC\n" + + set_io 0 + mov al, CMD_PS1; + CMD_RD2 + CMD_STP + out dx, al + + set_io P1_PAR0 + mov esi, esp + mov cx, 6 + @@: + lodsb + out dx, al + inc dx + loopw @r + + add esp, 6 + +; Notice this procedure does not ret, but continues to read_mac instead. + +;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Read MAC address ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;; + +read_mac: + + DEBUGF 1,"Reading MAC\n" + + xor esi, esi + mov cx, 16 + sub esp, 16 + mov edi, esp + call PIO_read + + mov esi, esp + add esp, 16 + lea edi, [device.mac] + mov ecx, 6 + .loop: + movsb + test [device.flags], FLAG_16BIT + jz .8bit + inc esi + .8bit: + loop .loop + + DEBUGF 1,"MAC=%x-%x-%x-%x-%x-%x\n",\ + [device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + + ret + + +;*************************************************************************** +; +; PIO_read +; +; Description +; Read a frame from the ethernet card via Programmed I/O +; src in si +; cnt in cx +; dst in edi +;*************************************************************************** +PIO_read: + + DEBUGF 1,"PIO Read from %x to %x, %u bytes ", si, edi, cx + +; start DMA + set_io 0 +; set_io P0_COMMAND + mov al, CMD_RD2 + CMD_STA + out dx, al + +; set length of data we're interested in + set_io P0_RBCR0 + mov al, cl + out dx, al + + set_io P0_RBCR1 + mov al, ch + out dx, al + +; set offset of what we want to read + set_io P0_RSAR0 + mov ax, si + out dx, al + + set_io P0_RSAR1 + shr ax, 8 + out dx, al + +; start DMA read + set_io P0_COMMAND + mov al, CMD_RD0 + CMD_STA + out dx, al + + set_io NE_ASIC + + test [device.flags], FLAG_16BIT + jz .8bits + + DEBUGF 1,"(16-bit mode)\n" + + shr cx, 1 ; note that if the number was odd, carry flag will be set + pushf + + .16bits: + in ax, dx + stosw + loopw .16bits + + inc cx + popf + jnc .done + jmp .8bits_ + + .8bits: + DEBUGF 1,"(8-bit mode)\n" + + .8bits_: + in al, dx + stosb + loopw .8bits_ + + + .done: +; set_io 0 +; set_io P0_ISR +; +; .dmawait: ; Wait for Remote DMA Complete +; in al, dx +; test al, ISR_RDC +; jz .dmawait +; and al, not ISR_RDC +; out dx, al ; clear the bit + + ret + + + + +;*************************************************************************** +; +; PIO_write +; +; Description +; writes a frame to the ethernet card via Programmed I/O +; dst in di +; cnt in cx +; src in esi +;*************************************************************************** +PIO_write: + + DEBUGF 1,"Eth PIO Write from %x to %x, %u bytes ", esi, di, cx + + set_io 0 +; set_io P0_COMMAND + mov al, CMD_RD2 + CMD_STA + out dx, al + + set_io P0_ISR + mov al, ISR_RDC + out dx, al + + set_io P0_RBCR0 + mov al, cl + out dx, al + + set_io P0_RBCR1 + mov al, ch + out dx, al + + mov ax, di + set_io P0_RSAR0 + out dx, al + shr ax, 8 + set_io P0_RSAR1 + out dx, al + + set_io P0_COMMAND + mov al, CMD_RD1 + CMD_STA + out dx, al + + set_io NE_ASIC + test [device.flags], FLAG_16BIT + jz .8_bit + + DEBUGF 1,"(16-bit mode)\n" + + shr cx, 1 ; note that if the number was odd, carry flag will be set + pushf ; save the flags for later + + .16bit: + lodsw + out dx, ax + loopw .16bit + + popf + jnc .done + inc cx + jmp .8_bit_ + + .8_bit: + + DEBUGF 1,"(8-bit mode)\n" + + .8_bit_: + lodsb + out dx, al + loopw .8_bit_ + + .done: +; set_io 0 +; set_io P0_ISR +; .dmawait: ; Wait for Remote DMA Complete +; in al, dx +; test al, ISR_RDC +; jz .dmawait +; and al, not ISR_RDC +; out dx, al ; clear the bit + + ret + + + +;all initialized data place here +align 4 + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'RTL8029/ne2000',0 ;max 16 chars include zero + +;device_1 db 'Realtek 8029',0 +;device_2 db 'Realtek 8019',0 +;device_3 db 'Realtek 8019AS',0 +;device_4 db 'ne2000',0 +;device_5 db 'DP8390',0 + +include_debug_strings + +section '.data' data readable writable align 16 ;place all uninitialized data place here + +device_list rd MAX_DEVICES + + + + + diff --git a/drivers/ethernet/RTL8139.asm b/drivers/ethernet/RTL8139.asm new file mode 100644 index 0000000000..7b4d298be1 --- /dev/null +++ b/drivers/ethernet/RTL8139.asm @@ -0,0 +1,1131 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Realtek 8139 driver for KolibriOS ;; +;; ;; +;; based on RTL8139.asm driver for menuetos ;; +;; and realtek8139.asm for SolarOS by Eugen Brasoveanu ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + RBLEN = 3 ; Receive buffer size: 0==8K 1==16k 2==32k 3==64k + NUM_TX_DESC = 4 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + + REG_IDR0 = 0x00 + REG_MAR0 = 0x08 ; multicast filter register 0 + REG_MAR4 = 0x0c ; multicast filter register 4 + REG_TSD0 = 0x10 ; transmit status of descriptor + REG_TSAD0 = 0x20 ; transmit start address of descriptor + REG_RBSTART = 0x30 ; RxBuffer start address + REG_COMMAND = 0x37 ; command register + REG_CAPR = 0x38 ; current address of packet read (word) R/W + REG_IMR = 0x3c ; interrupt mask register + REG_ISR = 0x3e ; interrupt status register + REG_TXCONFIG = 0x40 ; transmit configuration register + REG_RXCONFIG = 0x44 ; receive configuration register 0 + REG_MPC = 0x4c ; missed packet counter + REG_9346CR = 0x50 ; serial eeprom 93C46 command register + REG_CONFIG1 = 0x52 ; configuration register 1 + REG_MSR = 0x58 + REG_CONFIG4 = 0x5a ; configuration register 4 + REG_HLTCLK = 0x5b ; undocumented halt clock register + REG_BMCR = 0x62 ; basic mode control register + REG_ANAR = 0x66 ; auto negotiation advertisement register + REG_9346CR_WE = 11b shl 6 + + BIT_RUNT = 4 ; total packet length < 64 bytes + BIT_LONG = 3 ; total packet length > 4k + BIT_CRC = 2 ; crc error occured + BIT_FAE = 1 ; frame alignment error occured + BIT_ROK = 0 ; received packet is ok + + BIT_RST = 4 ; reset bit + BIT_RE = 3 ; receiver enabled + BIT_TE = 2 ; transmitter enabled + BUFE = 1 ; rx buffer is empty, no packet stored + + BIT_ISR_TOK = 2 ; transmit ok + BIT_ISR_RER = 1 ; receive error interrupt + BIT_ISR_ROK = 0 ; receive ok + + BIT_TX_MXDMA = 8 ; Max DMA burst size per Tx DMA burst + BIT_TXRR = 4 ; Tx Retry count 16+(TXRR*16) + + BIT_RXFTH = 13 ; Rx fifo threshold + BIT_RBLEN = 11 ; Ring buffer length indicator + BIT_RX_MXDMA = 8 ; Max DMA burst size per Rx DMA burst + BIT_NOWRAP = 7 ; transfered data wrapping + BIT_9356SEL = 6 ; eeprom selector 9346/9356 + BIT_AER = 5 ; accept error packets + BIT_AR = 4 ; accept runt packets + BIT_AB = 3 ; accept broadcast packets + BIT_AM = 2 ; accept multicast packets + BIT_APM = 1 ; accept physical match packets + BIT_AAP = 0 ; accept all packets + + BIT_93C46_EEM1 = 7 ; RTL8139 eeprom operating mode1 + BIT_93C46_EEM0 = 6 ; RTL8139 eeprom operating mode0 + BIT_93C46_EECS = 3 ; chip select + BIT_93C46_EESK = 2 ; serial data clock + BIT_93C46_EEDI = 1 ; serial data input + BIT_93C46_EEDO = 0 ; serial data output + + BIT_LWACT = 4 ; see REG_CONFIG1 + BIT_SLEEP = 1 ; sleep bit at older chips + BIT_PWRDWN = 0 ; power down bit at older chips + BIT_PMEn = 0 ; power management enabled + + BIT_LWPTN = 2 ; see REG_CONFIG4 + + BIT_ERTXTH = 16 ; early TX threshold + BIT_TOK = 15 ; transmit ok + BIT_OWN = 13 ; tx DMA operation is completed + + BIT_ANE = 12 ; auto negotiation enable + + BIT_TXFD = 8 ; 100base-T full duplex + BIT_TX = 7 ; 100base-T + BIT_10FD = 6 ; 10base-T full duplex + BIT_10 = 5 ; 10base-T + BIT_SELECTOR = 0 ; binary encoded selector CSMA/CD=00001 + + BIT_IFG1 = 25 + BIT_IFG0 = 24 + + TXRR = 8 ; total retries = 16+(TXRR*16) + TX_MXDMA = 6 ; 0=16 1=32 2=64 3=128 4=256 5=512 6=1024 7=2048 + ERTXTH = 8 ; in unit of 32 bytes e.g:(8*32)=256 + RX_MXDMA = 7 ; 0=16 1=32 2=64 3=128 4=256 5=512 6=1024 7=unlimited + RXFTH = 7 ; 0=16 1=32 2=64 3=128 4=256 5=512 6=1024 7=no threshold + + RX_CONFIG = (RBLEN shl BIT_RBLEN) or \ + (RX_MXDMA shl BIT_RX_MXDMA) or \ + (1 shl BIT_NOWRAP) or \ + (RXFTH shl BIT_RXFTH) or\ + (1 shl BIT_AB) or \ ; Accept broadcast packets + (1 shl BIT_APM) or \ ; Accept physical match packets + (1 shl BIT_AER) or \ ; Accept error packets + (1 shl BIT_AR) or \ ; Accept Runt packets (smaller then 64 bytes) + (1 shl BIT_AM) ; Accept multicast packets + + RX_BUFFER_SIZE = (8192 shl RBLEN);+16 + MAX_ETH_FRAME_SIZE = 1514 + + EE_93C46_REG_ETH_ID = 7 ; MAC offset + EE_93C46_READ_CMD = (6 shl 6) ; 110b + 6bit address + EE_93C56_READ_CMD = (6 shl 8) ; 110b + 8bit address + EE_93C46_CMD_LENGTH = 9 ; start bit + cmd + 6bit address + EE_93C56_CMD_LENGTH = 11 ; start bit + cmd + 8bit ddress + + VER_RTL8139 = 1100000b + VER_RTL8139A = 1110000b + VER_RTL8139AG = 1110100b + VER_RTL8139B = 1111000b + VER_RTL8130 = VER_RTL8139B + VER_RTL8139C = 1110100b + VER_RTL8100 = 1111010b + VER_RTL8100B = 1110101b + VER_RTL8139D = VER_RTL8100B + VER_RTL8139CP = 1110110b + VER_RTL8101 = 1110111b + + IDX_RTL8139 = 0 + IDX_RTL8139A = 1 + IDX_RTL8139B = 2 + IDX_RTL8139C = 3 + IDX_RTL8100 = 4 + IDX_RTL8139D = 5 + IDX_RTL8139D = 6 + IDX_RTL8101 = 7 + + ISR_SERR = 1 shl 15 + ISR_TIMEOUT = 1 shl 14 + ISR_LENCHG = 1 shl 13 + ISR_FIFOOVW = 1 shl 6 + ISR_PUN = 1 shl 5 + ISR_RXOVW = 1 shl 4 + ISR_TER = 1 shl 3 + ISR_TOK = 1 shl 2 + ISR_RER = 1 shl 1 + ISR_ROK = 1 shl 0 + + INTERRUPT_MASK = ISR_ROK or \ + ISR_RXOVW or \ + ISR_PUN or \ + ISR_FIFOOVW or \ + ISR_LENCHG or \ + ISR_TOK or \ + ISR_TER + + TSR_OWN = 1 shl 13 + TSR_TUN = 1 shl 14 + TSR_TOK = 1 shl 15 + + TSR_CDH = 1 shl 28 + TSR_OWC = 1 shl 29 + TSR_TABT = 1 shl 30 + TSR_CRS = 1 shl 31 + + +virtual at ebx + + device: + + ETH_DEVICE + + .rx_buffer dd ? + + .rx_data_offset dd ? + .io_addr dd ? + + .curr_tx_desc db ? + .pci_bus dd ? + .pci_dev dd ? + .irq_line db ? + .hw_ver_id db ? + + .TX_DESC rd NUM_TX_DESC + + .size = $ - device + +end virtual + + + +section '.flat' code readable align 16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 2, "Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + + mov ax, [eax+1] ; get the pci bus and device numbers + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base io addres of the PCI device + + PCI_find_io + +; We've found the io address, find IRQ now + + PCI_find_irq + + DEBUGF 2, "Hooking into device, dev:%x, bus:%x, irq:%x, I/O addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 + +; Allocate the receive buffer + + stdcall CreateRingBuffer, dword (RX_BUFFER_SIZE), dword PG_SW + test eax, eax + jz .err + mov [device.rx_buffer], eax + +; Ok, the eth_device structure is ready, let's probe the device + + call probe ; this function will output in eax + test eax, eax + jnz .err ; If an error occured, exit + + mov eax, [devices] ; Add the device structure to our device list + mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + je .destroy + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 2, "Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 2, "Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + .err: + stdcall KernelFree, [device.rx_buffer] + stdcall KernelFree, ebx + + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + +align 4 +unload: + ; TODO: (in this particular order) + ; + ; - Stop the device + ; - Detach int handler + ; - Remove device from local list (RTL8139_LIST) + ; - call unregister function in kernel + ; - Remove all allocated structures and buffers the card used + + or eax, -1 + +ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; probe: enables the device (if it really is RTL8139) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +probe: + DEBUGF 2, "Probing %s device\n", my_service + + PCI_make_bus_master + +; get chip version + set_io 0 + set_io REG_TXCONFIG + 2 + in ax, dx + shr ah, 2 + shr ax, 6 + and al, 01111111b + +; now find it in our array + mov ecx, HW_VER_ARRAY_SIZE-1 + .chip_ver_loop: + cmp al, [hw_ver_array + ecx] + je .chip_ver_found + dec ecx + jns .chip_ver_loop + .unknown: + mov ecx, 8 + .chip_ver_found: + cmp ecx, 8 + ja .unknown + + mov [device.hw_ver_id], cl + + mov ecx, [crosslist+ecx*4] + mov [device.name], ecx + + DEBUGF 2, "Chip version: %s\n", ecx + +; wake up the chip + set_io 0 + set_io REG_HLTCLK + mov al, 'R' ; run the clock + out dx, al + +; unlock config and BMCR registers + set_io REG_9346CR + mov al, (1 shl BIT_93C46_EEM1) or (1 shl BIT_93C46_EEM0) + out dx, al + +; enable power management + set_io REG_CONFIG1 + in al, dx + cmp [device.hw_ver_id], IDX_RTL8139B + jae .new_chip +; wake up older chips + and al, not ((1 shl BIT_SLEEP) or (1 shl BIT_PWRDWN)) + out dx, al + jmp .finish_wake_up + +; set LWAKE pin to active high (default value). +; it is for Wake-On-LAN functionality of some motherboards. +; this signal is used to inform the motherboard to execute a wake-up process. +; only at newer chips. + .new_chip: + or al, (1 shl BIT_PMEn) + and al, not (1 shl BIT_LWACT) + out dx, al + + set_io REG_CONFIG4 + in al, dx + and al, not (1 shl BIT_LWPTN) + out dx, al + +; lock config and BMCR registers + .finish_wake_up: + xor al, al + set_io 0 + set_io REG_9346CR + out dx, al + DEBUGF 2, "done!\n" + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; reset: Set up all registers and descriptors, clear some values +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +reset: + DEBUGF 2, "Reset\n" + +; attach int handler + movzx eax, [device.irq_line] + DEBUGF 1, "Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 1, "\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + +; reset chip + DEBUGF 1, "Resetting chip\n" + set_io 0 + set_io REG_COMMAND + mov al, 1 shl BIT_RST + out dx, al + mov cx, 1000 ; wait no longer for the reset + .wait_for_reset: + in al, dx + test al, 1 shl BIT_RST + jz .reset_completed ; RST remains 1 during reset + dec cx + jns .wait_for_reset + DEBUGF 1, "Reset timeout!\n" + .reset_completed: + +; unlock config and BMCR registers + set_io REG_9346CR + mov al, (1 shl BIT_93C46_EEM1) or (1 shl BIT_93C46_EEM0) + out dx, al + +; initialize multicast registers (no filtering) + mov eax, 0xffffffff + set_io REG_MAR0 + out dx, eax + set_io REG_MAR4 + out dx, eax + +; enable Rx/Tx + + mov al, (1 shl BIT_RE) or (1 shl BIT_TE) + set_io REG_COMMAND + out dx, al + +; Rxbuffer size, unlimited dma burst, no wrapping, no rx threshold +; accept broadcast packets, accept physical match packets + mov ax, RX_CONFIG + set_io REG_RXCONFIG + out dx, ax + +; 1024 bytes DMA burst, total retries = 16 + 8 * 16 = 144 + mov eax, (TX_MXDMA shl BIT_TX_MXDMA) or (TXRR shl BIT_TXRR) or BIT_IFG1 or BIT_IFG0 + set_io REG_TXCONFIG + out dx, eax + +; enable auto negotiation + set_io REG_BMCR + in ax, dx + or ax, (1 shl BIT_ANE) + out dx, ax + +; set auto negotiation advertisement + set_io REG_ANAR + in ax, dx + or ax, (1 shl BIT_SELECTOR) or (1 shl BIT_10) or (1 shl BIT_10FD) or (1 shl BIT_TX) or (1 shl BIT_TXFD) + out dx, ax + +; lock config and BMCR registers + xor eax, eax + set_io REG_9346CR + out dx, al + +; init RX/TX pointers + mov [device.rx_data_offset], eax + mov [device.curr_tx_desc], al +; set_io REG_CAPR +; out dx, ax + +; clear packet/byte counters + lea edi, [device.bytes_tx] + mov ecx, 6 + rep stosd + +; clear missing packet counter + set_io REG_MPC + out dx, eax + +; set RxBuffer address, init RX buffer offset + mov eax, [device.rx_buffer] + mov dword[eax], 0 ; clear receive flags for first packet (really needed??) + DEBUGF 2, "RX buffer virtual addr=0x%x\n", eax + GetRealAddr + DEBUGF 2, "RX buffer real addr=0x%x\n", eax + set_io REG_RBSTART + out dx, eax + +; Read MAC address + call read_mac + +; enable interrupts + set_io 0 + set_io REG_IMR + mov ax, INTERRUPT_MASK + out dx, ax + +; Set the mtu, kernel will be able to send now + mov [device.mtu], 1514 + + call cable + +; Indicate that we have successfully reset the card + xor eax, eax + ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +align 4 +transmit: + DEBUGF 1, "\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] + mov eax, [esp+4] + DEBUGF 1, "To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp+8], MAX_ETH_FRAME_SIZE + ja .fail + cmp dword [esp+8], 60 + jb .fail + +; check if we own the current discriptor + set_io 0 + set_io REG_TSD0 + movzx ecx, [device.curr_tx_desc] + shl ecx, 2 + add edx, ecx + in eax, dx + test eax, (1 shl BIT_OWN) + jz .wait_to_send + + .send_packet: +; get next descriptor + inc [device.curr_tx_desc] + and [device.curr_tx_desc], NUM_TX_DESC-1 + +; Update stats + inc [device.packets_tx] + mov eax, [esp+8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx+4], 0 + +; Set the buffer address + set_io REG_TSAD0 + mov eax, [esp+4] + mov [device.TX_DESC+ecx], eax + GetRealAddr + out dx, eax + +; And the size of the buffer + set_io REG_TSD0 + mov eax, [esp+8] + or eax, (ERTXTH shl BIT_ERTXTH) ; Early threshold + out dx, eax + + DEBUGF 1, "Packet Sent!\n" + xor eax, eax + ret 8 + + .wait_to_send: + DEBUGF 1, "Waiting for timeout\n" + + push edx + mov esi, 30 + stdcall Sleep + pop edx + + in ax, dx + test ax, (1 shl BIT_OWN) + jnz .send_packet + + pusha + call reset ; if chip hung, reset it + popa + + jmp .send_packet + + .fail: + DEBUGF 1, "failed!\n" + stdcall KernelFree, [esp+4] + or eax, -1 + ret 8 + + + + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1, "\n%s int\n", my_service + +; find pointer of device wich made IRQ occur + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + + set_io 0 + set_io REG_ISR + in ax, dx ; Get interrupt status + out dx, ax ; send it back to ACK + test ax, ax + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) + + .got_it: + + DEBUGF 1, "Device: %x Status: %x\n", ebx, ax + +;---------------------------------------------------- +; Received packet ok? + + test ax, ISR_ROK + jz @f + push ax + + .receive: + set_io 0 + set_io REG_COMMAND + in al, dx + test al, BUFE ; test if RX buffer is empty + jnz .finish + + DEBUGF 1, "RX: " + + mov eax, [device.rx_buffer] + add eax, [device.rx_data_offset] + test byte [eax], (1 shl BIT_ROK) ; check if packet is ok + jz .reset_rx + +; packet is ok, copy it + movzx ecx, word [eax+2] ; packet length + sub cx, 4 ; don't copy CRC + +; Update stats + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + inc [device.packets_rx] + + DEBUGF 1, "Received %u bytes\n", ecx + + push ebx eax ecx + stdcall KernelAlloc, ecx ; Allocate a buffer to put packet into + pop ecx + test eax, eax ; Test if we allocated succesfully + jz .abort + + mov edi, eax ; Where we will copy too + + mov esi, [esp] ; The buffer we will copy from + add esi, 4 ; Dont copy CRC + + push dword .abort ; Kernel will return to this address after EthReceiver + push ecx edi ; Save buffer pointer and size, to pass to kernel + + .copy: + shr ecx, 1 + jnc .nb + movsb + .nb: + shr ecx, 1 + jnc .nw + movsw + .nw: + jz .nd + rep movsd + .nd: + + jmp Eth_input ; Send it to kernel + + .abort: + pop eax ebx + ; update eth_data_start_offset + movzx eax, word [eax+2] ; packet length + add eax, [device.rx_data_offset] + add eax, 4+3 ; packet header is 4 bytes long + dword alignment + and eax, not 3 ; dword alignment + + cmp eax, RX_BUFFER_SIZE + jb .no_wrap + DEBUGF 2, "Wrapping" + sub eax, RX_BUFFER_SIZE + .no_wrap: + mov [device.rx_data_offset], eax + DEBUGF 1, "New RX ptr: %d\n", eax + + set_io 0 + set_io REG_CAPR ; update 'Current Address of Packet Read register' + sub eax, 0x10 ; value 0x10 is a constant for CAPR + out dx , ax + + jmp .receive ; check for multiple packets + + .reset_rx: + test byte [eax], (1 shl BIT_CRC) + jz .no_crc_error + DEBUGF 2, "\nCRC error!\n" + + .no_crc_error: + test byte [eax], (1 shl BIT_FAE) + jz .no_fae_error + DEBUGF 1, "\nFrame alignment error!\n" + + .no_fae_error: + DEBUGF 1, "Reset RX\n" + in al, dx ; read command register + push ax + and al, not (1 shl BIT_RE) ; Clear the RE bit + out dx, al + pop ax + out dx, al ; write original command back + + add edx, REG_RXCONFIG - REG_COMMAND ; Restore RX configuration + mov ax, RX_CONFIG + out dx, ax + + .finish: + pop ax + +;---------------------------------------------------- +; Transmit ok / Transmit error + @@: + test ax, ISR_TOK + ISR_TER + jz @f + + push ax + mov ecx, (NUM_TX_DESC-1)*4 + .txdescloop: + set_io 0 + set_io REG_TSD0 + add edx, ecx + in eax, dx + + test eax, TSR_OWN ; DMA operation completed + jz .notthisone + + cmp [device.TX_DESC+ecx], 0 + je .notthisone + +; .notxd: +; test eax, TSR_TUN +; jz .nobun +; DEBUGF 2, "TX: FIFO Buffer underrun!\n" +; +; .nobun: +; test eax, TSR_OWC +; jz .noowc +; DEBUGF 2, "TX: OWC!\n" +; +; .noowc: +; test eax, TSR_TABT +; jz .notabt +; DEBUGF 2, "TX: TABT!\n" +; +; .notabt: +; test eax, TSR_CRS +; jz .nocsl +; DEBUGF 2, "TX: Carrier Sense Lost!\n" +; +; .nocsl: + + DEBUGF 1, "TX OK: free buffer %x\n", [device.TX_DESC+ecx]:8 + push ecx ebx + stdcall KernelFree, [device.TX_DESC+ecx] + pop ebx ecx + mov [device.TX_DESC+ecx], 0 + + .notthisone: + sub ecx, 4 + ja .txdescloop + pop ax + +;---------------------------------------------------- +; Rx buffer overflow ? + @@: + test ax, ISR_RXOVW + jz @f + + push ax + DEBUGF 2, "RX-buffer overflow!\n" + + set_io 0 + set_io REG_ISR + mov ax, ISR_FIFOOVW or ISR_RXOVW + out dx, ax + pop ax + +;---------------------------------------------------- +; Packet underrun? + @@: + test ax, ISR_PUN + jz @f + + DEBUGF 2, "Packet underrun!\n" + +;---------------------------------------------------- +; Receive FIFO overflow ? + @@: + test ax, ISR_FIFOOVW + jz @f + + push ax + DEBUGF 2, "RX fifo overflow!\n" + + set_io 0 + set_io REG_ISR + mov ax, ISR_FIFOOVW or ISR_RXOVW + out dx, ax + pop ax + +;---------------------------------------------------- +; Something about Cable changed ? + @@: + test ax, ISR_LENCHG + jz .fail + + call cable + + .fail: + DEBUGF 2, "\n" + pop edi esi ebx + xor eax, eax + inc eax + + ret + + + + +;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Update Cable status ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +cable: + DEBUGF 1, "Updating Cable status\n" + + set_io 0 + set_io REG_MSR + in al, dx + + test al, 1 shl 2 ; 0 = link ok 1 = link fail + jnz .notconnected + + test al, 1 shl 3 ; 0 = 100 Mbps 1 = 10 Mbps + jnz .10mbps + + .100mbps: + mov [device.state], ETH_LINK_100M + call NetLinkChanged + + ret + + .10mbps: + mov [device.state], ETH_LINK_10M + call NetLinkChanged + + ret + + .notconnected: + mov [device.state], ETH_LINK_DOWN + call NetLinkChanged + + ret + + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Write MAC address ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +write_mac: ; in: mac pushed onto stack (as 3 words) + + DEBUGF 2, "Writing MAC: " + +; disable all in command registers + set_io 0 + set_io REG_9346CR + xor eax, eax + out dx, al + + set_io REG_IMR + xor eax, eax + out dx, ax + + set_io REG_ISR + mov eax, -1 + out dx, ax + +; enable writing + set_io REG_9346CR + mov eax, REG_9346CR_WE + out dx, al + + ; write the mac ... + set_io REG_IDR0 + pop eax + out dx, eax + + set_io REG_IDR0+4 + xor eax, eax + pop ax + out dx, eax + +; disable writing + set_io REG_9346CR + xor eax, eax + out dx, al + + DEBUGF 2, "ok!\n" + +; Notice this procedure does not ret, but continues to read_mac instead. + + +;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Read MAC address ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;; + +read_mac: + DEBUGF 2, "Reading MAC: " + + set_io 0 + lea edi, [device.mac] + in eax, dx + stosd + add edx, 4 + in ax, dx + stosw + + DEBUGF 2, "%x-%x-%x-%x-%x-%x\n",[edi-6]:2,[edi-5]:2,[edi-4]:2,[edi-3]:2,[edi-2]:2,[edi-1]:2 + + ret + + +; End of code + +section '.data' data readable writable align 16 ; place all uninitialized data place here +align 4 ; Place all initialised data here + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'RTL8139',0 ; max 16 chars include zero + +device_1 db 'Realtek 8139',0 +device_2 db 'Realtek 8139A',0 +device_3 db 'Realtek 8139B',0 +device_4 db 'Realtek 8139C',0 +device_5 db 'Realtek 8100',0 +device_6 db 'Realtek 8139D',0 +device_7 db 'Realtek 8139CP',0 +device_8 db 'Realtek 8101',0 +device_unknown db 'Unknown RTL8139 clone', 0 + +crosslist: + dd device_1 + dd device_2 + dd device_3 + dd device_4 + dd device_5 + dd device_6 + dd device_7 + dd device_8 + dd device_unknown + +hw_ver_array: ; This array is used by the probe routine to find out wich version of the RTL8139 we are working with + db VER_RTL8139 + db VER_RTL8139A + db VER_RTL8139B + db VER_RTL8139C + db VER_RTL8100 + db VER_RTL8139D + db VER_RTL8139CP + db VER_RTL8101 + db 0 + +HW_VER_ARRAY_SIZE = $-hw_ver_array + +include_debug_strings ; All data wich FDO uses will be included here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + diff --git a/drivers/ethernet/RTL8169.asm b/drivers/ethernet/RTL8169.asm new file mode 100644 index 0000000000..5570cc1266 --- /dev/null +++ b/drivers/ethernet/RTL8169.asm @@ -0,0 +1,1324 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; RTL8169 driver for KolibriOS ;; +;; ;; +;; Copyright 2007 mike.dld, ;; +;; mike.dld@gmail.com ;; +;; ;; +;; port to net branch by hidnplayr ;; +;; ;; +;; References: ;; +;; r8169.c - linux driver (etherboot project) ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + + NUM_TX_DESC = 4 + NUM_RX_DESC = 4 + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + + + REG_MAC0 = 0x0 ; Ethernet hardware address + REG_MAR0 = 0x8 ; Multicast filter + REG_TxDescStartAddr = 0x20 + REG_TxHDescStartAddr = 0x28 + REG_FLASH = 0x30 + REG_ERSR = 0x36 + REG_ChipCmd = 0x37 + REG_TxPoll = 0x38 + REG_IntrMask = 0x3C + REG_IntrStatus = 0x3E + REG_TxConfig = 0x40 + REG_RxConfig = 0x44 + REG_RxMissed = 0x4C + REG_Cfg9346 = 0x50 + REG_Config0 = 0x51 + REG_Config1 = 0x52 + REG_Config2 = 0x53 + REG_Config3 = 0x54 + REG_Config4 = 0x55 + REG_Config5 = 0x56 + REG_MultiIntr = 0x5C + REG_PHYAR = 0x60 + REG_TBICSR = 0x64 + REG_TBI_ANAR = 0x68 + REG_TBI_LPAR = 0x6A + REG_PHYstatus = 0x6C + REG_RxMaxSize = 0xDA + REG_CPlusCmd = 0xE0 + REG_RxDescStartAddr = 0xE4 + REG_ETThReg = 0xEC + REG_FuncEvent = 0xF0 + REG_FuncEventMask = 0xF4 + REG_FuncPresetState = 0xF8 + REG_FuncForceEvent = 0xFC + + ; InterruptStatusBits + ISB_SYSErr = 0x8000 + ISB_PCSTimeout = 0x4000 + ISB_SWInt = 0x0100 + ISB_TxDescUnavail = 0x80 + ISB_RxFIFOOver = 0x40 + ISB_LinkChg = 0x20 + ISB_RxOverflow = 0x10 + ISB_TxErr = 0x08 + ISB_TxOK = 0x04 + ISB_RxErr = 0x02 + ISB_RxOK = 0x01 + + ; RxStatusDesc + SD_RxRES = 0x00200000 + SD_RxCRC = 0x00080000 + SD_RxRUNT = 0x00100000 + SD_RxRWT = 0x00400000 + + ; ChipCmdBits + CMD_Reset = 0x10 + CMD_RxEnb = 0x08 + CMD_TxEnb = 0x04 + CMD_RxBufEmpty = 0x01 + + ; Cfg9346Bits + CFG_9346_Lock = 0x00 + CFG_9346_Unlock = 0xC0 + + ; rx_mode_bits + RXM_AcceptErr = 0x20 + RXM_AcceptRunt = 0x10 + RXM_AcceptBroadcast = 0x08 + RXM_AcceptMulticast = 0x04 + RXM_AcceptMyPhys = 0x02 + RXM_AcceptAllPhys = 0x01 + + ; RxConfigBits + RXC_FIFOShift = 13 + RXC_DMAShift = 8 + + ; TxConfigBits + TXC_InterFrameGapShift = 24 + TXC_DMAShift = 8 ; DMA burst value (0-7) is shift this many bits + + ; PHYstatus + PHYS_TBI_Enable = 0x80 + PHYS_TxFlowCtrl = 0x40 + PHYS_RxFlowCtrl = 0x20 + PHYS_1000bpsF = 0x10 + PHYS_100bps = 0x08 + PHYS_10bps = 0x04 + PHYS_LinkStatus = 0x02 + PHYS_FullDup = 0x01 + + ; GIGABIT_PHY_registers + PHY_CTRL_REG = 0 + PHY_STAT_REG = 1 + PHY_AUTO_NEGO_REG = 4 + PHY_1000_CTRL_REG = 9 + + ; GIGABIT_PHY_REG_BIT + PHY_Restart_Auto_Nego = 0x0200 + PHY_Enable_Auto_Nego = 0x1000 + + ; PHY_STAT_REG = 1 + PHY_Auto_Neco_Comp = 0x0020 + + ; PHY_AUTO_NEGO_REG = 4 + PHY_Cap_10_Half = 0x0020 + PHY_Cap_10_Full = 0x0040 + PHY_Cap_100_Half = 0x0080 + PHY_Cap_100_Full = 0x0100 + + ; PHY_1000_CTRL_REG = 9 + PHY_Cap_1000_Full = 0x0200 + PHY_Cap_1000_Half = 0x0100 + + PHY_Cap_PAUSE = 0x0400 + PHY_Cap_ASYM_PAUSE = 0x0800 + + PHY_Cap_Null = 0x0 + + ; _MediaType + MT_10_Half = 0x01 + MT_10_Full = 0x02 + MT_100_Half = 0x04 + MT_100_Full = 0x08 + MT_1000_Full = 0x10 + + ; _TBICSRBit + TBI_LinkOK = 0x02000000 + + ; _DescStatusBit + DSB_OWNbit = 0x80000000 + DSB_EORbit = 0x40000000 + DSB_FSbit = 0x20000000 + DSB_LSbit = 0x10000000 + + RX_BUF_SIZE = 1536 ; Rx Buffer size + +; max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4) + MAX_ETH_FRAME_SIZE = 1536 + + TX_FIFO_THRESH = 256 ; In bytes + + RX_FIFO_THRESH = 7 ; 7 means NO threshold, Rx buffer level before first PCI xfer + RX_DMA_BURST = 7 ; Maximum PCI burst, '6' is 1024 + TX_DMA_BURST = 7 ; Maximum PCI burst, '6' is 1024 + ETTh = 0x3F ; 0x3F means NO threshold + + EarlyTxThld = 0x3F ; 0x3F means NO early transmit + RxPacketMaxSize = 0x0800 ; Maximum size supported is 16K-1 + InterFrameGap = 0x03 ; 3 means InterFrameGap = the shortest one + + HZ = 1000 + + RTL_MIN_IO_SIZE = 0x80 + TX_TIMEOUT = (6*HZ) + + TIMER_EXPIRE_TIME = 100 + + ETH_HDR_LEN = 14 + DEFAULT_MTU = 1500 + DEFAULT_RX_BUF_LEN = 1536 + + +;ifdef JUMBO_FRAME_SUPPORT +; MAX_JUMBO_FRAME_MTU = 10000 +; MAX_RX_SKBDATA_SIZE = (MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN ) +;else + MAX_RX_SKBDATA_SIZE = 1600 +;end if + + MCFG_METHOD_01 = 0x01 + MCFG_METHOD_02 = 0x02 + MCFG_METHOD_03 = 0x03 + MCFG_METHOD_04 = 0x04 + MCFG_METHOD_05 = 0x05 + MCFG_METHOD_11 = 0x0b + MCFG_METHOD_12 = 0x0c + MCFG_METHOD_13 = 0x0d + MCFG_METHOD_14 = 0x0e + MCFG_METHOD_15 = 0x0f + + PCFG_METHOD_1 = 0x01 ; PHY Reg 0x03 bit0-3 == 0x0000 + PCFG_METHOD_2 = 0x02 ; PHY Reg 0x03 bit0-3 == 0x0001 + PCFG_METHOD_3 = 0x03 ; PHY Reg 0x03 bit0-3 == 0x0002 + +virtual at 0 + tx_desc: + .status dd ? + .vlan_tag dd ? + .buf_addr dq ? + .size = $ + rb (NUM_TX_DESC-1)*tx_desc.size + .buf_soft_addr dd ? +end virtual + +virtual at 0 + rx_desc: + .status dd ? + .vlan_tag dd ? + .buf_addr dq ? + .size = $ + rb (NUM_RX_DESC-1)*rx_desc.size + .buf_soft_addr dd ? +end virtual + +virtual at ebx + + device: + + ETH_DEVICE + + .io_addr dd ? + .pci_bus dd ? + .pci_dev dd ? + .irq_line db ? + + rb 256-(($ - device) and 255) ; align 256 + .tx_ring rb NUM_TX_DESC * tx_desc.size * 2 + + rb 256-(($ - device) and 255) ; align 256 + .rx_ring rb NUM_RX_DESC * rx_desc.size * 2 + + tpc: + .mmio_addr dd ? ; memory map physical address + .chipset dd ? + .pcfg dd ? + .mcfg dd ? + .cur_rx dd ? ; Index into the Rx descriptor buffer of next Rx pkt + .cur_tx dd ? ; Index into the Tx descriptor buffer of next Rx pkt + .TxDescArrays dd ? ; Index of Tx Descriptor buffer + .RxDescArrays dd ? ; Index of Rx Descriptor buffer + .TxDescArray dd ? ; Index of 256-alignment Tx Descriptor buffer + .RxDescArray dd ? ; Index of 256-alignment Rx Descriptor buffer + + device_size = $ - device + +end virtual + + intr_mask = ISB_LinkChg or ISB_RxOverflow or ISB_RxFIFOOver or ISB_TxErr or ISB_TxOK or ISB_RxErr or ISB_RxOK + rx_config = (RX_FIFO_THRESH shl RXC_FIFOShift) or (RX_DMA_BURST shl RXC_DMAShift) or 0x0000000E + + +macro udelay msec { + + push esi + mov esi, msec + call Sleep + pop esi + +} + +macro WRITE_GMII_REG RegAddr, value { + + set_io REG_PHYAR + if value eq ax + and eax, 0x0000ffff + or eax, 0x80000000 + (RegAddr shl 16) + else + mov eax, 0x80000000 + (RegAddr shl 16) + value + end if + out dx, eax + + call PHY_WAIT_WRITE +} + +macro READ_GMII_REG RegAddr { + +local .error, .done + + set_io REG_PHYAR + mov eax, RegAddr shl 16 + out dx, eax + + call PHY_WAIT_READ + jz .error + + in eax, dx + and eax, 0xFFFF + jmp .done + + .error: + or eax, -1 + .done: +} + +align 4 +PHY_WAIT_READ: ; io addr must already be set to REG_PHYAR + + udelay 1 ;;;1000 + + push ecx + mov ecx, 2000 + ; Check if the RTL8169 has completed writing/reading to the specified MII register + @@: + in eax, dx + test eax, 0x80000000 + jnz .exit + udelay 1 ;;;100 + loop @b + .exit: + pop ecx + ret + +align 4 +PHY_WAIT_WRITE: ; io addr must already be set to REG_PHYAR + + udelay 1 ;;;1000 + + push ecx + mov ecx, 2000 + ; Check if the RTL8169 has completed writing/reading to the specified MII register + @@: + in eax, dx + test eax, 0x80000000 + jz .exit + udelay 1 ;;;100 + loop @b + .exit: + pop ecx + ret + + + +section '.flat' code readable align 16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 2,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax , [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, device_size, .fail ; Allocate memory to put the device structure in + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base io addres of the PCI device + + PCI_find_io + mov [tpc.mmio_addr], eax ; CHECKME + +; We've found the io address, find IRQ now + + PCI_find_irq + + DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:8 + +; Ok, the eth_device structure is ready, let's probe the device +; Because initialization fires IRQ, IRQ handler must be aware of this device + mov eax, [devices] ; Add the device structure to our device list + mov [device_list + 4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + call probe ; this function will output in eax + test eax, eax + jnz .err2 ; If an error occured, exit + + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + je .destroy + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 2,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 2,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + .err2: + dec [devices] + .err: + DEBUGF 2,"removing device structure\n" + stdcall KernelFree, ebx + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +align 4 +unload: + + ret + + +align 4 +init_board: + + DEBUGF 1,"init_board\n" + + PCI_make_bus_master + + ; Soft reset the chip + set_io 0 + set_io REG_ChipCmd + mov al, CMD_Reset + out dx, al + + ; Check that the chip has finished the reset + mov ecx, 1000 + set_io REG_ChipCmd + @@: in al, dx + test al, CMD_Reset + jz @f + udelay 10 + loop @b + @@: + ; identify config method + set_io REG_TxConfig + in eax, dx + and eax, 0x7c800000 + DEBUGF 1,"init_board: TxConfig & 0x7c800000 = 0x%x\n", eax + mov esi, mac_info-8 + @@: add esi, 8 + mov ecx, eax + and ecx, [esi] + cmp ecx, [esi] + jne @b + mov eax, [esi+4] + mov [tpc.mcfg], eax + + mov [tpc.pcfg], PCFG_METHOD_3 + READ_GMII_REG 3 + and al, 0x0f + or al, al + jnz @f + mov [tpc.pcfg], PCFG_METHOD_1 + jmp .pconf + @@: dec al + jnz .pconf + mov [tpc.pcfg], PCFG_METHOD_2 + .pconf: + + ; identify chip attached to board + mov ecx, 10 + mov eax, [tpc.mcfg] + @@: dec ecx + js @f + cmp eax, [rtl_chip_info + ecx*8] + jne @b + mov [tpc.chipset], ecx + jmp .match + @@: + ; if unknown chip, assume array element #0, original RTL-8169 in this case + DEBUGF 1,"init_board: PCI device: unknown chip version, assuming RTL-8169\n" + set_io REG_TxConfig + in eax, dx + DEBUGF 1,"init_board: PCI device: TxConfig = 0x%x\n", eax + + mov [tpc.chipset], 0 + + xor eax, eax + inc eax + ret + + .match: + DEBUGF 1,"init_board: chipset=%u\n", ecx + xor eax,eax + ret + + + +;*************************************************************************** +; Function +; probe +; Description +; Searches for an ethernet card, enables it and clears the rx buffer +; If a card was found, it enables the ethernet -> TCPIP link +; Destroyed registers +; eax, ebx, ecx, edx +; +;*************************************************************************** +align 4 +probe: + + DEBUGF 1,"probe\n" + + call init_board + call read_mac + call PHY_config + +; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0x82h = 0x01h\n" + set_io 0 + set_io 0x82 + mov al, 0x01 + out dx, al + cmp [tpc.mcfg], MCFG_METHOD_03 + jae @f +; DEBUGF 1,"K : Set PCI Latency=0x40\n" +; stdcall pci_write_config_byte,PCI_LATENCY_TIMER,0x40 + @@: + cmp [tpc.mcfg], MCFG_METHOD_02 + jne @f +; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0x82h = 0x01h\n" + set_io 0x82 + mov al, 0x01 + out dx, al +; DEBUGF 1,"K : Set PHY Reg 0x0bh = 0x00h\n" + WRITE_GMII_REG 0x0b, 0x0000 ; w 0x0b 15 0 0 + @@: + ; if TBI is not enabled + set_io 0 + set_io REG_PHYstatus + in al, dx + test al, PHYS_TBI_Enable + jz .tbi_dis + READ_GMII_REG PHY_AUTO_NEGO_REG + + ; enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged + and eax, 0x0C1F + or eax, PHY_Cap_10_Half or PHY_Cap_10_Full or PHY_Cap_100_Half or PHY_Cap_100_Full + WRITE_GMII_REG PHY_AUTO_NEGO_REG, ax + + ; enable 1000 Full Mode + WRITE_GMII_REG PHY_1000_CTRL_REG, PHY_Cap_1000_Full or PHY_Cap_1000_Half ; rtl8168 + + ; Enable auto-negotiation and restart auto-nigotiation + WRITE_GMII_REG PHY_CTRL_REG, PHY_Enable_Auto_Nego or PHY_Restart_Auto_Nego + + udelay 100 + mov ecx, 10000 + ; wait for auto-negotiation process + @@: dec ecx + jz @f + set_io 0 + READ_GMII_REG PHY_STAT_REG + udelay 100 + test eax, PHY_Auto_Neco_Comp + jz @b + set_io REG_PHYstatus + in al, dx + jmp @f + .tbi_dis: + udelay 100 + @@: + + +;*************************************************************************** +; Function +; rt8169_reset +; Description +; Place the chip (ie, the ethernet card) into a virgin state +; Destroyed registers +; eax, ebx, ecx, edx +; +;*************************************************************************** +align 4 +reset: + + DEBUGF 1,"reset\n" + + lea eax, [device.tx_ring] + mov [tpc.TxDescArrays], eax + mov [tpc.TxDescArray], eax + + lea eax, [device.rx_ring] + mov [tpc.RxDescArrays], eax + mov [tpc.RxDescArray], eax + + call init_ring + call hw_start + +; clear packet/byte counters + + xor eax, eax + lea edi, [device.bytes_tx] + mov ecx, 6 + rep stosd + + mov [device.mtu], 1500 + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + + xor eax, eax + ret + + + + + +align 4 +PHY_config: + + DEBUGF 1,"hw_PHY_config: priv.mcfg=%d, priv.pcfg=%d\n",[tpc.mcfg],[tpc.pcfg] + + cmp [tpc.mcfg], MCFG_METHOD_04 + jne .not_4 + set_io 0 +; WRITE_GMII_REG 0x1F, 0x0001 +; WRITE_GMII_REG 0x1b, 0x841e +; WRITE_GMII_REG 0x0e, 0x7bfb +; WRITE_GMII_REG 0x09, 0x273a + WRITE_GMII_REG 0x1F, 0x0002 + WRITE_GMII_REG 0x01, 0x90D0 + WRITE_GMII_REG 0x1F, 0x0000 + jmp .exit + .not_4: + cmp [tpc.mcfg], MCFG_METHOD_02 + je @f + cmp [tpc.mcfg], MCFG_METHOD_03 + jne .not_2_or_3 + @@: + set_io 0 + WRITE_GMII_REG 0x1F, 0x0001 + WRITE_GMII_REG 0x15, 0x1000 + WRITE_GMII_REG 0x18, 0x65C7 + WRITE_GMII_REG 0x04, 0x0000 + WRITE_GMII_REG 0x03, 0x00A1 + WRITE_GMII_REG 0x02, 0x0008 + WRITE_GMII_REG 0x01, 0x1020 + WRITE_GMII_REG 0x00, 0x1000 + WRITE_GMII_REG 0x04, 0x0800 + WRITE_GMII_REG 0x04, 0x0000 + WRITE_GMII_REG 0x04, 0x7000 + WRITE_GMII_REG 0x03, 0xFF41 + WRITE_GMII_REG 0x02, 0xDE60 + WRITE_GMII_REG 0x01, 0x0140 + WRITE_GMII_REG 0x00, 0x0077 + WRITE_GMII_REG 0x04, 0x7800 + WRITE_GMII_REG 0x04, 0x7000 + WRITE_GMII_REG 0x04, 0xA000 + WRITE_GMII_REG 0x03, 0xDF01 + WRITE_GMII_REG 0x02, 0xDF20 + WRITE_GMII_REG 0x01, 0xFF95 + WRITE_GMII_REG 0x00, 0xFA00 + WRITE_GMII_REG 0x04, 0xA800 + WRITE_GMII_REG 0x04, 0xA000 + WRITE_GMII_REG 0x04, 0xB000 + WRITE_GMII_REG 0x03, 0xFF41 + WRITE_GMII_REG 0x02, 0xDE20 + WRITE_GMII_REG 0x01, 0x0140 + WRITE_GMII_REG 0x00, 0x00BB + WRITE_GMII_REG 0x04, 0xB800 + WRITE_GMII_REG 0x04, 0xB000 + WRITE_GMII_REG 0x04, 0xF000 + WRITE_GMII_REG 0x03, 0xDF01 + WRITE_GMII_REG 0x02, 0xDF20 + WRITE_GMII_REG 0x01, 0xFF95 + WRITE_GMII_REG 0x00, 0xBF00 + WRITE_GMII_REG 0x04, 0xF800 + WRITE_GMII_REG 0x04, 0xF000 + WRITE_GMII_REG 0x04, 0x0000 + WRITE_GMII_REG 0x1F, 0x0000 + WRITE_GMII_REG 0x0B, 0x0000 + jmp .exit + .not_2_or_3: + DEBUGF 1,"tpc.mcfg=%d, discard hw PHY config\n", [tpc.mcfg] + .exit: + ret + + + +align 4 +set_rx_mode: + + DEBUGF 1,"set_rx_mode\n" + + ; IFF_ALLMULTI + ; Too many to filter perfectly -- accept all multicasts + set_io 0 + set_io REG_RxConfig + in eax, dx + mov ecx, [tpc.chipset] + and eax, [rtl_chip_info + ecx * 8 + 4] ; RxConfigMask + or eax, rx_config or (RXM_AcceptBroadcast or RXM_AcceptMulticast or RXM_AcceptMyPhys) + out dx, eax + + ; Multicast hash filter + set_io REG_MAR0 + 0 + or eax, -1 + out dx, eax + set_io REG_MAR0 + 4 + out dx, eax + + ret + + +align 4 +init_ring: + + DEBUGF 1,"init_ring\n" + + xor eax, eax + mov [tpc.cur_rx], eax + mov [tpc.cur_tx], eax + + lea edi, [device.tx_ring] + mov ecx, (NUM_TX_DESC * tx_desc.size) / 4 + rep stosd + + lea edi, [device.rx_ring] + mov ecx, (NUM_RX_DESC * rx_desc.size) / 4 + rep stosd + + mov edi, [tpc.RxDescArray] + mov ecx, NUM_RX_DESC + .loop: + push ecx + stdcall KernelAlloc, RX_BUF_SIZE + mov [edi + rx_desc.buf_soft_addr], eax + call GetPgAddr + mov dword [edi + rx_desc.buf_addr], eax + mov [edi + rx_desc.status], DSB_OWNbit or RX_BUF_SIZE + add edi, rx_desc.size + pop ecx + loop .loop + or [edi - rx_desc.size + rx_desc.status], DSB_EORbit + + ret + + +align 4 +hw_start: + + DEBUGF 1,"hw_start\n" + +; attach int handler + movzx eax, [device.irq_line] + DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + + ; Soft reset the chip + set_io 0 + set_io REG_ChipCmd + mov al, CMD_Reset + out dx, al + + DEBUGF 1,"Waiting for chip to reset... " + ; Check that the chip has finished the reset + mov ecx, 1000 + set_io REG_ChipCmd + @@: in al, dx + test al, CMD_Reset + jz @f + udelay 10 + loop @b + @@: + DEBUGF 1,"done!\n" + + set_io REG_Cfg9346 + mov al, CFG_9346_Unlock + out dx, al + + set_io REG_ChipCmd + mov al, CMD_TxEnb or CMD_RxEnb + out dx, al + + set_io REG_ETThReg + mov al, ETTh + out dx, al + + ; For gigabit rtl8169 + set_io REG_RxMaxSize + mov ax, RxPacketMaxSize + out dx, ax + + ; Set Rx Config register + set_io REG_RxConfig + in ax, dx + mov ecx, [tpc.chipset] + and eax, [rtl_chip_info + ecx * 8 + 4] ; RxConfigMask + or eax, rx_config + out dx, eax + + ; Set DMA burst size and Interframe Gap Time + set_io REG_TxConfig + mov eax, (TX_DMA_BURST shl TXC_DMAShift) or (InterFrameGap shl TXC_InterFrameGapShift) + out dx, eax + + set_io REG_CPlusCmd + in ax, dx + out dx, ax + + in ax, dx + or ax, 1 shl 3 + cmp [tpc.mcfg], MCFG_METHOD_02 + jne @f + cmp [tpc.mcfg], MCFG_METHOD_03 + jne @f + or ax,1 shl 14 + DEBUGF 1,"Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n" + jmp .set + @@: + DEBUGF 1,"Set MAC Reg C+CR Offset 0xE0: bit-3\n" + .set: + set_io REG_CPlusCmd + out dx, ax + + set_io 0xE2 +; mov ax, 0x1517 +; out dx, ax +; mov ax, 0x152a +; out dx, ax +; mov ax, 0x282a +; out dx, ax + xor ax, ax + out dx, ax + + xor eax, eax + mov [tpc.cur_rx], eax + lea eax, [device.tx_ring] + GetRealAddr + set_io REG_TxDescStartAddr + out dx, eax + + lea eax, [device.rx_ring] + GetRealAddr + set_io REG_RxDescStartAddr + out dx, eax + + set_io REG_Cfg9346 + mov al, CFG_9346_Lock + out dx, al + + udelay 10 + + xor eax, eax + set_io REG_RxMissed + out dx, eax + + call set_rx_mode + + set_io 0 + ; no early-rx interrupts + set_io REG_MultiIntr + in ax, dx + and ax, 0xF000 + out dx, ax + + ; set interrupt mask + set_io REG_IntrMask + mov ax, intr_mask + out dx, ax + + xor eax, eax + ret + + +align 4 +read_mac: + + set_io 0 + set_io REG_MAC0 + xor ecx, ecx + lea edi, [device.mac] + mov ecx, 6 + + ; Get MAC address. FIXME: read EEPROM + @@: in al, dx + stosb + inc edx + loop @r + + DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n",\ + [device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + + ret + +align 4 +write_mac: + + ret 6 + + + + + +;*************************************************************************** +; Function +; transmit +; Description +; Transmits a packet of data via the ethernet card +; +; Destroyed registers +; eax, edx, esi, edi +; +;*************************************************************************** +align 4 +transmit: + + DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] + mov eax, [esp+4] + DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp+8], MAX_ETH_FRAME_SIZE + ja .fail + +;---------------------------------- +; Find currentTX descriptor address + + mov eax, tx_desc.size + mul [tpc.cur_tx] + lea esi, [eax + device.tx_ring] + + DEBUGF 1,"Using TX desc: %x\n", esi + +;--------------------------- +; Program the packet pointer + + mov eax, [esp + 4] + mov [esi + tx_desc.buf_soft_addr], eax + GetRealAddr + mov dword [esi + tx_desc.buf_addr], eax + +;------------------------ +; Program the packet size + + mov eax, [esp + 8] + @@: or eax, DSB_OWNbit or DSB_FSbit or DSB_LSbit + cmp [tpc.cur_tx], NUM_TX_DESC - 1 + jne @f + or eax, DSB_EORbit + @@: mov [esi + tx_desc.status], eax + +;----------------------------------------- +; Set the polling bit (start transmission) + + set_io 0 + set_io REG_TxPoll + mov al, 0x40 ; set polling bit + out dx, al + +;----------------------- +; Update TX descriptor + + inc [tpc.cur_tx] + and [tpc.cur_tx], NUM_TX_DESC - 1 + +;------------- +; Update stats + + inc [device.packets_tx] + mov eax, [esp + 8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + + xor eax, eax + ret 8 + + .fail: + DEBUGF 1,"transmit failed\n" + or eax, -1 + stdcall KernelFree, [esp+4] + ret 8 + + +;;;DSB_OWNbit + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service + +; find pointer of device wich made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + + set_io 0 + set_io REG_IntrStatus + in ax, dx + test ax, ax + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) + + .got_it: + + DEBUGF 1,"Device: %x Status: %x ", ebx, ax + + cmp ax, 0xFFFF ; if so, hardware is no longer present + je .fail + +;-------- +; Receive + + test ax, ISB_RxOK + jz .no_rx + + push ax + push ebx + + .check_more: + pop ebx + DEBUGF 1,"ebx = 0x%x\n", ebx + mov eax, rx_desc.size + mul [tpc.cur_rx] + lea esi, [eax + device.rx_ring] + + DEBUGF 1,"RxDesc.status = 0x%x\n", [esi + rx_desc.status] + + mov eax, [esi + rx_desc.status] + test eax, DSB_OWNbit ;;; + jnz .rx_return + + DEBUGF 1,"tpc.cur_rx = %u\n", [tpc.cur_rx] + + test eax, SD_RxRES + jnz .rx_return ;;;;; RX error! + + push ebx + push .check_more + and eax, 0x00001FFF + add eax, -4 ; we dont need CRC + push eax + DEBUGF 1,"data length = %u\n", ax + +;------------- +; Update stats + + add dword [device.bytes_rx], eax + adc dword [device.bytes_rx + 4], 0 + inc dword [device.packets_rx] + + push [esi + rx_desc.buf_soft_addr] + +;---------------------- +; Allocate a new buffer + + stdcall KernelAlloc, RX_BUF_SIZE + mov [esi + rx_desc.buf_soft_addr], eax + GetRealAddr + mov dword [esi + rx_desc.buf_addr], eax + +;--------------- +; re set OWN bit + + mov eax, DSB_OWNbit or RX_BUF_SIZE + cmp [tpc.cur_rx], NUM_RX_DESC - 1 + jne @f + or eax, DSB_EORbit + @@: mov [esi + rx_desc.status], eax + +;-------------- +; Update rx ptr + + inc [tpc.cur_rx] + and [tpc.cur_rx], NUM_RX_DESC - 1 + + jmp Eth_input + .rx_return: + + pop ax + .no_rx: + +;--------- +; Transmit + + test ax, ISB_TxOK + jz .no_tx + push ax + + DEBUGF 1,"TX ok!\n" + + mov ecx, NUM_TX_DESC + lea esi, [device.tx_ring] + .txloop: + cmp [esi + tx_desc.buf_soft_addr], 0 + jz .maybenext + + test [esi + tx_desc.status], DSB_OWNbit + jnz .maybenext + + push ecx + DEBUGF 1,"Freeing up TX desc: %x\n", esi + stdcall KernelFree, [esi + tx_desc.buf_soft_addr] + pop ecx + and [esi + tx_desc.buf_soft_addr], 0 + + .maybenext: + add esi, tx_desc.size + dec ecx + jnz .txloop + + pop ax + .no_tx: + +;------- +; Finish + + set_io 0 + set_io REG_IntrStatus + out dx, ax ; ACK all interrupts + + .fail: + pop edi esi ebx + xor eax, eax + inc eax + + ret + + + + + + + + + +; End of code +align 4 ; Place all initialised data here + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'RTL8169',0 ; max 16 chars include zero + +include_debug_strings ; All data wich FDO uses will be included here + +rtl_chip_info dd \ + MCFG_METHOD_01, 0xff7e1880, \ ; RTL8169 + MCFG_METHOD_02, 0xff7e1880, \ ; RTL8169s/8110s + MCFG_METHOD_03, 0xff7e1880, \ ; RTL8169s/8110s + MCFG_METHOD_04, 0xff7e1880, \ ; RTL8169sb/8110sb + MCFG_METHOD_05, 0xff7e1880, \ ; RTL8169sc/8110sc + MCFG_METHOD_11, 0xff7e1880, \ ; RTL8168b/8111b // PCI-E + MCFG_METHOD_12, 0xff7e1880, \ ; RTL8168b/8111b // PCI-E + MCFG_METHOD_13, 0xff7e1880, \ ; RTL8101e // PCI-E 8139 + MCFG_METHOD_14, 0xff7e1880, \ ; RTL8100e // PCI-E 8139 + MCFG_METHOD_15, 0xff7e1880 ; RTL8100e // PCI-E 8139 + +mac_info dd \ + 0x38800000, MCFG_METHOD_15, \ + 0x38000000, MCFG_METHOD_12, \ + 0x34000000, MCFG_METHOD_13, \ + 0x30800000, MCFG_METHOD_14, \ + 0x30000000, MCFG_METHOD_11, \ + 0x18000000, MCFG_METHOD_05, \ + 0x10000000, MCFG_METHOD_04, \ + 0x04000000, MCFG_METHOD_03, \ + 0x00800000, MCFG_METHOD_02, \ + 0x00000000, MCFG_METHOD_01 ; catch-all + +name_01 db "RTL8169", 0 +name_02_03 db "RTL8169s/8110s", 0 +name_04 db "RTL8169sb/8110sb", 0 +name_05 db "RTL8169sc/8110sc", 0 +name_11_12 db "RTL8168b/8111b", 0 ; PCI-E +name_13 db "RTL8101e", 0 ; PCI-E 8139 +name_14_15 db "RTL8100e", 0 ; PCI-E 8139 + + +section '.data' data readable writable align 16 ; place all uninitialized data place here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + + diff --git a/drivers/ethernet/bcm57xx.asm b/drivers/ethernet/bcm57xx.asm new file mode 100644 index 0000000000..7b8f57ca55 --- /dev/null +++ b/drivers/ethernet/bcm57xx.asm @@ -0,0 +1,424 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Broadcom NetXtreme 57xx driver for KolibriOS ;; +;; ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;; Broadcom's programmers's manual for the BCM57xx ;; +;; http://www.broadcom.com/collateral/pg/57XX-PG105-R.pdf ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + ; TODO: make better use of the available descriptors + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + + +virtual at ebx + device: + ETH_DEVICE + + .mmio_addr dd ? + .pci_bus dd ? + .pci_dev dd ? + .irq_line db ? + + .cur_tx dd ? + .last_tx dd ? + + rb 0x100 - (($ - device) and 0xff) + .rx_desc rd 256/8 + + rb 0x100 - (($ - device) and 0xff) + .tx_desc rd 256/8 + + sizeof.device_struct = $ - device + +end virtual + +section '.flat' code readable align 16 + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 2,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax, [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte [device.pci_bus] + jne .next + cmp ah, byte [device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + .next: + add esi, 4 + loop .nextdevice + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, sizeof.device_struct, .fail ; Allocate the buffer for device structure + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte [eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte [eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base mmio addres of the PCI device + + PCI_find_mmio32 + +; Create virtual mapping of the physical memory + + push 1Bh ; PG_SW+PG_NOCACHE + push 10000h ; size of the map + push eax + call MapIoMem + mov [device.mmio_addr], eax + +; We've found the mmio address, find IRQ now + + PCI_find_irq + + DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.mmio_addr]:8 + +; Ok, the eth_device structure is ready, let's probe the device + call probe ; this function will output in eax + test eax, eax + jnz .err ; If an error occured, exit + + mov eax, [devices] ; Add the device structure to our device list + mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + je .destroy + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 1,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 1,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + .err: + stdcall KernelFree, ebx + + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + +align 4 +unload: + ; TODO: (in this particular order) + ; + ; - Stop the device + ; - Detach int handler + ; - Remove device from local list (device_list) + ; - call unregister function in kernel + ; - Remove all allocated structures and buffers the card used + + or eax, -1 + +ret + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; probe: enables the device (if it really is I8254X) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +align 4 +probe: + + DEBUGF 1,"Probe\n" + + PCI_make_bus_master + + ; TODO: validate the device + + + + + +align 4 +reset: + + DEBUGF 1,"Reset\n" + + movzx eax, [device.irq_line] + DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 1,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + + call read_mac + +; Set the mtu, kernel will be able to send now + mov [device.mtu], 1514 + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + + ret + + + + +align 4 +read_mac: + + DEBUGF 1,"Read MAC\n" + + mov esi, [device.mmio_addr] + lea edi, [device.mac] + movsd + movsw + + .mac_ok: + DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n",\ + [device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + + ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +align 4 +transmit: + DEBUGF 2,"\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] + mov eax, [esp+4] + DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp + 8], 1514 + ja .fail + cmp dword [esp + 8], 60 + jb .fail + + + + +; Update stats + inc [device.packets_tx] + mov eax, [esp + 8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + + ret 8 + + .fail: + DEBUGF 1,"Send failed\n" + ret 8 + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service +;------------------------------------------- +; Find pointer of device wich made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + +; mov edi, [device.mmio_addr] +; mov eax, [edi + REG_ICR] + test eax, eax + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret + + .got_it: + + DEBUGF 1,"Device: %x Status: %x ", ebx, eax + + pop edi esi ebx + xor eax, eax + inc eax + + ret + + + + +; End of code + +section '.data' data readable writable align 16 +align 4 + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'BCM57XX',0 ; max 16 chars include zero + +include_debug_strings ; All data wich FDO uses will be included here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + + diff --git a/drivers/ethernet/dec21x4x.asm b/drivers/ethernet/dec21x4x.asm new file mode 100644 index 0000000000..c08c50dec7 --- /dev/null +++ b/drivers/ethernet/dec21x4x.asm @@ -0,0 +1,1702 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; DEC 21x4x driver for KolibriOS ;; +;; ;; +;; Based on dec21140.Asm from Solar OS by ;; +;; Eugen Brasoveanu, ;; +;; Ontanu Bogdan Valentin ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + RX_DES_COUNT = 4 ; no of RX descriptors, must be power of 2 + RX_BUFF_SIZE = 2048 ; size of buffer for each descriptor, must be multiple of 4 and <= 2048 TDES1_TBS1_MASK + + TX_DES_COUNT = 4 ; no of TX descriptors, must be power of 2 + TX_BUFF_SIZE = 2048 ; size of buffer for each descriptor, used for memory allocation only + + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + +virtual at ebx + + device: + + ETH_DEVICE + + .rx_p_des dd ? ; descriptors ring with received packets + .tx_p_des dd ? ; descriptors ring with 'to transmit' packets + .tx_free_des dd ? ; Tx descriptors available + .tx_wr_des dd ? ; Tx current descriptor to write data to + .tx_rd_des dd ? ; Tx current descriptor to read TX completion + .rx_crt_des dd ? ; Rx current descriptor + + .io_addr dd ? + .pci_bus dd ? + .pci_dev dd ? + .irq_line db ? + + .size = $ - device + +end virtual + +;------------------------------------------- +; configuration registers +;------------------------------------------- +CFCS = 4 ; configuration and status register + +CSR0 = 0x00 ; Bus mode +CSR1 = 0x08 ; Transmit Poll Command +CSR2 = 0x10 ; Receive Poll Command +CSR3 = 0x18 ; Receive list base address +CSR4 = 0x20 ; Transmit list base address +CSR5 = 0x28 ; Status +CSR6 = 0x30 ; Operation mode +CSR7 = 0x38 ; Interrupt enable +CSR8 = 0x40 ; Missed frames and overflow counter +CSR9 = 0x48 ; Boot ROM, serial ROM, and MII management +CSR10 = 0x50 ; Boot ROM programming address +CSR11 = 0x58 ; General-purpose timer +CSR12 = 0x60 ; General-purpose port +CSR13 = 0x68 +CSR14 = 0x70 +CSR15 = 0x78 ; Watchdog timer + +;--------bits/commands of CSR0------------------- +CSR0_RESET = 1b + +CSR0_WIE = 1 shl 24 ; Write and Invalidate Enable +CSR0_RLE = 1 shl 23 ; PCI Read Line Enable +CSR0_RML = 1 shl 21 ; PCI Read Multiple + +CSR0_CACHEALIGN_NONE = 00b shl 14 +CSR0_CACHEALIGN_32 = 01b shl 14 +CSR0_CACHEALIGN_64 = 10b shl 14 +CSR0_CACHEALIGN_128 = 11b shl 14 + +; using values from linux driver.. +CSR0_DEFAULT = CSR0_WIE + CSR0_RLE + CSR0_RML + CSR0_CACHEALIGN_NONE + +;------- CSR5 -STATUS- bits -------------------------------- +CSR5_TI = 1 shl 0 ; Transmit interupt - frame transmition completed +CSR5_TPS = 1 shl 1 ; Transmit process stopped +CSR5_TU = 1 shl 2 ; Transmit Buffer unavailable +CSR5_TJT = 1 shl 3 ; Transmit Jabber Timeout (transmitter had been excessively active) +CSR5_UNF = 1 shl 5 ; Transmit underflow - FIFO underflow +CSR5_RI = 1 shl 6 ; Receive Interrupt +CSR5_RU = 1 shl 7 ; Receive Buffer unavailable +CSR5_RPS = 1 shl 8 ; Receive Process stopped +CSR5_RWT = 1 shl 9 ; Receive Watchdow Timeout +CSR5_ETI = 1 shl 10 ; Early transmit Interrupt +CSR5_GTE = 1 shl 11 ; General Purpose Timer Expired +CSR5_FBE = 1 shl 13 ; Fatal bus error +CSR5_ERI = 1 shl 14 ; Early receive Interrupt +CSR5_AIS = 1 shl 15 ; Abnormal interrupt summary +CSR5_NIS = 1 shl 16 ; normal interrupt summary +CSR5_RS_SH = 17 ; Receive process state -shift +CSR5_RS_MASK = 111b ; -mask +CSR5_TS_SH = 20 ; Transmit process state -shift +CSR5_TS_MASK = 111b ; -mask +CSR5_EB_SH = 23 ; Error bits -shift +CSR5_EB_MASK = 111b ; Error bits -mask + +;CSR5 TS values +CSR5_TS_STOPPED = 000b +CSR5_TS_RUNNING_FETCHING_DESC = 001b +CSR5_TS_RUNNING_WAITING_TX = 010b +CSR5_TS_RUNNING_READING_BUFF = 011b +CSR5_TS_RUNNING_SETUP_PCKT = 101b +CSR5_TS_SUSPENDED = 110b +CSR5_TS_RUNNING_CLOSING_DESC = 111b + +;------- CSR6 -OPERATION MODE- bits -------------------------------- +CSR6_HP = 1 shl 0 ; Hash/Perfect Receive Filtering mode +CSR6_SR = 1 shl 1 ; Start/Stop receive +CSR6_HO = 1 shl 2 ; Hash only Filtering mode +CSR6_PB = 1 shl 3 ; Pass bad frames +CSR6_IF = 1 shl 4 ; Inverse filtering +CSR6_SB = 1 shl 5 ; Start/Stop backoff counter +CSR6_PR = 1 shl 6 ; Promiscuos mode -default after reset +CSR6_PM = 1 shl 7 ; Pass all multicast +CSR6_F = 1 shl 9 ; Full Duplex mode +CSR6_OM_SH = 10 ; Operating Mode -shift +CSR6_OM_MASK = 11b ; -mask +CSR6_FC = 1 shl 12 ; Force Collision Mode +CSR6_ST = 1 shl 13 ; Start/Stop Transmission Command +CSR6_TR_SH = 14 ; Threshold Control -shift +CSR6_TR_MASK = 11b ; -mask +CSR6_CA = 1 shl 17 ; Capture Effect Enable +CSR6_PS = 1 shl 18 ; Port select SRL / MII/SYM +CSR6_HBD = 1 shl 19 ; Heartbeat Disable +CSR6_SF = 1 shl 21 ; Store and Forward -transmit full packet only +CSR6_TTM = 1 shl 22 ; Transmit Threshold Mode - +CSR6_PCS = 1 shl 23 ; PCS active and MII/SYM port operates in symbol mode +CSR6_SCR = 1 shl 24 ; Scrambler Mode +CSR6_MBO = 1 shl 25 ; Must Be One +CSR6_RA = 1 shl 30 ; Receive All +CSR6_SC = 1 shl 31 ; Special Capture Effect Enable + + +;------- CSR7 -INTERRUPT ENABLE- bits -------------------------------- +CSR7_TI = 1 shl 0 ; transmit Interrupt Enable (set with CSR7<16> & CSR5<0> ) +CSR7_TS = 1 shl 1 ; transmit Stopped Enable (set with CSR7<15> & CSR5<1> ) +CSR7_TU = 1 shl 2 ; transmit buffer underrun Enable (set with CSR7<16> & CSR5<2> ) +CSR7_TJ = 1 shl 3 ; transmit jabber timeout enable (set with CSR7<15> & CSR5<3> ) +CSR7_UN = 1 shl 5 ; underflow Interrupt enable (set with CSR7<15> & CSR5<5> ) +CSR7_RI = 1 shl 6 ; receive Interrupt enable (set with CSR7<16> & CSR5<5> ) +CSR7_RU = 1 shl 7 ; receive buffer unavailable enable (set with CSR7<15> & CSR5<7> ) +CSR7_RS = 1 shl 8 ; Receive stopped enable (set with CSR7<15> & CSR5<8> ) +CSR7_RW = 1 shl 9 ; receive watchdog timeout enable (set with CSR7<15> & CSR5<9> ) +CSR7_ETE = 1 shl 10 ; Early transmit Interrupt enable (set with CSR7<15> & CSR5<10> ) +CSR7_GPT = 1 shl 11 ; general purpose timer enable (set with CSR7<15> & CSR5<11> ) +CSR7_FBE = 1 shl 13 ; Fatal bus error enable (set with CSR7<15> & CSR5<13> ) +CSR7_ERE = 1 shl 14 ; Early receive enable (set with CSR7<16> & CSR5<14> ) +CSR7_AI = 1 shl 15 ; Abnormal Interrupt Summary Enable (enables CSR5<0,3,7,8,9,10,13>) +CSR7_NI = 1 shl 16 ; Normal Interrup Enable (enables CSR5<0,2,6,11,14>) + +CSR7_DEFAULT = CSR7_TI + CSR7_TS + CSR7_RI + CSR7_RS + CSR7_TU + CSR7_TJ + CSR7_UN + \ + CSR7_RU + CSR7_RW + CSR7_FBE + CSR7_AI + CSR7_NI + +;----------- descriptor structure --------------------- +struc DES { + .status dd ? ; bit 31 is 'own' and rest is 'status' + .length dd ? ; control bits + bytes-count buffer 1 + bytes-count buffer 2 + .buffer1 dd ? ; pointer to buffer1 + .buffer2 dd ? ; pointer to buffer2 or in this case to next descriptor, as we use a chained structure + .virtaddr dd ? + .size = 64 ; 64, for alignment purposes +} + +virtual at 0 + DES DES +end virtual + +;common to Rx and Tx +DES0_OWN = 1 shl 31 ; if set, the NIC controls the descriptor, otherwise driver 'owns' the descriptors + +;receive +RDES0_ZER = 1 shl 0 ; must be 0 if legal length :D +RDES0_CE = 1 shl 1 ; CRC error, valid only on last desc (RDES0<8>=1) +RDES0_DB = 1 shl 2 ; dribbling bit - not multiple of 8 bits, valid only on last desc (RDES0<8>=1) +RDES0_RE = 1 shl 3 ; Report on MII error.. i dont realy know what this means :P +RDES0_RW = 1 shl 4 ; received watchdog timer expiration - must set CSR5<9>, valid only on last desc (RDES0<8>=1) +RDES0_FT = 1 shl 5 ; frame type: 0->IEEE802.0 (len<1500) 1-> ETHERNET frame (len>1500), valid only on last desc (RDES0<8>=1) +RDES0_CS = 1 shl 6 ; Collision seen, valid only on last desc (RDES0<8>=1) +RDES0_TL = 1 shl 7 ; Too long(>1518)-NOT AN ERROR, valid only on last desc (RDES0<8>=1) +RDES0_LS = 1 shl 8 ; Last descriptor of current frame +RDES0_FS = 1 shl 9 ; First descriptor of current frame +RDES0_MF = 1 shl 10 ; Multicast frame, valid only on last desc (RDES0<8>=1) +RDES0_RF = 1 shl 11 ; Runt frame, valid only on last desc (RDES0<8>=1) and id overflow +RDES0_DT_SERIAL = 00b shl 12 ; Data type-Serial recv frame, valid only on last desc (RDES0<8>=1) +RDES0_DT_INTERNAL = 01b shl 12 ; Data type-Internal loopback recv frame, valid only on last desc (RDES0<8>=1) +RDES0_DT_EXTERNAL = 11b shl 12 ; Data type-External loopback recv frame, valid only on last desc (RDES0<8>=1) +RDES0_DE = 1 shl 14 ; Descriptor error - cant own a new desc and frame doesnt fit, valid only on last desc (RDES0<8>=1) +RDES0_ES = 1 shl 15 ; Error Summmary - bits 1+6+11+14, valid only on last desc (RDES0<8>=1) +RDES0_FL_SH = 16 ; Field length shift, valid only on last desc (RDES0<8>=1) +RDES0_FL_MASK = 11111111111111b ; Field length mask (+CRC), valid only on last desc (RDES0<8>=1) +RDES0_FF = 1 shl 30 ; Filtering fail-frame failed address recognition test(must CSR6<30>=1), valid only on last desc (RDES0<8>=1) + +RDES1_RBS1_MASK = 11111111111b ; first buffer size MASK +RDES1_RBS2_SH = 11 ; second buffer size SHIFT +RDES1_RBS2_MASK = 11111111111b ; second buffer size MASK +RDES1_RCH = 1 shl 24 ; Second address chained - second address (buffer) is next desc address +RDES1_RER = 1 shl 25 ; Receive End of Ring - final descriptor, NIC must return to first desc + +;transmition +TDES0_DE = 1 shl 0 ; Deffered +TDES0_UF = 1 shl 1 ; Underflow error +TDES0_LF = 1 shl 2 ; Link fail report (only if CSR6<23>=1) +TDES0_CC_SH = 3 ; Collision Count shift - no of collision before transmition +TDES0_CC_MASK = 1111b ; Collision Count mask +TDES0_HF = 1 shl 7 ; Heartbeat fail +TDES0_EC = 1 shl 8 ; Excessive Collisions - >16 collisions +TDES0_LC = 1 shl 9 ; Late collision +TDES0_NC = 1 shl 10 ; No carrier +TDES0_LO = 1 shl 11 ; Loss of carrier +TDES0_TO = 1 shl 14 ; Transmit Jabber Timeout +TDES0_ES = 1 shl 15 ; Error summary TDES0<1+8+9+10+11+14>=1 + +TDES1_TBS1_MASK = 11111111111b ; Buffer 1 size mask +TDES1_TBS2_SH = 11 ; Buffer 2 size shift +TDES1_TBS2_MASK = 11111111111b ; Buffer 2 size mask +TDES1_FT0 = 1 shl 22 ; Filtering type 0 +TDES1_DPD = 1 shl 23 ; Disabled padding for packets <64bytes, no padding +TDES1_TCH = 1 shl 24 ; Second address chained - second buffer pointer is to next desc +TDES1_TER = 1 shl 25 ; Transmit end of ring - final descriptor +TDES1_AC = 1 shl 26 ; Add CRC disable -pretty obvious +TDES1_SET = 1 shl 27 ; Setup packet +TDES1_FT1 = 1 shl 28 ; Filtering type 1 +TDES1_FS = 1 shl 29 ; First segment - buffer is first segment of frame +TDES1_LS = 1 shl 30 ; Last segment +TDES1_IC = 1 shl 31 ; Interupt on completion (CSR5<0>=1) valid when TDES1<30>=1 + +MAX_ETH_FRAME_SIZE = 1514 + +RX_MEM_TOTAL_SIZE = RX_DES_COUNT*(DES.size+RX_BUFF_SIZE) +TX_MEM_TOTAL_SIZE = TX_DES_COUNT*(DES.size+TX_BUFF_SIZE) + +;============================================================================= +; serial ROM operations +;============================================================================= +CSR9_SR = 1 shl 11 ; SROM Select +CSR9_RD = 1 shl 14 ; ROM Read Operation +CSR9_SROM_DO = 1 shl 3 ; Data Out for SROM +CSR9_SROM_DI = 1 shl 2 ; Data In to SROM +CSR9_SROM_CK = 1 shl 1 ; clock for SROM +CSR9_SROM_CS = 1 shl 0 ; chip select.. always needed + +; assume dx is CSR9 +macro SROM_Delay { + push eax + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + pop eax +} + +; assume dx is CSR9 +macro MDIO_Delay { + push eax + in eax, dx + pop eax +} + +macro Bit_Set a_bit { + in eax, dx + or eax, a_bit + out dx , eax +} + +macro Bit_Clear a_bit { + in eax, dx + and eax, not (a_bit) + out dx, eax +} + + +section '.flat' code readable align 16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 2,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax , [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + push edx + stdcall KernelAlloc, dword device.size ; Allocate the buffer for eth_device structure + pop edx + test eax, eax + jz .fail + mov ebx, eax ; ebx is always used as a pointer to the structure (in driver, but also in kernel code) + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base io addres of the PCI device + + PCI_find_io + +; We've found the io address, find IRQ now + + PCI_find_irq + + DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:8 + + allocate_and_clear [device.rx_p_des], RX_DES_COUNT*(DES.size+RX_BUFF_SIZE), .err + allocate_and_clear [device.tx_p_des], TX_DES_COUNT*(DES.size+TX_BUFF_SIZE), .err + +; Ok, the eth_device structure is ready, let's probe the device +; Because initialization fires IRQ, IRQ handler must be aware of this device + mov eax, [devices] ; Add the device structure to our device list + mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + call probe ; this function will output in eax + test eax, eax + jnz .err2 ; If an error occured, exit + + + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + je .destroy + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 2,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 2,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + .err2: + dec [devices] + .err: + DEBUGF 2,"removing device structure\n" + stdcall KernelFree, [device.rx_p_des] + stdcall KernelFree, [device.tx_p_des] + stdcall KernelFree, ebx + + + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + + +align 4 +unload: + ; TODO: (in this particular order) + ; + ; - Stop the device + ; - Detach int handler + ; - Remove device from local list (RTL8139_LIST) + ; - call unregister function in kernel + ; - Remove all allocated structures and buffers the card used + + or eax,-1 + +ret + + +macro status { + set_io CSR5 + in eax, dx + DEBUGF 1,"CSR5: %x\n", eax +} + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Probe ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +probe: + + DEBUGF 2,"Probing dec21x4x device: " + + PCI_make_bus_master + + stdcall PciRead32, [device.pci_bus], [device.pci_dev], 0 ; get device/vendor id + DEBUGF 1,"Vendor id: 0x%x\n", ax + + cmp ax, 0x1011 + je .dec + cmp ax, 0x1317 + je .admtek + jmp .notfound + + .dec: + shr eax, 16 + DEBUGF 1,"Vendor ok!, device id: 0x%x\n", ax ; TODO: use another method to detect chip! + + cmp ax, 0x0009 + je .supported_device + + cmp ax, 0x0019 + je .supported_device2 + + .admtek: + shr eax, 16 + DEBUGF 1,"Vendor ok!, device id: 0x%x\n", ax + + cmp ax, 0x0985 + je .supported_device + + .notfound: + DEBUGF 1,"Device not supported!\n" + or eax, -1 + ret + + .supported_device2: + + ; wake up the 21143 + + xor eax, eax + stdcall PciWrite32, [device.pci_bus], [device.pci_dev], 0x40, eax + + + .supported_device: + call SROM_GetWidth ; TODO: use this value returned in ecx + ; in the read_word routine! + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Reset ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +reset: + + DEBUGF 2,"Resetting dec21x4x\n" + +;----------------------------------------------------------- +; board software reset - if fails, dont do nothing else + + set_io 0 + status + set_io CSR0 + mov eax, CSR0_RESET + out dx, eax + +; wait at least 50 PCI cycles + mov esi, 1000 + call Sleep + +;----------- +; setup CSR0 + + set_io 0 + status + set_io CSR0 + mov eax, CSR0_DEFAULT + out dx, eax + + +; wait at least 50 PCI cycles + mov esi, 1000 + call Sleep + +;----------------------------------- +; Read mac from eeprom to driver ram + + call read_mac_eeprom + +;-------------------------------- +; insert irq handler on given irq + + movzx eax, [device.irq_line] + DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 1,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + + set_io 0 + status + + call init_ring + +;-------------------------------------------- +; setup CSR3 & CSR4 (pointers to descriptors) + + set_io 0 + status + set_io CSR3 + mov eax, [device.rx_p_des] + GetRealAddr + DEBUGF 1,"RX descriptor base address: %x\n", eax + out dx, eax + + set_io CSR4 + mov eax, [device.tx_p_des] + GetRealAddr + DEBUGF 1,"TX descriptor base address: %x\n", eax + out dx, eax + +;------------------------------------------------------- +; setup interrupt mask register -expect IRQs from now on + + status + DEBUGF 1,"Enabling interrupts\n" + set_io CSR7 + mov eax, CSR7_DEFAULT + out dx, eax + status + +;---------- +; enable RX + + set_io 0 + status + DEBUGF 1,"Enable RX\n" + + set_io CSR6 + Bit_Set CSR6_SR; or CSR6_PR or CSR6_ST + DEBUGF 1,"CSR6: %x\n", eax + + status + + call start_link + +; wait a bit + mov esi, 3000 + call Sleep + +;---------------------------------------------------- +; send setup packet to notify the board about the MAC + + call Send_Setup_Packet + + xor eax, eax +; clear packet/byte counters + + lea edi, [device.bytes_tx] + mov ecx, 6 + rep stosd + +; Set the mtu, kernel will be able to send now + mov [device.mtu], 1514 + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + + DEBUGF 1,"Reset done\n" + + ret + + + +align 4 +init_ring: + +;------------------------------------------ +; Setup RX descriptors (use chained method) + + mov eax, [device.rx_p_des] + GetRealAddr + mov edx, eax + push eax + lea esi, [eax + RX_DES_COUNT*(DES.size)] ; jump over RX descriptors + mov eax, [device.rx_p_des] + add eax, RX_DES_COUNT*(DES.size) ; jump over RX descriptors + mov edi, [device.rx_p_des] + mov ecx, RX_DES_COUNT + .loop_rx_des: + add edx, DES.size + mov [edi + DES.status], DES0_OWN ; hardware owns buffer + mov [edi + DES.length], 1984 + RDES1_RCH ; only size of first buffer, chained buffers + mov [edi + DES.buffer1], esi ; hw buffer address + mov [edi + DES.buffer2], edx ; pointer to next descriptor + mov [edi + DES.virtaddr], eax ; virtual buffer address + DEBUGF 1,"RX desc: buff addr: %x, next desc: %x, real buff addr: %x, real descr addr: %x \n", esi, edx, eax, edi + + add esi, RX_BUFF_SIZE + add eax, RX_BUFF_SIZE + add edi, DES.size + dec ecx + jnz .loop_rx_des + +; set last descriptor as LAST + sub edi, DES.size + or [edi + DES.length], RDES1_RER ; EndOfRing + pop [edi + DES.buffer2] ; point it to the first descriptor + +;--------------------- +; Setup TX descriptors + + mov eax, [device.tx_p_des] + GetRealAddr + mov edx, eax + push eax + lea esi, [eax + TX_DES_COUNT*(DES.size)] ; jump over TX descriptors + mov eax, [device.tx_p_des] + add eax, TX_DES_COUNT*(DES.size) ; jump over TX descriptors + mov edi, [device.tx_p_des] + mov ecx, TX_DES_COUNT + .loop_tx_des: + add edx, DES.size + mov [edi + DES.status], 0 ; owned by driver + mov [edi + DES.length], TDES1_TCH ; chained method + mov [edi + DES.buffer1], esi ; pointer to buffer + mov [edi + DES.buffer2], edx ; pointer to next descr + mov [edi + DES.virtaddr], eax + DEBUGF 1,"TX desc: buff addr: %x, next desc: %x, virt buff addr: %x, virt descr addr: %x \n", esi, edx, eax, edi + + add esi, TX_BUFF_SIZE + add eax, TX_BUFF_SIZE + add edi, DES.size + dec ecx + jnz .loop_tx_des + +; set last descriptor as LAST + sub edi, DES.size + or [edi + DES.length], TDES1_TER ; EndOfRing + pop [edi + DES.buffer2] ; point it to the first descriptor + +;------------------ +; Reset descriptors + + mov [device.tx_wr_des], 0 + mov [device.tx_rd_des], 0 + mov [device.rx_crt_des], 0 + mov [device.tx_free_des], TX_DES_COUNT + + ret + + +align 4 +start_link: + + ; TODO: write working code here + + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Send setup packet ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +Send_Setup_Packet: + + DEBUGF 1,"Sending setup packet\n" + +; if no descriptors available, out + mov ecx, 1000 +@@loop_wait_desc: + cmp [device.tx_free_des], 0 + jne @f + + dec ecx + jnz @@loop_wait_desc + + mov eax, -1 + ret + @@: + +; go to current send descriptor + mov edi, [device.tx_p_des] + mov eax, [device.tx_wr_des] + DEBUGF 1,"Got free descriptor: %u (%x)", eax, edi + mov edx, DES.size + mul edx + add edi, eax + DEBUGF 1,"=>%x\n", edi + +; if NOT sending FIRST setup packet, must set current descriptor to 0 size for both buffers, +; and go to next descriptor for real setup packet... ;; TODO: check if 2 descriptors are available + +; cmp [device.tx_packets], 0 +; je .first +; +; and [edi+DES.des1], 0 +; mov [edi+DES.des0], DES0_OWN +; +; go to next descriptor +; inc [device.tx_wr_des] +; and [device.tx_wr_des], TX_DES_COUNT-1 +; +; dec free descriptors count +; cmp [device.tx_free_des], 0 +; jz @f +; dec [device.tx_free_des] +; @@: +; +; ; recompute pointer to current descriptor +; mov edi, [device.tx_p_des] +; mov eax, [device.tx_wr_des] +; mov edx, DES.size +; mul edx +; add edi, eax + + .first: + + push edi +; copy setup packet to current descriptor + mov edi, [edi + DES.virtaddr] +; copy the address once + lea esi, [device.mac] + DEBUGF 1,"copying packet to %x from %x\n", edi, esi + mov ecx, 3 ; mac is 6 bytes thus 3 words + .loop: + DEBUGF 1,"%x ", [esi]:4 + movsw + inc edi + inc edi + dec ecx + jnz .loop + + DEBUGF 1,"\n" + +; copy 15 times the broadcast address + mov ecx, 3*15 + mov eax, 0xffffffff + rep stosd + + pop edi + +; setup descriptor + DEBUGF 1,"setting up descriptor\n" + mov [edi + DES.length], TDES1_IC + TDES1_SET + TDES1_TCH + 192 ; size must be EXACTLY 192 bytes + mov [edi + DES.status], DES0_OWN + + DEBUGF 1,"status: %x\n", [edi + DES.status]:8 + DEBUGF 1,"length: %x\n", [edi + DES.length]:8 + DEBUGF 1,"buffer1: %x\n", [edi + DES.buffer1]:8 + DEBUGF 1,"buffer2: %x\n", [edi + DES.buffer2]:8 + +; go to next descriptor + inc [device.tx_wr_des] + and [device.tx_wr_des], TX_DES_COUNT-1 + +; dec free descriptors count + cmp [device.tx_free_des], 0 + jz @f + dec [device.tx_free_des] + @@: + +; start tx + set_io 0 + status + set_io CSR6 + in eax, dx + test eax, CSR6_ST ; if NOT started, start now + jnz .already_started + or eax, CSR6_ST + DEBUGF 1,"Starting TX\n" + jmp .do_it + .already_started: + ; if already started, issue a Transmit Poll command + set_io CSR1 + xor eax, eax + DEBUGF 1,"Issuing transmit poll command\n" + .do_it: + out dx, eax + status + + DEBUGF 1,"Sending setup packet, completed!\n" + + ret + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +transmit: + + DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8] + mov eax, [esp+4] + DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp+8], MAX_ETH_FRAME_SIZE + ja .fail + + cmp [device.tx_free_des], 0 + je .fail + +;-------------------------- +; copy packet to crt buffer + + mov eax, [device.tx_wr_des] + mov edx, DES.size + mul edx + add eax, [device.tx_p_des] + mov edi, [eax + DES.virtaddr] ; pointer to buffer + mov esi, [esp+4] + mov ecx, [esp+8] + DEBUGF 1,"copying %u bytes from %x to %x\n", ecx, esi, edi + rep movsb + +; set packet size + mov ecx, [eax+DES.length] + and ecx, TDES1_TER ; preserve 'End of Ring' bit + or ecx, [esp+8] ; set size + or ecx, TDES1_FS or TDES1_LS or TDES1_IC or TDES1_TCH ; first descr, last descr, interrupt on complete, chained modus + mov [eax+DES.length], ecx + +; set descriptor info + mov [eax+DES.status], DES0_OWN ; say it is now owned by the 21x4x + +; start tx + set_io 0 + status + set_io CSR6 + in eax, dx + test eax, CSR6_ST ; if NOT started, start now + jnz .already_started + or eax, CSR6_ST + DEBUGF 1,"Starting TX\n" + jmp .do_it + .already_started: + ; if already started, issues a Transmit Poll command + set_io CSR1 + mov eax, -1 + .do_it: + out dx , eax + +; Update stats + + inc [device.packets_tx] + mov eax, [esp+8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + +; go to next descriptor + inc [device.tx_wr_des] + and [device.tx_wr_des], TX_DES_COUNT-1 + +; dec free descriptors count + test [device.tx_free_des], -1 + jz .end + dec [device.tx_free_des] + .end: + status + + DEBUGF 1,"transmit ok\n" + xor eax, eax + stdcall KernelFree, [esp+4] + ret 8 + + .fail: + DEBUGF 1,"transmit failed\n" + or eax, -1 + stdcall KernelFree, [esp+4] + ret 8 + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service + +; find pointer of device wich made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + + set_io 0 + set_io CSR5 + in eax, dx + test eax, eax + jnz .got_it + out dx, eax ; send it back to ACK + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) + + .got_it: + + DEBUGF 1,"Device: %x CSR5: %x ", ebx, ax + +;---------------------------------- +; TX ok? + + test ax, CSR5_TI + jz .not_tx + push ax esi ecx + + DEBUGF 1,"TX ok!\n" + + ; go to current descriptor + mov edi, [device.tx_p_des] + + mov eax, [device.tx_rd_des] + mov edx, DES.size + mul edx + add edi, eax + + .loop_tx: + + ; done if all desc are free + cmp [device.tx_free_des], TX_DES_COUNT + jz .end_tx + + mov eax, [edi+DES.status] + + ; we stop at first desc that is owned be NIC + test eax, DES0_OWN + jnz .end_tx + + ; detect is setup packet + cmp eax, (0ffffffffh - DES0_OWN) ; all other bits are 1 + jne .not_setup_packet + DEBUGF 1,"Setup Packet detected\n" + .not_setup_packet: + + DEBUGF 1,"packet status: %x\n", eax + + ; next descriptor + add edi, DES.size + inc [device.tx_rd_des] + and [device.tx_rd_des], TX_DES_COUNT-1 + + ; inc free desc + inc [device.tx_free_des] + cmp [device.tx_free_des], TX_DES_COUNT + jbe @f + mov [device.tx_free_des], TX_DES_COUNT + @@: + + jmp .loop_tx + .end_tx: + + ;------------------------------------------------------ + ; here must be called standard Ethernet Tx Irq Handler + ;------------------------------------------------------ + + pop ecx esi ax + +;---------------------------------- +; RX irq + .not_tx: + test ax, CSR5_RI + jz .not_rx + push ax esi ecx + + DEBUGF 1,"RX ok!\n" + + push ebx + .rx_loop: + pop ebx + + ; get current descriptor + mov edi, [device.rx_p_des] + mov eax, [device.rx_crt_des] + mov edx, DES.size + mul edx + add edi, eax + + ; now check status + mov eax, [edi + DES.status] + + test eax, DES0_OWN + jnz .end_rx ; current desc is busy, nothing to do + + test eax, RDES0_FS + jz .end_rx ; current desc is NOT first packet, ERROR! + + test eax, RDES0_LS ; if not last desc of packet, error for now + jz .end_rx + + test eax, RDES0_ES + jnz .end_rx + + mov esi, [edi + DES.virtaddr] + mov ecx, [edi + DES.status] + shr ecx, RDES0_FL_SH + and ecx, RDES0_FL_MASK + sub ecx, 4 ; crc, we dont need it + + DEBUGF 1,"Received packet!, size=%u, addr:%x\n", ecx, esi + + push esi edi ecx + stdcall KernelAlloc, ecx ; Allocate a buffer to put packet into + pop ecx edi esi + test eax, eax + jz .fail + + push ebx + push dword .rx_loop + push ecx eax + mov edi, eax + +; update statistics + inc [device.packets_rx] + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + +; copy packet data + shr cx , 1 + jnc .nb + movsb + .nb: + shr cx , 1 + jnc .nw + movsw + .nw: + rep movsd + + mov [edi + DES.status], DES0_OWN ; free descriptor + + inc [device.rx_crt_des] ; next descriptor + and [device.rx_crt_des], RX_DES_COUNT-1 + + jmp Eth_input + + .end_rx: + .fail: + pop ecx esi ax + .not_rx: + + pop edi esi ebx + ret + + + +align 4 +write_mac: ; in: mac pushed onto stack (as 3 words) + + DEBUGF 2,"Writing MAC: " + +; write data into driver cache + mov esi, esp + lea edi, [device.mac] + movsd + movsw + add esp, 6 + +; send setup packet (only if driver is started) + call Send_Setup_Packet + +align 4 +read_mac: + + DEBUGF 1,"Read_mac\n" + + ret + + + +align 4 +read_mac_eeprom: + + DEBUGF 1,"Read_mac_eeprom\n" + + lea edi, [device.mac] + mov esi, 20/2 ; read words, start address is 20 + .loop: + push esi edi + call SROM_Read_Word + pop edi esi + stosw + inc esi + cmp esi, 26/2 + jb .loop + + DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[edi-6]:2,[edi-5]:2,[edi-4]:2,[edi-3]:2,[edi-2]:2,[edi-1]:2 + + ret + +align 4 +write_mac_eeprom: + + DEBUGF 1,"Write_mac_eeprom\n" + + ret + + +align 4 +SROM_GetWidth: ; should be 6 or 8 according to some manuals (returns in ecx) + + DEBUGF 1,"SROM_GetWidth\n" + + call SROM_Idle + call SROM_EnterAccessMode + +; set_io 0 +; set_io CSR9 + + ; send 110b + + in eax, dx + or eax, CSR9_SROM_DI + call SROM_out + + in eax, dx + or eax, CSR9_SROM_DI + call SROM_out + + in eax, dx + and eax, not (CSR9_SROM_DI) + call SROM_out + + mov ecx,1 + .loop2: + Bit_Set CSR9_SROM_CK + SROM_Delay + + in eax, dx + and eax, CSR9_SROM_DO + jnz .not_zero + + Bit_Clear CSR9_SROM_CK + SROM_Delay + jmp .end_loop2 + .not_zero: + + Bit_Clear CSR9_SROM_CK + SROM_Delay + + inc ecx + cmp ecx, 12 + jbe .loop2 + .end_loop2: + + DEBUGF 1,"Srom width=%u\n", ecx + + call SROM_Idle + call SROM_EnterAccessMode + call SROM_Idle + + ret + + +align 4 +SROM_out: + + out dx, eax + SROM_Delay + Bit_Set CSR9_SROM_CK + SROM_Delay + Bit_Clear CSR9_SROM_CK + SROM_Delay + + ret + + + +align 4 +SROM_EnterAccessMode: + + DEBUGF 1,"SROM_EnterAccessMode\n" + + set_io 0 + set_io CSR9 + mov eax, CSR9_SR + out dx, eax + SROM_Delay + + Bit_Set CSR9_RD + SROM_Delay + + Bit_Clear CSR9_SROM_CK + SROM_Delay + + Bit_Set CSR9_SROM_CS + SROM_Delay + + ret + + + +align 4 +SROM_Idle: + + DEBUGF 1,"SROM_Idle\n" + + call SROM_EnterAccessMode + +; set_io 0 +; set_io CSR9 + + mov ecx, 25 + .loop_clk: + + Bit_Clear CSR9_SROM_CK + SROM_Delay + Bit_Set CSR9_SROM_CK + SROM_Delay + + dec ecx + jnz .loop_clk + + + Bit_Clear CSR9_SROM_CK + SROM_Delay + Bit_Clear CSR9_SROM_CS + SROM_Delay + + xor eax, eax + out dx, eax + + ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Read serial EEprom word ;; +;; ;; +;; In: esi = read address ;; +;; OUT: ax = data word ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +align 4 +SROM_Read_Word: + + DEBUGF 1,"SROM_Read_word at: %x result: ", esi + + set_io 0 + set_io CSR9 + +; enter access mode + mov eax, CSR9_SR + CSR9_RD + out dx , eax + or eax, CSR9_SROM_CS + out dx , eax + + ; TODO: change this hard-coded 6-bit stuff to use value from srom_getwidth + +; send read command "110b" + address to read from + and esi, 111111b + or esi, 110b shl 6 + + mov ecx, 1 shl 9 + .loop_cmd: + mov eax, CSR9_SR + CSR9_RD + CSR9_SROM_CS + test esi, ecx + jz @f + or eax, CSR9_SROM_DI + @@: + out dx , eax + SROM_Delay + or eax, CSR9_SROM_CK + out dx , eax + SROM_Delay + + shr ecx, 1 + jnz .loop_cmd + +; read data from SROM + + xor esi, esi + mov ecx, 17 ;;; TODO: figure out why 17, not 16 + .loop_read: + + mov eax, CSR9_SR + CSR9_RD + CSR9_SROM_CS + CSR9_SROM_CK + out dx , eax + SROM_Delay + + in eax, dx + and eax, CSR9_SROM_DO + shr eax, 3 + shl esi, 1 + or esi, eax + + mov eax, CSR9_SR + CSR9_RD + CSR9_SROM_CS + out dx , eax + SROM_Delay + + dec ecx + jnz .loop_read + + mov eax, esi + + DEBUGF 1,"%x\n", ax + + ret + + + + + + + +;<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + +;********************************************************************* +;* Media Descriptor Code * +;********************************************************************* + +; MII transceiver control section. +; Read and write the MII registers using software-generated serial +; MDIO protocol. See the MII specifications or DP83840A data sheet +; for details. + +; The maximum data clock rate is 2.5 Mhz. The minimum timing is usually +; met by back-to-back PCI I/O cycles, but we insert a delay to avoid +; "overclocking" issues or future 66Mhz PCI. + +; Read and write the MII registers using software-generated serial +; MDIO protocol. It is just different enough from the EEPROM protocol +; to not share code. The maxium data clock rate is 2.5 Mhz. + +MDIO_SHIFT_CLK = 0x10000 +MDIO_DATA_WRITE0 = 0x00000 +MDIO_DATA_WRITE1 = 0x20000 +MDIO_ENB = 0x00000 ; Ignore the 0x02000 databook setting. +MDIO_ENB_IN = 0x40000 +MDIO_DATA_READ = 0x80000 + +; MII transceiver control section. +; Read and write the MII registers using software-generated serial +; MDIO protocol. See the MII specifications or DP83840A data sheet +; for details. + +align 4 +mdio_read: ; phy_id:edx, location:esi + + DEBUGF 1,"mdio read, phy=%x, location=%x", edx, esi + + shl edx, 5 + or esi, edx + or esi, 0xf6 shl 10 + + set_io 0 + set_io CSR9 + +; if (tp->chip_id == LC82C168) { +; int i = 1000; +; outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); +; inl(ioaddr + 0xA0); +; inl(ioaddr + 0xA0); +; while (--i > 0) +; if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) +; return retval & 0xffff; +; return 0xffff; +; } +; +; if (tp->chip_id == COMET) { +; if (phy_id == 1) { +; if (location < 7) +; return inl(ioaddr + 0xB4 + (location<<2)); +; else if (location == 17) +; return inl(ioaddr + 0xD0); +; else if (location >= 29 && location <= 31) +; return inl(ioaddr + 0xD4 + ((location-29)<<2)); +; } +; return 0xffff; +; } + +; Establish sync by sending at least 32 logic ones. + + mov ecx, 32 + .loop: + mov eax, MDIO_ENB or MDIO_DATA_WRITE1 + out dx, eax + MDIO_Delay + + or eax, MDIO_SHIFT_CLK + out dx, eax + MDIO_Delay + + dec ecx + jnz .loop + + +; Shift the read command bits out. + + mov ecx, 1 shl 15 + .loop2: + mov eax, MDIO_ENB + test esi, ecx + jz @f + or eax, MDIO_DATA_WRITE1 + @@: + out dx, eax + MDIO_Delay + + or eax, MDIO_SHIFT_CLK + out dx, eax + MDIO_Delay + + shr ecx, 1 + jnz .loop2 + + +; Read the two transition, 16 data, and wire-idle bits. + + xor esi, esi + mov ecx, 19 + .loop3: + mov eax, MDIO_ENB_IN + out dx, eax + MDIO_Delay + + shl esi, 1 + in eax, dx + test eax, MDIO_DATA_READ + jz @f + inc esi + @@: + + mov eax, MDIO_ENB_IN or MDIO_SHIFT_CLK + out dx, eax + MDIO_Delay + + dec ecx + jnz .loop3 + + shr esi, 1 + movzx eax, si + + DEBUGF 1,", data=%x\n", ax + + ret + + + + +align 4 +mdio_write: ;int phy_id: edx, int location: edi, int value: ax) + + DEBUGF 1,"mdio write, phy=%x, location=%x, data=%x\n", edx, edi, ax + + shl edi, 18 + or edi, 0x5002 shl 16 + shl edx, 23 + or edi, edx + mov di, ax + + set_io 0 + set_io CSR9 + +; if (tp->chip_id == LC82C168) { +; int i = 1000; +; outl(cmd, ioaddr + 0xA0); +; do +; if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) +; break; +; while (--i > 0); +; return; +; } + +; if (tp->chip_id == COMET) { +; if (phy_id != 1) +; return; +; if (location < 7) +; outl(value, ioaddr + 0xB4 + (location<<2)); +; else if (location == 17) +; outl(value, ioaddr + 0xD0); +; else if (location >= 29 && location <= 31) +; outl(value, ioaddr + 0xD4 + ((location-29)<<2)); +; return; +; } + + +; Establish sync by sending at least 32 logic ones. + + mov ecx, 32 + .loop: + mov eax, MDIO_ENB or MDIO_DATA_WRITE1 + out dx, eax + MDIO_Delay + + or eax, MDIO_SHIFT_CLK + out dx, eax + MDIO_Delay + + dec ecx + jnz .loop + + +; Shift the command bits out. + + mov ecx, 1 shl 31 + .loop2: + mov eax, MDIO_ENB + test edi, ecx + jz @f + or eax, MDIO_DATA_WRITE1 + @@: + out dx, eax + MDIO_Delay + + or eax, MDIO_SHIFT_CLK + out dx, eax + MDIO_Delay + + shr ecx, 1 + jnz .loop2 + + +; Clear out extra bits. + + mov ecx, 2 + .loop3: + mov eax, MDIO_ENB + out dx, eax + MDIO_Delay + + or eax, MDIO_SHIFT_CLK + out dx, eax + MDIO_Delay + + dec ecx + jnz .loop3 + + ret + + +; End of code +align 4 ; Place all initialised data here + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'DEC21X4X',0 ; max 16 chars include zero + +include_debug_strings ; All data wich FDO uses will be included here + +section '.data' data readable writable align 16 ; place all uninitialized data place here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + + diff --git a/drivers/ethernet/forcedeth.asm b/drivers/ethernet/forcedeth.asm new file mode 100644 index 0000000000..c9599499fc --- /dev/null +++ b/drivers/ethernet/forcedeth.asm @@ -0,0 +1,1992 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; FORCEDETH.INC ;; +;; ;; +;; Ethernet driver for Kolibri OS ;; +;; ;; +;; Driver for chips of NVIDIA nForce2 ;; +;; References: ;; +;; forcedeth.c - linux driver (etherboot project) ;; +;; ethernet driver template by Mike Hibbett ;; +;; ;; +;; The copyright statement is ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;; Copyright 2008 shurf, ;; +;; cit.utc@gmail.com ;; +;; ;; +;; See file COPYING for details ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + RBLEN = 0 ; Receive buffer size: 0=4K 1=8k 2=16k 3=32k 4=64k + ; FIXME: option 1 and 2 will not allocate buffer correctly causing data loss! + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + + RX_RING = 4 + TX_RING = 4 + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../struct.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + +;************************************************************************** +; forcedeth Register Definitions +;************************************************************************** + +PCI_DEVICE_ID_NVIDIA_NVENET_1 = 0x01c3 +PCI_DEVICE_ID_NVIDIA_NVENET_2 = 0x0066 +PCI_DEVICE_ID_NVIDIA_NVENET_4 = 0x0086 +PCI_DEVICE_ID_NVIDIA_NVENET_5 = 0x008c +PCI_DEVICE_ID_NVIDIA_NVENET_3 = 0x00d6 +PCI_DEVICE_ID_NVIDIA_NVENET_7 = 0x00df +PCI_DEVICE_ID_NVIDIA_NVENET_6 = 0x00e6 +PCI_DEVICE_ID_NVIDIA_NVENET_8 = 0x0056 +PCI_DEVICE_ID_NVIDIA_NVENET_9 = 0x0057 +PCI_DEVICE_ID_NVIDIA_NVENET_10 = 0x0037 +PCI_DEVICE_ID_NVIDIA_NVENET_11 = 0x0038 +PCI_DEVICE_ID_NVIDIA_NVENET_12 = 0x0268 +PCI_DEVICE_ID_NVIDIA_NVENET_13 = 0x0269 +PCI_DEVICE_ID_NVIDIA_NVENET_14 = 0x0372 +PCI_DEVICE_ID_NVIDIA_NVENET_15 = 0x0373 + +UNKSETUP1_VAL = 0x16070f +UNKSETUP2_VAL = 0x16 +UNKSETUP3_VAL1 = 0x200010 +UNKSETUP4_VAL = 8 +UNKSETUP5_BIT31 = (1 shl 31) +UNKSETUP6_VAL = 3 + +TXRXCTL_RXCHECK = 0x0400 +MIISTAT_ERROR = 0x0001 +MIISTAT_MASK = 0x000f +MIISTAT_MASK2 = 0x000f +MIICTL_INUSE = 0x08000 +MIICTL_WRITE = 0x00400 +MIICTL_ADDRSHIFT = 5 + +MIISPEED_BIT8 = (1 shl 8) +MIIDELAY = 5 + +IRQ_RX_ERROR = 0x0001 +IRQ_RX = 0x0002 +IRQ_RX_NOBUF = 0x0004 +IRQ_LINK = 0x0040 +IRQ_TIMER = 0x0020 +IRQMASK_WANTED_2 = 0x0147 + +IRQ_RX_ALL = IRQ_RX_ERROR or IRQ_RX or IRQ_RX_NOBUF +IRQ_TX_ALL = 0 ; ??????????? +IRQ_OTHER_ALL = IRQ_LINK ;or IRQ_TIMER + +IRQSTAT_MASK = 0x1ff + +TXRXCTL_KICK = 0x0001 +TXRXCTL_BIT1 = 0x0002 +TXRXCTL_BIT2 = 0x0004 +TXRXCTL_IDLE = 0x0008 +TXRXCTL_RESET = 0x0010 +TXRXCTL_RXCHECK = 0x0400 + +MCASTADDRA_FORCE = 0x01 + +MAC_RESET_ASSERT = 0x0F3 + +MISC1_HD = 0x02 +MISC1_FORCE = 0x3b0f3c + +PFF_ALWAYS = 0x7F0008 +PFF_PROMISC = 0x80 +PFF_MYADDR = 0x20 + +OFFLOAD_HOMEPHY = 0x601 +OFFLOAD_NORMAL = 4096 shl RBLEN + +RNDSEED_MASK = 0x00ff +RNDSEED_FORCE = 0x7f00 +RNDSEED_FORCE2 = 0x2d00 +RNDSEED_FORCE3 = 0x7400 + +; POLL_DEFAULT is the interval length of the timer source on the nic +; POLL_DEFAULT=97 would result in an interval length of 1 ms +POLL_DEFAULT = 970 + +ADAPTCTL_START = 0x02 +ADAPTCTL_LINKUP = 0x04 +ADAPTCTL_PHYVALID = 0x40000 +ADAPTCTL_RUNNING = 0x100000 +ADAPTCTL_PHYSHIFT = 24 + +WAKEUPFLAGS_VAL = 0x7770 + +POWERSTATE_POWEREDUP = 0x8000 +POWERSTATE_VALID = 0x0100 +POWERSTATE_MASK = 0x0003 +POWERSTATE_D0 = 0x0000 +POWERSTATE_D1 = 0x0001 +POWERSTATE_D2 = 0x0002 +POWERSTATE_D3 = 0x0003 + +POWERSTATE2_POWERUP_MASK = 0x0F11 +POWERSTATE2_POWERUP_REV_A3= 0x0001 + +RCVCTL_START = 0x01 +RCVSTAT_BUSY = 0x01 + +XMITCTL_START = 0x01 + +LINKSPEED_FORCE = 0x10000 +LINKSPEED_10 = 1000 +LINKSPEED_100 = 100 +LINKSPEED_1000 = 50 + +RINGSZ_TXSHIFT = 0 +RINGSZ_RXSHIFT = 16 + +LPA_1000FULL = 0x0800 + +; Link partner ability register. +LPA_SLCT = 0x001f ; Same as advertise selector +LPA_10HALF = 0x0020 ; Can do 10mbps half-duplex +LPA_10FULL = 0x0040 ; Can do 10mbps full-duplex +LPA_100HALF = 0x0080 ; Can do 100mbps half-duplex +LPA_100FULL = 0x0100 ; Can do 100mbps full-duplex +LPA_100BASE4 = 0x0200 ; Can do 100mbps 4k packets +LPA_RESV = 0x1c00 ; Unused... +LPA_RFAULT = 0x2000 ; Link partner faulted +LPA_LPACK = 0x4000 ; Link partner acked us +LPA_NPAGE = 0x8000 ; Next page bit + +MII_READ = (-1) +MII_PHYSID1 = 0x02 ; PHYS ID 1 +MII_PHYSID2 = 0x03 ; PHYS ID 2 +MII_BMCR = 0x00 ; Basic mode control register +MII_BMSR = 0x01 ; Basic mode status register +MII_ADVERTISE = 0x04 ; Advertisement control reg +MII_LPA = 0x05 ; Link partner ability reg +MII_SREVISION = 0x16 ; Silicon revision +MII_RESV1 = 0x17 ; Reserved... +MII_NCONFIG = 0x1c ; Network interface config + +; PHY defines +PHY_OUI_MARVELL = 0x5043 +PHY_OUI_CICADA = 0x03f1 +PHYID1_OUI_MASK = 0x03ff +PHYID1_OUI_SHFT = 6 +PHYID2_OUI_MASK = 0xfc00 +PHYID2_OUI_SHFT = 10 +PHY_INIT1 = 0x0f000 +PHY_INIT2 = 0x0e00 +PHY_INIT3 = 0x01000 +PHY_INIT4 = 0x0200 +PHY_INIT5 = 0x0004 +PHY_INIT6 = 0x02000 +PHY_GIGABIT = 0x0100 + +PHY_TIMEOUT = 0x1 +PHY_ERROR = 0x2 + +PHY_100 = 0x1 +PHY_1000 = 0x2 +PHY_HALF = 0x100 + +PHY_RGMII = 0x10000000 + +; desc_ver values: +; This field has two purposes: +; - Newer nics uses a different ring layout. The layout is selected by +; comparing np->desc_ver with DESC_VER_xy. +; - It contains bits that are forced on when writing to TxRxControl. +DESC_VER_1 = 0x0 +DESC_VER_2 = (0x02100 or TXRXCTL_RXCHECK) + +MAC_ADDR_LEN = 6 + +NV_TX_LASTPACKET = (1 shl 16) +NV_TX_RETRYERROR = (1 shl 19) +NV_TX_LASTPACKET1 = (1 shl 24) +NV_TX_DEFERRED = (1 shl 26) +NV_TX_CARRIERLOST = (1 shl 27) +NV_TX_LATECOLLISION = (1 shl 28) +NV_TX_UNDERFLOW = (1 shl 29) +NV_TX_ERROR = (1 shl 30) +NV_TX_VALID = (1 shl 31) + +NV_TX2_LASTPACKET = (1 shl 29) +NV_TX2_RETRYERROR = (1 shl 18) +NV_TX2_LASTPACKET1 = (1 shl 23) +NV_TX2_DEFERRED = (1 shl 25) +NV_TX2_CARRIERLOST = (1 shl 26) +NV_TX2_LATECOLLISION = (1 shl 27) +NV_TX2_UNDERFLOW = (1 shl 28) +; error and valid are the same for both +NV_TX2_ERROR = (1 shl 30) +NV_TX2_VALID = (1 shl 31) + +NV_RX_DESCRIPTORVALID = (1 shl 16) +NV_RX_AVAIL = (1 shl 31) + +NV_RX2_DESCRIPTORVALID = (1 shl 29) + +FLAG_MASK_V1 = 0xffff0000 +FLAG_MASK_V2 = 0xffffc000 +LEN_MASK_V1 = (0xffffffff xor FLAG_MASK_V1) +LEN_MASK_V2 = (0xffffffff xor FLAG_MASK_V2) + +; Miscelaneous hardware related defines: +NV_PCI_REGSZ_VER1 = 0x270 +NV_PCI_REGSZ_VER2 = 0x604 +; various timeout delays: all in usec +NV_TXRX_RESET_DELAY = 4 +NV_TXSTOP_DELAY1 = 10 +NV_TXSTOP_DELAY1MAX = 500000 +NV_TXSTOP_DELAY2 = 100 +NV_RXSTOP_DELAY1 = 10 +NV_RXSTOP_DELAY1MAX = 500000 +NV_RXSTOP_DELAY2 = 100 +NV_SETUP5_DELAY = 5 +NV_SETUP5_DELAYMAX = 50000 +NV_POWERUP_DELAY = 5 +NV_POWERUP_DELAYMAX = 5000 +NV_MIIBUSY_DELAY = 50 +NV_MIIPHY_DELAY = 10 +NV_MIIPHY_DELAYMAX = 10000 +NV_MAC_RESET_DELAY = 64 +NV_WAKEUPPATTERNS = 5 +NV_WAKEUPMASKENTRIES = 4 + +; Advertisement control register. +ADVERTISE_SLCT = 0x001f ; Selector bits +ADVERTISE_CSMA = 0x0001 ; Only selector supported +ADVERTISE_10HALF = 0x0020 ; Try for 10mbps half-duplex +ADVERTISE_10FULL = 0x0040 ; Try for 10mbps full-duplex +ADVERTISE_100HALF = 0x0080 ; Try for 100mbps half-duplex +ADVERTISE_100FULL = 0x0100 ; Try for 100mbps full-duplex +ADVERTISE_100BASE4 = 0x0200 ; Try for 100mbps 4k packets +ADVERTISE_RESV = 0x1c00 ; Unused... +ADVERTISE_RFAULT = 0x2000 ; Say we can detect faults +ADVERTISE_LPACK = 0x4000 ; Ack link partners response +ADVERTISE_NPAGE = 0x8000 ; Next page bit + +ADVERTISE_FULL = (ADVERTISE_100FULL or ADVERTISE_10FULL or ADVERTISE_CSMA) +ADVERTISE_ALL = (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL) + +MII_1000BT_CR = 0x09 +MII_1000BT_SR = 0x0a +ADVERTISE_1000FULL = 0x0200 +ADVERTISE_1000HALF = 0x0100 + +BMCR_ANRESTART = 0x0200 ; Auto negotiation restart +BMCR_ANENABLE = 0x1000 ; Enable auto negotiation +BMCR_SPEED100 = 0x2000 ; Select 100Mbps +BMCR_LOOPBACK = 0x4000 ; TXD loopback bits +BMCR_RESET = 0x8000 ; Reset the DP83840 + +; Basic mode status register. +BMSR_ERCAP = 0x0001 ; Ext-reg capability +BMSR_JCD = 0x0002 ; Jabber detected +BMSR_LSTATUS = 0x0004 ; Link status +BMSR_ANEGCAPABLE = 0x0008 ; Able to do auto-negotiation +BMSR_RFAULT = 0x0010 ; Remote fault detected +BMSR_ANEGCOMPLETE = 0x0020 ; Auto-negotiation complete +BMSR_RESV = 0x07c0 ; Unused... +BMSR_10HALF = 0x0800 ; Can do 10mbps, half-duplex +BMSR_10FULL = 0x1000 ; Can do 10mbps, full-duplex +BMSR_100HALF = 0x2000 ; Can do 100mbps, half-duplex +BMSR_100FULL = 0x4000 ; Can do 100mbps, full-duplex +BMSR_100BASE4 = 0x8000 ; Can do 100mbps, 4k packets + +struct TxDesc + PacketBuffer dd ? + FlagLen dd ? +ends + +struct RxDesc + PacketBuffer dd ? + FlagLen dd ? +ends + +virtual at ebx + + device: + + ETH_DEVICE + + .pci_bus dd ? + .pci_dev dd ? + + .mmio_addr dd ? + .vendor_id dw ? + .device_id dw ? + .txflags dd ? + .desc_ver dd ? + .irqmask dd ? + .wolenabled dd ? + .in_shutdown dd ? + .cur_rx dd ? + .phyaddr dd ? + .phy_oui dd ? + .gigabit dd ? + .needs_mac_reset dd ? + .linkspeed dd ? + .duplex dd ? + .next_tx dd ? + .nocable dd ? + + rb 0x100 - (($ - device) and 0xff) + .tx_ring rd (TX_RING * sizeof.TxDesc) /4*2 + + rb 0x100 - (($ - device) and 0xff) + .rx_ring rd (RX_RING * sizeof.RxDesc) /4*2 + + sizeof.device_struct = $ - device +end virtual + + +virtual at edi + IrqStatus dd ? + IrqMask dd ? + UnknownSetupReg6 dd ? + PollingInterval dd ? +end virtual + +virtual at edi + 0x3c + MacReset dd ? +end virtual + +virtual at edi + 0x80 + Misc1 dd ? + TransmitterControl dd ? + TransmitterStatus dd ? + PacketFilterFlags dd ? + OffloadConfig dd ? + ReceiverControl dd ? + ReceiverStatus dd ? + RandomSeed dd ? + UnknownSetupReg1 dd ? + UnknownSetupReg2 dd ? + MacAddrA dd ? + MacAddrB dd ? + MulticastAddrA dd ? + MulticastAddrB dd ? + MulticastMaskA dd ? + MulticastMaskB dd ? + PhyInterface dd ? +end virtual + +virtual at edi + 0x100 + TxRingPhysAddr dd ? + RxRingPhysAddr dd ? + RingSizes dd ? + UnknownTransmitterReg dd ? + LinkSpeed dd ? +end virtual + +virtual at edi + 0x130 + UnknownSetupReg5 dd ? +end virtual + +virtual at edi + 0x13c + UnknownSetupReg3 dd ? +end virtual + +virtual at edi + 0x144 + TxRxControl dd ? +end virtual + +virtual at edi + 0x180 + MIIStatus dd ? + UnknownSetupReg4 dd ? + AdapterControl dd ? + MIISpeed dd ? + MIIControl dd ? + MIIData dd ? +end virtual + +virtual at edi + 0x200 + WakeUpFlags dd ? +end virtual + +virtual at edi + 0x26c + PowerState dd ? +end virtual + +virtual at edi + 0x600 + PowerState2 dd ? +end virtual + + +section '.flat' code readable align 16 + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + DEBUGF 2,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .exit: + xor eax, eax + ret + +endp + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax, [eax+1] + .nextdevice: + mov ebx, [esi] + cmp al, byte [device.pci_bus] ; compare with pci and device num in device list (notice the usage of word instead of byte) + jne @f + cmp ah, byte [device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, sizeof.device_struct, .fail ; Allocate the buffer for device structure + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], .fail + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte [eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte [eax+2] + mov [device.pci_dev], ecx + + DEBUGF 1,"Hooking into device, dev:%x, bus:%x\n", [device.pci_dev], [device.pci_bus] + +; Ok, the eth_device structure is ready, let's probe the device + call probe ; this function will output in eax + test eax, eax + jnz .err ; If an error occured, exit + + mov eax, [devices] ; Add the device structure to our device list + mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + je .destroy + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 1,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 1,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + .err: + stdcall KernelFree, ebx + .fail: + + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + + + +;*************************************************************************** +; Function +; probe +; Description +; Searches for an ethernet card, enables it and clears the rx buffer +; +;*************************************************************************** +align 4 +probe: + + DEBUGF 1,"probe\n" + + mov [device.needs_mac_reset], 0 + + PCI_make_bus_master + PCI_adjust_latency 32 + PCI_find_mmio32 + + DEBUGF 1,"mmio_addr= 0x%x\n", [device.mmio_addr]:8 + + stdcall MapIoMem, [device.mmio_addr], 2048, (PG_SW + PG_NOCACHE) + test eax, eax + jz fail + mov [device.mmio_addr], eax + mov edi, eax + + DEBUGF 1,"mapped mmio_addr= 0x%x\n", [device.mmio_addr]:8 + +;------------------------------------- +; handle different descriptor versions + mov [device.desc_ver], DESC_VER_1 + movzx eax, [device.device_id] + cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_1 + je .ver1 + cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_2 + je .ver1 + cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_3 + je .ver1 + mov [device.desc_ver], DESC_VER_2 + .ver1: + + call read_mac + + ; disable WOL + mov [WakeUpFlags], 0 + mov [device.wolenabled], 0 + + mov [device.txflags], (NV_TX2_LASTPACKET or NV_TX2_VALID) + cmp [device.desc_ver], DESC_VER_1 + jne @f + mov [device.txflags], (NV_TX_LASTPACKET or NV_TX_VALID) + @@: + +; BEGIN of switch (pci->dev_id) + + cmp [device.device_id], 0x01C3 + jne .next_0x0066 + ; nforce + mov [device.irqmask], 0 ;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) + jmp .find_phy + + .next_0x0066: + cmp [device.device_id], 0x0066 + je @f + cmp [device.device_id], 0x00D6 + je @f + jmp .next_0x0086 + @@: + mov [device.irqmask], 0 ;;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) + cmp [device.desc_ver], DESC_VER_1 + jne @f + or [device.txflags], NV_TX_LASTPACKET1 + jmp .find_phy + @@: + or [device.txflags], NV_TX2_LASTPACKET1 + jmp .find_phy + + .next_0x0086: + cmp [device.device_id], 0x0086 + je @f + cmp [device.device_id], 0x008c + je @f + cmp [device.device_id], 0x00e6 + je @f + cmp [device.device_id], 0x00df + je @f + cmp [device.device_id], 0x0056 + je @f + cmp [device.device_id], 0x0057 + je @f + cmp [device.device_id], 0x0037 + je @f + cmp [device.device_id], 0x0038 + je @f + jmp .find_phy + + @@: + mov [device.irqmask], 0 ;;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) + + cmp [device.desc_ver], DESC_VER_1 + jne @f + or [device.txflags], NV_TX_LASTPACKET1 + jmp .find_phy + @@: + or [device.txflags], NV_TX2_LASTPACKET1 + jmp .find_phy + +.next_0x0268: +; cmp word [device_id], 0x0268 +; je @f +; cmp word [device_id], 0x0269 +; je @f +; cmp word [device_id], 0x0372 +; je @f +; cmp word [device_id], 0x0373 +; je @f +; jmp .default_switch +;@@: + cmp [device.device_id], 0x0268 + jb .undefined + +; Get device revision + + stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REVISION_ID + +; take phy and nic out of low power mode + mov ecx, [PowerState2] + and ecx, not POWERSTATE2_POWERUP_MASK + cmp [device.device_id], PCI_DEVICE_ID_NVIDIA_NVENET_12 + jne @f + cmp [device.device_id], PCI_DEVICE_ID_NVIDIA_NVENET_13 + jne @f + cmp al, 0xA3 + jb @f + or ecx, POWERSTATE2_POWERUP_REV_A3 + @@: + mov [PowerState2], ecx + + ; DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ + mov [device.irqmask], 0 ;;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) + + mov [device.needs_mac_reset], 1 + cmp [device.desc_ver], DESC_VER_1 + jne @f + or [device.txflags], NV_TX_LASTPACKET1 + jmp .find_phy + @@: + cmp [device.desc_ver], DESC_VER_2 + jne .undefined + or [device.txflags], NV_TX2_LASTPACKET1 + jmp .find_phy + + .undefined: + DEBUGF 1,"Your card was undefined in this driver.\n" + DEBUGF 1,"Review driver_data in Kolibri driver and send a patch\n" + +; Find a suitable phy +; Start with address 1 to 31, then do 0, then fail + + .find_phy: + xor edx, edx + .phy_loop: + inc edx + and edx, 0x1f ; phyaddr = i & 0x1f + mov eax, MII_PHYSID1 + mov ecx, MII_READ + call mii_rw ; EDX - addr, EAX - miireg, ECX - value + + cmp eax, 0xffff + je .try_next + cmp eax, 0 + jl .try_next + mov esi, eax + + mov eax, MII_PHYSID2 + mov ecx, MII_READ + call mii_rw + + cmp eax, 0xffff + je .try_next + cmp eax, 0 + jl .try_next + jmp .got_it + + .try_next: + test edx, edx + jnz .phy_loop + + ; PHY in isolate mode? No phy attached and user wants to test loopback? + ; Very odd, but can be correct. + + DEBUGF 1,"Could not find a valid PHY.\n" + jmp .no_phy + + .got_it: + + and esi, PHYID1_OUI_MASK + shl esi, PHYID1_OUI_SHFT + + and eax, PHYID2_OUI_MASK + shr eax, PHYID2_OUI_SHFT + + DEBUGF 1,"Found PHY 0x%x:0x%x at address 0x%x\n", esi:8, eax:8, edx + + mov [device.phyaddr], edx + or eax, esi + mov [device.phy_oui], eax + + call phy_init + + .no_phy: + + cmp [device.needs_mac_reset], 0 + je @f + call mac_reset + @@: + +;*************************************************************************** +; Function +; reset +; Description +; Place the chip (ie, the ethernet card) into a virgin state +; No inputs +; All registers destroyed +; +;*************************************************************************** +reset: + + DEBUGF 1,"Resetting\n" + + stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REG_IRQ + movzx eax, al + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 1,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + +; erase previous misconfiguration + + mov edi, [device.mmio_addr] + mov [MulticastAddrA], MCASTADDRA_FORCE + mov [MulticastAddrB], 0 + mov [MulticastMaskA], 0 + mov [MulticastMaskB], 0 + mov [PacketFilterFlags], 0 + mov [TransmitterControl], 0 + mov [ReceiverControl], 0 + mov [AdapterControl], 0 + +; initialize descriptor rings + + call init_ring + + mov [LinkSpeed], 0 + mov [UnknownTransmitterReg], 0 + + call txrx_reset + + mov [UnknownSetupReg6], 0 + mov [device.in_shutdown], 0 + +; give hw rings + + lea eax, [device.rx_ring] + GetRealAddr + mov [RxRingPhysAddr], eax + + lea eax, [device.tx_ring] + GetRealAddr + mov [TxRingPhysAddr], eax + + mov [RingSizes], (((RX_RING - 1) shl RINGSZ_RXSHIFT) + ((TX_RING - 1) shl RINGSZ_TXSHIFT)) + +; + + mov [device.linkspeed], (LINKSPEED_FORCE or LINKSPEED_10) + mov [device.duplex], 0 + mov [LinkSpeed], (LINKSPEED_FORCE or LINKSPEED_10) + mov [UnknownSetupReg3], UNKSETUP3_VAL1 + + mov eax, [device.desc_ver] + mov [TxRxControl], eax + call pci_push + or eax, TXRXCTL_BIT1 + mov [TxRxControl], eax + + stdcall reg_delay, UnknownSetupReg5-edi, UNKSETUP5_BIT31, UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, 0 + + mov [UnknownSetupReg4], 0 + mov [MIIStatus], MIISTAT_MASK2 + +; + + mov [Misc1], (MISC1_FORCE or MISC1_HD) + + mov eax, [TransmitterStatus] + mov [TransmitterStatus], eax + + mov [PacketFilterFlags], PFF_ALWAYS + + mov [OffloadConfig], OFFLOAD_NORMAL + + mov eax, [ReceiverStatus] + mov [ReceiverStatus], eax + +; set random seed + push ebx + stdcall GetTimerTicks ; bad idea, driver is started at system startup in 90% of cases.. + pop ebx + + mov edi, [device.mmio_addr] + + and eax, RNDSEED_MASK + or eax, RNDSEED_FORCE + mov [RandomSeed], eax + + mov [UnknownSetupReg1], UNKSETUP1_VAL + mov [UnknownSetupReg2], UNKSETUP2_VAL + mov [PollingInterval], POLL_DEFAULT + mov [UnknownSetupReg6], UNKSETUP6_VAL + + mov eax, [device.phyaddr] + shl eax, ADAPTCTL_PHYSHIFT + or eax, (ADAPTCTL_PHYVALID or ADAPTCTL_RUNNING) + mov [AdapterControl], eax + + mov [MIISpeed], (MIISPEED_BIT8 or MIIDELAY) + mov [UnknownSetupReg4], UNKSETUP4_VAL + mov [WakeUpFlags], WAKEUPFLAGS_VAL + + or [PowerState], POWERSTATE_POWEREDUP + call pci_push + + mov esi, 10 + call Sleep + + or [PowerState], POWERSTATE_VALID + mov [IrqMask], 0 + +;;; ; ??? Mask RX interrupts + mov [IrqMask], IRQ_RX_ALL + IRQ_TX_ALL +;;; ; ??? Mask TX interrupts +;;; mov [IrqMask], IRQ_TX_ALL +;;; ; ??? Mask OTHER interrupts +;;; mov [IrqMask], IRQ_OTHER_ALL + call pci_push + + mov [MIIStatus], MIISTAT_MASK2 + mov [IrqStatus], IRQSTAT_MASK + call pci_push + + mov [MulticastAddrA], MCASTADDRA_FORCE + mov [MulticastAddrB], 0 + mov [MulticastMaskA], 0 + mov [MulticastMaskB], 0 + + mov [PacketFilterFlags], (PFF_ALWAYS or PFF_MYADDR) + + call set_multicast + + ; One manual link speed update: Interrupts are enabled, future link + ; speed changes cause interrupts and are handled by nv_link_irq(). + + mov eax, [MIIStatus] + mov [MIIStatus], MIISTAT_MASK + DEBUGF 1,"startup: got 0x%x\n", eax + + call update_linkspeed + + mov [TransmitterControl], XMITCTL_START ; start TX + call pci_push + + mov [device.nocable], 0 + test eax, eax + jnz .return + DEBUGF 1,"no link during initialization.\n" + mov [device.nocable], 1 + + .return: + xor eax, eax ; Indicate that we have successfully reset the card + mov [device.mtu], 1514 ;;; FIXME + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + + ret + + +fail: + or eax, -1 + + ret + +;-------------------------------------------------------- +; +; MII_RW +; +; read/write a register on the PHY. +; Caller must guarantee serialization +; Input: EAX - miireg, EDX - addr, ECX - value +; Output: EAX - retval +; +;-------------------------------------------------------- + +mii_rw: + + DEBUGF 1,"mii_rw: 0x%x to reg %d at PHY %d\n", ecx, eax, edx + + push edx + + mov edi, [device.mmio_addr] + mov [MIIStatus], MIISTAT_MASK + + test [MIIControl], MIICTL_INUSE + jz @f + mov [MIIControl], MIICTL_INUSE + + mov esi, NV_MIIBUSY_DELAY + call Sleep + @@: + + shl edx, MIICTL_ADDRSHIFT + or edx, eax + + cmp ecx, MII_READ + je @f + + mov [MIIData], ecx + or edx, MIICTL_WRITE + @@: + mov [MIIControl], edx + + stdcall reg_delay, MIIControl-edi, MIICTL_INUSE, 0, NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, 0 + + test eax, eax + jz @f + DEBUGF 1,"mii_rw timed out.\n" + or eax, -1 + jmp .return + @@: + + cmp ecx, MII_READ + je @f +; it was a write operation - fewer failures are detectable + DEBUGF 1,"mii_rw write: ok\n" + xor eax, eax + jmp .return + @@: + + mov eax, [MIIStatus] + test eax, MIISTAT_ERROR + jz @f + DEBUGF 1,"mii read: failed.\n" + or eax, -1 + jmp .return + @@: + + mov eax, [MIIData] + DEBUGF 1,"mii read: 0x%x.\n", eax + + .return: + pop edx + ret + + + + + +; Input: offset:word, mask:dword, target:dword, delay:word, delaymax:word, msg:dword +; Output: EAX - 0|1 + +proc reg_delay, offset:dword, mask:dword, target:dword, delay:dword, delaymax:dword, msg:dword + +; DEBUGF 1,"reg_delay\n" + + push esi + call pci_push + + .loop: + mov esi, [delay] + call Sleep + mov eax, [delaymax] + sub eax, [delay] + mov [delaymax], eax + + cmp eax, 0 + jl .fail + + mov eax, [offset] + mov eax, [edi + eax] + and eax, [mask] + cmp eax, [target] + jne .loop + + pop esi + xor eax, eax + ret + + .fail: + pop esi + xor eax, eax + inc eax + ret + +endp + + + + + +; Input: none +; Output: EAX - result (0 = OK, other = error) +phy_init: + + push ebx ecx + + ; set advertise register + mov edx, [device.phyaddr] + mov eax, MII_ADVERTISE + mov ecx, MII_READ + call mii_rw + + or eax, (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL or 0x800 or 0x400) + + mov ecx, eax + mov eax, MII_ADVERTISE + call mii_rw + + test eax, eax + jz @f + + DEBUGF 1,"phy write to advertise failed.\n" + + mov eax, PHY_ERROR + jmp .return + @@: + + ; get phy interface type + mov edi, [device.mmio_addr] + mov eax, [PhyInterface] + DEBUGF 1,"phy interface type = 0x%x\n", eax:8 + + ; see if gigabit phy + mov eax, MII_BMSR + mov ecx, MII_READ + call mii_rw + + test eax, PHY_GIGABIT + jnz .gigabit + mov [device.gigabit], 0 + jmp .next_if + + .gigabit: + mov [device.gigabit], PHY_GIGABIT + + mov eax, MII_1000BT_CR + mov ecx, MII_READ + call mii_rw + + and eax, (not ADVERTISE_1000HALF) + + test [PhyInterface], PHY_RGMII + jz @f + or eax, ADVERTISE_1000FULL + jmp .next + @@: + + and eax, (not ADVERTISE_1000FULL) + + .next: + mov ecx, eax + mov eax, MII_1000BT_CR + call mii_rw + + test eax, eax + jz .next_if + + DEBUGF 1,"phy init failed.\n" + + mov eax, PHY_ERROR + jmp .return + + .next_if: + + call phy_reset + test eax, eax + jz @f + + DEBUGF 1,"phy reset failed.\n" + + mov eax, PHY_ERROR + jmp .return + @@: + + ; phy vendor specific configuration + cmp [device.phy_oui], PHY_OUI_CICADA + jne .next_if2 + test [PhyInterface], PHY_RGMII + jz .next_if2 + + mov eax, MII_RESV1 + mov ecx, MII_READ + call mii_rw + + and eax, (not (PHY_INIT1 or PHY_INIT2)) + or eax, (PHY_INIT3 or PHY_INIT4) + mov ecx, eax + mov eax, MII_RESV1 + call mii_rw + + test eax, eax + jz @f + + DEBUGF 1,"phy init failed.\n" + + mov eax, PHY_ERROR + jmp .return + @@: + + mov eax, MII_NCONFIG + mov ecx, MII_READ + call mii_rw + + or eax, PHY_INIT5 + mov ecx, eax + mov eax, MII_NCONFIG + call mii_rw + test eax, eax + jz .next_if2 + + DEBUGF 1,"phy init failed.\n" + + mov eax, PHY_ERROR + jmp .return + + + + .next_if2: + + cmp [device.phy_oui], PHY_OUI_CICADA + jne .restart + + mov eax, MII_SREVISION + mov ecx, MII_READ + call mii_rw + + or eax, PHY_INIT6 + mov ecx, eax + mov eax, MII_SREVISION + call mii_rw + test eax, eax + jz .restart + + DEBUGF 1,"phy init failed.\n" + + jmp .return + + .restart: + ; restart auto negotiation + + mov eax, MII_BMCR + mov ecx, MII_READ + call mii_rw + + or eax, (BMCR_ANRESTART or BMCR_ANENABLE) + mov ecx, eax + mov eax, MII_BMCR + call mii_rw + test eax, eax + jz .ok + + mov eax, PHY_ERROR + jmp .return + + .ok: + xor eax, eax + .return: + pop ecx ebx + + ret + + +; Input: none +; Output: EAX - result (0 = OK, other = error) +phy_reset: + + DEBUGF 1,"phy_reset\n" + + push ebx ecx edx + + mov edx, [device.phyaddr] + mov eax, MII_BMCR + mov ecx, MII_READ + call mii_rw + + or eax, BMCR_RESET + push eax + mov ecx, eax + mov eax, MII_BMCR + call mii_rw + + test eax, eax + jz @f + + pop eax + mov eax, 0xffffffff + jmp .return + @@: + + pop eax + + mov esi, 500 + call Sleep + + ; must wait till reset is deasserted + mov esi, 100 ; FIXME: 100 tries seem excessive + .while_loop: + test eax, BMCR_RESET + jz .while_loop_exit + + push esi + mov esi, 10 + call Sleep + pop esi + + mov eax, MII_BMCR + mov ecx, MII_READ + call mii_rw + + dec esi + jnz .while_loop + + mov eax, 0xffffffff + jmp .return + + .while_loop_exit: + xor eax, eax + .return: + pop edx ecx ebx + + ret + + +align 4 +pci_push: + + push eax + mov eax, [edi] + pop eax + + ret + + + + +align 4 +mac_reset: + + push esi edi + + DEBUGF 1,"mac_reset.\n" + + mov edi, [device.mmio_addr] + mov eax, [device.desc_ver] + or eax, (TXRXCTL_BIT2 or TXRXCTL_RESET) + mov [TxRxControl], eax + call pci_push + + mov [MacReset], MAC_RESET_ASSERT + call pci_push + + mov esi, NV_MAC_RESET_DELAY + call Sleep + + mov [MacReset], 0 + call pci_push + + mov esi, NV_MAC_RESET_DELAY + call Sleep + + mov eax, [device.desc_ver] + or eax, TXRXCTL_BIT2 + mov [TxRxControl], eax + call pci_push + + pop edi esi + + ret + + + + + +align 4 +init_ring: + + DEBUGF 1,"init rings\n" + push eax esi ecx + + mov [device.next_tx], 0 + + mov ecx, TX_RING + lea esi, [device.tx_ring] + .tx_loop: + mov [esi + TxDesc.FlagLen], 0 + add esi, sizeof.TxDesc + dec ecx + jnz .tx_loop + + mov [device.cur_rx], 0 + + mov ecx, RX_RING + lea esi, [device.rx_ring] + .rx_loop: + push ecx esi + stdcall KernelAlloc, 4096 shl RBLEN ; push/pop esi not needed, but just in case... + pop esi + mov [esi + RX_RING*sizeof.RxDesc], eax + GetRealAddr + mov [esi + RxDesc.PacketBuffer], eax + mov [esi + RxDesc.FlagLen], (4096 shl RBLEN or NV_RX_AVAIL) + add esi, sizeof.RxDesc + pop ecx + dec ecx + jnz .rx_loop + + pop ecx esi eax + + ret + + + + + +; Input: none +; Output: none +align 4 +txrx_reset: + + push eax esi + + DEBUGF 1,"txrx_reset\n" + + mov edi, [device.mmio_addr] + mov eax, [device.desc_ver] + or eax, (TXRXCTL_BIT2 or TXRXCTL_RESET) + mov [TxRxControl], eax + call pci_push + + mov esi, NV_TXRX_RESET_DELAY + call Sleep + + mov eax, [device.desc_ver] + or eax, TXRXCTL_BIT2 + mov [TxRxControl], eax + call pci_push + + pop esi eax + + ret + + + + + +; Input: none +; Output: none +set_multicast: + + ; u32 addr[2]; + ; u32 mask[2]; + ; u32 pff; + ; u32 alwaysOff[2]; + ; u32 alwaysOn[2]; + ; + ; memset(addr, 0, sizeof(addr)); + ; memset(mask, 0, sizeof(mask)); + ; + ; pff = PFF_MYADDR; + ; + ; alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0; + ; + ; addr[0] = alwaysOn[0]; + ; addr[1] = alwaysOn[1]; + ; mask[0] = alwaysOn[0] | alwaysOff[0]; + ; mask[1] = alwaysOn[1] | alwaysOff[1]; + ; + ; addr[0] |= MCASTADDRA_FORCE; + ; pff |= PFF_ALWAYS; + + call stop_rx + + mov edi, [device.mmio_addr] + mov [MulticastAddrA], MCASTADDRA_FORCE + + mov [MulticastAddrB], 0 + mov [MulticastMaskA], 0 + mov [MulticastMaskB], 0 + mov [PacketFilterFlags], (PFF_MYADDR or PFF_ALWAYS) + + call start_rx + + ret + + + + + +; Input: none +; Output: none +start_rx: + + push edi + + DEBUGF 1,"start_rx\n" + + ; Already running? Stop it. + mov edi, [device.mmio_addr] + mov eax, [ReceiverControl] + test eax, RCVCTL_START + jz @f + mov [ReceiverControl], 0 + call pci_push + @@: + + mov eax, [device.linkspeed] + mov [LinkSpeed], eax + call pci_push + + mov [ReceiverControl], RCVCTL_START + call pci_push + + pop edi + + ret + + + + +; Input: none +; Output: none +stop_rx: + + push esi edi + + DEBUGF 1,"stop_rx.\n" + + mov edi, [device.mmio_addr] + mov [ReceiverControl], 0 + + push ebx edx edi + stdcall reg_delay, ReceiverStatus-edi, RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, 0 + pop edi edx ebx + + mov esi, NV_RXSTOP_DELAY2 + call Sleep + + mov [LinkSpeed], 0 + + pop edi esi + + ret + + + + +; Input: none +; Output: EAX +update_linkspeed: + + DEBUGF 1,"update linkspeed\n" + +; BMSR_LSTATUS is latched, read it twice: we want the current value. + + mov edx, [device.phyaddr] + mov eax, MII_BMSR + mov ecx, MII_READ + call mii_rw + + mov eax, MII_BMSR + mov ecx, MII_READ + call mii_rw + + test eax, BMSR_LSTATUS ; Link up? + jz .10mbit_hd + + test eax, BMSR_ANEGCOMPLETE ; still in autonegotiation? + jz .10mbit_hd + + cmp [device.gigabit], PHY_GIGABIT + jne .no_gigabit + + ;mov edx, [device.phyaddr] + mov eax, MII_1000BT_CR + mov ecx, MII_READ + call mii_rw + push eax + + ;mov edx, [device.phyaddr] + mov eax, MII_1000BT_SR + mov ecx, MII_READ + call mii_rw + pop ecx + + test eax, LPA_1000FULL + jz .no_gigabit + test ecx, ADVERTISE_1000FULL + jz .no_gigabit + + DEBUGF 1,"update_linkspeed: GBit ethernet detected.\n" + mov ecx, (LINKSPEED_FORCE or LINKSPEED_1000) + xor eax, eax + inc eax + jmp set_speed + .no_gigabit: + + ;mov edx, [device.phyaddr] + mov eax, MII_ADVERTISE + mov ecx, MII_READ + call mii_rw ; adv = eax + push eax + + ;mov edx, [device.phyaddr] + mov eax, MII_LPA + mov ecx, MII_READ + call mii_rw ; lpa = eax + pop ecx + + DEBUGF 1,"PHY advertises 0x%x, lpa 0x%x\n", ecx, eax + and eax, ecx ; FIXME: handle parallel detection properly, handle gigabit ethernet + + test eax, LPA_100FULL + jz @f + DEBUGF 1,"update_linkspeed: 100 mbit full duplex\n" + mov ecx, (LINKSPEED_FORCE or LINKSPEED_100) + xor eax, eax + inc eax + jmp set_speed + @@: + + test eax, LPA_100HALF + jz @f + DEBUGF 1,"update_linkspeed: 100 mbit half duplex\n" + mov ecx, (LINKSPEED_FORCE or LINKSPEED_100) + xor eax, eax + jmp set_speed + @@: + + test eax, LPA_10FULL + jz @f + DEBUGF 1,"update_linkspeed: 10 mbit full duplex\n" + mov ecx, (LINKSPEED_FORCE or LINKSPEED_10) + xor eax, eax + inc eax + jmp set_speed + @@: + + .10mbit_hd: + DEBUGF 1,"update_linkspeed: 10 mbit half duplex\n" + mov ecx, (LINKSPEED_FORCE or LINKSPEED_10) + xor eax, eax + jmp set_speed + + +align 4 +set_speed: + + cmp eax, [device.duplex] + jne .update + cmp ecx, [device.linkspeed] + jne .update + + ret + + .update: + DEBUGF 1,"update_linkspeed: changing link to 0x%x/XD.\n", ecx + + mov [device.duplex], eax + mov [device.linkspeed], ecx + + cmp [device.gigabit], PHY_GIGABIT + jne .no_gigabit + + mov edi, [device.mmio_addr] + mov eax, [RandomSeed] + + and eax, not (0x3FF00) + mov ecx, eax ; phyreg = ecx + + mov eax, [device.linkspeed] + and eax, 0xFFF + cmp eax, LINKSPEED_10 + jne @f + or ecx, RNDSEED_FORCE3 + jmp .end_if4 + @@: + + cmp eax, LINKSPEED_100 + jne @f + or ecx, RNDSEED_FORCE2 + jmp .end_if4 + @@: + + cmp eax, LINKSPEED_1000 + jne .end_if4 + or ecx, RNDSEED_FORCE + .end_if4: + mov [RandomSeed], ecx + .no_gigabit: + + mov ecx, [PhyInterface] + and ecx, not (PHY_HALF or PHY_100 or PHY_1000) + + cmp [device.duplex], 0 + jne @f + or ecx, PHY_HALF + @@: + + mov eax, [device.linkspeed] + and eax, 0xFFF + cmp eax, LINKSPEED_100 + jne @f + or ecx, PHY_100 + jmp .end_if5 + @@: + + cmp eax, LINKSPEED_1000 + jne .end_if5 + or ecx, PHY_1000 + + .end_if5: + mov [PhyInterface], ecx + + cmp [device.duplex], 0 + je @f + xor ecx, ecx + jmp .next + @@: + + mov ecx, MISC1_HD + .next: + or ecx, MISC1_FORCE + mov [Misc1], ecx + + call pci_push + + mov eax, [device.linkspeed] + mov [LinkSpeed], eax + + call pci_push + + ret + + + + + + +align 4 +read_mac: + + mov edi, [device.mmio_addr] + + mov eax, [MacAddrA] + mov ecx, [MacAddrB] + + mov dword [device.mac], eax + mov word [device.mac + 4], cx + + cmp [device.device_id], 0x03E5 + jae @f + bswap eax + xchg cl, ch + mov dword [device.mac + 2], eax + mov word [device.mac], cx + @@: + + DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n", \ + [device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + + ret + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +align 4 +transmit: + DEBUGF 2,"\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] + mov eax, [esp+4] + DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp + 8], 1514 + ja .fail + cmp dword [esp + 8], 60 + jb .fail + +; get the descriptor address + mov eax, [device.next_tx] + mov cl, sizeof.TxDesc + mul cl + lea esi, [device.tx_ring + eax] + mov eax, [esp + 4] + mov [esi + TX_RING*sizeof.TxDesc], eax + GetRealAddr + mov [esi + TxDesc.PacketBuffer], eax + + mov ecx, [esp + 8] + or ecx, [device.txflags] + mov [esi + TxDesc.FlagLen], eax + + mov edi, [device.mmio_addr] + mov eax, [device.desc_ver] + or eax, TXRXCTL_KICK + mov [TxRxControl], eax + + call pci_push + + inc [device.next_tx] + and [device.next_tx], (TX_RING-1) + +; Update stats + inc [device.packets_tx] + mov eax, [esp + 8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + + xor eax, eax + ret 8 + + .fail: + xor eax, eax + inc eax + ret 8 + + + + + + +; Interrupt handler +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 2,"\n%s INT\n", my_service + +;------------------------------------------- +; Find pointer of device wich made IRQ occur + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .fail + .nextdevice: + mov ebx, dword [esi] + add esi, 4 + + mov edi, [device.mmio_addr] + mov eax, [IrqStatus] + test eax, eax + jnz .got_it + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret + + .got_it: + mov [IrqStatus], eax + DEBUGF 2,"IrqStatus = %x\n", eax + + test eax, IRQ_RX + jz .no_rx + + .top: + mov eax, [device.cur_rx] + mov cx, sizeof.RxDesc + mul cx + lea esi, [device.rx_ring + eax] + mov eax, [esi + RxDesc.FlagLen] + + test eax, NV_RX_AVAIL ; still owned by hardware + jnz .return0 + + cmp [device.desc_ver], DESC_VER_1 + jne @f + test eax, NV_RX_DESCRIPTORVALID + jz .return0 + jmp .next + @@: + test eax, NV_RX2_DESCRIPTORVALID + jz .return0 + + .next: + + cmp dword [device.desc_ver], DESC_VER_1 + jne @f + and eax, LEN_MASK_V1 + jmp .next2 + @@: + and eax, LEN_MASK_V2 + .next2: + + ; got a valid packet - forward it to the network core + push .top + push eax + push dword [esi + RX_RING*sizeof.RxDesc] + + inc [device.cur_rx] + and [device.cur_rx], (RX_RING-1) + +; Allocate new buffer + + stdcall KernelAlloc, 4096 shl RBLEN + mov [esi + RX_RING*sizeof.RxDesc], eax + GetRealAddr + mov [esi + RxDesc.PacketBuffer], eax + mov [esi + RxDesc.FlagLen], (4096 shl RBLEN or NV_RX_AVAIL) + + jmp Eth_input + + .return0: + + + .no_rx: + test eax, IRQ_RX_ERROR + jz .no_rx_err + + push eax + DEBUGF 2,"RX error!\n" + + mov eax, [device.cur_rx] + mov cx, sizeof.RxDesc + mul cx + lea esi, [device.rx_ring + eax] + mov eax, [esi + RxDesc.FlagLen] + + DEBUGF 2,"Flaglen=%x\n", eax + + ; TODO: allocate new buff + pop eax + + .no_rx_err: + test eax, IRQ_LINK + jz .no_link + + push eax + call update_linkspeed + pop eax + + .no_link: + .fail: + + pop edi esi ebx + xor eax, eax + inc eax + + ret + + + + +; End of code + +section '.data' data readable writable align 16 ; place all uninitialized data place here +align 4 ; Place all initialised data here + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'FORCEDETH',0 ; max 16 chars include zero + +include_debug_strings ; All data wich FDO uses will be included here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling diff --git a/drivers/ethernet/i8254x.asm b/drivers/ethernet/i8254x.asm new file mode 100644 index 0000000000..e910b59d57 --- /dev/null +++ b/drivers/ethernet/i8254x.asm @@ -0,0 +1,818 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; i8254x driver for KolibriOS ;; +;; ;; +;; based on i8254x.asm from baremetal os ;; +;; ;; +;; Written by hidnplayr (hidnplayr@gmail.com) ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + ; TODO: make better use of the available descriptors + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + + MAX_PKT_SIZE = 16384 ; Maximum packet size + + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../struct.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + + + +; Register list +REG_CTRL = 0x0000 ; Control Register +REG_STATUS = 0x0008 ; Device Status Register +REG_CTRLEXT = 0x0018 ; Extended Control Register +REG_MDIC = 0x0020 ; MDI Control Register +REG_FCAL = 0x0028 ; Flow Control Address Low +REG_FCAH = 0x002C ; Flow Control Address High +REG_FCT = 0x0030 ; Flow Control Type +REG_VET = 0x0038 ; VLAN Ether Type +REG_ICR = 0x00C0 ; Interrupt Cause Read +REG_ITR = 0x00C4 ; Interrupt Throttling Register +REG_ICS = 0x00C8 ; Interrupt Cause Set Register +REG_IMS = 0x00D0 ; Interrupt Mask Set/Read Register +REG_IMC = 0x00D8 ; Interrupt Mask Clear Register +REG_RCTL = 0x0100 ; Receive Control Register +REG_FCTTV = 0x0170 ; Flow Control Transmit Timer Value +REG_TXCW = 0x0178 ; Transmit Configuration Word +REG_RXCW = 0x0180 ; Receive Configuration Word +REG_TCTL = 0x0400 ; Transmit Control Register +REG_TIPG = 0x0410 ; Transmit Inter Packet Gap + +REG_LEDCTL = 0x0E00 ; LED Control +REG_PBA = 0x1000 ; Packet Buffer Allocation + +REG_RDBAL = 0x2800 ; RX Descriptor Base Address Low +REG_RDBAH = 0x2804 ; RX Descriptor Base Address High +REG_RDLEN = 0x2808 ; RX Descriptor Length +REG_RDH = 0x2810 ; RX Descriptor Head +REG_RDT = 0x2818 ; RX Descriptor Tail +REG_RDTR = 0x2820 ; RX Delay Timer Register +REG_RXDCTL = 0x3828 ; RX Descriptor Control +REG_RADV = 0x282C ; RX Int. Absolute Delay Timer +REG_RSRPD = 0x2C00 ; RX Small Packet Detect Interrupt + +REG_TXDMAC = 0x3000 ; TX DMA Control +REG_TDBAL = 0x3800 ; TX Descriptor Base Address Low +REG_TDBAH = 0x3804 ; TX Descriptor Base Address High +REG_TDLEN = 0x3808 ; TX Descriptor Length +REG_TDH = 0x3810 ; TX Descriptor Head +REG_TDT = 0x3818 ; TX Descriptor Tail +REG_TIDV = 0x3820 ; TX Interrupt Delay Value +REG_TXDCTL = 0x3828 ; TX Descriptor Control +REG_TADV = 0x382C ; TX Absolute Interrupt Delay Value +REG_TSPMT = 0x3830 ; TCP Segmentation Pad & Min Threshold + +REG_RXCSUM = 0x5000 ; RX Checksum Control + +; Register list for i8254x +I82542_REG_RDTR = 0x0108 ; RX Delay Timer Register +I82542_REG_RDBAL = 0x0110 ; RX Descriptor Base Address Low +I82542_REG_RDBAH = 0x0114 ; RX Descriptor Base Address High +I82542_REG_RDLEN = 0x0118 ; RX Descriptor Length +I82542_REG_RDH = 0x0120 ; RDH for i82542 +I82542_REG_RDT = 0x0128 ; RDT for i82542 +I82542_REG_TDBAL = 0x0420 ; TX Descriptor Base Address Low +I82542_REG_TDBAH = 0x0424 ; TX Descriptor Base Address Low +I82542_REG_TDLEN = 0x0428 ; TX Descriptor Length +I82542_REG_TDH = 0x0430 ; TDH for i82542 +I82542_REG_TDT = 0x0438 ; TDT for i82542 + +; CTRL - Control Register (0x0000) +CTRL_FD = 0x00000001 ; Full Duplex +CTRL_LRST = 0x00000008 ; Link Reset +CTRL_ASDE = 0x00000020 ; Auto-speed detection +CTRL_SLU = 0x00000040 ; Set Link Up +CTRL_ILOS = 0x00000080 ; Invert Loss of Signal +CTRL_SPEED_MASK = 0x00000300 ; Speed selection +CTRL_SPEED_SHIFT = 8 +CTRL_FRCSPD = 0x00000800 ; Force Speed +CTRL_FRCDPLX = 0x00001000 ; Force Duplex +CTRL_SDP0_DATA = 0x00040000 ; SDP0 data +CTRL_SDP1_DATA = 0x00080000 ; SDP1 data +CTRL_SDP0_IODIR = 0x00400000 ; SDP0 direction +CTRL_SDP1_IODIR = 0x00800000 ; SDP1 direction +CTRL_RST = 0x04000000 ; Device Reset +CTRL_RFCE = 0x08000000 ; RX Flow Ctrl Enable +CTRL_TFCE = 0x10000000 ; TX Flow Ctrl Enable +CTRL_VME = 0x40000000 ; VLAN Mode Enable +CTRL_PHY_RST = 0x80000000 ; PHY reset + +; STATUS - Device Status Register (0x0008) +STATUS_FD = 0x00000001 ; Full Duplex +STATUS_LU = 0x00000002 ; Link Up +STATUS_TXOFF = 0x00000010 ; Transmit paused +STATUS_TBIMODE = 0x00000020 ; TBI Mode +STATUS_SPEED_MASK = 0x000000C0 ; Link Speed setting +STATUS_SPEED_SHIFT = 6 +STATUS_ASDV_MASK = 0x00000300 ; Auto Speed Detection +STATUS_ASDV_SHIFT = 8 +STATUS_PCI66 = 0x00000800 ; PCI bus speed +STATUS_BUS64 = 0x00001000 ; PCI bus width +STATUS_PCIX_MODE = 0x00002000 ; PCI-X mode +STATUS_PCIXSPD_MASK = 0x0000C000 ; PCI-X speed +STATUS_PCIXSPD_SHIFT = 14 + +; CTRL_EXT - Extended Device Control Register (0x0018) +CTRLEXT_PHY_INT = 0x00000020 ; PHY interrupt +CTRLEXT_SDP6_DATA = 0x00000040 ; SDP6 data +CTRLEXT_SDP7_DATA = 0x00000080 ; SDP7 data +CTRLEXT_SDP6_IODIR = 0x00000400 ; SDP6 direction +CTRLEXT_SDP7_IODIR = 0x00000800 ; SDP7 direction +CTRLEXT_ASDCHK = 0x00001000 ; Auto-Speed Detect Chk +CTRLEXT_EE_RST = 0x00002000 ; EEPROM reset +CTRLEXT_SPD_BYPS = 0x00008000 ; Speed Select Bypass +CTRLEXT_RO_DIS = 0x00020000 ; Relaxed Ordering Dis. +CTRLEXT_LNKMOD_MASK = 0x00C00000 ; Link Mode +CTRLEXT_LNKMOD_SHIFT = 22 + +; MDIC - MDI Control Register (0x0020) +MDIC_DATA_MASK = 0x0000FFFF ; Data +MDIC_REG_MASK = 0x001F0000 ; PHY Register +MDIC_REG_SHIFT = 16 +MDIC_PHY_MASK = 0x03E00000 ; PHY Address +MDIC_PHY_SHIFT = 21 +MDIC_OP_MASK = 0x0C000000 ; Opcode +MDIC_OP_SHIFT = 26 +MDIC_R = 0x10000000 ; Ready +MDIC_I = 0x20000000 ; Interrupt Enable +MDIC_E = 0x40000000 ; Error + +; ICR - Interrupt Cause Read (0x00c0) +ICR_TXDW = 0x00000001 ; TX Desc Written back +ICR_TXQE = 0x00000002 ; TX Queue Empty +ICR_LSC = 0x00000004 ; Link Status Change +ICR_RXSEQ = 0x00000008 ; RX Sence Error +ICR_RXDMT0 = 0x00000010 ; RX Desc min threshold reached +ICR_RXO = 0x00000040 ; RX Overrun +ICR_RXT0 = 0x00000080 ; RX Timer Interrupt +ICR_MDAC = 0x00000200 ; MDIO Access Complete +ICR_RXCFG = 0x00000400 +ICR_PHY_INT = 0x00001000 ; PHY Interrupt +ICR_GPI_SDP6 = 0x00002000 ; GPI on SDP6 +ICR_GPI_SDP7 = 0x00004000 ; GPI on SDP7 +ICR_TXD_LOW = 0x00008000 ; TX Desc low threshold hit +ICR_SRPD = 0x00010000 ; Small RX packet detected + +; RCTL - Receive Control Register (0x0100) +RCTL_EN = 0x00000002 ; Receiver Enable +RCTL_SBP = 0x00000004 ; Store Bad Packets +RCTL_UPE = 0x00000008 ; Unicast Promiscuous Enabled +RCTL_MPE = 0x00000010 ; Xcast Promiscuous Enabled +RCTL_LPE = 0x00000020 ; Long Packet Reception Enable +RCTL_LBM_MASK = 0x000000C0 ; Loopback Mode +RCTL_LBM_SHIFT = 6 +RCTL_RDMTS_MASK = 0x00000300 ; RX Desc Min Threshold Size +RCTL_RDMTS_SHIFT = 8 +RCTL_MO_MASK = 0x00003000 ; Multicast Offset +RCTL_MO_SHIFT = 12 +RCTL_BAM = 0x00008000 ; Broadcast Accept Mode +RCTL_BSIZE_MASK = 0x00030000 ; RX Buffer Size +RCTL_BSIZE_SHIFT = 16 +RCTL_VFE = 0x00040000 ; VLAN Filter Enable +RCTL_CFIEN = 0x00080000 ; CFI Enable +RCTL_CFI = 0x00100000 ; Canonical Form Indicator Bit +RCTL_DPF = 0x00400000 ; Discard Pause Frames +RCTL_PMCF = 0x00800000 ; Pass MAC Control Frames +RCTL_BSEX = 0x02000000 ; Buffer Size Extension +RCTL_SECRC = 0x04000000 ; Strip Ethernet CRC + +; TCTL - Transmit Control Register (0x0400) +TCTL_EN = 0x00000002 ; Transmit Enable +TCTL_PSP = 0x00000008 ; Pad short packets +TCTL_SWXOFF = 0x00400000 ; Software XOFF Transmission + +; PBA - Packet Buffer Allocation (0x1000) +PBA_RXA_MASK = 0x0000FFFF ; RX Packet Buffer +PBA_RXA_SHIFT = 0 +PBA_TXA_MASK = 0xFFFF0000 ; TX Packet Buffer +PBA_TXA_SHIFT = 16 + +; Flow Control Type +FCT_TYPE_DEFAULT = 0x8808 + +; === TX Descriptor fields === + +; TX Packet Length (word 2) +TXDESC_LEN_MASK = 0x0000ffff + +; TX Descriptor CMD field (word 2) +TXDESC_IDE = 0x80000000 ; Interrupt Delay Enable +TXDESC_VLE = 0x40000000 ; VLAN Packet Enable +TXDESC_DEXT = 0x20000000 ; Extension +TXDESC_RPS = 0x10000000 ; Report Packet Sent +TXDESC_RS = 0x08000000 ; Report Status +TXDESC_IC = 0x04000000 ; Insert Checksum +TXDESC_IFCS = 0x02000000 ; Insert FCS +TXDESC_EOP = 0x01000000 ; End Of Packet + +; TX Descriptor STA field (word 3) +TXDESC_TU = 0x00000008 ; Transmit Underrun +TXDESC_LC = 0x00000004 ; Late Collision +TXDESC_EC = 0x00000002 ; Excess Collisions +TXDESC_DD = 0x00000001 ; Descriptor Done + +; === RX Descriptor fields === + +; RX Packet Length (word 2) +RXDESC_LEN_MASK = 0x0000ffff + +; RX Descriptor STA field (word 3) +RXDESC_PIF = 0x00000080 ; Passed In-exact Filter +RXDESC_IPCS = 0x00000040 ; IP cksum calculated +RXDESC_TCPCS = 0x00000020 ; TCP cksum calculated +RXDESC_VP = 0x00000008 ; Packet is 802.1Q +RXDESC_IXSM = 0x00000004 ; Ignore cksum indication +RXDESC_EOP = 0x00000002 ; End Of Packet +RXDESC_DD = 0x00000001 ; Descriptor Done + + +virtual at ebx + device: + ETH_DEVICE + + .mmio_addr dd ? + .pci_bus dd ? + .pci_dev dd ? + .irq_line db ? + + .cur_tx dd ? + .last_tx dd ? + + rb 0x100 - (($ - device) and 0xff) + .rx_desc rd 256/8 + + rb 0x100 - (($ - device) and 0xff) + .tx_desc rd 256/8 + + sizeof.device_struct = $ - device + +end virtual + +section '.flat' code readable align 16 + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 2,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax, [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte [device.pci_bus] + jne .next + cmp ah, byte [device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + .next: + add esi, 4 + loop .nextdevice + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, sizeof.device_struct, .fail ; Allocate the buffer for device structure + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte [eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte [eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base mmio addres of the PCI device + + PCI_find_mmio32 + +; Create virtual mapping of the physical memory + + push 1Bh ; PG_SW+PG_NOCACHE + push 10000h ; size of the map + push eax + call MapIoMem + mov [device.mmio_addr], eax + +; We've found the mmio address, find IRQ now + + PCI_find_irq + + DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.mmio_addr]:8 + +; Ok, the eth_device structure is ready, let's probe the device + call probe ; this function will output in eax + test eax, eax + jnz .err ; If an error occured, exit + + mov eax, [devices] ; Add the device structure to our device list + mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + call start_i8254x + + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + je .destroy + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 1,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 1,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + .err: + stdcall KernelFree, ebx + + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + +align 4 +unload: + ; TODO: (in this particular order) + ; + ; - Stop the device + ; - Detach int handler + ; - Remove device from local list (device_list) + ; - call unregister function in kernel + ; - Remove all allocated structures and buffers the card used + + or eax, -1 + +ret + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; probe: enables the device (if it really is I8254X) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +align 4 +probe: + + DEBUGF 1,"Probe\n" + + PCI_make_bus_master + + ; TODO: validate the device + + call read_mac + + movzx eax, [device.irq_line] + DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 1,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + + +reset_dontstart: + DEBUGF 1,"Reset\n" + + mov esi, [device.mmio_addr] + + or dword [esi + REG_CTRL], CTRL_RST ; reset device + .loop: + push esi + xor esi, esi + inc esi + call Sleep + pop esi + test dword [esi + REG_CTRL], CTRL_RST + jnz .loop + + mov dword [esi + REG_IMC], 0xffffffff ; Disable all interrupt causes + mov eax, dword [esi + REG_ICR] ; Clear any pending interrupts + mov dword [esi + REG_ITR], 0 ; Disable interrupt throttling logic + + mov dword [esi + REG_PBA], 0x00000030 ; PBA: set the RX buffer size to 48KB (TX buffer is calculated as 64-RX buffer) + mov dword [esi + REG_RDTR], 0 ; RDTR: set no delay + + mov dword [esi + REG_TXCW], 0x08008060 ; TXCW: set ANE, TxConfigWord (Half/Full duplex, Next Page Reqest) + + mov eax, [esi + REG_CTRL] + or eax, 1 shl 6 + 1 shl 5 + and eax, not (1 shl 3 + 1 shl 7 + 1 shl 30 + 1 shl 31) + mov dword [esi + REG_CTRL], eax ; CTRL: clear LRST, set SLU and ASDE, clear RSTPHY, VME, and ILOS + + lea edi, [esi + 0x5200] ; MTA: reset + mov eax, 0xffffffff + stosd + stosd + stosd + stosd + + stdcall KernelAlloc, 48*1024 + mov dword [device.rx_desc + 16], eax + GetRealAddr + mov dword [device.rx_desc], eax + mov dword [device.rx_desc + 4], 0 + + lea eax, [device.rx_desc] + GetRealAddr + mov dword [esi + REG_RDBAL], eax ; Receive Descriptor Base Address Low + mov dword [esi + REG_RDBAH], 0 ; Receive Descriptor Base Address High + mov dword [esi + REG_RDLEN], (1 * 128) ; Receive Descriptor Length + mov dword [esi + REG_RDH], 0 ; Receive Descriptor Head + mov dword [esi + REG_RDT], 1 ; Receive Descriptor Tail + mov dword [esi + REG_RCTL], RCTL_EN or RCTL_SBP or RCTL_BAM or RCTL_SECRC or RCTL_UPE or RCTL_MPE + ; Receiver Enable, Store Bad Packets, Broadcast Accept Mode, Strip Ethernet CRC from incoming packet, Promiscuous mode + + mov dword [device.tx_desc], 0 + mov dword [device.tx_desc + 4], 0 + mov dword [device.tx_desc + 16], 0 + + lea eax, [device.tx_desc] + GetRealAddr + mov dword [esi + REG_TDBAL], eax ; Transmit Descriptor Base Address Low + mov dword [esi + REG_TDBAH], 0 ; Transmit Descriptor Base Address High + mov dword [esi + REG_TDLEN], (1 * 128) ; Transmit Descriptor Length + mov dword [esi + REG_TDH], 0 ; Transmit Descriptor Head + mov dword [esi + REG_TDT], 0 ; Transmit Descriptor Tail + mov dword [esi + REG_TCTL], 0x010400fa ; Enabled, Pad Short Packets, 15 retrys, 64-byte COLD, Re-transmit on Late Collision + mov dword [esi + REG_TIPG], 0x0060200A ; IPGT 10, IPGR1 8, IPGR2 6 + + xor eax, eax + ret + +align 4 +reset: + call reset_dontstart + +start_i8254x: + + xor eax, eax + mov [esi + REG_RDTR], eax ; Clear the Receive Delay Timer Register + mov [esi + REG_RADV], eax ; Clear the Receive Interrupt Absolute Delay Timer + mov [esi + REG_RSRPD], eax ; Clear the Receive Small Packet Detect Interrupt +; or eax, 1 shl 0 + 1 shl 7 ; TXDW + RXT0 + mov eax, 1+4+16 ;;;; hack! + mov [esi + REG_IMS], eax ; Enable interrupt types + + mov [device.mtu], 1514 + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + + xor eax, eax + ret + + + + +align 4 +read_mac: + + DEBUGF 1,"Read MAC\n" + + mov esi, [device.mmio_addr] + + mov eax, [esi+0x5400] ; RAL + test eax, eax + jz .try_eeprom + + mov dword [device.mac], eax + mov eax, [esi+0x5404] ; RAH + mov word [device.mac+4], ax + + jmp .mac_ok + + .try_eeprom: + mov dword [esi+0x14], 0x00000001 + mov eax, [esi+0x14] + shr eax, 16 + mov word [device.mac], ax + + mov dword [esi+0x14], 0x00000101 + mov eax, [esi+0x14] + shr eax, 16 + mov word [device.mac+2], ax + + mov dword [esi+0x14], 0x00000201 + mov eax, [esi+0x14] + shr eax, 16 + mov word [device.mac+4], ax + + .mac_ok: + DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n",\ + [device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + + ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +align 4 +transmit: + DEBUGF 2,"\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] + mov eax, [esp+4] + DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp + 8], 1514 + ja .fail + cmp dword [esp + 8], 60 + jb .fail + + +; Program the descriptor (use legacy mode) + lea edi, [device.tx_desc] ; Transmit Descriptor Base Address + mov dword [edi + 16], eax ; Store the data location (for driver) + GetRealAddr ; + mov dword [edi], eax ; Real addr (for i8254x) + mov dword [edi + 4], 0x00000000 ; + + mov ecx, [esp + 8] + or ecx, 1 shl 24 + 1 shl 25 + 1 shl 27 ; EOP + IFCS + RS + mov dword [edi + 8], ecx ; Packet size + mov dword [edi + 12], 0x00000000 + +; Tell i8254x wich descriptor(s) we programmed + mov edi, [device.mmio_addr] + mov dword [edi + REG_TDH], 0 ; TDH - Transmit Descriptor Head + mov dword [edi + REG_TDT], 1 ; TDT - Transmit Descriptor Tail + +; Update stats + inc [device.packets_tx] + mov eax, [esp + 8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + + ret 8 + + .fail: + DEBUGF 1,"Send failed\n" + ret 8 + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service +;------------------------------------------- +; Find pointer of device wich made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + + mov edi, [device.mmio_addr] + mov eax, [edi + REG_ICR] + test eax, eax + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret + + .got_it: + + DEBUGF 1,"Device: %x Status: %x ", ebx, eax + +;--------- +; RX done? + + test eax, ICR_RXDMT0 + jz .no_rx + + push eax ebx + push .retaddr + +; Get last descriptor addr + lea esi, [device.rx_desc] + + cmp byte [esi + 12], 0 ; Check status field + je .retaddr + + movzx ecx, word [esi + 8] ; Get the packet length + DEBUGF 2,"got %u bytes\n", ecx + push ecx + push dword [esi + 16] ; Get packet pointer + +; Update stats + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + inc dword [device.packets_rx] + +; allocate new descriptor + stdcall KernelAlloc, 48*1024 + mov dword [esi + 16], eax + GetRealAddr + mov dword [esi], eax + +; reset descriptor status + mov esi, [device.mmio_addr] + mov dword [esi + REG_RDH], 0x00000000 ; Receive Descriptor Head + mov dword [esi + REG_RDT], 0x00000001 ; Receive Descriptor Tail + + jmp Eth_input + .retaddr: + pop ebx eax + + .no_rx: + +;-------------- +; Link Changed? + + test eax, ICR_LSC + jz .no_link + + DEBUGF 2,"Link Changed\n" + + .no_link: + +;--------------- +; Transmit done? + + test eax, ICR_TXDW + jz .no_tx + + DEBUGF 2,"Transmit done\n" + + lea edi, [device.tx_desc] ; Transmit Descriptor Base Address + push dword [edi + 16] ; Store the data location (for driver) + call KernelFree + + .no_tx: + .fail: + pop edi esi ebx + xor eax, eax + inc eax + + ret + + + + +; End of code + +section '.data' data readable writable align 16 +align 4 + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'I8254X',0 ; max 16 chars include zero + +include_debug_strings ; All data wich FDO uses will be included here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + + diff --git a/drivers/ethernet/i8255x.asm b/drivers/ethernet/i8255x.asm new file mode 100644 index 0000000000..c607d188fa --- /dev/null +++ b/drivers/ethernet/i8255x.asm @@ -0,0 +1,1255 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; i8255x (Intel eepro 100) driver for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;; Some parts of this driver are based on the code of eepro100.c ;; +;; from linux. ;; +;; ;; +;; Intel's programming manual for i8255x: ;; +;; http://www.intel.com/design/network/manuals/8255x_opensdm.htm ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; TODO: use separate descriptors in memory instead of placing them in front of packets! + + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + +virtual at ebx + + device: + + ETH_DEVICE + + .io_addr dd ? + .pci_bus dd ? + .pci_dev dd ? + .irq_line db ? + + .rx_desc dd ? + + .ee_bus_width db ? + + rb 0x100 - (($ - device) and 0xff) + + txfd: + .status dw ? + .command dw ? + .link dd ? + .tx_desc_addr dd ? + .count dd ? + + .tx_buf_addr0 dd ? + .tx_buf_size0 dd ? + + rb 0x100 - (($ - device) and 0xff) + + confcmd: + .status dw ? + .command dw ? + .link dd ? + .data rb 64 + + rb 0x100 - (($ - device) and 0xff) + + lstats: + tx_good_frames dd ? + tx_coll16_errs dd ? + tx_late_colls dd ? + tx_underruns dd ? + tx_lost_carrier dd ? + tx_deferred dd ? + tx_one_colls dd ? + tx_multi_colls dd ? + tx_total_colls dd ? + + rx_good_frames dd ? + rx_crc_errs dd ? + rx_align_errs dd ? + rx_resource_errs dd ? + rx_overrun_errs dd ? + rx_colls_errs dd ? + rx_runt_errs dd ? + + last_tx_buffer dd ? ;;; fixme + + sizeof.device_struct = $ - device + +end virtual + + +virtual at 0 + + rxfd: + .status dw ? + .command dw ? + .link dd ? + .rx_buf_addr dd ? + .count dw ? + .size dw ? + .packet: + +end virtual + + +; Serial EEPROM + +EE_SK = 1 shl 0 ; serial clock +EE_CS = 1 shl 1 ; chip select +EE_DI = 1 shl 2 ; data in +EE_DO = 1 shl 3 ; data out +EE_MASK = EE_SK + EE_CS + EE_DI + EE_DO + +; opcodes, first bit is start bit and must be 1 +EE_READ = 110b +EE_WRITE = 101b +EE_ERASE = 111b + +; The SCB accepts the following controls for the Tx and Rx units: + +CU_START = 0x0010 +CU_RESUME = 0x0020 +CU_STATSADDR = 0x0040 +CU_SHOWSTATS = 0x0050 ; Dump statistics counters. +CU_CMD_BASE = 0x0060 ; Base address to add CU commands. +CU_DUMPSTATS = 0x0070 ; Dump then reset stats counters. + +RX_START = 0x0001 +RX_RESUME = 0x0002 +RX_ABORT = 0x0004 +RX_ADDR_LOAD = 0x0006 +RX_RESUMENR = 0x0007 +INT_MASK = 0x0100 +DRVR_INT = 0x0200 ; Driver generated interrupt + +CmdIASetup = 0x0001 +CmdConfigure = 0x0002 +CmdTx = 0x0004 +CmdTxFlex = 0x0008 +Cmdsuspend = 0x4000 + + +reg_scb_status = 0 +reg_scb_cmd = 2 +reg_scb_ptr = 4 +reg_port = 8 +reg_eeprom = 14 +reg_mdi_ctrl = 16 + + +macro delay { + push eax + in ax, dx + in ax, dx + in ax, dx + in ax, dx + in ax, dx + in ax, dx + in ax, dx + in ax, dx + in ax, dx + in ax, dx + pop eax +} + +section '.flat' code readable align 16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 1,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax , [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, sizeof.device_struct, .fail ; Allocate the buffer for device structure + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base io addres of the PCI device + + PCI_find_io + +; We've found the io address, find IRQ now + + PCI_find_irq + + DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 + +; Ok, the eth_device structure is ready, let's probe the device + + pushf + cli ; disable ints until initialisation is done + + call probe ; this function will output in eax + test eax, eax + jnz .err ; If an error occured, exit + + mov eax, [devices] ; Add the device structure to our device list + mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + popf + + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + je .err + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 2,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 2,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .err: + stdcall KernelFree, ebx + + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + + + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + +unload: + ; TODO: (in this particular order) + ; + ; - Stop the device + ; - Detach int handler + ; - Remove device from local list (device_list) + ; - call unregister function in kernel + ; - Remove all allocated structures and buffers the card used + + or eax,-1 + +ret + + +;------------- +; +; Probe +; +;------------- + +align 4 +probe: + + DEBUGF 1,"Probing i8255x\n" + + PCI_make_bus_master + +;--------------------------- +; First, identify the device + + stdcall PciRead32, [device.pci_bus], [device.pci_dev], PCI_VENDOR_ID ; get device/vendor id + + DEBUGF 1,"Vendor_id=0x%x\n", ax + + cmp ax, 0x8086 + jne .notfound + shr eax, 16 + + DEBUGF 1,"Device_id=0x%x\n", ax + + mov ecx, DEVICE_IDs + mov edi, device_id_list + repne scasw + jne .notfound + jmp .found + + .notfound: + DEBUGF 1,"ERROR: Unsupported device!\n" + or eax, -1 + ret + + .found: + + call ee_get_width + call MAC_read_eeprom + + ;;; TODO: detect phy + + + +;---------- +; +; Reset +; +;---------- + +align 4 +reset: + + movzx eax, [device.irq_line] + DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 1,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + + DEBUGF 1,"Resetting %s\n", my_service + +;--------------- +; reset the card + + set_io 0 + set_io reg_port + xor eax, eax ; Software Reset + out dx, eax + + mov esi, 10 + call Sleep ; Give the card time to warm up. + +;--------------------------------- +; Tell device where to store stats + + lea eax, [lstats] + GetRealAddr + set_io 0 + set_io reg_scb_ptr + out dx, eax + + mov ax, INT_MASK + CU_STATSADDR + set_io reg_scb_cmd + out dx, ax + call cmd_wait + +;----------------- +; setup RX + + set_io reg_scb_ptr + xor eax, eax + out dx, eax + + set_io reg_scb_cmd + mov ax, INT_MASK + RX_ADDR_LOAD + out dx, ax + call cmd_wait + +;----------------------------- +; Create RX and TX descriptors + + call create_ring + +; RX start + + set_io 0 + set_io reg_scb_ptr + mov eax, [device.rx_desc] + GetRealAddr + out dx, eax + + mov ax, INT_MASK + RX_START + set_io reg_scb_cmd + out dx, ax + call cmd_wait + +; Set-up TX + + set_io reg_scb_ptr + xor eax, eax + out dx, eax + + set_io reg_scb_cmd + mov ax, INT_MASK + CU_CMD_BASE + out dx, ax + call cmd_wait + +; -------------------- + + mov [confcmd.command], CmdConfigure + Cmdsuspend + mov [confcmd.status], 0 + lea eax, [txfd] + GetRealAddr + mov [confcmd.link], eax + + mov esi, confcmd_data + lea edi, [confcmd.data] + mov ecx, 22 + rep movsb + + mov byte[confcmd.data + 1], 0x88 ; fifo of 8 each + mov byte[confcmd.data + 4], 0 + mov byte[confcmd.data + 5], 0x80 + mov byte[confcmd.data + 15], 0x48 + mov byte[confcmd.data + 19], 0x80 + mov byte[confcmd.data + 21], 0x05 + + mov [txfd.command], CmdIASetup + mov [txfd.status], 0 + lea eax, [confcmd] + GetRealAddr + mov [txfd.link], eax + +;;; copy in our MAC + + lea edi, [txfd.tx_desc_addr] + lea esi, [device.mac] + movsd + movsw + + set_io reg_scb_ptr + lea eax, [txfd] + GetRealAddr + out dx, eax + +; Start CU & enable ints + + set_io reg_scb_cmd + mov ax, CU_START + out dx, ax + call cmd_wait + +;----------------------- +; build txfd structure (again!) + + lea eax, [txfd] + GetRealAddr + mov [txfd.link], eax + mov [txfd.count], 0x02208000 + lea eax, [txfd.tx_buf_addr0] + GetRealAddr + mov [txfd.tx_desc_addr], eax + +; Indicate that we have successfully reset the card + + DEBUGF 1,"Resetting %s complete\n", my_service + + mov [device.mtu], 1514 + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + + xor eax, eax ; indicate that we have successfully reset the card + ret + + +align 4 +create_ring: + + DEBUGF 1,"Creating ring\n" + +;--------------------- +; build rxfd structure + + stdcall KernelAlloc, 2000 + mov [device.rx_desc], eax + mov esi, eax + GetRealAddr + mov [esi + rxfd.status], 0x0000 + mov [esi + rxfd.command], 0x0000 + mov [esi + rxfd.link], eax + mov [esi + rxfd.count], 0 + mov [esi + rxfd.size], 1528 + +;----------------------- +; build txfd structure + + lea eax, [txfd] + GetRealAddr + mov [txfd.link], eax + mov [txfd.count], 0x02208000 + lea eax, [txfd.tx_buf_addr0] + GetRealAddr + mov [txfd.tx_desc_addr], eax + + ret + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +transmit: + + DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] + mov eax, [esp+4] + DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp+8], 1514 + ja .error ; packet is too long + cmp dword [esp+8], 60 + jb .error ; packet is too short + + ;;; TODO: check if current descriptor is in use + ; fill in buffer address and size + mov eax, [esp+4] + mov [last_tx_buffer], eax ;;; FIXME + GetRealAddr + mov [txfd.tx_buf_addr0], eax + mov eax, [esp+8] + mov [txfd.tx_buf_size0], eax + + mov [txfd.status], 0 + mov [txfd.command], Cmdsuspend + CmdTx + CmdTxFlex + 1 shl 15 ;;; EL bit + + ; mov [txfd.count], 0x02208000 ;;;;;;;;;;; + + ; Inform device of the new/updated transmit descriptor + lea eax, [txfd] + GetRealAddr + set_io 0 + set_io reg_scb_ptr + out dx, eax + + ; Start the transmit + mov ax, CU_START + set_io reg_scb_cmd + out dx, ax + call cmd_wait + +; set_io 0 ;; why? +; in ax, dx ;; +; +; @@: +; cmp [txfd.status], 0 ; wait for completion? dont seems a good idea to me.. +; je @r +; +; set_io 0 ;; why? +; in ax, dx ;; + +; Update stats + inc [device.packets_tx] + mov eax, [esp + 8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + + DEBUGF 1,"Transmit OK\n" + + xor eax, eax + ret 8 + + .error: + stdcall KernelFree, [esp+4] + or eax, -1 + ret 8 + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service + +; find pointer of device wich made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + +; set_io 0 ; reg_scb_status = 0 + set_io reg_scb_status + in ax, dx + out dx, ax ; send it back to ACK + test ax, ax + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) + + .got_it: + + DEBUGF 1,"Device: %x Status: %x\n", ebx, ax + + test ax, 1 shl 14 ; did we receive a frame? + jz .no_rx + + push ax + + DEBUGF 1,"Receiving\n" + + push ebx + .rx_loop: + pop ebx + + mov esi, [device.rx_desc] + cmp [esi + rxfd.status], 0 ; we could also check bits C and OK (bit 15 and 13) + je .nodata + + DEBUGF 1,"rxfd status=0x%x\n", [esi + rxfd.status]:4 + + movzx ecx, [esi + rxfd.count] + and ecx, 0x3fff + + push ebx + push .rx_loop + push ecx + add esi, rxfd.packet + push esi + +; Update stats + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + inc dword [device.packets_rx] + +; allocate new descriptor + + stdcall KernelAlloc, 2000 + mov [device.rx_desc], eax + mov esi, eax + GetRealAddr + mov [esi + rxfd.status], 0x0000 + mov [esi + rxfd.command], 0xc000 ; End of list + Suspend + mov [esi + rxfd.link], eax + mov [esi + rxfd.count], 0 + mov [esi + rxfd.size], 1528 + +; restart RX + + set_io 0 + set_io reg_scb_ptr +; lea eax, [device.rx_desc] +; GetRealAddr + out dx, eax + + set_io reg_scb_cmd + mov ax, RX_START + out dx, ax + call cmd_wait + +; And give packet to kernel + + jmp Eth_input + + .nodata: + DEBUGF 1, "no more data\n" + pop ax + + .no_rx: + +; Cleanup after TX + cmp [txfd.status], 0 + je .done + cmp [last_tx_buffer], 0 + je .done + push ax + DEBUGF 1, "Removing packet 0x%x from RAM!\n", [last_tx_buffer] + stdcall KernelFree, [last_tx_buffer] + mov [last_tx_buffer], 0 + pop ax + + .done: + and ax, 00111100b + cmp ax, 00001000b + jne .fail + + DEBUGF 1, "out of resources!\n" +; Restart the RX + +; allocate new descriptor + + stdcall KernelAlloc, 2000 + mov [device.rx_desc], eax + mov esi, eax + GetRealAddr + mov [esi + rxfd.status], 0x0000 + mov [esi + rxfd.command], 0xc000 ; End of list + Suspend + mov [esi + rxfd.link], eax + mov [esi + rxfd.count], 0 + mov [esi + rxfd.size], 1528 + +; restart RX + + set_io 0 + set_io reg_scb_ptr +; lea eax, [device.rx_desc] +; GetRealAddr + out dx, eax + + set_io reg_scb_cmd + mov ax, RX_START + out dx, ax + call cmd_wait + + .fail: + pop edi esi ebx + xor eax, eax + inc eax + + ret + + + + +align 4 +cmd_wait: + + in al, dx + test al, al + jnz cmd_wait + + ret + + + + + + +align 4 +ee_read: ; esi = address to read + + DEBUGF 1,"Eeprom read from 0x%x", esi + + set_io 0 + set_io reg_eeprom + +;----------------------------------------------------- +; Prepend start bit + read opcode to the address field +; and shift it to the very left bits of esi + + mov cl, 29 + sub cl, [device.ee_bus_width] + shl esi, cl + or esi, EE_READ shl 29 + + movzx ecx, [device.ee_bus_width] + add ecx, 3 + + mov al, EE_CS + out dx, al + delay + +;----------------------- +; Write this to the chip + + .loop: + mov al, EE_CS + EE_SK + shl esi, 1 + jnc @f + or al, EE_DI + @@: + out dx, al + delay + + and al, not EE_SK + out dx, al + delay + + loop .loop + +;------------------------------ +; Now read the data from eeprom + + xor esi, esi + mov ecx, 16 + + .loop2: + shl esi, 1 + mov al, EE_CS + EE_SK + out dx, al + delay + + in al, dx + test al, EE_DO + jz @f + inc esi + @@: + + mov al, EE_CS + out dx, al + delay + + loop .loop2 + +;----------------------- +; de-activate the eeprom + + xor ax, ax + out dx, ax + + + DEBUGF 1,"=0x%x\n", esi:4 + ret + + + +align 4 +ee_write: ; esi = address to write to, di = data + + DEBUGF 1,"Eeprom write 0x%x to 0x%x\n", di, esi + + set_io 0 + set_io reg_eeprom + +;----------------------------------------------------- +; Prepend start bit + write opcode to the address field +; and shift it to the very left bits of esi + + mov cl, 29 + sub cl, [device.ee_bus_width] + shl esi, cl + or esi, EE_WRITE shl 29 + + movzx ecx, [device.ee_bus_width] + add ecx, 3 + + mov al, EE_CS ; enable chip + out dx, al + +;----------------------- +; Write this to the chip + + .loop: + mov al, EE_CS + EE_SK + shl esi, 1 + jnc @f + or al, EE_DI + @@: + out dx, al + delay + + and al, not EE_SK + out dx, al + delay + + loop .loop + +;----------------------------- +; Now write the data to eeprom + + mov ecx, 16 + + .loop2: + mov al, EE_CS + EE_SK + shl di, 1 + jnc @f + or al, EE_DI + @@: + out dx, al + delay + + and al, not EE_SK + out dx, al + delay + + loop .loop2 + +;----------------------- +; de-activate the eeprom + + xor al, al + out dx, al + + + ret + + + +align 4 +ee_get_width: + +; DEBUGF 1,"Eeprom get width\n" + + set_io 0 + set_io reg_eeprom + + mov al, EE_CS ; activate eeprom + out dx, al + delay + + mov si, EE_READ shl 13 + xor ecx, ecx + .loop: + mov al, EE_CS + EE_SK + shl si, 1 + jnc @f + or al, EE_DI + @@: + out dx, al + delay + + and al, not EE_SK + out dx, al + delay + + inc ecx + + cmp ecx, 15 + jae .give_up + + in al, dx + test al, EE_DO + jnz .loop + + .give_up: + xor al, al + out dx, al ; de-activate eeprom + + sub cl, 3 ; dont count the opcode bits + + mov [device.ee_bus_width], cl + DEBUGF 1,"Eeprom width=%u bit\n", ecx + + +;----------------------- +; de-activate the eeprom + + xor eax, eax + out dx, eax + + ret + + + +; cx = phy addr +; dx = phy reg addr + +; ax = data + +align 4 +mdio_read: + + DEBUGF 1,"MDIO read\n" + + shl ecx, 21 ; PHY addr + shl edx, 16 ; PHY reg addr + + mov eax, ecx + or eax, edx + or eax, 10b shl 26 ; read opcode + + set_io 0 + set_io reg_mdi_ctrl + out dx, eax + + .wait: + delay + in eax, dx + test eax, 1 shl 28 ; ready bit + jz .wait + + ret + +; ax = data +; cx = phy addr +; dx = phy reg addr + +; ax = data + +align 4 +mdio_write: + + DEBUGF 1,"MDIO write\n" + + and eax, 0xffff + + shl ecx, 21 ; PHY addr + shl edx, 16 ; PHY reg addr + + or eax, ecx + or eax, edx + or eax, 01b shl 26 ; write opcode + + set_io 0 + set_io reg_mdi_ctrl + out dx, eax + + .wait: + delay + in eax, dx + test eax, 1 shl 28 ; ready bit + jz .wait + + ret + +read_mac: + + ret + + + +align 4 +MAC_read_eeprom: + + mov esi, 0 + call ee_read + mov word[device.mac], si + + mov esi, 1 + call ee_read + mov word[device.mac+2], si + + mov esi, 2 + call ee_read + mov word[device.mac+4], si + + + ret + + +align 4 +MAC_write: + +;;;; + + ret + + + + +; End of code + +align 4 ; Place all initialised data here + +devices dd 0 ; number of currently running devices +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'i8255x', 0 ; max 16 chars include zero +devicename db 'Intel Etherexpress pro/100', 0 + +confcmd_data db 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1 + db 0, 0x2e, 0, 0x60, 0, 0xf2, 0x48, 0, 0x40, 0xf2 + db 0x80, 0x3f, 0x05 ; 22 bytes total + + +device_id_list: + + dw 0x1029 + dw 0x1030 + dw 0x1031 + dw 0x1032 + dw 0x1033 + dw 0x1034 + dw 0x1038 + dw 0x1039 + dw 0x103A + dw 0x103B + dw 0x103C + dw 0x103D + dw 0x103E + dw 0x1050 + dw 0x1051 + dw 0x1052 + dw 0x1053 + dw 0x1054 + dw 0x1055 + dw 0x1056 + dw 0x1057 + dw 0x1059 + dw 0x1064 + dw 0x1065 + dw 0x1066 + dw 0x1067 + dw 0x1068 + dw 0x1069 + dw 0x106A + dw 0x106B + dw 0x1091 + dw 0x1092 + dw 0x1093 + dw 0x1094 + dw 0x1095 + dw 0x10fe + dw 0x1209 + dw 0x1229 + dw 0x2449 + dw 0x2459 + dw 0x245D + dw 0x27DC + +DEVICE_IDs = ($ - device_id_list) / 2 + +mac_82557_D100_A = 0 +mac_82557_D100_B = 1 +mac_82557_D100_C = 2 +mac_82558_D101_A4 = 4 +mac_82558_D101_B0 = 5 +mac_82559_D101M = 8 +mac_82559_D101S = 9 +mac_82550_D102 = 12 +mac_82550_D102_C = 13 +mac_82551_E = 14 +mac_82551_F = 15 +mac_82551_10 = 16 +mac_unknown = 0xFF + +phy_100a = 0x000003E0 +phy_100c = 0x035002A8 +phy_82555_tx = 0x015002A8 +phy_nsc_tx = 0x5C002000 +phy_82562_et = 0x033002A8 +phy_82562_em = 0x032002A8 +phy_82562_ek = 0x031002A8 +phy_82562_eh = 0x017002A8 +phy_82552_v = 0xd061004d +phy_unknown = 0xFFFFFFFF + + +include_debug_strings ; All data wich FDO uses will be included here + +section '.data' data readable writable align 16 ; place all uninitialized data place here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + diff --git a/drivers/ethernet/mtd80x.asm b/drivers/ethernet/mtd80x.asm new file mode 100644 index 0000000000..db93d28d99 --- /dev/null +++ b/drivers/ethernet/mtd80x.asm @@ -0,0 +1,1266 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; MTD80x driver for KolibriOS ;; +;; ;; +;; Based on mtd80x.c from the etherboot project ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + + NUM_TX_DESC = 4 + NUM_RX_DESC = 4 + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + + +; for different PHY + + MysonPHY = 1 + AhdocPHY = 2 + SeeqPHY = 3 + MarvellPHY = 4 + Myson981 = 5 + LevelOnePHY = 6 + OtherPHY = 10 + +; Offsets to the Command and Status Registers. + + PAR0 = 0x0 ; physical address 0-3 + PAR1 = 0x04 ; physical address 4-5 + MAR0 = 0x08 ; multicast address 0-3 + MAR1 = 0x0C ; multicast address 4-7 + FAR0 = 0x10 ; flow-control address 0-3 + FAR1 = 0x14 ; flow-control address 4-5 + TCRRCR = 0x18 ; receive & transmit configuration + BCR = 0x1C ; bus command + TXPDR = 0x20 ; transmit polling demand + RXPDR = 0x24 ; receive polling demand + RXCWP = 0x28 ; receive current word pointer + TXLBA = 0x2C ; transmit list base address + RXLBA = 0x30 ; receive list base address + ISR = 0x34 ; interrupt status + IMR = 0x38 ; interrupt mask + FTH = 0x3C ; flow control high/low threshold + MANAGEMENT = 0x40 ; bootrom/eeprom and mii management + TALLY = 0x44 ; tally counters for crc and mpa + TSR = 0x48 ; tally counter for transmit status + BMCRSR = 0x4c ; basic mode control and status + PHYIDENTIFIER = 0x50 ; phy identifier + ANARANLPAR = 0x54 ; auto-negotiation advertisement and link partner ability + ANEROCR = 0x58 ; auto-negotiation expansion and pci conf. + BPREMRPSR = 0x5c ; bypass & receive error mask and phy status + +; Bits in the interrupt status/enable registers. + + RFCON = 0x00020000 ; receive flow control xon packet + RFCOFF = 0x00010000 ; receive flow control xoff packet + LSCStatus = 0x00008000 ; link status change + ANCStatus = 0x00004000 ; autonegotiation completed + FBE = 0x00002000 ; fatal bus error + FBEMask = 0x00001800 ; mask bit12-11 + ParityErr = 0x00000000 ; parity error + TargetErr = 0x00001000 ; target abort + MasterErr = 0x00000800 ; master error + TUNF = 0x00000400 ; transmit underflow + ROVF = 0x00000200 ; receive overflow + ETI = 0x00000100 ; transmit early int + ERI = 0x00000080 ; receive early int + CNTOVF = 0x00000040 ; counter overflow + RBU = 0x00000020 ; receive buffer unavailable + TBU = 0x00000010 ; transmit buffer unavilable + TI = 0x00000008 ; transmit interrupt + RI = 0x00000004 ; receive interrupt + RxErr = 0x00000002 ; receive error + +; Bits in the NetworkConfig register. + + RxModeMask = 0xe0 + AcceptAllPhys = 0x80 ; promiscuous mode + AcceptBroadcast = 0x40 ; accept broadcast + AcceptMulticast = 0x20 ; accept mutlicast + AcceptRunt = 0x08 ; receive runt pkt + ALP = 0x04 ; receive long pkt + AcceptErr = 0x02 ; receive error pkt + + AcceptMyPhys = 0x00000000 + RxEnable = 0x00000001 + RxFlowCtrl = 0x00002000 + TxEnable = 0x00040000 + TxModeFDX = 0x00100000 + TxThreshold = 0x00e00000 + + PS1000 = 0x00010000 + PS10 = 0x00080000 + FD = 0x00100000 + + +; Bits in network_desc.status + + RXOWN = 0x80000000 ; own bit + FLNGMASK = 0x0fff0000 ; frame length + FLNGShift = 16 + MARSTATUS = 0x00004000 ; multicast address received + BARSTATUS = 0x00002000 ; broadcast address received + PHYSTATUS = 0x00001000 ; physical address received + RXFSD = 0x00000800 ; first descriptor + RXLSD = 0x00000400 ; last descriptor + ErrorSummary = 0x80 ; error summary + RUNT = 0x40 ; runt packet received + LONG = 0x20 ; long packet received + FAE = 0x10 ; frame align error + CRC = 0x08 ; crc error + RXER = 0x04 ; receive error + +; rx_desc_control_bits + + RXIC = 0x00800000 ; interrupt control + RBSShift = 0 + +; tx_desc_status_bits + + TXOWN = 0x80000000 ; own bit + JABTO = 0x00004000 ; jabber timeout + CSL = 0x00002000 ; carrier sense lost + LC = 0x00001000 ; late collision + EC = 0x00000800 ; excessive collision + UDF = 0x00000400 ; fifo underflow + DFR = 0x00000200 ; deferred + HF = 0x00000100 ; heartbeat fail + NCRMask = 0x000000ff ; collision retry count + NCRShift = 0 + +; tx_desc_control_bits + + TXIC = 0x80000000 ; interrupt control + ETIControl = 0x40000000 ; early transmit interrupt + TXLD = 0x20000000 ; last descriptor + TXFD = 0x10000000 ; first descriptor + CRCEnable = 0x08000000 ; crc control + PADEnable = 0x04000000 ; padding control + RetryTxLC = 0x02000000 ; retry late collision + PKTSMask = 0x3ff800 ; packet size bit21-11 + PKTSShift = 11 + TBSMask = 0x000007ff ; transmit buffer bit 10-0 + TBSShift = 0 + +; BootROM/EEPROM/MII Management Register + + MASK_MIIR_MII_READ = 0x00000000 + MASK_MIIR_MII_WRITE = 0x00000008 + MASK_MIIR_MII_MDO = 0x00000004 + MASK_MIIR_MII_MDI = 0x00000002 + MASK_MIIR_MII_MDC = 0x00000001 + +; ST+OP+PHYAD+REGAD+TA + + OP_READ = 0x6000 ; ST:01+OP:10+PHYAD+REGAD+TA:Z0 + OP_WRITE = 0x5002 ; ST:01+OP:01+PHYAD+REGAD+TA:10 + +; ------------------------------------------------------------------------- +; Constants for Myson PHY +; ------------------------------------------------------------------------- + + MysonPHYID = 0xd0000302 + MysonPHYID0 = 0x0302 + StatusRegister = 18 + SPEED100 = 0x0400 ; bit10 + FULLMODE = 0x0800 ; bit11 + +; ------------------------------------------------------------------------- +; Constants for Seeq 80225 PHY +; ------------------------------------------------------------------------- + + SeeqPHYID0 = 0x0016 + MIIRegister18 = 18 + SPD_DET_100 = 0x80 + DPLX_DET_FULL = 0x40 + +; ------------------------------------------------------------------------- +; Constants for Ahdoc 101 PHY +; ------------------------------------------------------------------------- + + AhdocPHYID0 = 0x0022 + DiagnosticReg = 18 + DPLX_FULL = 0x0800 + Speed_100 = 0x0400 + +; -------------------------------------------------------------------------- +; Constants +; -------------------------------------------------------------------------- + + MarvellPHYID0 = 0x0141 + LevelOnePHYID0 = 0x0013 + + MII1000BaseTControlReg = 9 + MII1000BaseTStatusReg = 10 + SpecificReg = 17 + +; for 1000BaseT Control Register + + PHYAbletoPerform1000FullDuplex = 0x0200 + PHYAbletoPerform1000HalfDuplex = 0x0100 + PHY1000AbilityMask = 0x300 + +; for phy specific status register, marvell phy. + + SpeedMask = 0x0c000 + Speed_1000M = 0x08000 + Speed_100M = 0x4000 + Speed_10M = 0 + Full_Duplex = 0x2000 + +; for phy specific status register, levelone phy + + LXT1000_100M = 0x08000 + LXT1000_1000M = 0x0c000 + LXT1000_Full = 0x200 + +; for PHY + + LinkIsUp = 0x0004 + LinkIsUp2 = 0x00040000 + + + +virtual at 0 + + mtd_desc: + .status dd ? + .control dd ? + .buffer dd ? + .next_desc dd ? + + .next_desc_logical dd ? + .skbuff dd ? + + .reserved1 dd ? + .reserved2 dd ? + + .size = $ + +end virtual + + +virtual at ebx + + device: + + ETH_DEVICE + + .tx_desc rb NUM_TX_DESC*mtd_desc.size + .rx_desc rb NUM_RX_DESC*mtd_desc.size + + .io_addr dd ? + .pci_bus dd ? + .pci_dev dd ? + .irq_line db ? + .dev_id dw ? + + .flags dd ? + + .crvalue dd ? + .bcrvalue dd ? + + .cur_rx dd ? + .cur_tx dd ? + +; These values are keep track of the transceiver/media in use. + + .linkok dd ? + .line_speed dd ? + .duplexmode dd ? + .default_port dd ? + .PHYType dd ? + +; MII transceiver section. + + .mii_cnt dd ? ; MII device addresses. + .phys db ? ; MII device addresses. + + device_size = $ - device + +end virtual + + + +section '.flat' code readable align 16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 2,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax , [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, device_size, .fail + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base io addres of the PCI device + + PCI_find_io + +; We've found the io address, find IRQ now + + PCI_find_irq + + DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:8 + +; Ok, the eth_device structure is ready, let's probe the device +; Because initialization fires IRQ, IRQ handler must be aware of this device + mov eax, [devices] ; Add the device structure to our device list + mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + call probe ; this function will output in eax + test eax, eax + jnz .err2 ; If an error occured, exit + + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + je .destroy + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 2,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 2,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + .err2: + dec [devices] + .err: + DEBUGF 2,"removing device structure\n" + stdcall KernelFree, ebx + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + + +align 4 +unload: + ; TODO: (in this particular order) + ; + ; - Stop the device + +; /* Disable Tx Rx*/ +; outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR ); +; +; /* Reset the chip to erase previous misconfiguration. */ +; mtd_reset(nic); + + ; - Detach int handler + ; - Remove device from local list (device_list) + ; - call unregister function in kernel + ; - Remove all allocated structures and buffers the card used + + or eax,-1 + +ret + + +;------- +; +; PROBE +; +;------- +align 4 +probe: + + DEBUGF 2,"Probing mtd80x device\n" + + PCI_make_bus_master + + stdcall PciRead32, [device.pci_bus], [device.pci_dev], 0 + + cmp ax, 0x1516 + jne .notfound + shr eax, 16 + mov [device.dev_id], ax + + cmp ax, 0x0800 + je .has_mii_xcvr + + cmp ax, 0x0803 + je .has_chip_xcvr + + cmp ax, 0x0891 + je .has_mii_xcvr + + .notfound: + DEBUGF 1,"Device not supported!\n" + xor eax, eax + dec eax + ret + + .has_chip_xcvr: + DEBUGF 1,"Device has chip xcvr\n" + + jmp .xcvr_set + + .has_mii_xcvr: + DEBUGF 1,"Device has mii xcvr\n" + + .xcvr_set: + + call read_mac + +; Reset the chip to erase previous misconfiguration. + + set_io 0 + set_io BCR + xor eax, eax + inc eax + out dx, eax + +; find the connected MII xcvrs + + cmp [device.dev_id], 0x0803 + je .is_803 + +; int phy, phy_idx = 0; +; +; for (phy = 1; phy < 32 && phy_idx < 1; phy++) { +; int mii_status = mdio_read(nic, phy, 1); +; +; if (mii_status != 0xffff && mii_status != 0x0000) { +; mtdx.phys[phy_idx] = phy; +; +; DBG ( "%s: MII PHY found at address %d, status " +; "0x%4.4x.\n", mtdx.nic_name, phy, mii_status ); +; /* get phy type */ +; { +; unsigned int data; +; +; data = mdio_read(nic, mtdx.phys[phy_idx], 2); +; if (data equ= SeeqPHYID0) +; mtdx.PHYType = SeeqPHY; +; else if (data equ= AhdocPHYID0) +; mtdx.PHYType = AhdocPHY; +; else if (data equ= MarvellPHYID0) +; mtdx.PHYType = MarvellPHY; +; else if (data equ= MysonPHYID0) +; mtdx.PHYType = Myson981; +; else if (data equ= LevelOnePHYID0) +; mtdx.PHYType = LevelOnePHY; +; else +; mtdx.PHYType = OtherPHY; +; } +; phy_idx++; +; } +; } +; +; mtdx.mii_cnt = phy_idx; +; if (phy_idx equ= 0) { +; printf("%s: MII PHY not found -- this device may " +; "not operate correctly.\n", mtdx.nic_name); +; } + + jmp .no_803 + + .is_803: + + mov [device.phys], 32 + +; get phy type + set_io 0 + set_io PHYIDENTIFIER + in eax, dx + + cmp eax, MysonPHYID + jne @f + + mov [device.PHYType], MysonPHY + DEBUGF 1,"MysonPHY\n" + jmp .no_803 + + @@: + mov [device.PHYType], OtherPHY + DEBUGF 1,"OtherPHY\n" + + .no_803: + +;------- +; +; RESET +; +;------- +align 4 +reset: + + DEBUGF 1,"Resetting mtd80x\n" + +;-------------------------------- +; insert irq handler on given irq + + movzx eax, [device.irq_line] + DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 1,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + +; Reset the chip to erase previous misconfiguration. + + set_io 0 + set_io BCR + xor eax, eax + inc eax + out dx, eax + + call init_ring + +; Initialize other registers. +; Configure the PCI bus bursts and FIFO thresholds. + + mov [device.bcrvalue], 0x10 ; little-endian, 8 burst length + mov [device.crvalue], 0xa00 ; 128 burst length + + cmp [device.dev_id], 0x891 + jne @f + or [device.bcrvalue], 0x200 ; set PROG bit + or [device.crvalue], 0x02000000 ; set enhanced bit + @@: + + or [device.crvalue], RxEnable + TxThreshold + TxEnable + + call set_rx_mode + + set_io 0 + set_io BCR + mov eax, [device.bcrvalue] + out dx, eax + + set_io TCRRCR + mov eax, [device.crvalue] + out dx, eax + + call getlinkstatus + call getlinktype + +; Restart Rx engine if stopped. + + set_io 0 + set_io RXPDR + xor eax, eax + out dx, eax + +; Enable interrupts + + set_io 0 + set_io ISR + mov eax, (FBE or TUNF or CNTOVF or RBU or TI or RI) + out dx, eax + + set_io IMR +; mov eax, (FBE or TUNF or CNTOVF or RBU or TI or RI) + out dx, eax + +; clear packet/byte counters + + xor eax, eax + lea edi, [device.bytes_tx] + mov ecx, 6 + rep stosd + + mov [device.mtu], 1514 + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + + xor eax, eax + ret + + + + +align 4 +init_ring: + + DEBUGF 1,"initializing rx and tx ring\n" + +; Initialize all Rx descriptors + + lea esi, [device.rx_desc] + mov [device.cur_rx], esi + mov ecx, NUM_RX_DESC + .rx_desc_loop: + mov [esi + mtd_desc.status], RXOWN + mov [esi + mtd_desc.control], 1536 shl RBSShift + + lea eax, [esi + mtd_desc.size] + mov [esi + mtd_desc.next_desc_logical], eax + push ecx esi + GetRealAddr + mov [esi + mtd_desc.next_desc], eax + + stdcall KernelAlloc, 1536 + pop esi + push esi + mov [esi + mtd_desc.skbuff], eax + call GetPgAddr + pop esi ecx + mov [esi + mtd_desc.buffer], eax + + add esi, mtd_desc.size + loop .rx_desc_loop + +; Mark the last entry as wrapping the ring. + + lea eax, [device.rx_desc] + mov [esi - mtd_desc.size + mtd_desc.next_desc_logical], eax + push esi + GetRealAddr + pop esi + mov [esi - mtd_desc.size + mtd_desc.next_desc], eax + + set_io 0 + set_io RXLBA + out dx, eax + +; Initialize all Tx descriptors + + lea esi, [device.tx_desc] + mov [device.cur_tx], esi + mov ecx, NUM_TX_DESC + .tx_desc_loop: + mov [esi + mtd_desc.status], 0 + + lea eax, [esi + mtd_desc.size] + mov [esi + mtd_desc.next_desc_logical], eax + push ecx esi + GetRealAddr + pop esi ecx + mov [esi + mtd_desc.next_desc], eax + + add esi, mtd_desc.size + loop .tx_desc_loop + +; Mark the last entry as wrapping the ring. + + lea eax, [device.tx_desc] + mov [esi - mtd_desc.size + mtd_desc.next_desc_logical], eax + push esi + GetRealAddr + pop esi + mov [esi - mtd_desc.size + mtd_desc.next_desc], eax + + set_io 0 + set_io TXLBA + out dx, eax + + ret + + +align 4 +set_rx_mode: + + DEBUGF 1,"Setting RX mode\n" + +; Too many to match, or accept all multicasts. + + set_io 0 + set_io MAR0 + xor eax, eax + not eax + out dx, eax + set_io MAR1 + out dx, eax + + and [device.crvalue], not (RxModeMask) + or [device.crvalue], AcceptBroadcast + AcceptMulticast + AcceptMyPhys + + ret + + +align 4 +getlinkstatus: + + DEBUGF 1,"Getting link status\n" + + mov [device.linkok], 0 + + cmp [device.PHYType], MysonPHY + jne .no_myson_phy + + set_io 0 + set_io BMCRSR + mov ecx, 1000 + .loop1: + in eax, dx + test eax, LinkIsUp2 + jnz .link_ok + + push ecx edx ebx + mov esi, 10 + call Sleep + pop ebx edx ecx + loop .loop1 + + ret + + .no_myson_phy: + +; for (i = 0; i < DelayTime; ++i) { +; if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) { +; mtdx.linkok = 1; +; return; +; } +; m80x_delay(100); + + ret + + .link_ok: + DEBUGF 1,"Link is up\n" + inc [device.linkok] + ret + + + + +align 4 +getlinktype: + + DEBUGF 1,"Getting link type\n" + + cmp [device.PHYType], MysonPHY + jne .no_myson_phy + + DEBUGF 1,"myson PHY\n" + + set_io 0 + set_io TCRRCR + in eax, dx + + mov [device.duplexmode], 1 ; 1 = half duplex + test eax, FD + jne @f + DEBUGF 1,"full duplex\n" + inc [device.duplexmode] ; 2 = full duplex + @@: + + mov [device.line_speed], 1 ; 1 = 10M + test eax, PS10 + jne @f + DEBUGF 1,"100mbit\n" + inc [device.line_speed] ; 2 = 100M + @@: + + ret + + .no_myson_phy: + + DEBUGF 1,"no myson phy\n" + +; if (mtdx.PHYType equ= SeeqPHY) { /* this PHY is SEEQ 80225 */ +; unsigned int data; +; +; data = mdio_read(dev, mtdx.phys[0], MIIRegister18); +; if (data & SPD_DET_100) +; mtdx.line_speed = 2; /* 100M */ +; else +; mtdx.line_speed = 1; /* 10M */ +; if (data & DPLX_DET_FULL) +; mtdx.duplexmode = 2; /* full duplex mode */ +; else +; mtdx.duplexmode = 1; /* half duplex mode */ +; } else if (mtdx.PHYType equ= AhdocPHY) { +; unsigned int data; +; +; data = mdio_read(dev, mtdx.phys[0], DiagnosticReg); +; if (data & Speed_100) +; mtdx.line_speed = 2; /* 100M */ +; else +; mtdx.line_speed = 1; /* 10M */ +; if (data & DPLX_FULL) +; mtdx.duplexmode = 2; /* full duplex mode */ +; else +; mtdx.duplexmode = 1; /* half duplex mode */ +; } +; else if (mtdx.PHYType equ= MarvellPHY) { +; unsigned int data; +; +; data = mdio_read(dev, mtdx.phys[0], SpecificReg); +; if (data & Full_Duplex) +; mtdx.duplexmode = 2; /* full duplex mode */ +; else +; mtdx.duplexmode = 1; /* half duplex mode */ +; data &= SpeedMask; +; if (data equ= Speed_1000M) +; mtdx.line_speed = 3; /* 1000M */ +; else if (data equ= Speed_100M) +; mtdx.line_speed = 2; /* 100M */ +; else +; mtdx.line_speed = 1; /* 10M */ +; } +; else if (mtdx.PHYType equ= Myson981) { +; unsigned int data; +; +; data = mdio_read(dev, mtdx.phys[0], StatusRegister); +; +; if (data & SPEED100) +; mtdx.line_speed = 2; +; else +; mtdx.line_speed = 1; +; +; if (data & FULLMODE) +; mtdx.duplexmode = 2; +; else +; mtdx.duplexmode = 1; +; } +; else if (mtdx.PHYType equ= LevelOnePHY) { +; unsigned int data; +; +; data = mdio_read(dev, mtdx.phys[0], SpecificReg); +; if (data & LXT1000_Full) +; mtdx.duplexmode = 2; /* full duplex mode */ +; else +; mtdx.duplexmode = 1; /* half duplex mode */ +; data &= SpeedMask; +; if (data equ= LXT1000_1000M) +; mtdx.line_speed = 3; /* 1000M */ +; else if (data equ= LXT1000_100M) +; mtdx.line_speed = 2; /* 100M */ +; else + ; mtdx.line_speed = 1; /* 10M */ + ; } + +; // chage crvalue +; // mtdx.crvalue&equ(~PS10)&(~FD); +; mtdx.crvalue &= (~PS10) & (~FD) & (~PS1000); +; if (mtdx.line_speed equ= 1) +; mtdx.crvalue |= PS10; +; else if (mtdx.line_speed equ= 3) +; mtdx.crvalue |= PS1000; +; if (mtdx.duplexmode equ= 2) +; mtdx.crvalue |= FD; +; + + ret + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +transmit: + + DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8] + mov eax, [esp+4] + DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp+8], 1514 + ja .fail + + mov esi, [device.cur_tx] + push [esi + mtd_desc.next_desc_logical] + pop [device.cur_tx] + + ; todo: check if descriptor is not owned by the device! + + mov eax, [esp + 4] + mov [esi + mtd_desc.skbuff], eax + GetRealAddr + mov [esi + mtd_desc.buffer], eax + + mov eax, [esp + 8] + shl eax, PKTSShift ; packet size + or eax, TXLD + TXFD + CRCEnable + PADEnable + TXIC + 1536 shl TBSShift ; buffer size + mov [esi + mtd_desc.control], eax + + mov [esi + mtd_desc.status], TXOWN + +;------------- +; Update stats + + inc [device.packets_tx] + mov eax, [esp+8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + +; Point to transmit descriptor + + set_io 0 + set_io TXLBA + mov eax, esi + GetRealAddr + out dx, eax + +; set_io TCRRCR +; mov eax, [device.crvalue] +; out dx, eax + +; Wake the potentially-idle transmit channel. + + set_io TXPDR ; TX Poll + xor eax, eax + out dx, eax + + DEBUGF 1,"transmit ok\n" + xor eax, eax + ret 8 + + .fail: + DEBUGF 1,"transmit failed\n" + or eax, -1 + stdcall KernelFree, [esp + 4] + ret 8 + + + +align 4 +read_mac: + + set_io 0 + set_io PAR0 + lea edi, [device.mac] + insd + stosd + set_io PAR1 + insw + stosw + + DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n",\ + [device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + + ret + +align 4 +write_mac: + + ret + + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service + +; find pointer of device wich made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + + set_io 0 + set_io ISR + in eax, dx + out dx, eax ; send it back to ACK + test eax, eax + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) + + .got_it: + + DEBUGF 1,"Device: %x Status: %x ", ebx, ax + + test ax, RI ; receive interrupt + jz .no_rx + + DEBUGF 1,"Receive interrupt\n" + .rx: + push ax + + .rx_loop: + mov esi, [device.cur_rx] + + test [esi + mtd_desc.status], RXOWN + jnz .fail_rx + + push .rx_complete + + mov ecx, [esi + mtd_desc.status] + shr ecx, FLNGShift + sub ecx, 4 ; we dont need CRC + push ecx + +;------------- +; Update stats + + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + inc dword [device.packets_rx] + + + push [esi + mtd_desc.skbuff] + + jmp Eth_input + + .rx_complete: + mov esi, [device.cur_rx] + + mov [esi + mtd_desc.control], 1536 shl RBSShift + + stdcall KernelAlloc, 1536 + mov [esi + mtd_desc.skbuff], eax + call GetPgAddr + mov [esi + mtd_desc.buffer], eax + + mov [esi + mtd_desc.status], RXOWN + + mov eax, [esi + mtd_desc.next_desc_logical] + mov [device.cur_rx], eax + + jmp .rx_loop +; +; while( ( mtdx.cur_rx->status & RXOWN ) == 0 ) +; { +; mtdx.cur_rx->status = RXOWN; +; mtdx.cur_rx = mtdx.cur_rx->next_desc_logical; +; } +; +; /* Restart Rx engine if stopped. */ +; outl(0, mtdx.ioaddr + RXPDR); + + .fail_rx: + DEBUGF 1,"RX failed\n" + + pop ax + .no_rx: + + test ax, TI ; transmit interrupt + jz .no_tx + + DEBUGF 1,"Transmit interrupt\n" + push ax + + lea esi, [device.tx_desc] + mov ecx, NUM_TX_DESC + .tx_loop: + + test [esi + mtd_desc.status], TXOWN + jnz .skip_this_one + + mov eax, [esi + mtd_desc.skbuff] + test eax, eax + je .skip_this_one + + mov [esi + mtd_desc.skbuff], 0 + + DEBUGF 1,"freeing buffer:%x\n", eax + stdcall KernelFree, eax + + .skip_this_one: + mov esi, [esi + mtd_desc.next_desc_logical] + loop .tx_loop + + pop ax + + .no_tx: + + test ax, TBU + jz .no_tbu + + DEBUGF 1,"Transmit buffer unavailable!\n" + + .no_tbu: + + .fail: + pop edi esi ebx + xor eax, eax + inc eax + + ret + + +; End of code + +align 4 ; Place all initialised data here + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'mtd80x',0 ; max 16 chars include zero + + +; 0x1516, 0x0800, "MTD800", "Myson MTD800" +; 0x1516, 0x0803, "MTD803", "Surecom EP-320X" +; 0x1516, 0x0891, "MTD891", "Myson MTD891" + + +include_debug_strings ; All data wich FDO uses will be included here + +section '.data' data readable writable align 16 ; place all uninitialized data place here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + + diff --git a/drivers/ethernet/pcnet32.asm b/drivers/ethernet/pcnet32.asm new file mode 100644 index 0000000000..4ce47c743e --- /dev/null +++ b/drivers/ethernet/pcnet32.asm @@ -0,0 +1,1578 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; AMD PCnet driver for KolibriOS ;; +;; ;; +;; By hidnplayr & clevermouse ;; +;; ;; +;; Based on the PCnet32 driver for MenuetOS, by Jarek Pelczar ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + API_VERSION = 0x01000100 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + + MAX_DEVICES = 4 + MAX_ETH_FRAME_SIZE = 1514 + + TX_RING_SIZE = 4 + RX_RING_SIZE = 4 + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + + + PORT_AUI = 0x00 + PORT_10BT = 0x01 + PORT_GPSI = 0x02 + PORT_MII = 0x03 + PORT_PORTSEL = 0x03 + PORT_ASEL = 0x04 + PORT_100 = 0x40 + PORT_FD = 0x80 + + DMA_MASK = 0xffffffff + + LOG_TX_BUFFERS = 2 ; FIXME + LOG_RX_BUFFERS = 2 + + TX_RING_MOD_MASK = (TX_RING_SIZE-1) + TX_RING_LEN_BITS = (LOG_TX_BUFFERS shl 12) + + RX_RING_MOD_MASK = (RX_RING_SIZE-1) + RX_RING_LEN_BITS = (LOG_RX_BUFFERS shl 4) + + PKT_BUF_SZ = 1544 + + WIO_RDP = 0x10 + WIO_RAP = 0x12 + WIO_RESET = 0x14 + WIO_BDP = 0x16 + + DWIO_RDP = 0x10 + DWIO_RAP = 0x14 + DWIO_RESET = 0x18 + DWIO_BDP = 0x1C + +; CSR registers + + CSR_CSR = 0x00 + CSR_IAB0 = 0x01 + CSR_IAB1 = 0x02 + CSR_IMR = 0x03 + CSR_TFEAT = 0x04 + CSR_EXTCTL1 = 0x05 + CSR_DTBLLEN = 0x06 + CSR_EXTCTL2 = 0x07 + CSR_MAR0 = 0x08 + CSR_MAR1 = 0x09 + CSR_MAR2 = 0x0A + CSR_MAR3 = 0x0B + CSR_PAR0 = 0x0C + CSR_PAR1 = 0x0D + CSR_PAR2 = 0x0E + CSR_MODE = 0x0F + CSR_RXADDR0 = 0x18 + CSR_RXADDR1 = 0x19 + CSR_TXADDR0 = 0x1E + CSR_TXADDR1 = 0x1F + CSR_TXPOLL = 0x2F + CSR_RXPOLL = 0x31 + CSR_RXRINGLEN = 0x4C + CSR_TXRINGLEN = 0x4E + CSR_DMACTL = 0x50 + CSR_BUSTIMER = 0x52 + CSR_MEMERRTIMEO = 0x64 + CSR_ONNOWMISC = 0x74 + CSR_ADVFEAT = 0x7A + CSR_MACCFG = 0x7D + CSR_CHIPID0 = 0x58 + CSR_CHIPID1 = 0x59 + +; Control and Status Register (CSR0) + + CSR_INIT = 1 shl 0 + CSR_START = 1 shl 1 + CSR_STOP = 1 shl 2 + CSR_TX = 1 shl 3 + CSR_TXON = 1 shl 4 + CSR_RXON = 1 shl 5 + CSR_INTEN = 1 shl 6 + CSR_INTR = 1 shl 7 + CSR_IDONE = 1 shl 8 + CSR_TINT = 1 shl 9 + CSR_RINT = 1 shl 10 + CSR_MERR = 1 shl 11 + CSR_MISS = 1 shl 12 + CSR_CERR = 1 shl 13 + +; Interrupt masks and deferral control (CSR3) + + IMR_BSWAP = 0x0004 + IMR_ENMBA = 0x0008 ; enable modified backoff alg + IMR_DXMT2PD = 0x0010 + IMR_LAPPEN = 0x0020 ; lookahead packet processing enb + IMR_DXSUFLO = 0x0040 ; disable TX stop on underflow + IMR_IDONE = 0x0100 + IMR_TINT = 0x0200 + IMR_RINT = 0x0400 + IMR_MERR = 0x0800 + IMR_MISS = 0x1000 + + IMR = IMR_IDONE ; IMR_TINT + IMR_RINT + IMR_MERR + IMR_MISS ;+ IMR_IDONE + +; Test and features control (CSR4) + + TFEAT_TXSTRTMASK = 0x0004 + TFEAT_TXSTRT = 0x0008 + TFEAT_RXCCOFLOWM = 0x0010 ; Rx collision counter oflow + TFEAT_RXCCOFLOW = 0x0020 + TFEAT_UINT = 0x0040 + TFEAT_UINTREQ = 0x0080 + TFEAT_MISSOFLOWM = 0x0100 + TFEAT_MISSOFLOW = 0x0200 + TFEAT_STRIP_FCS = 0x0400 + TFEAT_PAD_TX = 0x0800 + TFEAT_TXDPOLL = 0x1000 + TFEAT_DMAPLUS = 0x4000 + +; Extended control and interrupt 1 (CSR5) + + EXTCTL1_SPND = 0x0001 ; suspend + EXTCTL1_MPMODE = 0x0002 ; magic packet mode + EXTCTL1_MPENB = 0x0004 ; magic packet enable + EXTCTL1_MPINTEN = 0x0008 ; magic packet interrupt enable + EXTCTL1_MPINT = 0x0010 ; magic packet interrupt + EXTCTL1_MPPLBA = 0x0020 ; magic packet phys. logical bcast + EXTCTL1_EXDEFEN = 0x0040 ; excessive deferral interrupt enb. + EXTCTL1_EXDEF = 0x0080 ; excessive deferral interrupt + EXTCTL1_SINTEN = 0x0400 ; system interrupt enable + EXTCTL1_SINT = 0x0800 ; system interrupt + EXTCTL1_LTINTEN = 0x4000 ; last TX interrupt enb + EXTCTL1_TXOKINTD = 0x8000 ; TX OK interrupt disable + +; RX/TX descriptor len (CSR6) + + DTBLLEN_RLEN = 0x0F00 + DTBLLEN_TLEN = 0xF000 + +; Extended control and interrupt 2 (CSR7) + + EXTCTL2_MIIPDTINTE = 0x0001 + EXTCTL2_MIIPDTINT = 0x0002 + EXTCTL2_MCCIINTE = 0x0004 + EXTCTL2_MCCIINT = 0x0008 + EXTCTL2_MCCINTE = 0x0010 + EXTCTL2_MCCINT = 0x0020 + EXTCTL2_MAPINTE = 0x0040 + EXTCTL2_MAPINT = 0x0080 + EXTCTL2_MREINTE = 0x0100 + EXTCTL2_MREINT = 0x0200 + EXTCTL2_STINTE = 0x0400 + EXTCTL2_STINT = 0x0800 + EXTCTL2_RXDPOLL = 0x1000 + EXTCTL2_RDMD = 0x2000 + EXTCTL2_RXFRTG = 0x4000 + EXTCTL2_FASTSPNDE = 0x8000 + +; Mode (CSR15) + + MODE_RXD = 0x0001 ; RX disable + MODE_TXD = 0x0002 ; TX disable + MODE_LOOP = 0x0004 ; loopback enable + MODE_TXCRCD = 0x0008 + MODE_FORCECOLL = 0x0010 + MODE_RETRYD = 0x0020 + MODE_INTLOOP = 0x0040 + MODE_PORTSEL = 0x0180 + MODE_RXVPAD = 0x2000 + MODE_RXNOBROAD = 0x4000 + MODE_PROMISC = 0x8000 + +; BCR (Bus Control Registers) + + BCR_MMRA = 0x00 ; Master Mode Read Active + BCR_MMW = 0x01 ; Master Mode Write Active + BCR_MISCCFG = 0x02 + BCR_LED0 = 0x04 + BCR_LED1 = 0x05 + BCR_LED2 = 0x06 + BCR_LED3 = 0x07 + BCR_DUPLEX = 0x09 + BCR_BUSCTL = 0x12 + BCR_EECTL = 0x13 + BCR_SSTYLE = 0x14 + BCR_PCILAT = 0x16 + BCR_PCISUBVENID = 0x17 + BCR_PCISUBSYSID = 0x18 + BCR_SRAMSIZE = 0x19 + BCR_SRAMBOUND = 0x1A + BCR_SRAMCTL = 0x1B + BCR_MIICTL = 0x20 + BCR_MIIADDR = 0x21 + BCR_MIIDATA = 0x22 + BCR_PCIVENID = 0x23 + BCR_PCIPCAP = 0x24 + BCR_DATA0 = 0x25 + BCR_DATA1 = 0x26 + BCR_DATA2 = 0x27 + BCR_DATA3 = 0x28 + BCR_DATA4 = 0x29 + BCR_DATA5 = 0x2A + BCR_DATA6 = 0x2B + BCR_DATA7 = 0x2C + BCR_ONNOWPAT0 = 0x2D + BCR_ONNOWPAT1 = 0x2E + BCR_ONNOWPAT2 = 0x2F + BCR_PHYSEL = 0x31 + +; RX status register + + RXSTAT_BPE = 0x0080 ; bus parity error + RXSTAT_ENP = 0x0100 ; end of packet + RXSTAT_STP = 0x0200 ; start of packet + RXSTAT_BUFF = 0x0400 ; buffer error + RXSTAT_CRC = 0x0800 ; CRC error + RXSTAT_OFLOW = 0x1000 ; rx overrun + RXSTAT_FRAM = 0x2000 ; framing error + RXSTAT_ERR = 0x4000 ; error summary + RXSTAT_OWN = 0x8000 + +; TX status register + + TXSTAT_TRC = 0x0000000F ; transmit retries + TXSTAT_RTRY = 0x04000000 ; retry + TXSTAT_LCAR = 0x08000000 ; lost carrier + TXSTAT_LCOL = 0x10000000 ; late collision + TXSTAT_EXDEF = 0x20000000 ; excessive deferrals + TXSTAT_UFLOW = 0x40000000 ; transmit underrun + TXSTAT_BUFF = 0x80000000 ; buffer error + + TXCTL_OWN = 0x8000 + TXCTL_ERR = 0x4000 ; error summary + TXCTL_ADD_FCS = 0x2000 ; add FCS to pkt + TXCTL_MORE_LTINT = 0x1000 + TXCTL_ONE = 0x0800 + TXCTL_DEF = 0x0400 + TXCTL_STP = 0x0200 + TXCTL_ENP = 0x0100 + TXCTL_BPE = 0x0080 + + TXCTL_MBO = 0x0000F000 + TXCTL_BUFSZ = 0x00000FFF + +; + + MAX_PHYS = 32 + + +virtual at ebx + + device: + + ETH_DEVICE + +; device specific + + rb 0x100-(($ - device) and 0xff) ; align 256 + .private: + .mode_ dw ? + .tlen_rlen dw ? + .phys_addr dp ? + .reserved dw ? + .filter dq ? + .rx_ring_phys dd ? + .tx_ring_phys dd ? + + rb 0x100-(($ - device) and 0xff) ; align 256 + .rx_ring rb RX_RING_SIZE * descriptor.size + + rb 0x100-(($ - device) and 0xff) ; align 256 + .tx_ring rb TX_RING_SIZE * descriptor.size + + .cur_rx db ? + .cur_tx db ? + .last_tx db ? + .options dd ? + .full_duplex db ? + .chip_version dw ? + .mii db ? + .ltint db ? + .dxsuflo db ? + .fset db ? + .fdx db ? + + .io_addr dd ? + .irq_line db ? + .pci_bus dd ? + .pci_dev dd ? + + .phy dw ? + + .read_csr dd ? + .write_csr dd ? + .read_bcr dd ? + .write_bcr dd ? + .read_rap dd ? + .write_rap dd ? + .sw_reset dd ? + + device_size = $ - device + +end virtual + +struc descriptor { + .base dd ? + .length dw ? + .status dw ? + .msg_length dw ? + .misc dw ? + .virtual dd ? + + .size: +} + +virtual at 0 + descriptor descriptor +end virtual + + + + +section '.flat' code readable align 16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 1,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + + mov esi, device_list +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax , [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + +; This device doesnt have its own eth_device structure yet, lets create one + + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, device_size, .fail + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base io addres of the PCI device + + PCI_find_io + +; We've found the io address, find IRQ now + + PCI_find_irq + + DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 + +; Ok, the eth_device structure is ready, let's probe the device +; Because initialization fires IRQ, IRQ handler must be aware of this device + mov eax, [devices] ; Add the device structure to our device list + mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + call probe ; this function will output in eax + test eax, eax + jnz .destroy ; If an error occured, exit + + mov [device.type], NET_TYPE_ETH + call NetRegDev + cmp eax, -1 + je .destroy + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 1,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 1,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + dec [devices] + .err: + DEBUGF 1,"Error, removing all data !\n" + stdcall KernelFree, ebx + + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + +align 4 +unload: + ; TODO: (in this particular order) + ; + ; - Stop the device + ; - Detach int handler + ; - Remove device from local list (RTL8139_LIST) + ; - call unregister function in kernel + ; - Remove all allocated structures and buffers the card used + + or eax,-1 + +ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; probe: enables the device (if it really is a PCnet device) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +probe: + + mov edx, [device.io_addr] + + call wio_reset + + xor ecx, ecx + call wio_read_csr + cmp eax, 4 + jne .try_dwio + + ; Try Word I/O + mov ax, 88 + add edx, WIO_RAP + out dx, ax + nop + nop + in ax, dx + sub edx, WIO_RAP + cmp ax, 88 + jne .try_dwio + + call switch_to_wio + + jmp .L1 + + .try_dwio: + call dwio_reset + + xor ecx, ecx + call dwio_read_csr + cmp eax, 4 + jne .no_dev + + ; Try Dword I/O + add edx, DWIO_RAP + mov eax, 88 + out dx, eax + nop + nop + in eax, dx + sub edx, DWIO_RAP + and eax, 0xffff + cmp eax, 88 + jne .no_dev + + call switch_to_dwio + + jmp .L1 + + .no_dev: + DEBUGF 1,"PCnet device not found!\n" + mov eax, 1 + ret + + .L1: + mov ecx, CSR_CHIPID0 + call [device.read_csr] + + mov esi, eax + shr esi, 12 + + and ax, 0xfff + cmp ax, 3 + jne .no_dev + + mov ecx, CSR_CHIPID1 + call [device.read_csr] + shl eax, 4 + or eax, esi + mov [device.chip_version], ax + + mov [device.fdx], 0 + mov [device.mii], 0 + mov [device.fset], 0 + mov [device.dxsuflo], 0 + mov [device.ltint], 0 + + cmp ax, 0x2420 + je .L2 + cmp ax, 0x2430 + je .L2 + + mov [device.fdx], 1 + + cmp ax, 0x2621 + je .L4 + cmp ax, 0x2623 + je .L5 + cmp ax, 0x2624 + je .L6 + cmp ax, 0x2625 + je .L7 + cmp ax, 0x2626 + je .L8 + cmp ax, 0x2627 + je .L9 + + DEBUGF 1,"Invalid chip rev\n" + jmp .no_dev + .L2: + mov [device.name], device_l2 + jmp .L10 + .L4: + mov [device.name], device_l4 +; mov [device.fdx], 1 + jmp .L10 + .L5: + mov [device.name], device_l5 +; mov [device.fdx], 1 + mov [device.mii], 1 + mov [device.fset], 1 + mov [device.ltint], 1 + jmp .L10 + .L6: + mov [device.name], device_l6 +; mov [device.fdx], 1 + mov [device.mii], 1 + mov [device.fset], 1 + jmp .L10 + .L7: + mov [device.name], device_l7 +; mov [device.fdx], 1 + mov [device.mii], 1 + jmp .L10 + .L8: + mov [device.name], device_l8 +; mov [device.fdx], 1 + mov ecx, CSR_RXPOLL + call dword [device.read_bcr] + call dword [device.write_bcr] + jmp .L10 + .L9: + mov [device.name], device_l9 +; mov [device.fdx], 1 + mov [device.mii], 1 + .L10: + DEBUGF 1,"device name: %s\n", [device.name] + + cmp [device.fset], 1 + jne .L11 + mov ecx, BCR_BUSCTL + call [device.read_bcr] + or eax, 0x800 + call [device.write_bcr] + + mov ecx, CSR_DMACTL + call [device.read_csr] +; and eax, 0xc00 +; or eax, 0xc00 + mov eax, 0xc00 + call [device.write_csr] + + mov [device.dxsuflo],1 + mov [device.ltint],1 + .L11: + + PCI_make_bus_master + + mov [device.options], PORT_ASEL + mov [device.mode_], MODE_RXD + MODE_TXD ; disable receive and transmit + mov [device.tlen_rlen], (TX_RING_LEN_BITS or RX_RING_LEN_BITS) + + mov dword [device.filter], 0 + mov dword [device.filter+4], 0 + +align 4 +reset: + +; attach int handler + + movzx eax, [device.irq_line] + DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 1,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + + mov edx, [device.io_addr] + + call [device.sw_reset] + + ; Switch pcnet32 to 32bit mode + mov ecx, BCR_SSTYLE + mov eax, 2 + call [device.write_bcr] + + ; set/reset autoselect bit + mov ecx, BCR_MISCCFG + call [device.read_bcr] + and eax, not 2 + test [device.options], PORT_ASEL + jz @f + or eax, 2 + @@: + call [device.write_bcr] + + ; Handle full duplex setting + cmp byte [device.full_duplex], 0 + je .duplex_ok + mov ecx, BCR_DUPLEX + call [device.read_bcr] + and eax, not 3 + test [device.options], PORT_FD + jz @f + or eax, 1 + cmp [device.options], PORT_FD or PORT_AUI + jne .set_duplex + or eax, 2 + jmp .set_duplex + @@: + test [device.options], PORT_ASEL + jz .set_duplex + cmp [device.chip_version], 0x2627 + jne .set_duplex + or eax, 3 + .set_duplex: + mov ecx, BCR_DUPLEX + call [device.write_bcr] + .duplex_ok: + + ; set/reset GPSI bit in test register + mov ecx, 124 + call [device.read_csr] + mov ecx, [device.options] + and ecx, PORT_PORTSEL + cmp ecx, PORT_GPSI + jne @f + or eax, 0x10 + @@: + call [device.write_csr] + cmp [device.mii], 0 + je .L6 + test [device.options], PORT_ASEL + jnz .L6 + mov ecx, BCR_MIICTL + call [device.read_bcr] + and eax, not 0x38 + test [device.options], PORT_FD + jz @f + or eax, 0x10 + @@: + test [device.options], PORT_100 + jz @f + or eax, 0x08 + @@: + call [device.write_bcr] + jmp .L9 + .L6: + test [device.options], PORT_ASEL + jz .L9 + mov ecx, BCR_MIICTL + DEBUGF 1,"ASEL, enable auto-negotiation\n" + call [device.read_bcr] + and eax, not 0x98 + or eax, 0x20 + call [device.write_bcr] + .L9: + cmp [device.ltint], 0 + je @f + mov ecx, 5 + call [device.read_csr] + or eax, (1 shl 14) + call [device.write_csr] + @@: + mov eax, [device.options] + and eax, PORT_PORTSEL + shl eax, 7 + mov [device.mode_], ax + mov dword [device.filter], -1 + mov dword [device.filter+4], -1 + + + +;----------------------------- + + test [device.mii], 1 + jz .no_mii + + mov [device.phy], 0 + + .mii_loop: + mov ecx, MII_PHYSID1 + call mdio_read + cmp ax, 0xffff + je .next + + DEBUGF 1, "0x%x\n", ax + + mov ecx, MII_PHYSID2 + call mdio_read + cmp ax, 0xffff + je .next + + DEBUGF 1, "0x%x\n", ax + + jmp .got_phy + + cmp [device.phy], 31 + jne .next + mov ax, [device.chip_version] + inc ax + and ax, 0xfffe + cmp ax, 0x2624 ; 79c971 & 79c972 have phantom phy at id 31 + je .got_phy + + .next: + inc [device.phy] + cmp [device.phy], MAX_PHYS + jb .mii_loop + + DEBUGF 1, "No PHY found!\n" + + or eax, -1 + ret + + .got_phy: + DEBUGF 1, "Found PHY at 0x%x\n", [device.phy]:4 + + .no_mii: + +;----------------------------------------------- + + call read_mac + + lea esi, [device.mac] + lea edi, [device.phys_addr] + movsd + movsw + + call init_ring + + mov edx, [device.io_addr] ; init ring destroys edx + + lea eax, [device.private] + GetRealAddr + push eax + and eax, 0xffff + mov ecx, 1 + call [device.write_csr] + pop eax + shr eax, 16 + mov ecx, 2 + call [device.write_csr] + + mov ecx, 4 + mov eax, 0x0915 + call [device.write_csr] + +; Set the interrupt mask + mov ecx, CSR_IMR + mov eax, IMR + call [device.write_csr] + +; Initialise the device + xor ecx, ecx + mov eax, CSR_INIT + call [device.write_csr] + + mov esi, 100 +; xor ecx, ecx + @@: + call [device.read_csr] + test ax, CSR_IDONE + jnz @f + + dec esi + jnz @r + DEBUGF 1,"Initialize timeout!\n" + @@: + +; Start the device and enable interrupts + xor ecx, ecx + mov eax, CSR_START + CSR_INTEN + call [device.write_csr] + +; Set the mtu, kernel will be able to send now + mov [device.mtu], 1514 + +; get link status + mov [device.state], ETH_LINK_UNKOWN + + call check_media + + DEBUGF 1,"reset complete\n" + xor eax, eax + ret + + +align 4 +init_ring: + + DEBUGF 1,"init ring\n" + + lea edi, [device.rx_ring] + mov eax, edi + GetRealAddr + mov [device.rx_ring_phys], eax + mov ecx, RX_RING_SIZE + .rx_init: + push ecx + stdcall KernelAlloc, PKT_BUF_SZ + pop ecx + mov [edi + descriptor.virtual], eax + GetRealAddr + mov [edi + descriptor.base], eax + mov [edi + descriptor.length], - PKT_BUF_SZ + mov [edi + descriptor.status], RXSTAT_OWN + mov dword [edi + descriptor.msg_length], 0 ; also clears misc field + add edi, descriptor.size + dec ecx + jnz .rx_init + + lea edi, [device.tx_ring] + mov eax, edi + GetRealAddr + mov [device.tx_ring_phys], eax + mov ecx, TX_RING_SIZE + .tx_init: + mov [edi + descriptor.status], 0 + add edi, descriptor.size + dec ecx + jnz .tx_init + + mov [device.tlen_rlen], (TX_RING_LEN_BITS or RX_RING_LEN_BITS) + + mov [device.cur_tx], 0 + mov [device.last_tx], 0 + mov [device.cur_rx], 0 + + ret + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +transmit: + DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] + mov eax, [esp+4] + DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp+8], 1514 + ja .nospace ; packet is too long + cmp dword [esp+8], 60 + jb .nospace ; packet is too short + +; check descriptor + lea edi, [device.tx_ring] + movzx eax, [device.cur_tx] + shl eax, 4 + add edi, eax + + test [edi + descriptor.status], TXCTL_OWN + jnz .nospace +; descriptor is free, use it + mov eax, [esp+4] + mov [edi + descriptor.virtual], eax + GetRealAddr + mov [edi + descriptor.base], eax +; set length + mov eax, [esp+8] + neg eax + mov [edi + descriptor.length], ax +; put to transfer queue + mov [edi + descriptor.status], TXCTL_OWN + TXCTL_STP + TXCTL_ENP + +; trigger an immediate send + mov edx, [device.io_addr] + xor ecx, ecx ; CSR0 + call [device.read_csr] + or eax, CSR_TX + call [device.write_csr] + +; get next descriptor 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, ... + inc [device.cur_tx] + and [device.cur_tx], TX_RING_SIZE - 1 + DEBUGF 2," - Packet Sent! " + +; Update stats + inc [device.packets_tx] + mov eax, [esp+8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + + .finish: + DEBUGF 2," - Done!\n" + xor eax, eax + ret 8 + + .nospace: + DEBUGF 1, 'ERROR: no free transmit descriptors\n' + stdcall KernelFree, [esp+4] + or eax, -1 + ret 8 + + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service + +; find pointer of device wich made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + + mov edx, [device.io_addr] + push ecx + xor ecx, ecx ; CSR0 + call [device.read_csr] ; get IRQ reason + call [device.write_csr] ; write it back to ACK + pop ecx + and ax, CSR_RINT or CSR_TINT + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret + + .got_it: + DEBUGF 1,"Device: %x status: %x\n", ebx, eax:2 + + push ax + test ax, CSR_RINT + jz .not_receive + + push ebx + .rx_loop: + pop ebx + movzx eax, [device.cur_rx] + shl eax, 4 + lea edi, [device.rx_ring] + add edi, eax ; edi now points to current rx ring entry + + mov ax, [edi + descriptor.status] + DEBUGF 1,"RX packet status: %x\n", eax:4 + + test ax, RXSTAT_OWN ; If this bit is set, the controller OWN's the packet, if not, we do + jnz .not_receive + + test ax, RXSTAT_ENP + jz .not_receive + + test ax, RXSTAT_STP + jz .not_receive + + movzx ecx, [edi + descriptor.msg_length] ; get packet length in ecx + sub ecx, 4 ; + +; Set pointers for ETH_input + push ebx + + push .rx_loop ; return address + push ecx ; packet size + push [edi + descriptor.virtual] ; packet address + +; Update stats + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + inc [device.packets_rx] + +; now allocate a new buffer + stdcall KernelAlloc, PKT_BUF_SZ ; Allocate a buffer for the next packet + mov [edi + descriptor.virtual], eax ; set virtual address + GetRealAddr + mov [edi + descriptor.base], eax ; and real address + +; mov word [edi + descriptor.length], - PKT_BUF_SZ + mov [edi + descriptor.status], RXSTAT_OWN ; give it back to PCnet controller + + inc [device.cur_rx] ; set next receive descriptor + and [device.cur_rx], RX_RING_SIZE - 1 + + jmp Eth_input + + .not_receive: + pop ax + + test ax, CSR_TINT + jz .not_transmit + + .tx_loop: + lea edi, [device.tx_ring] + movzx eax, [device.last_tx] + shl eax, 4 + add edi, eax + + test [edi + descriptor.status], TXCTL_OWN + jnz .not_transmit + + mov eax, [edi + descriptor.virtual] + test eax, eax + jz .not_transmit + + mov [edi + descriptor.virtual], 0 + + DEBUGF 1,"Removing packet %x from memory\n", eax + + stdcall KernelFree, eax + + inc [device.last_tx] + and [device.last_tx], TX_RING_SIZE - 1 + jmp .tx_loop + + .not_transmit: + pop edi esi ebx + xor eax, eax + inc eax + + ret + + + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Write MAC address ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +write_mac: ; in: mac pushed onto stack (as 3 words) + + DEBUGF 1,"Writing MAC: %x-%x-%x-%x-%x-%x",[esp+0]:2,[esp+1]:2,[esp+2]:2,[esp+3]:2,[esp+4]:2,[esp+5]:2 + + mov edx, [device.io_addr] + add dx, 2 + xor eax, eax + + mov ecx, CSR_PAR0 + @@: + pop ax + call [device.write_csr] + DEBUGF 1,"." + inc ecx + cmp ecx, CSR_PAR2 + jb @r + + DEBUGF 1,"\n" + +; Notice this procedure does not ret, but continues to read_mac instead. + +;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Read MAC address ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;; +align 4 +read_mac: + DEBUGF 1,"Reading MAC" + + mov edx, [device.io_addr] + add dx, 6 + @@: + dec dx + dec dx + in ax, dx + push ax + DEBUGF 1,"." + cmp edx, [device.io_addr] + ja @r + + DEBUGF 1," %x-%x-%x-%x-%x-%x\n",[esp+0]:2,[esp+1]:2,[esp+2]:2,[esp+3]:2,[esp+4]:2,[esp+5]:2 + + lea edi, [device.mac] + pop ax + stosw + pop ax + stosw + pop ax + stosw + + ret + +align 4 +switch_to_wio: + + DEBUGF 1,"Switching to 16-bit mode\n" + + mov [device.read_csr], wio_read_csr + mov [device.write_csr], wio_write_csr + mov [device.read_bcr], wio_read_bcr + mov [device.write_bcr], wio_write_bcr + mov [device.read_rap], wio_read_rap + mov [device.write_rap], wio_write_rap + mov [device.sw_reset], wio_reset + + ret + +align 4 +switch_to_dwio: + + DEBUGF 1,"Switching to 32-bit mode\n" + + mov [device.read_csr], dwio_read_csr + mov [device.write_csr], dwio_write_csr + mov [device.read_bcr], dwio_read_bcr + mov [device.write_bcr], dwio_write_bcr + mov [device.read_rap], dwio_read_rap + mov [device.write_rap], dwio_write_rap + mov [device.sw_reset], dwio_reset + + ret + + +; ecx - index +; return: +; eax - data +align 4 +wio_read_csr: + + add edx, WIO_RAP + mov ax, cx + out dx, ax + add edx, WIO_RDP - WIO_RAP + in ax, dx + and eax, 0xffff + sub edx, WIO_RDP + + ret + + +; eax - data +; ecx - index +align 4 +wio_write_csr: + + add edx, WIO_RAP + xchg eax, ecx + out dx, ax + xchg eax, ecx + add edx, WIO_RDP - WIO_RAP + out dx, ax + sub edx, WIO_RDP + + ret + + +; ecx - index +; return: +; eax - data +align 4 +wio_read_bcr: + + add edx, WIO_RAP + mov ax, cx + out dx, ax + add edx, WIO_BDP - WIO_RAP + in ax, dx + and eax, 0xffff + sub edx, WIO_BDP + + ret + + +; eax - data +; ecx - index +align 4 +wio_write_bcr: + + add edx, WIO_RAP + xchg eax, ecx + out dx, ax + xchg eax, ecx + add edx, WIO_BDP - WIO_RAP + out dx, ax + sub edx, WIO_BDP + + ret + +align 4 +wio_read_rap: + + add edx, WIO_RAP + in ax, dx + and eax, 0xffff + sub edx, WIO_RAP + + ret + +; eax - val +align 4 +wio_write_rap: + + add edx, WIO_RAP + out dx, ax + sub edx, WIO_RAP + + ret + +align 4 +wio_reset: + + push eax + add edx, WIO_RESET + in ax, dx + pop eax + sub edx, WIO_RESET + + ret + + + +; ecx - index +; return: +; eax - data +align 4 +dwio_read_csr: + + add edx, DWIO_RAP + mov eax, ecx + out dx, eax + add edx, DWIO_RDP - DWIO_RAP + in eax, dx + and eax, 0xffff + sub edx, DWIO_RDP + + ret + + +; ecx - index +; eax - data +align 4 +dwio_write_csr: + + add edx, DWIO_RAP + xchg eax, ecx + out dx, eax + add edx, DWIO_RDP - DWIO_RAP + xchg eax, ecx + out dx, eax + sub edx, DWIO_RDP + + ret + +; ecx - index +; return: +; eax - data +align 4 +dwio_read_bcr: + + add edx, DWIO_RAP + mov eax, ecx + out dx, eax + add edx, DWIO_BDP - DWIO_RAP + in eax, dx + and eax, 0xffff + sub edx, DWIO_BDP + + ret + + +; ecx - index +; eax - data +align 4 +dwio_write_bcr: + + add edx, DWIO_RAP + xchg eax, ecx + out dx, eax + add edx, DWIO_BDP - DWIO_RAP + xchg eax, ecx + out dx, eax + sub edx, DWIO_BDP + + ret + +align 4 +dwio_read_rap: + + add edx, DWIO_RAP + in eax, dx + and eax, 0xffff + sub edx, DWIO_RAP + + ret + + +; eax - val +align 4 +dwio_write_rap: + + add edx, DWIO_RAP + out dx, eax + sub edx, DWIO_RAP + + ret + +align 4 +dwio_reset: + + push eax + add edx, DWIO_RESET + in eax, dx + pop eax + sub edx, DWIO_RESET + + ret + + +align 4 +mdio_read: + + and ecx, 0x1f + mov ax, [device.phy] + and ax, 0x1f + shl ax, 5 + or ax, cx + + mov ecx, BCR_MIIADDR + call [device.write_bcr] + + mov ecx, BCR_MIIDATA + call [device.read_bcr] + + ret + + +align 4 +mdio_write: + + push eax + and ecx, 0x1f + mov ax, [device.phy] + and ax, 0x1f + shl ax, 5 + or ax, cx + + mov ecx, BCR_MIIADDR + call [device.write_bcr] + + pop eax + mov ecx, BCR_MIIDATA + call [device.write_bcr] + + ret + + +align 4 +check_media: + + DEBUGF 1, "check_media\n" + + test [device.mii], 1 + jnz mii_link_ok + + mov ecx, BCR_LED0 + call [device.read_bcr] + cmp eax, 0xc0 + + DEBUGF 1, "link status=0x%x\n", ax + + ret + + + +; End of code + +align 4 ; Place all initialised data here + +devices dd 0 +version dd (5 shl 16) or (API_VERSION and 0xFFFF) +my_service db 'PCnet',0 ; max 16 chars include zero + +device_l2 db "PCnet/PCI 79C970",0 +device_l4 db "PCnet/PCI II 79C970A",0 +device_l5 db "PCnet/FAST 79C971",0 +device_l6 db "PCnet/FAST+ 79C972",0 +device_l7 db "PCnet/FAST III 79C973",0 +device_l8 db "PCnet/Home 79C978",0 +device_l9 db "PCnet/FAST III 79C975",0 + +options_mapping: +dd PORT_ASEL ; 0 Auto-select +dd PORT_AUI ; 1 BNC/AUI +dd PORT_AUI ; 2 AUI/BNC +dd PORT_ASEL ; 3 not supported +dd PORT_10BT or PORT_FD ; 4 10baseT-FD +dd PORT_ASEL ; 5 not supported +dd PORT_ASEL ; 6 not supported +dd PORT_ASEL ; 7 not supported +dd PORT_ASEL ; 8 not supported +dd PORT_MII ; 9 MII 10baseT +dd PORT_MII or PORT_FD ; 10 MII 10baseT-FD +dd PORT_MII ; 11 MII (autosel) +dd PORT_10BT ; 12 10BaseT +dd PORT_MII or PORT_100 ; 13 MII 100BaseTx +dd PORT_MII or PORT_100 or PORT_FD ; 14 MII 100BaseTx-FD +dd PORT_ASEL ; 15 not supported + +include_debug_strings ; All data wich FDO uses will be included here + +section '.data' data readable writable align 16 ; place all uninitialized data place here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling diff --git a/drivers/ethernet/rhine.asm b/drivers/ethernet/rhine.asm new file mode 100644 index 0000000000..51685cfd8c --- /dev/null +++ b/drivers/ethernet/rhine.asm @@ -0,0 +1,1679 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2010-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; rhine.asm ;; +;; ;; +;; Ethernet driver for Kolibri OS ;; +;; ;; +;; This driver is based on the via-rhine driver from ;; +;; the etherboot 5.0.6 project. The copyright statement is ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;; Rewritten in flat assembler by Asper (asper.85@mail.ru) ;; +;; and hidnplayr (hidnplayr@gmail.com) ;; +;; ;; +;; See file COPYING for details ;; +;; ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + + TX_RING_SIZE = 4 + RX_RING_SIZE = 4 + + ; max time out delay time + W_MAX_TIMEOUT = 0x0FFF + + ; Size of the in-memory receive ring. + RX_BUF_LEN_IDX = 3 ; 0==8K, 1==16K, 2==32K, 3==64K + RX_BUF_LEN = (8192 shl RX_BUF_LEN_IDX) + + ; PCI Tuning Parameters + ; Threshold is bytes transferred to chip before transmission starts. + TX_FIFO_THRESH = 256 ; In bytes, rounded down to 32 byte units. + + ; The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. + RX_FIFO_THRESH = 4 ; Rx buffer level before first PCI xfer. + RX_DMA_BURST = 4 ; Maximum PCI burst, '4' is 256 bytes + TX_DMA_BURST = 4 + + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public service_proc +public version + + +;************************************************************************** +; VIA Rhine Register Definitions +;************************************************************************** +byPAR0 = 0x00 +byRCR = 0x06 +byTCR = 0x07 +byCR0 = 0x08 +byCR1 = 0x09 +byISR0 = 0x0c +byISR1 = 0x0d +byIMR0 = 0x0e +byIMR1 = 0x0f +byMAR0 = 0x10 +byMAR1 = 0x11 +byMAR2 = 0x12 +byMAR3 = 0x13 +byMAR4 = 0x14 +byMAR5 = 0x15 +byMAR6 = 0x16 +byMAR7 = 0x17 +dwCurrentRxDescAddr = 0x18 +dwCurrentTxDescAddr = 0x1c +dwCurrentRDSE0 = 0x20 +dwCurrentRDSE1 = 0x24 +dwCurrentRDSE2 = 0x28 +dwCurrentRDSE3 = 0x2c +dwNextRDSE0 = 0x30 +dwNextRDSE1 = 0x34 +dwNextRDSE2 = 0x38 +dwNextRDSE3 = 0x3c +dwCurrentTDSE0 = 0x40 +dwCurrentTDSE1 = 0x44 +dwCurrentTDSE2 = 0x48 +dwCurrentTDSE3 = 0x4c +dwNextTDSE0 = 0x50 +dwNextTDSE1 = 0x54 +dwNextTDSE2 = 0x58 +dwNextTDSE3 = 0x5c +dwCurrRxDMAPtr = 0x60 +dwCurrTxDMAPtr = 0x64 +byMPHY = 0x6c +byMIISR = 0x6d +byBCR0 = 0x6e +byBCR1 = 0x6f +byMIICR = 0x70 +byMIIAD = 0x71 +wMIIDATA = 0x72 +byEECSR = 0x74 +byTEST = 0x75 +byGPIO = 0x76 +byCFGA = 0x78 +byCFGB = 0x79 +byCFGC = 0x7a +byCFGD = 0x7b +wTallyCntMPA = 0x7c +wTallyCntCRC = 0x7d +bySTICKHW = 0x83 +byWOLcrClr = 0xA4 +byWOLcgClr = 0xA7 +byPwrcsrClr = 0xAC + +;--------------------- Exioaddr Definitions ------------------------- + +; Bits in the RCR register +RCR_RRFT2 = 0x80 +RCR_RRFT1 = 0x40 +RCR_RRFT0 = 0x20 +RCR_PROM = 0x10 +RCR_AB = 0x08 +RCR_AM = 0x04 +RCR_AR = 0x02 +RCR_SEP = 0x01 +; Bits in the TCR register +TCR_RTSF = 0x80 +TCR_RTFT1 = 0x40 +TCR_RTFT0 = 0x20 +TCR_OFSET = 0x08 +TCR_LB1 = 0x04 ; loopback[1] +TCR_LB0 = 0x02 ; loopback[0] +; Bits in the CR0 register +CR0_RDMD = 0x40 ; rx descriptor polling demand +CR0_TDMD = 0x20 ; tx descriptor polling demand +CR0_TXON = 0x10 +CR0_RXON = 0x08 +CR0_STOP = 0x04 ; stop NIC, default = 1 +CR0_STRT = 0x02 ; start NIC +CR0_INIT = 0x01 ; start init process +; Bits in the CR1 register +CR1_SFRST = 0x80 ; software reset +CR1_RDMD1 = 0x40 ; RDMD1 +CR1_TDMD1 = 0x20 ; TDMD1 +CR1_KEYPAG = 0x10 ; turn on par/key +CR1_DPOLL = 0x08 ; disable rx/tx auto polling +CR1_FDX = 0x04 ; full duplex mode +CR1_ETEN = 0x02 ; early tx mode +CR1_EREN = 0x01 ; early rx mode +; Bits in the CR register +CR_RDMD = 0x0040 ; rx descriptor polling demand +CR_TDMD = 0x0020 ; tx descriptor polling demand +CR_TXON = 0x0010 +CR_RXON = 0x0008 +CR_STOP = 0x0004 ; stop NIC, default = 1 +CR_STRT = 0x0002 ; start NIC +CR_INIT = 0x0001 ; start init process +CR_SFRST = 0x8000 ; software reset +CR_RDMD1 = 0x4000 ; RDMD1 +CR_TDMD1 = 0x2000 ; TDMD1 +CR_KEYPAG = 0x1000 ; turn on par/key +CR_DPOLL = 0x0800 ; disable rx/tx auto polling +CR_FDX = 0x0400 ; full duplex mode +CR_ETEN = 0x0200 ; early tx mode +CR_EREN = 0x0100 ; early rx mode +; Bits in the IMR0 register +IMR0_CNTM = 0x80 +IMR0_BEM = 0x40 +IMR0_RUM = 0x20 +IMR0_TUM = 0x10 +IMR0_TXEM = 0x08 +IMR0_RXEM = 0x04 +IMR0_PTXM = 0x02 +IMR0_PRXM = 0x01 +; define imrshadow +IMRShadow = 0x5AFF +; Bits in the IMR1 register +IMR1_INITM = 0x80 +IMR1_SRCM = 0x40 +IMR1_NBFM = 0x10 +IMR1_PRAIM = 0x08 +IMR1_RES0M = 0x04 +IMR1_ETM = 0x02 +IMR1_ERM = 0x01 +; Bits in the ISR register +ISR_INITI = 0x8000 +ISR_SRCI = 0x4000 +ISR_ABTI = 0x2000 +ISR_NORBF = 0x1000 +ISR_PKTRA = 0x0800 +ISR_RES0 = 0x0400 +ISR_ETI = 0x0200 +ISR_ERI = 0x0100 +ISR_CNT = 0x0080 +ISR_BE = 0x0040 +ISR_RU = 0x0020 +ISR_TU = 0x0010 +ISR_TXE = 0x0008 +ISR_RXE = 0x0004 +ISR_PTX = 0x0002 +ISR_PRX = 0x0001 +; Bits in the ISR0 register +ISR0_CNT = 0x80 +ISR0_BE = 0x40 +ISR0_RU = 0x20 +ISR0_TU = 0x10 +ISR0_TXE = 0x08 +ISR0_RXE = 0x04 +ISR0_PTX = 0x02 +ISR0_PRX = 0x01 +; Bits in the ISR1 register +ISR1_INITI = 0x80 +ISR1_SRCI = 0x40 +ISR1_NORBF = 0x10 +ISR1_PKTRA = 0x08 +ISR1_ETI = 0x02 +ISR1_ERI = 0x01 +; ISR ABNORMAL CONDITION +ISR_ABNORMAL = ISR_BE+ISR_RU+ISR_TU+ISR_CNT+ISR_NORBF+ISR_PKTRA +; Bits in the MIISR register +MIISR_MIIERR = 0x08 +MIISR_MRERR = 0x04 +MIISR_LNKFL = 0x02 +MIISR_SPEED = 0x01 +; Bits in the MIICR register +MIICR_MAUTO = 0x80 +MIICR_RCMD = 0x40 +MIICR_WCMD = 0x20 +MIICR_MDPM = 0x10 +MIICR_MOUT = 0x08 +MIICR_MDO = 0x04 +MIICR_MDI = 0x02 +MIICR_MDC = 0x01 +; Bits in the EECSR register +EECSR_EEPR = 0x80 ; eeprom programed status, 73h means programed +EECSR_EMBP = 0x40 ; eeprom embeded programming +EECSR_AUTOLD = 0x20 ; eeprom content reload +EECSR_DPM = 0x10 ; eeprom direct programming +EECSR_CS = 0x08 ; eeprom CS pin +EECSR_SK = 0x04 ; eeprom SK pin +EECSR_DI = 0x02 ; eeprom DI pin +EECSR_DO = 0x01 ; eeprom DO pin +; Bits in the BCR0 register +BCR0_CRFT2 = 0x20 +BCR0_CRFT1 = 0x10 +BCR0_CRFT0 = 0x08 +BCR0_DMAL2 = 0x04 +BCR0_DMAL1 = 0x02 +BCR0_DMAL0 = 0x01 +; Bits in the BCR1 register +BCR1_CTSF = 0x20 +BCR1_CTFT1 = 0x10 +BCR1_CTFT0 = 0x08 +BCR1_POT2 = 0x04 +BCR1_POT1 = 0x02 +BCR1_POT0 = 0x01 +; Bits in the CFGA register +CFGA_EELOAD = 0x80 ; enable eeprom embeded and direct programming +CFGA_JUMPER = 0x40 +CFGA_MTGPIO = 0x08 +CFGA_T10EN = 0x02 +CFGA_AUTO = 0x01 +; Bits in the CFGB register +CFGB_PD = 0x80 +CFGB_POLEN = 0x02 +CFGB_LNKEN = 0x01 +; Bits in the CFGC register +CFGC_M10TIO = 0x80 +CFGC_M10POL = 0x40 +CFGC_PHY1 = 0x20 +CFGC_PHY0 = 0x10 +CFGC_BTSEL = 0x08 +CFGC_BPS2 = 0x04 ; bootrom select[2] +CFGC_BPS1 = 0x02 ; bootrom select[1] +CFGC_BPS0 = 0x01 ; bootrom select[0] +; Bits in the CFGD register +CFGD_GPIOEN = 0x80 +CFGD_DIAG = 0x40 +CFGD_MAGIC = 0x10 +CFGD_RANDOM = 0x08 +CFGD_CFDX = 0x04 +CFGD_CEREN = 0x02 +CFGD_CETEN = 0x01 +; Bits in RSR +RSR_RERR = 0x00000001 +RSR_CRC = 0x00000002 +RSR_FAE = 0x00000004 +RSR_FOV = 0x00000008 +RSR_LONG = 0x00000010 +RSR_RUNT = 0x00000020 +RSR_SERR = 0x00000040 +RSR_BUFF = 0x00000080 +RSR_EDP = 0x00000100 +RSR_STP = 0x00000200 +RSR_CHN = 0x00000400 +RSR_PHY = 0x00000800 +RSR_BAR = 0x00001000 +RSR_MAR = 0x00002000 +RSR_RXOK = 0x00008000 +RSR_ABNORMAL = RSR_RERR+RSR_LONG+RSR_RUNT +; Bits in TSR +TSR_NCR0 = 0x00000001 +TSR_NCR1 = 0x00000002 +TSR_NCR2 = 0x00000004 +TSR_NCR3 = 0x00000008 +TSR_COLS = 0x00000010 +TSR_CDH = 0x00000080 +TSR_ABT = 0x00000100 +TSR_OWC = 0x00000200 +TSR_CRS = 0x00000400 +TSR_UDF = 0x00000800 +TSR_TBUFF = 0x00001000 +TSR_SERR = 0x00002000 +TSR_JAB = 0x00004000 +TSR_TERR = 0x00008000 +TSR_ABNORMAL = TSR_TERR+TSR_OWC+TSR_ABT+TSR_JAB+TSR_CRS +TSR_OWN_BIT = 0x80000000 + +CB_DELAY_LOOP_WAIT = 10 ; 10ms +; enabled mask value of irq +W_IMR_MASK_VALUE = 0x1BFF ; initial value of IMR + +; Ethernet address filter type +PKT_TYPE_DIRECTED = 0x0001 ; obsolete, directed address is always accepted +PKT_TYPE_MULTICAST = 0x0002 +PKT_TYPE_ALL_MULTICAST = 0x0004 +PKT_TYPE_BROADCAST = 0x0008 +PKT_TYPE_PROMISCUOUS = 0x0020 +PKT_TYPE_LONG = 0x2000 +PKT_TYPE_RUNT = 0x4000 +PKT_TYPE_ERROR = 0x8000 ; accept error packets, e.g. CRC error + +; Loopback mode + +NIC_LB_NONE = 0x00 +NIC_LB_INTERNAL = 0x01 +NIC_LB_PHY = 0x02 ; MII or Internal-10BaseT loopback + +PKT_BUF_SZ = 1536 ; Size of each temporary Rx buffer. + +PCI_REG_MODE3 = 0x53 +MODE3_MIION = 0x04 ; in PCI_REG_MOD3 OF PCI space + +; VIA Rhine revisions +VT86C100A = 0x00 +VTunknown0 = 0x20 +VT6102 = 0x40 +VT8231 = 0x50 ; Integrated MAC +VT8233 = 0x60 ; Integrated MAC +VT8235 = 0x74 ; Integrated MAC +VT8237 = 0x78 ; Integrated MAC +VTunknown1 = 0x7C +VT6105 = 0x80 +VT6105_B0 = 0x83 +VT6105L = 0x8A +VT6107 = 0x8C +VTunknown2 = 0x8E +VT6105M = 0x90 + +; Rx status bits +RX_SBITS_RERR = 1 shl 0 +RX_SBITS_CRC_ERROR = 1 shl 1 +RX_SBITS_FAE = 1 shl 2 +RX_SBITS_FOV = 1 shl 3 +RX_SBITS_TOOLONG = 1 shl 4 +RX_SBITS_RUNT = 1 shl 5 +RX_SBITS_SERR = 1 shl 6 +RX_SBITS_BUFF = 1 shl 7 +RX_SBITS_EDP = 1 shl 8 +RX_SBITS_STP = 1 shl 9 +RX_SBITS_CHN = 1 shl 10 +RX_SBITS_PHY = 1 shl 11 +RX_SBITS_BAR = 1 shl 12 +RX_SBITS_MAR = 1 shl 13 +RX_SBITS_RESERVED_1 = 1 shl 14 +RX_SBITS_RXOK = 1 shl 15 +RX_SBITS_FRAME_LENGTH = 0x7FF shl 16 +RX_SBITS_RESERVED_2 = 0xF shl 27 +RX_SBITS_OWN_BIT = 1 shl 31 + +; Rx control bits +RX_CBITS_RX_BUF_SIZE = 0x7FF +RX_CBITS_EXTEND_RX_BUF_SIZE = 0xF shl 11 +RX_CBITS_RESERVED_1 = 0x1FFFF shl 15 + +; Tx status bits +TX_SBITS_NCR0 = 1 shl 0 +TX_SBITS_NCR1 = 1 shl 1 +TX_SBITS_NCR2 = 1 shl 2 +TX_SBITS_NCR3 = 1 shl 3 +TX_SBITS_COLS = 1 shl 4 +TX_SBITS_RESERVED_1 = 1 shl 5 +TX_SBITS_CDH = 1 shl 7 +TX_SBITS_ABT = 1 shl 8 +TX_SBITS_OWC = 1 shl 9 +TX_SBITS_CRS = 1 shl 10 +TX_SBITS_UDF = 1 shl 11 +TX_SBITS_TBUFF = 1 shl 12 +TX_SBITS_SERR = 1 shl 13 +TX_SBITS_JAB = 1 shl 14 +TX_SBITS_TERR = 1 shl 15 +TX_SBITS_RESERVED_2 = 0x7FFF shl 16 +TX_SBITS_OWN_BIT = 1 shl 31 + +; Tx control bits +TX_CBITS_TX_BUF_SIZE = 0x7FF +TX_CBITS_EXTEND_TX_BUF_SIZE = 0xF shl 11 +TX_CBITS_CHN = 1 shl 15 +TX_CBITS_CRC = 1 shl 16 +TX_CBITS_RESERVED_1 = 0xF shl 17 +TX_CBITS_STP = 1 shl 21 +TX_CBITS_EDP = 1 shl 22 +TX_CBITS_IC = 1 shl 23 +TX_CBITS_RESERVED_2 = 0xFF shl 24 + + + +; Offsets to the device registers. + StationAddr = 0x00 + RxConfig = 0x06 + TxConfig = 0x07 + ChipCmd = 0x08 + IntrStatus = 0x0C + IntrEnable = 0x0E + MulticastFilter0 = 0x10 + MulticastFilter1 = 0x14 + RxRingPtr = 0x18 + TxRingPtr = 0x1C + GFIFOTest = 0x54 + MIIPhyAddr = 0x6C + MIIStatus = 0x6D + PCIBusConfig = 0x6E + MIICmd = 0x70 + MIIRegAddr = 0x71 + MIIData = 0x72 + MACRegEEcsr = 0x74 + ConfigA = 0x78 + ConfigB = 0x79 + ConfigC = 0x7A + ConfigD = 0x7B + RxMissed = 0x7C + RxCRCErrs = 0x7E + MiscCmd = 0x81 + StickyHW = 0x83 + IntrStatus2 = 0x84 + WOLcrClr = 0xA4 + WOLcgClr = 0xA7 + PwrcsrClr = 0xAC + +; Bits in the interrupt status/mask registers. + IntrRxDone = 0x0001 + IntrRxErr = 0x0004 + IntrRxEmpty = 0x0020 + IntrTxDone = 0x0002 + IntrTxError = 0x0008 + IntrTxUnderrun = 0x0010 + IntrPCIErr = 0x0040 + IntrStatsMax = 0x0080 + IntrRxEarly = 0x0100 + IntrRxOverflow = 0x0400 + IntrRxDropped = 0x0800 + IntrRxNoBuf = 0x1000 + IntrTxAborted = 0x2000 + IntrLinkChange = 0x4000 + IntrRxWakeUp = 0x8000 + IntrNormalSummary = 0x0003 + IntrAbnormalSummary = 0xC260 + IntrTxDescRace = 0x080000 ; mapped from IntrStatus2 + IntrTxErrSummary = 0x082218 + +DEFAULT_INTR = (IntrRxDone or IntrRxErr or IntrRxEmpty or IntrRxOverflow or IntrRxDropped or IntrRxNoBuf) + + +virtual at ebx + + device: + + ETH_DEVICE + + .io_addr dd ? + .pci_dev dd ? + .pci_bus dd ? + .revision db ? + .irq_line db ? + .chip_id dw ? + + .cur_rx dw ? + .cur_tx dw ? + .last_tx dw ? + + rb 0x100-(($ - device) and 0xff) ; align 256 + .tx_ring rb tx_head.sizeof*TX_RING_SIZE + + rb 0x100-(($ - device) and 0xff) ; align 256 + .rx_ring rb rx_head.sizeof*RX_RING_SIZE + + .size = $ - device + +end virtual + +virtual at 0 + rx_head: + .status dd ? + .control dd ? + .buff_addr dd ? ; address + .next_desc dd ? ; + + .buff_addr_virt dd ? + rd 3 ; alignment + .sizeof: +end virtual + + +virtual at 0 + tx_head: + .status dd ? + .control dd ? + .buff_addr dd ? ; address + .next_desc dd ? ; + + .buff_addr_virt dd ? + rd 3 ; alignment + .sizeof: +end virtual + + + +section '.flat' code readable align 16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc START ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc START stdcall, state:dword + + cmp [state], 1 + jne .exit + + .entry: + + DEBUGF 2,"Loading %s driver\n", my_service + stdcall RegService, my_service, service_proc + ret + + .fail: + .exit: + xor eax, eax + ret + +endp + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; proc SERVICE_PROC ;; +;; ;; +;; (standard driver proc) ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +proc service_proc stdcall, ioctl:dword + + mov edx, [ioctl] + mov eax, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jb .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jb .fail + + mov eax, [IOCTL.input] + cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given + jne .fail ; other types arent supported for this card yet + +; check if the device is already listed + + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax , [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice + + +; This device doesnt have its own eth_device structure yet, lets create one + .firstdevice: + cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card + jae .fail + + allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx + +; Now, it's time to find the base io addres of the PCI device + + PCI_find_io + +; We've found the io address, find IRQ now + + PCI_find_irq + + DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 + +; Ok, the eth_device structure is ready, let's probe the device + ;;; cli + + call probe ; this function will output in eax + test eax, eax + jnz .err_sti ; If an error occured, exit + + mov eax, [devices] ; Add the device structure to our device list + mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) + inc [devices] ; + + mov [device.type], NET_TYPE_ETH + call NetRegDev + ;;; sti + + cmp eax, -1 + je .destroy + + ret + +; If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + DEBUGF 1,"Trying to find device number of already registered device\n" + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + DEBUGF 1,"Kernel says: %u\n", eax + ret + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + ; todo: reset device into virgin state + + .err_sti: + sti + + .err: + stdcall KernelFree, ebx + + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + + +probe: + + mov eax, [device.io_addr] + DEBUGF 1, "Probing card at 0x%x\n", eax + +; make the card a bus master + PCI_make_bus_master + +; get device id + stdcall PciRead16, [device.pci_bus], [device.pci_dev], PCI_DEVICE_ID + mov [device.chip_id], ax + +; get revision id. + PCI_find_rev + + movzx eax, [device.revision] + DEBUGF 1, "Card revision = 0x%x\n", eax + +; D-Link provided reset code (with comment additions) + cmp al, 0x40 + jb .below_x40 + + mov ax, [device.chip_id] + DEBUGF 1, "Enabling Sticky Bit Workaround for Chip_id: 0x%x\n", ax + + ; clear sticky bit before reset & read ethernet address + set_io 0 + set_io bySTICKHW + in al, dx + and al, 0xFC + out dx, al + + ; (bits written are cleared?) + ; disable force PME-enable + set_io byWOLcgClr + mov al, 0x80 + out dx, al + + ; disable power-event config bit + mov al, 0xFF + out dx, al + + ; clear power status (undocumented in vt6102 docs?) + set_io byPwrcsrClr + out dx, al + + .below_x40: + +; Reset the chip to erase previous misconfiguration. + set_io 0 + set_io byCR0 + mov ax, CR_SFRST + out dx, ax + +; if vt3043 delay after reset + cmp [device.revision], 0x40 + jae @f + mov esi, 2000 ; 2000ms + call Sleep + @@: + +; polling till software reset complete + mov ecx, W_MAX_TIMEOUT + .poll_again: + in ax, dx + test ax, CR_SFRST + jz @f + loop .poll_again + DEBUGF 1, "Soft reset timeout!\n" + @@: + +; issue AUTOLoad in EECSR to reload eeprom + set_io byEECSR + mov al, 0x20 + out dx, al + +; if vt3065 delay after reset + cmp [device.revision], 0x40 + jb .not_vt3065 + + ; delay 8ms to let MAC stable + mov esi, 8 ; 8ms + call Sleep + + ; for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA + ; turned on. it makes MAC receive magic packet + ; automatically. So, we turn it off. (D-Link) + + set_io byCFGA + in al, dx + and al, 0xFE + out dx, al + + ; turn on bit2 in PCI configuration register 0x53 , only for 3065 + stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REG_MODE3 + or al, MODE3_MIION + stdcall PciWrite8, [device.pci_bus], [device.pci_dev], PCI_REG_MODE3, eax + .not_vt3065: + +; back off algorithm, disable the right-most 4-bit off CFGD + set_io 0 + set_io byCFGD + in al, dx + and al, not (CFGD_RANDOM or CFGD_CFDX or CFGD_CEREN or CFGD_CETEN) + out dx, al + +; reload eeprom + call reload_eeprom + +; read MAC + call read_mac + +; restart MII auto-negotiation + stdcall WriteMII, 0, 1 shl 9, 1 + + DEBUGF 1, "Analyzing Media type, this may take several seconds" + + mov ecx, 5 + .read_again: + DEBUGF 1, "." + mov esi, 1 + call Sleep + + stdcall ReadMII, 1 + test eax, 0x0020 + jnz .read_done + loop .read_again + DEBUGF 1, "timeout!\n" + .read_done: + DEBUGF 1, " OK\n" + +if DEBUG + + set_io 0 + set_io 0x6C + in al, dx + and eax, 0xFF + DEBUGF 1, "MII : Address %x\n", ax + + stdcall ReadMII, 1 + DEBUGF 1, "status 0x%x\n", ax + + stdcall ReadMII, 4 + DEBUGF 1, "advertising 0x%x\n", ax + + stdcall ReadMII, 5 + DEBUGF 1, "link 0x%x\n", ax + +end if + +; query MII to know LineSpeed, duplex mode + set_io 0 + set_io MIIStatus + in al, dx + test al, MIISR_SPEED + jz .100mbps + DEBUGF 1, "Linespeed=10Mbs\n" + jmp @f + + .100mbps: + DEBUGF 1, "Linespeed=100Mbs\n" + @@: + + call QueryAuto + + test eax, 1 + jz .halfduplex + + DEBUGF 1, "Fullduplex\n" + set_io 0 + set_io byCR0 + mov ax, CR_FDX + out dx, ax + jmp @f + + .halfduplex: + DEBUGF 1, "Halfduplex\n" + @@: + +; set MII 10 FULL ON, only apply in vt3043 + cmp [device.chip_id], 0x3043 + jne @f + stdcall WriteMII, 0x17, 1 shl 1, 1 + @@: + +; turn on MII link change + set_io 0 + set_io byMIICR + in al, dx + and al, 0x7F + out dx, al + push eax + + call MIIDelay + + set_io byMIIAD + mov al, 0x41 + out dx, al + + call MIIDelay + + pop eax + or al, 0x80 + set_io byMIICR + out dx, al + +;**************************************************************************; +;* ETH_RESET - Reset adapter *; +;**************************************************************************; + +reset: + + DEBUGF 1, "reset\n" + +; attach int handler + + movzx eax, [device.irq_line] + DEBUGF 2,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 2,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + +; Soft reset the chip. + set_io 0 + set_io byCR0 + mov ax, CR_SFRST + out dx, ax + + call MIIDelay + +; Initialize rings + call init_ring + +; Setup Multicast + call set_rx_mode + +; set TCR RCR threshold to store and forward + set_io 0 + set_io byBCR0 + mov al, 0x3E + out dx, al + + set_io byBCR1 + mov al, 0x38 + out dx, al + + set_io byRCR + mov al, 0x2C + out dx, al + + set_io byTCR + mov al, 0x60 + out dx, al + +; Set Fulldupex + + call QueryAuto + test eax, eax ; full duplex? + jz @f + + set_io 0 + set_io byCFGD + mov al, CFGD_CFDX + out dx, al + + set_io byCR0 + mov ax, CR_FDX + out dx, ax + @@: + +; ENABLE interrupts + set_io 0 + set_io byIMR0 + mov ax, DEFAULT_INTR + out dx, ax + +; KICK NIC to WORK + + set_io byCR0 + in ax, dx + and ax, not CR_STOP + or ax, CR_STRT or CR_TXON or CR_RXON or CR_DPOLL + out dx, ax + +; Set the mtu, kernel will be able to send now + mov [device.mtu], 1514 + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + +; say reset was successfull + xor eax, eax + ret + + + +align 4 +unload: + + call reset + push eax edx + DEBUGF 1, "rhine disable\n" + + ; Switch to loopback mode to avoid hardware races. + set_io 0 + set_io byTCR + mov al, 0x61 + out dx, al + + ; Stop the chip's Tx and Rx processes. + set_io byCR0 + mov ax, CR_STOP + out dx, ax + pop edx eax + + ret + + + + +align 4 +reload_eeprom: + + DEBUGF 1, "Reload eeprom\n" + + set_io 0 + set_io byEECSR + mov al, 0x20 + out dx, al + ; Typically 2 cycles to reload. + mov ecx, 150 + .reload: + in al, dx + test al, 0x20 + jz @f + loop .reload + DEBUGF 1, "Reload timeout!\n" + @@: + + ret + +; Initialize the Rx and Tx rings, along with various 'dev' bits. +align 4 +init_ring: + + DEBUGF 1, "Init ring\n" + + lea edi, [device.rx_ring] + mov eax, edi + GetRealAddr + mov esi, eax + push esi + mov ecx, RX_RING_SIZE + .rx_init: + add esi, rx_head.sizeof + mov [edi + rx_head.status], RX_SBITS_OWN_BIT + mov [edi + rx_head.control], PKT_BUF_SZ + push ecx + stdcall KernelAlloc, PKT_BUF_SZ + pop ecx + mov [edi + rx_head.buff_addr_virt], eax + GetRealAddr + mov [edi + rx_head.buff_addr], eax ; buffer ptr + mov [edi + rx_head.next_desc], esi ; next head + add edi, rx_head.sizeof + dec ecx + jnz .rx_init + pop [edi - rx_head.sizeof + rx_head.next_desc] ; Mark the last entry as wrapping the ring. + + + lea edi, [device.tx_ring] + mov eax, edi + GetRealAddr + mov esi, eax + push esi + mov ecx, TX_RING_SIZE + .tx_init: + add esi, tx_head.sizeof + mov [edi + tx_head.status], 0 + mov [edi + tx_head.control], 0x00E08000 + mov [edi + tx_head.buff_addr], 0 + mov [edi + tx_head.next_desc], esi + mov [edi + tx_head.buff_addr_virt], 0 + add edi, tx_head.sizeof + dec ecx + jnz .tx_init + pop [edi - tx_head.sizeof + tx_head.next_desc] ; Mark the last entry as wrapping the ring. + +; write Descriptors to MAC + lea eax, [device.rx_ring] + GetRealAddr + set_io 0 + set_io dwCurrentRxDescAddr + out dx, eax + + lea eax, [device.tx_ring] + GetRealAddr + set_io dwCurrentTxDescAddr + out dx, eax + + xor eax, eax + mov [device.cur_rx], ax + mov [device.cur_tx], ax + mov [device.last_tx], ax + + ret + + +align 4 +QueryAuto: + + DEBUGF 1, "Query Auto\n" + + push ecx + stdcall ReadMII, 0x04 ; advertised + mov ecx, eax + stdcall ReadMII, 0x05 + and ecx, eax + + xor eax, eax + test ecx, 0x100 + jnz .one + + and ecx, 0x1C0 + cmp ecx, 0x40 + jne .zero + .one: + inc eax + DEBUGF 1, "AutoNego OK!\n" + .zero: + pop ecx + + ret + + +proc ReadMII stdcall, byMIIIndex:dword + +; DEBUGF 1, "ReadMII Index=%x\n", [byMIIIndex] + + push esi ebx ecx edx + + set_io 0 + set_io byMIIAD + in al, dx + mov bl, al + + set_io byMIICR + in al, dx + mov bh, al + and al, 0x7F + out dx, al + + call MIIDelay + + mov al, byte [byMIIIndex] + set_io byMIIAD + out dx, al + + call MIIDelay + + set_io byMIICR + in al, dx + or al, 0x40 + out dx, al + + mov ecx, 200 + .read_again: + in al, dx + test al, 0x40 + jz @f + + mov esi, 10 + call Sleep + dec ecx + jnz .read_again + DEBUGF 1, "\nReadMII timeout!\n" + @@: + + call MIIDelay + + set_io byMIIAD + in ax, dx + + push eax + mov ax, bx + set_io byMIIAD + out dx, al + + shr ax, 8 + set_io byMIICR + out dx, al + + call MIIDelay + + pop eax + and eax, 0xFFFF + rol ax, 8 ;;;;; I dont know how or why but it seems needed... + + pop edx ecx ebx esi + ret +endp + +proc WriteMII stdcall, byMIISetByte:dword, byMIISetBit:dword, byMIIOP:dword + +; DEBUGF 1, "WriteMII SetByte=%x SetBit=%x OP=%x\n", [byMIISetByte], [byMIISetBit], [byMIIOP] + + push ebx eax ecx edx + + set_io 0 + set_io byMIIAD + in al, dx + mov bl, al + + set_io byMIICR + in al, dx + mov bh, al + and al, 0x7F + out dx, al + + call MIIDelay + + mov al, byte [byMIISetByte] + set_io byMIIAD + out dx, al + + call MIIDelay + + set_io byMIICR + in al, dx + or al, 0x40 + out dx, al + + mov ecx, 200 + .read_again0: + in al, dx + test al, 0x40 + jz .done + + mov esi, 10 + call Sleep + dec ecx + jnz .read_again0 + DEBUGF 1, "WriteMII timeout 1\n" + .done: + + call MIIDelay + + set_io wMIIDATA + in ax, dx + + mov ecx, [byMIISetBit] + rol cx, 8 ;;;;;;;;;;;;;;;;; CHECKME + + cmp byte [byMIIOP], 0 + jne @f + not ecx + and ax, cx + jmp .end_mascarad + @@: + or ax, cx + .end_mascarad: + + set_io wMIIDATA + out dx, ax + + call MIIDelay + + set_io byMIICR + in al, dx + or al, 0x20 + out dx, al + + mov ecx, 200 + .read_again1: + in al, dx + test al, 0x20 + jz @f + + mov esi, 10 + call Sleep + dec ecx + jnz .read_again1 + DEBUGF 1, "WriteMII timeout 2\n" + @@: + + call MIIDelay + + mov ax, bx + and al, 0x7F + set_io byMIIAD + out dx, al + + shr ax, 8 + set_io byMIICR + out dx, al + + call MIIDelay + + pop edx ecx eax ebx + ret +endp + + +align 4 +MIIDelay: + + mov ecx, 0x7FFF + @@: + in al, 0x61 + in al, 0x61 + in al, 0x61 + in al, 0x61 + loop @b + + ret + + +align 4 +set_rx_mode: + + DEBUGF 1, "Set RX mode\n" + + ; ! IFF_PROMISC + mov eax, 0xffffffff + set_io 0 + set_io byMAR0 + out dx, eax + + set_io byMAR4 + out dx, eax + + set_io byRCR + mov al, 0x6C ;rx_mode = 0x0C; + out dx, al ;outb(0x60 /* thresh */ | rx_mode, byRCR ); + + ret + + + + + +; Beware of PCI posted writes +macro IOSYNC +{ + set_io StationAddr + in al, dx +} + + + +align 4 +read_mac: + + DEBUGF 1, "Ethernet Address: " + + lea edi, [device.mac] + set_io 0 + set_io byPAR0 + mov ecx, 6 + .next: + in al, dx + stosb + DEBUGF 1, "-%x", al + inc edx + dec ecx + jnz .next + DEBUGF 1, "\n" + + ret + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +align 4 +transmit: + DEBUGF 2,"\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] + mov eax, [esp+4] + DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp+8], 1514 + ja .fail + cmp dword [esp+8], 60 + jb .fail + + movzx eax, [device.cur_tx] + mov ecx, tx_head.sizeof + mul ecx + lea edi, [device.tx_ring] + add edi, eax + + cmp [edi + tx_head.buff_addr_virt], 0 + jne .fail + + mov eax, [esp+4] + mov [edi + tx_head.buff_addr_virt], eax + GetRealAddr + mov [edi + tx_head.buff_addr], eax + mov ecx, [esp+8] + and ecx, TX_CBITS_TX_BUF_SIZE + or ecx, 0x00E08000 + mov [edi + tx_head.control], ecx + or [edi + tx_head.status], TX_SBITS_OWN_BIT + + set_io 0 + set_io byCR1 + in al, dx + or al, CR1_TDMD1 + out dx, al + + inc [device.cur_tx] + and [device.cur_tx], TX_RING_SIZE-1 + + ;outw(IMRShadow,byIMR0); ; + +; Update stats + inc [device.packets_tx] + mov ecx, [esp+8] ;;;;; + add dword [device.bytes_tx], ecx + adc dword [device.bytes_tx + 4], 0 + + ret 8 + + .fail: + DEBUGF 1, "Failed!\n" + + ret 8 + + + + + + + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int ", my_service + +; Find pointer of device wich made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + + set_io 0 + set_io IntrStatus + in ax, dx + out dx, ax ; send it back to ACK + test ax, ax + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) + + + + .got_it: + + DEBUGF 1, "status=0x%x\n", ax + + push ax + + test ax, IntrRxDone + jz .not_RX + + push ebx + .more_RX: + pop ebx + +; Get the current descripter pointer + + movzx eax, [device.cur_rx] + mov ecx, rx_head.sizeof + mul ecx + lea edi, [device.rx_ring] + add edi, eax + +; Check it's status + + test [edi + rx_head.status], RX_SBITS_OWN_BIT + jnz .not_bit_own + + DEBUGF 1, "Packet status = 0x%x\n", [edi + rx_head.status] + +; TODO: check error bits + +; get length + + mov ecx, [edi + rx_head.status] + and ecx, RX_SBITS_FRAME_LENGTH + shr ecx, 16 + sub ecx, 4 ; We dont want CRC + +; Update stats + + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + inc [device.packets_rx] + +; Push packet size and pointer, kernel will need it.. + + push ebx + push .more_RX ; return ptr + + push ecx ; full packet size + push [edi + rx_head.buff_addr_virt] + +; reset the RX descriptor + + push edi + stdcall KernelAlloc, PKT_BUF_SZ + pop edi + mov [edi + rx_head.buff_addr_virt], eax + GetRealAddr + mov [edi + rx_head.buff_addr], eax + mov [edi + rx_head.status], RX_SBITS_OWN_BIT + +; Use next descriptor next time + + inc [device.cur_rx] + and [device.cur_rx], RX_RING_SIZE - 1 + +; At last, send packet to kernel + + jmp Eth_input + + .not_bit_own: + .not_RX: + + pop ax + + test ax, IntrTxDone + jz .not_TX + + .loop_tx: + movzx eax, [device.last_tx] + mov ecx, tx_head.sizeof + mul ecx + lea edi, [device.tx_ring] + add edi, eax + + test [edi + tx_head.status], TX_SBITS_OWN_BIT + jnz .not_TX + + cmp [edi + tx_head.buff_addr_virt], 0 + je .not_TX + + DEBUGF 1,"Freeing buffer 0x%x\n", [edi + tx_head.buff_addr_virt] + + push [edi + tx_head.buff_addr_virt] + mov [edi + tx_head.buff_addr_virt], 0 + call KernelFree + + inc [device.last_tx] + and [device.last_tx], TX_RING_SIZE - 1 + + jmp .loop_tx + + .not_TX: + + ; On Rhine-II, Bit 3 indicates Tx descriptor write-back race. +if 0 + cmp [device.chip_id], 0x3065 ;if (tp->chip_id == 0x3065) + jne @f + push ax + xor eax, eax + set_io IntrStatus2 + in al, dx ; intr_status |= inb(nic->ioaddr + IntrStatus2) << 16; + shl eax, 16 + pop ax + @@: +end if + +if 0 + + ; Acknowledge all of the current interrupt sources ASAP. + xor ecx, ecx + test eax, IntrTxDescRace + jz @f + set_io 0 + set_io IntrStatus2 + push ax + mov al, 0x08 + out dx, al + pop ax + @@: + set_io 0 + set_io IntrStatus + out dx, ax + IOSYNC + +end if + + pop edi esi ebx + xor eax, eax + inc eax + + ret + + + + + +; End of code + +section '.data' data readable writable align 16 ; place all uninitialized data here +align 4 ; Place all initialised data here + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'RHINE',0 ; max 16 chars including zero + +devicelist: + dd 0x30431106, rhine_3043;, RHINE_IOTYPE, RHINE_I_IOSIZE, CanHaveMII or ReqTxAlign or HasV1TxStat + dd 0x61001106, rhine_6100;, RHINE_IOTYPE, RHINE_I_IOSIZE, CanHaveMII or ReqTxAlign or HasV1TxStat + dd 0x30651106, rhine_6102;, RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII or HasWOL + dd 0x31061106, rhine_6105;, RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII or HasWOL + ; Duplicate entry, with 'M' features enabled. + dd 0x31061106, rhine_6105;, RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII or HasWOL or HasIPChecksum or HasVLAN + dd 0x30531106, rhine_3053;, RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII or HasWOL + dd 0 + +rhine_3043 db "VIA VT3043 Rhine", 0 +rhine_6100 db "VIA VT86C100A Rhine", 0 +rhine_6102 db "VIA VT6102 Rhine-II", 0 +rhine_6105 db "VIA VT6105LOM Rhine-III (3106)", 0 +rhine_3053 db "VIA VT6105M Rhine-III (3053 prototype)", 0 + +include_debug_strings ; All data wich FDO uses will be included here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + diff --git a/drivers/ethernet/sis900.asm b/drivers/ethernet/sis900.asm new file mode 100644 index 0000000000..49726a0107 --- /dev/null +++ b/drivers/ethernet/sis900.asm @@ -0,0 +1,1222 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Ethernet driver for KolibriOS ;; +;; This is an adaptation of MenuetOS driver with minimal changes. ;; +;; Changes were made by CleverMouse. Original copyright follows. ;; +;; ;; +;; This driver is based on the SIS900 driver from ;; +;; the etherboot 5.0.6 project. The copyright statement is ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;; remaining parts Copyright 2004 Jason Delozier, ;; +;; cordata51@hotmail.com ;; +;; ;; +;; See file COPYING for details ;; +;; ;; +;; Updates: ;; +;; Revision Look up table and SIS635 Mac Address by Jarek Pelczar ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + NUM_RX_DESC = 4 ; Number of RX descriptors + NUM_TX_DESC = 4 ; Number of TX descriptors + RX_BUFF_SZ = 1520 ; Buffer size for each Rx buffer + TX_BUFF_SZ = 1516 ; Buffer size for each Tx buffer + MAX_ETH_FRAME_SIZE = 1516 + + API_VERSION = 0x01000100 + DRIVER_VERSION = 5 + + MAX_DEVICES = 16 + + DEBUG = 1 + __DEBUG__ = 1 + __DEBUG_LEVEL__ = 2 + + DSIZE = 0x00000fff + CRC_SIZE = 4 + RFADDR_shift = 16 + +; If you are having problems sending/receiving packet try changing the +; Max DMA Burst, Possible settings are as follows: +; +; 0x00000000 = 512 bytes +; 0x00100000 = 4 bytes +; 0x00200000 = 8 bytes +; 0x00300000 = 16 bytes +; 0x00400000 = 32 bytes +; 0x00500000 = 64 bytes +; 0x00600000 = 128 bytes +; 0x00700000 = 256 bytes + + RX_DMA = 0x00600000 + TX_DMA = 0x00600000 + +;------------------------------------------------------------------------------------------------- +; Symbolic offsets to registers. + cr = 0x0 ; Command Register + cfg = 0x4 ; Configuration Register + mear = 0x8 ; EEPROM Access Register + ptscr = 0xc ; PCI Test Control Register + isr = 0x10 ; Interrupt Status Register + imr = 0x14 ; Interrupt Mask Register + ier = 0x18 ; Interrupt Enable Register + epar = 0x18 ; Enhanced PHY Access Register + txdp = 0x20 ; Transmit Descriptor Pointer Register + txcfg = 0x24 ; Transmit Configuration Register + rxdp = 0x30 ; Receive Descriptor Pointer Register + rxcfg = 0x34 ; Receive Configuration Register + flctrl = 0x38 ; Flow Control Register + rxlen = 0x3c ; Receive Packet Length Register + rfcr = 0x48 ; Receive Filter Control Register + rfdr = 0x4C ; Receive Filter Data Register + pmctrl = 0xB0 ; Power Management Control Register + pmer = 0xB4 ; Power Management Wake-up Event Register + +; Command Register Bits + RELOAD = 0x00000400 + ACCESSMODE = 0x00000200 + RESET = 0x00000100 + SWI = 0x00000080 + RxRESET = 0x00000020 + TxRESET = 0x00000010 + RxDIS = 0x00000008 + RxENA = 0x00000004 + TxDIS = 0x00000002 + TxENA = 0x00000001 + +; Configuration Register Bits + DESCRFMT = 0x00000100 ; 7016 specific + REQALG = 0x00000080 + SB = 0x00000040 + POW = 0x00000020 + EXD = 0x00000010 + PESEL = 0x00000008 + LPM = 0x00000004 + BEM = 0x00000001 + RND_CNT = 0x00000400 + FAIR_BACKOFF = 0x00000200 + EDB_MASTER_EN = 0x00002000 + +; Eeprom Access Reigster Bits + MDC = 0x00000040 + MDDIR = 0x00000020 + MDIO = 0x00000010 ; 7016 specific + EECS = 0x00000008 + EECLK = 0x00000004 + EEDO = 0x00000002 + EEDI = 0x00000001 + +; TX Configuration Register Bits + ATP = 0x10000000 ; Automatic Transmit Padding + MLB = 0x20000000 ; Mac Loopback Enable + HBI = 0x40000000 ; HeartBeat Ignore (Req for full-dup) + CSI = 0x80000000 ; CarrierSenseIgnore (Req for full-du + +; RX Configuration Register Bits + AJAB = 0x08000000 ; + ATX = 0x10000000 ; Accept Transmit Packets + ARP = 0x40000000 ; accept runt packets (<64bytes) + AEP = 0x80000000 ; accept error packets + +; Interrupt Register Bits + WKEVT = 0x10000000 + TxPAUSEEND = 0x08000000 + TxPAUSE = 0x04000000 + TxRCMP = 0x02000000 ; Transmit Reset Complete + RxRCMP = 0x01000000 ; Receive Reset Complete + DPERR = 0x00800000 + SSERR = 0x00400000 + RMABT = 0x00200000 + RTABT = 0x00100000 + RxSOVR = 0x00010000 + HIBERR = 0x00008000 + SWINT = 0x00001000 + MIBINT = 0x00000800 + TxURN = 0x00000400 + TxIDLE = 0x00000200 + TxERR = 0x00000100 + TxDESC = 0x00000080 + TxOK = 0x00000040 + RxORN = 0x00000020 + RxIDLE = 0x00000010 + RxEARLY = 0x00000008 + RxERR = 0x00000004 + RxDESC = 0x00000002 + RxOK = 0x00000001 + +; Interrupt Enable Register Bits + IE = RxOK + TxOK + +; Revision ID + SIS900B_900_REV = 0x03 + SIS630A_900_REV = 0x80 + SIS630E_900_REV = 0x81 + SIS630S_900_REV = 0x82 + SIS630EA1_900_REV = 0x83 + SIS630ET_900_REV = 0x84 + SIS635A_900_REV = 0x90 + SIS900_960_REV = 0x91 + +; Receive Filter Control Register Bits + RFEN = 0x80000000 ; enable + RFAAB = 0x40000000 ; accept all broadcasts + RFAAM = 0x20000000 ; accept all multicasts + RFAAP = 0x10000000 ; accept all packets + +; Reveive Filter Data Mask + RFDAT = 0x0000FFFF + +; Eeprom Address + EEPROMSignature = 0x00 + EEPROMVendorID = 0x02 + EEPROMDeviceID = 0x03 + EEPROMMACAddr = 0x08 + EEPROMChecksum = 0x0b + +; The EEPROM commands include the alway-set leading bit. + EEread = 0x0180 + EEwrite = 0x0140 + EEerase = 0x01C0 + EEwriteEnable = 0x0130 + EEwriteDisable = 0x0100 + EEeraseAll = 0x0120 + EEwriteAll = 0x0110 + EEaddrMask = 0x013F + EEcmdShift = 16 + +; For SiS962 or SiS963, request the eeprom software access + EEREQ = 0x00000400 + EEDONE = 0x00000200 + EEGNT = 0x00000100 + + +include '../proc32.inc' +include '../imports.inc' +include '../fdo.inc' +include '../netdrv.inc' + +public START +public version + + +virtual at ebx + device: + + ETH_DEVICE + + .io_addr dd ? + .pci_bus dd ? + .pci_dev dd ? + .irq_line db ? + .cur_rx db ? + .cur_tx db ? + .last_tx db ? + .pci_revision db ? + .table_entries db ? + rb 2 ; alignment + + .txd rd (4 * NUM_TX_DESC) + .rxd rd (4 * NUM_RX_DESC) + + .size = $ - device + +end virtual + +macro ee_delay { + push eax + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + pop eax +} + + +section '.flat' code readable align 16 + +; Driver entry point - register our service when the driver is loading. +; TODO: add needed operations when unloading +START: + cmp dword [esp+4], 1 + jne .exit + stdcall RegService, my_service, service_proc + ret 4 + .exit: + xor eax, eax + ret 4 + +; Service procedure for the driver - handle all I/O requests for the driver. +; Currently handled requests are: SRV_GETVERSION = 0 and SRV_HOOK = 1. +service_proc: +; 1. Get parameter from the stack: [esp+4] is the first parameter, +; pointer to IOCTL structure. + mov edx, [esp+4] ; edx -> IOCTL +; 2. Get request code and select a handler for the code. + mov eax, [IOCTL.io_code] + test eax, eax ; check for SRV_GETVERSION + jnz @f +; 3. This is SRV_GETVERSION request, no input, 4 bytes output, API_VERSION. +; 3a. Output size must be at least 4 bytes. + cmp [IOCTL.out_size], 4 + jb .fail +; 3b. Write result to the output buffer. + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION +; 3c. Return success. + xor eax, eax + ret 4 + @@: + dec eax ; check for SRV_HOOK + jnz .fail +; 4. This is SRV_HOOK request, input defines the device to hook, no output. +; 4a. The driver works only with PCI devices, +; so input must be at least 3 bytes long. + cmp [IOCTL.inp_size], 3 + jb .fail +; 4b. First byte of input is bus type, 1 stands for PCI. + mov eax, [IOCTL.input] + cmp byte [eax], 1 + jne .fail +; 4c. Second and third bytes of the input define the device: bus and dev. +; Word in bx holds both bytes. + mov bx, [eax+1] +; 4d. Check if the device was already hooked, +; scan through the list of known devices. +; check if the device is already listed + mov esi, device_list + mov ecx, [devices] + test ecx, ecx + jz .firstdevice + +; mov eax, [IOCTL.input] ; get the pci bus and device numbers + mov ax, [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp al, byte[device.pci_bus] + jne @f + cmp ah, byte[device.pci_dev] + je .find_devicenum ; Device is already loaded, let's find it's device number + @@: + add esi, 4 + loop .nextdevice +; 4e. This device doesn't have its own eth_device structure yet, let's create one + .firstdevice: +; 4f. Check that we have place for new device. + cmp [devices], MAX_DEVICES + jae .fail +; 4g. Allocate memory for device descriptor and receive+transmit buffers. +; 4h. Zero the structure. + allocate_and_clear ebx, device.size, .fail +; 4i. Save PCI coordinates + mov eax, [IOCTL.input] + movzx ecx, byte[eax+1] + mov [device.pci_bus], ecx + movzx ecx, byte[eax+2] + mov [device.pci_dev], ecx +; 4j. Fill in the direct call addresses into the struct. + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.unload], unload + mov [device.name], my_service + +; 4k. Now, it's time to find the base io addres of the PCI device +; TODO: implement check if bus and dev exist on this machine + +; Now, it's time to find the base io addres of the PCI device + PCI_find_io + +; We've found the io address, find IRQ now + PCI_find_irq + +; 4m. Add new device to the list (required for int_handler). + mov eax, [devices] + mov [device_list+4*eax], ebx + inc [devices] + +; 4m. Ok, the eth_device structure is ready, let's probe the device + call probe + test eax, eax + jnz .destroy +; 4n. If device was successfully initialized, register it for the kernel. + + mov [device.type], NET_TYPE_ETH + call NetRegDev + + cmp eax, -1 + je .destroy + + ret 4 + +; 5. If the device was already loaded, find the device number and return it in eax + + .find_devicenum: + call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx + ; into a device number in edi + mov eax, edi ; Application wants it in eax instead + ret 4 + +; If an error occured, remove all allocated data and exit (returning -1 in eax) + + .destroy: + dec [devices] + ; todo: reset device into virgin state + + .err: + stdcall KernelFree, ebx + + .fail: + xor eax, eax + ret 4 + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + +unload: + ; TODO: (in this particular order) + ; + ; - Stop the device + ; - Detach int handler + ; - Remove device from local list + ; - call unregister function in kernel + ; - Remove all allocated structures and buffers the card used + + or eax,-1 + +ret + +;*************************************************************************** +; +; probe +; +; checks the card and enables it +; +; TODO: probe mii transceivers +; +;*************************************************************************** +align 4 +probe: + DEBUGF 1, "Probe\n" + +; wake up device CHECKME + stdcall PciWrite8, [device.pci_bus], [device.pci_dev], 0x40, 0 + + PCI_make_bus_master + + PCI_adjust_latency 64 + +; Get Card Revision + stdcall PciRead8, [device.pci_bus], [device.pci_dev], 0x08 + mov [device.pci_revision], al ; save the revision for later use + +; Look up through the specific_table + mov esi, specific_table + .tableloop: + cmp dword [esi], 0 ; Check if we reached end of the list + je .notsupported + cmp al, [esi] ; Check if revision is OK + je .ok + add esi, 12 ; Advance to next entry + jmp .tableloop + + .ok: + + call dword[esi + 4] ; "get MAC" function + +; Set table entries + mov [device.table_entries], 16 + cmp [device.pci_revision], SIS635A_900_REV + jae @f + cmp [device.pci_revision], SIS900B_900_REV + je @f + mov [device.table_entries], 8 + @@: + +; TODO: Probe for mii transceiver + + jmp reset + + .notsupported: + DEBUGF 1, "Device not supported\n" + or eax, -1 + + ret + +reset: + + DEBUGF 1, "reset\n" + + movzx eax, [device.irq_line] + stdcall AttachIntHandler, eax, int_handler, 0 + +;-------------------------------------------- +; Disable Interrupts and reset Receive Filter + + set_io 0 + set_io ier + xor eax, eax + out dx, eax + + set_io imr + out dx, eax + + set_io rfcr + out dx, eax + +;----------- +; Reset Card + + set_io cr + in eax, dx ; Get current Command Register + or eax, RESET + RxRESET + TxRESET ; set flags + out dx, eax ; Write new Command Register + +;---------- +; Wait loop + + set_io isr + mov ecx, 1000 + .loop: + dec ecx + jz .fail + in eax, dx ; read interrupt status + test eax, TxRCMP + RxRCMP + jz .loop + DEBUGF 1, "status=%x\n", eax + +;------------------------------------------------------ +; Set Configuration Register depending on Card Revision + + set_io cfg + mov eax, PESEL ; Configuration Register Bit + cmp [device.pci_revision], SIS635A_900_REV + je .match + cmp [device.pci_revision], SIS900B_900_REV ; Check card revision + jne .done + .match: ; Revision match + or eax, RND_CNT ; Configuration Register Bit + .done: + out dx, eax + + DEBUGF 1, "Initialising RX Filter\n" + +; Get Receive Filter Control Register + set_io rfcr + in eax, dx + push eax + +; disable packet filtering before setting filter + and eax, not RFEN + out dx, eax + +; load MAC addr to filter data register + xor ecx, ecx + .macloop: + mov eax, ecx + set_io 0 + set_io rfcr + shl eax, 16 ; high word of eax tells card which mac byte to write + out dx, eax ; + set_io rfdr + mov ax, word [device.mac + ecx*2] ; Get Mac ID word + out dx, ax ; Send Mac ID + inc cl ; send next word + cmp cl, 3 ; more to send? + jne .macloop + +; enable packet filtering + pop eax ; old register value + set_io rfcr + or eax, RFEN ; enable filtering + out dx, eax ; set register + + DEBUGF 1, "Initialising TX Descriptors\n" + + mov ecx, NUM_TX_DESC + lea esi, [device.txd] + .txdescloop: + lea eax, [esi + 16] ; next ptr + GetRealAddr + mov dword [esi], eax ; link to next desc + mov dword [esi + 4], 0 ; status field + mov dword [esi + 8], 0 ; ptr to buffer + add esi, 16 + dec ecx + jnz .txdescloop + + lea eax, [device.txd] + GetRealAddr + mov dword [esi - 16], eax ; correct last descriptor link ptr + + set_io txdp ; TX Descriptor Pointer +; lea eax, [device.txd] +; GetRealAddr + out dx, eax + + mov [device.cur_tx], 0 ; Set current tx descriptor to 0 + mov [device.last_tx], 0 + + DEBUGF 1, "Initialising RX Descriptors\n" + + mov ecx, NUM_RX_DESC + lea esi, [device.rxd] + .rxdescloop: + lea eax, [esi + 16] ; next ptr + GetRealAddr + mov dword [esi], eax + mov dword [esi + 4], RX_BUFF_SZ ; size + + push ecx esi + stdcall KernelAlloc, RX_BUFF_SZ + pop esi ecx + test eax, eax + jz .fail + mov dword [esi + 12], eax ; address + GetRealAddr + mov dword [esi + 8], eax ; real address + add esi, 16 + dec ecx + jnz .rxdescloop + + lea eax, [device.rxd] + GetRealAddr + mov dword [esi - 16], eax ; correct last descriptor link ptr + + set_io 0 + set_io rxdp +; lea eax, [device.rxd] +; GetRealAddr + out dx, eax + + mov [device.cur_rx], 0 ; Set current rx descriptor to 0 + + DEBUGF 1, "setting RX mode\n" + + xor cl, cl + .rxfilterloop: + set_io 0 + set_io rfcr ; Receive Filter Control Reg offset + mov eax, 4 ; determine table entry + add al, cl + shl eax, 16 + out dx, eax ; tell card which entry to modify + + set_io rfdr ; Receive Filter Control Reg offset + mov eax, 0xffff ; entry value + out dx, ax ; write value to table in card + + inc cl ; next entry + cmp cl, [device.table_entries] + jb .rxfilterloop + + set_io rfcr ; Receive Filter Control Register offset + mov eax, RFAAB + RFAAM + RFAAP + RFEN + out dx, eax + + set_io rxcfg ; Receive Config Register offset + mov eax, ATX + RX_DMA + 2 ; 0x2 : RX Drain Threshold = 8*8=64 bytes + out dx, eax + + DEBUGF 1, "setting TX mode\n" + + set_io txcfg ; Transmit config Register offset + mov eax, ATP + HBI + CSI + TX_DMA + 0x120 + ; TX Fill threshold = 0x100 + ; TX Drain Threshold = 0x20 + out dx, eax + + DEBUGF 1, "Enabling interrupts\n" + + set_io imr + mov eax, IE ; Interrupt enable mask + out dx, eax + + set_io cr + in eax, dx + or eax, RxENA ; Enable Receive + out dx, eax + + set_io ier ; Interrupt enable + mov eax, 1 + out dx, eax + + mov [device.mtu], 1514 + +; Set link state to unknown + mov [device.state], ETH_LINK_UNKOWN + + xor eax, eax + ret + + .fail: + DEBUGF 1, "Resetting device failed\n" + or eax, -1 + + ret + + +;*************************************************************************** +; +; SIS960_get_mac_addr: - Get MAC address for SiS962 or SiS963 model +; +; SiS962 or SiS963 model, use EEPROM to store MAC address. +; EEPROM is shared by LAN and 1394. +; When access EEPROM, send EEREQ signal to hardware first, and wait for EEGNT. +; If EEGNT is ON, EEPROM is permitted to be accessed by LAN, otherwise is not. +; After MAC address is read from EEPROM, send +; EEDONE signal to refuse EEPROM access by LAN. +; The EEPROM map of SiS962 or SiS963 is different to SiS900. +; The signature field in SiS962 or SiS963 spec is meaningless. +; +; Return 0 is EAX = failure +; +;*************************************************************************** +align 4 +SIS960_get_mac_addr: + DEBUGF 1, "SIS960 - get mac: " + +;------------------------------- +; Send Request for eeprom access + + set_io 0 + set_io mear ; Eeprom access register + mov eax, EEREQ ; Request access to eeprom + out dx, eax ; Send request + +;----------------------------------------------------- +; Loop 4000 times and if access not granted, error out + + mov ecx, 4000 + .loop: + in eax, dx ; get eeprom status + test eax, EEGNT ; see if eeprom access granted flag is set + jnz .got_access ; if it is, go access the eeprom + loop .loop ; else keep waiting + + DEBUGF 1, "Access to EEprom failed!\n", 0 + + set_io mear ; Eeprom access register + mov eax, EEDONE ; tell eeprom we are done + out dx, eax + + or eax, -1 ; error + ret + + .got_access: + +;------------------------------------------ +; EEprom access granted, read MAC from card + + ; zero based so 3-16 bit reads will take place + + mov ecx, 2 + .read_loop: + mov eax, EEPROMMACAddr ; Base Mac Address + add eax, ecx ; Current Mac Byte Offset + push ecx + call read_eeprom ; try to read 16 bits + pop ecx + mov word [device.mac+ecx*2], ax ; save 16 bits to the MAC ID varible + dec ecx ; one less word to read + jns .read_loop ; if more read more + mov eax, 1 ; return non-zero indicating success + + DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + +;------------------------------------- +; Tell EEPROM We are Done Accessing It + + .done: + set_io 0 + set_io mear ; Eeprom access register + mov eax, EEDONE ; tell eeprom we are done + out dx, eax + + xor eax, eax ; ok + ret + + + + +;*************************************************************************** +; +; get_mac_addr: - Get MAC address for stand alone SiS900 model +; +; Older SiS900 and friends, use EEPROM to store MAC address. +; +;*************************************************************************** +align 4 +SIS900_get_mac_addr: + DEBUGF 1, "SIS900 - get mac: " + +;------------------------------------ +; check to see if we have sane EEPROM + + mov eax, EEPROMSignature ; Base Eeprom Signature + call read_eeprom ; try to read 16 bits + cmp ax, 0xffff + je .err + test ax, ax + je .err + +;----------- +; Read MacID + +; zero based so 3-16 bit reads will take place + + mov ecx, 2 + .loop: + mov eax, EEPROMMACAddr ; Base Mac Address + add eax, ecx ; Current Mac Byte Offset + push ecx + call read_eeprom ; try to read 16 bits + pop ecx + mov word [device.mac+ecx*2], ax ; save 16 bits to the MAC ID storage + dec ecx ; one less word to read + jns .loop ; if more read more + + DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + + xor eax, eax + ret + + + .err: + DEBUGF 1, "Access to EEprom failed!\n", 0 + + or eax, -1 + ret + + +;*************************************************************************** +; +; Get_Mac_SIS635_900_REV: - Get MAC address for model 635 +; +;*************************************************************************** +align 4 +Get_Mac_SIS635_900_REV: + DEBUGF 1, "SIS635 - get mac: " + + set_io 0 + set_io rfcr + in eax, dx + mov esi, eax + + set_io cr + or eax, RELOAD + out dx, eax + + xor eax, eax + out dx, eax + +;----------------------------------------------- +; Disable packet filtering before setting filter + + set_io rfcr + mov eax, esi + and eax, not RFEN + out dx, eax + +;--------------------------------- +; Load MAC to filter data register + + xor ecx, ecx + lea edi, [device.mac] + .loop: + set_io 0 + set_io rfcr + mov eax, ecx + shl eax, RFADDR_shift + out dx, eax + + set_io rfdr + in ax, dx + stosw + inc ecx + cmp ecx, 3 + jb .loop + +;------------------------ +; Enable packet filtering + + set_io rfcr + mov eax, esi + or eax, RFEN + out dx, eax + + DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 + + xor eax, eax + ret + +;*************************************************************************** +; +; read_eeprom +; +; reads and returns a given location from EEPROM +; +; IN: si = addr +; OUT: ax = data +; +;*************************************************************************** +align 4 +read_eeprom: + + set_io 0 + set_io mear + + xor eax, eax ; start send + out dx, eax + ee_delay + + or eax, EECLK + out dx, eax + ee_delay + +;------------------------------------ +; Send the read command + + or esi, EEread + mov ecx, 1 shl 9 + + .loop: + mov eax, EECS + test esi, ecx + jz @f + or eax, EEDI + @@: + out dx, eax + ee_delay + + or eax, EECLK + out dx, eax + ee_delay + + shr esi, 1 + jnc .loop + + mov eax, EECS + out dx, eax + ee_delay + +;------------------------ +; Read 16-bits of data in + + xor esi, esi + mov cx, 16 + .loop2: + mov eax, EECS + out dx, eax + ee_delay + + or eax, EECLK + out dx, eax + ee_delay + + in eax, dx + shl esi, 1 + test eax, EEDO + jz @f + inc esi + @@: + loop .loop2 + +;---------------------------- +; Terminate the EEPROM access + + xor eax, eax + out dx, eax + ee_delay + + mov eax, EECLK + out dx, eax + ee_delay + + movzx eax, si + + ret + + + +align 4 +write_mac: + DEBUGF 1,'Setting MAC is not supported for SIS900 card.\n' + add esp, 6 + ret + + + + +;*************************************************************************** +; Function +; transmit +; Description +; Transmits a packet of data via the ethernet card +; buffer pointer in [esp+4] +; size of buffer in [esp+8] +; pointer to device structure in ebx +; +;*************************************************************************** +align 4 +transmit: + DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8] + mov eax, [esp+4] + DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ + [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ + [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ + [eax+13]:2,[eax+12]:2 + + cmp dword [esp + 8], MAX_ETH_FRAME_SIZE + ja .error + cmp dword [esp + 8], 60 + jb .error + + movzx ecx, [device.cur_tx] + shl ecx, 4 ; *16 + lea ecx, [device.txd + ecx] + + test dword [ecx + 4], 0x80000000 ; card owns descriptor ? + jnz .error + + mov eax, [esp + 4] + mov dword [ecx + 12], eax + GetRealAddr + mov dword [ecx + 8], eax ; buffer address + + mov eax, [esp + 8] + and eax, DSIZE + or eax, 0x80000000 ; card owns descriptor + mov dword [ecx + 4], eax ; status field + + set_io 0 + set_io cr + in eax, dx + or eax, TxENA ; Enable the transmit state machine + out dx, eax + + inc [device.cur_tx] + and [device.cur_tx], NUM_TX_DESC-1 + +; update stats + mov ecx, [esp + 8] + inc [device.packets_tx] + add dword [device.bytes_tx], ecx + adc dword [device.bytes_tx + 4], 0 + + .finish: + DEBUGF 1,"Packet sent!\n" + xor eax, eax + ret 8 + + .error: + DEBUGF 1,"ERROR!\n" + stdcall KernelFree, [esp+4] + or eax, -1 + ret 8 + + +;*************************************************************************** +; +; int_handler +; +; handles received IRQs, which signal received packets +; +; Currently only supports one descriptor per packet, if packet is fragmented +; between multiple descriptors you will lose part of the packet +; +;*************************************************************************** + +align 4 +int_handler: + + push ebx esi edi + + DEBUGF 1,"\n%s int\n", my_service + +; find pointer of device which made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .nothing + mov esi, device_list + .nextdevice: + mov ebx, [esi] + + set_io 0 + set_io isr + in eax, dx ; note that this clears all interrupts + test ax, IE + jnz .got_it + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + .nothing: + pop edi esi ebx + xor eax, eax + + ret + + .got_it: + + DEBUGF 1,"Device: %x Status: %x ", ebx, ax + + test ax, RxOK + jz .no_rx_ + + push ax + + .rx_loop: + +;----------- +; Get Status + movzx eax, [device.cur_rx] ; find current descriptor + shl eax, 4 ; * 16 + mov ecx, dword[device.rxd + eax + 4] ; get receive status + +;------------------------------------------- +; Check RX_Status to see if packet is waiting + test ecx, 0x80000000 + jz .no_rx + +;---------------------------------------------- +; There is a packet waiting check it for errors + test ecx, 0x67C0000 ; see if there are any errors + jnz .error_status + +;--------------------- +; Check size of packet + and ecx, DSIZE ; get packet size minus CRC + sub ecx, CRC_SIZE ; make sure packet contains data + jbe .error_size + +; update statistics + inc dword [device.packets_rx] + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + + push ebx + push .return + push ecx ; packet size + pushd [device.rxd + eax + 12] ; packet ptr + DEBUGF 1, "Packet received OK\n" + jmp Eth_input + .return: + pop ebx + +; Reset status, allow ethernet card access to descriptor + stdcall KernelAlloc, RX_BUFF_SZ + test eax, eax + jz .fail + movzx ecx, [device.cur_rx] + shl ecx, 4 ; *16 + lea ecx, [device.rxd + ecx] + mov dword [ecx + 12], eax + GetRealAddr + mov dword [ecx + 8], eax + mov dword [ecx + 4], RX_BUFF_SZ + + inc [device.cur_rx] ; get next descriptor + and [device.cur_rx], NUM_RX_DESC-1 ; only 4 descriptors 0-3 + + jmp .rx_loop + + .no_rx: + set_io 0 + set_io cr + in eax, dx + or eax, RxENA ; Re-Enable the Receive state machine + out dx, eax + + pop ax + + .no_rx_: + test ax, TxOK + jz .no_tx + + DEBUGF 1, "TX ok!\n" + + .tx_loop: + movzx ecx, [device.last_tx] + shl ecx, 4 ; *16 + lea ecx, [device.txd + ecx] + + test dword [ecx + 4], 0x80000000 ; card owns descr + jnz .no_tx + cmp dword [ecx + 12], 0 + je .no_tx + + DEBUGF 1, "Freeing packet = %x\n", [ecx + 12]:8 + push dword [ecx + 12] + mov dword [ecx + 12], 0 + call KernelFree + + inc [device.last_tx] + and [device.last_tx], NUM_TX_DESC-1 + jmp .tx_loop + + .no_tx: + .fail: + pop edi esi ebx + xor eax, eax + inc eax + + ret + + ret + + .error_status: + DEBUGF 1, "Packet error: %x\n", ecx + jmp .fail + + .error_size: + DEBUGF 1, "Packet too large/small\n" + jmp .fail + + + + + +; End of code + +align 4 ; Place all initialised data here + +devices dd 0 + +specific_table: +; dd SIS630A_900_REV, Get_Mac_SIS630A_900_REV, 0 +; dd SIS630E_900_REV, Get_Mac_SIS630E_900_REV, 0 + dd SIS630S_900_REV, Get_Mac_SIS635_900_REV, 0 + dd SIS630EA1_900_REV, Get_Mac_SIS635_900_REV, 0 + dd SIS630ET_900_REV, Get_Mac_SIS635_900_REV, 0 ;SIS630ET_900_REV_SpecialFN + dd SIS635A_900_REV, Get_Mac_SIS635_900_REV, 0 + dd SIS900_960_REV, SIS960_get_mac_addr, 0 + dd SIS900B_900_REV, SIS900_get_mac_addr, 0 + dd 0 ; end of list + +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'SIS900',0 ; max 16 chars include zero + +include_debug_strings ; All data wich FDO uses will be included here + +section '.data' data readable writable align 16; place all uninitialized data place here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + diff --git a/drivers/fdo.inc b/drivers/fdo.inc new file mode 100644 index 0000000000..8ff75fff6e --- /dev/null +++ b/drivers/fdo.inc @@ -0,0 +1,432 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +; +; Formatted Debug Output (FDO) +; Copyright (c) 2005-2006, mike.dld +; Created: 2005-01-29, Changed: 2006-11-10 +; +; For questions and bug reports, mail to mike.dld@gmail.com +; +; Available format specifiers are: %s, %d, %u, %x (with partial width support) +; + +; to be defined: +; __DEBUG__ equ 1 +; __DEBUG_LEVEL__ equ 5 + +macro debug_func name { + if used name + name@of@func equ name +} + +macro debug_beginf { + align 4 + name@of@func: +} + +debug_endf fix end if + +macro DEBUGS _sign,[_str] { + common + local tp + tp equ 0 + match _arg:_num,_str \{ + DEBUGS_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _str \{ + DEBUGS_N _sign,,_arg + \} +} + +macro DEBUGS_N _sign,_num,[_str] { + common + pushf + pushad + local ..str,..label,is_str + is_str = 0 + forward + if _str eqtype '' + is_str = 1 + end if + common + if is_str = 1 + jmp ..label + ..str db _str,0 + ..label: + add esp,4*8+4 + mov edx,..str + sub esp,4*8+4 + else + mov edx,_str + end if + if ~_num eq + if _num eqtype eax + if _num in + mov esi,_num + else if ~_num eq esi + movzx esi,_num + end if + else if _num eqtype 0 + mov esi,_num + else + local tp + tp equ 0 + match [_arg],_num \{ + mov esi,dword[_arg] + tp equ 1 + \} + match =0 =dword[_arg],tp _num \{ + mov esi,dword[_arg] + tp equ 1 + \} + match =0 =word[_arg],tp _num \{ + movzx esi,word[_arg] + tp equ 1 + \} + match =0 =byte[_arg],tp _num \{ + movzx esi,byte[_arg] + tp equ 1 + \} + match =0,tp \{ + 'Error: specified string width is incorrect' + \} + end if + else + mov esi,0x7FFFFFFF + end if + call fdo_debug_outstr + popad + popf +} + +macro DEBUGD _sign,_dec { + local tp + tp equ 0 + match _arg:_num,_dec \{ + DEBUGD_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _dec \{ + DEBUGD_N _sign,,_arg + \} +} + +macro DEBUGD_N _sign,_num,_dec { + pushf + pushad + if (~_num eq) + if (_dec eqtype eax | _dec eqtype 0) + 'Error: precision allowed only for in-memory variables' + end if + if (~_num in <1,2,4>) + if _sign + 'Error: 1, 2 and 4 are only allowed for precision in %d' + else + 'Error: 1, 2 and 4 are only allowed for precision in %u' + end if + end if + end if + if _dec eqtype eax + if _dec in + mov eax,_dec + else if ~_dec eq eax + if _sign = 1 + movsx eax,_dec + else + movzx eax,_dec + end if + end if + else if _dec eqtype 0 + mov eax,_dec + else + add esp,4*8+4 + if _num eq + mov eax,dword _dec + else if _num = 1 + if _sign = 1 + movsx eax,byte _dec + else + movzx eax,byte _dec + end if + else if _num = 2 + if _sign = 1 + movsx eax,word _dec + else + movzx eax,word _dec + end if + else + mov eax,dword _dec + end if + sub esp,4*8+4 + end if + mov cl,_sign + call fdo_debug_outdec + popad + popf +} + +macro DEBUGH _sign,_hex { + local tp + tp equ 0 + match _arg:_num,_hex \{ + DEBUGH_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _hex \{ + DEBUGH_N _sign,,_arg + \} +} + +macro DEBUGH_N _sign,_num,_hex { + pushf + pushad + if (~_num eq) & (~_num in <1,2,3,4,5,6,7,8>) + 'Error: 1..8 are only allowed for precision in %x' + end if + if _hex eqtype eax + if _hex in + if ~_hex eq eax + mov eax,_hex + end if + mov edx,8 + else if _hex in + if ~_hex eq ax + movzx eax,_hex + end if + if (_num eq) + mov edx,4 + end if + else if _hex in + if ~_hex eq al + movzx eax,_hex + end if + if (_num eq) + mov edx,2 + end if + end if + else if _hex eqtype 0 + mov eax,_hex + else + add esp,4*8+4 + mov eax,dword _hex + sub esp,4*8+4 + end if + if ~_num eq + mov edx,_num + else + if ~_hex eqtype eax + mov edx,8 + end if + end if + call fdo_debug_outhex + popad + popf +} + +;----------------------------------------------------------------------------- + +debug_func fdo_debug_outchar +debug_beginf + pushad + movzx ebx,al + mov eax,1 +; mov ecx,sys_msg_board +; call ecx ; sys_msg_board + stdcall SysMsgBoardChar + popad + ret +debug_endf + +debug_func fdo_debug_outstr +debug_beginf + mov eax,1 + .l1: dec esi + js .l2 + movzx ebx,byte[edx] + or bl,bl + jz .l2 +; mov ecx,sys_msg_board +; call ecx ; sys_msg_board + stdcall SysMsgBoardChar + inc edx + jmp .l1 + .l2: ret +debug_endf + +debug_func fdo_debug_outdec +debug_beginf + or cl,cl + jz @f + or eax,eax + jns @f + neg eax + push eax + mov al,'-' + call fdo_debug_outchar + pop eax + @@: push 10 + pop ecx + push -'0' + .l1: xor edx,edx + div ecx + push edx + test eax,eax + jnz .l1 + .l2: pop eax + add al,'0' + jz .l3 + call fdo_debug_outchar + jmp .l2 + .l3: ret +debug_endf + +debug_func fdo_debug_outhex + __fdo_hexdigits db '0123456789ABCDEF' +debug_beginf + mov cl,dl + neg cl + add cl,8 + shl cl,2 + rol eax,cl + .l1: rol eax,4 + push eax + and eax,0x0000000F + mov al,[__fdo_hexdigits+eax] + call fdo_debug_outchar + pop eax + dec edx + jnz .l1 + ret +debug_endf + +;----------------------------------------------------------------------------- + +macro DEBUGF _level,_format,[_arg] { + common + if __DEBUG__ = 1 & _level >= __DEBUG_LEVEL__ + local ..f1,f2,a1,a2,c1,c2,c3,..lbl + _debug_str_ equ __debug_str_ # a1 + a1 = 0 + c2 = 0 + c3 = 0 + f2 = 0 + repeat ..lbl-..f1 + virtual at 0 + db _format,0,0 + load c1 word from %-1 + end virtual + if c1 = '%s' + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER S,a1,0,_arg + else if c1 = '%x' + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER H,a1,0,_arg + else if c1 = '%d' | c1 = '%u' + local c4 + if c1 = '%d' + c4 = 1 + else + c4 = 0 + end if + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER D,a1,c4,_arg + else if c1 = '\n' + c3 = c3 + 1 + end if + end repeat + virtual at 0 + db _format,0,0 + load c1 from f2-c2 + end virtual + if (c1<>0)&(f2<>..lbl-..f1-1) + DEBUGS 0,_debug_str_+f2-c2 + end if + virtual at 0 + ..f1 db _format,0 + ..lbl: + __debug_strings equ __debug_strings,_debug_str_,<_format>,..lbl-..f1-1-c2-c3 + end virtual + end if +} + +macro __include_debug_strings dummy,[_id,_fmt,_len] { + common + local c1,a1,a2 + forward + if defined _len & ~_len eq + _id: + a1 = 0 + a2 = 0 + repeat _len + virtual at 0 + db _fmt,0,0 + load c1 word from %+a2-1 + end virtual + if (c1='%s')|(c1='%x')|(c1='%d')|(c1='%u') + db 0 + a2 = a2 + 1 + else if (c1='\n') + dw $0A0D + a1 = a1 + 1 + a2 = a2 + 1 + else + db c1 and 0x0FF + end if + end repeat + db 0 + end if +} + +macro DEBUGF_HELPER _letter,_num,_sign,[_arg] { + common + local num + num = 0 + forward + if num = _num + DEBUG#_letter _sign,_arg + end if + num = num+1 + common + _num = _num+1 +} + +macro include_debug_strings { + if __DEBUG__ = 1 + match dbg_str,__debug_strings \{ + __include_debug_strings dbg_str + \} + end if +} diff --git a/drivers/imports.inc b/drivers/imports.inc index c9642c402b..f26fd9aa10 100644 --- a/drivers/imports.inc +++ b/drivers/imports.inc @@ -1,151 +1,102 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; all exported kernel functions and data - -if used RegService - extrn RegService -end if -if used GetService - extrn GetService -end if -if used ServiceHandler - extrn ServiceHandler -end if -if used AttachIntHandler - extrn AttachIntHandler -end if -if used FpuSave - extrn FpuSave -end if -if used FpuRestore - extrn FpuRestore -end if - -if used PciApi - extrn PciApi -end if -if used PciRead32 - extrn PciRead32 -end if -if used PciRead8 - extrn PciRead8 -end if -if used PciWrite8 - extrn PciWrite8 -end if - -if used AllocPage - extrn AllocPage -end if -if used AllocPages - extrn AllocPages -end if -if used FreePage - extrn FreePage -end if -if used MapPage - extrn MapPage -end if -if used MapSpace - extrn MapSpace -end if -if used GetPgAddr - extrn GetPgAddr -end if -if used CommitPages - extrn CommitPages -end if -if used ReleasePages - extrn ReleasePages -end if - -if used AllocKernelSpace - extrn AllocKernelSpace -end if -if used FreeKernelSpace - extrn FreeKernelSpace -end if -if used KernelAlloc - extrn KernelAlloc -end if -if used KernelFree - extrn KernelFree -end if -if used UserAlloc - extrn UserAlloc -end if -if used UserFree - extrn UserFree -end if -if used Kmalloc - extrn Kmalloc -end if -if used Kfree - extrn Kfree -end if - -if used CreateObject - extrn CreateObject -end if -if used DestroyObject - extrn DestroyObject -end if -if used CreateEvent - extrn CreateEvent -end if -if used RaiseEvent - extrn RaiseEvent -end if -if used WaitEvent - extrn WaitEvent -end if -if used DestroyEvent - extrn DestroyEvent -end if -if used ClearEvent - extrn ClearEvent -end if - -if used LoadCursor - extrn LoadCursor -end if -if used SetHwCursor - extrn SetHwCursor -end if -if used HwCursorRestore - extrn HwCursorRestore -end if -if used HwCursorCreate - extrn HwCursorCreate -end if - -if used SysMsgBoardStr - extrn SysMsgBoardStr -end if -if used GetCurrentTask - extrn GetCurrentTask -end if -if used LoadFile - extrn LoadFile -end if -if used SendEvent - extrn SendEvent -end if -if used SetMouseData - extrn SetMouseData -end if -if used Sleep - extrn Sleep -end if -if used GetTimerTicks - extrn GetTimerTicks -end if -if used LFBAddress - extrn LFBAddress -end if - +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +macro kernel_export [name]{ +forward + if used name + if DEBUG + display 'uses: ',`name,#13,#10 + end if + extrn name + end if +} +; all exported kernel functions and data + + +kernel_export \ + RegService,\ + GetService,\ + ServiceHandler,\ + AttachIntHandler,\ + GetIntHandler,\ + FpuSave,\ + FpuRestore,\ + ReservePortArea,\ + Boot_Log,\ +\ + MutexInit,\ + MutexLock,\ + MutexUnlock,\ +\ + PciApi,\ + PciRead32,\ + PciRead16,\ + PciRead8,\ + PciWrite8,\ + PciWrite16,\ + PciWrite32,\ +\ + AllocPage,\ + AllocPages,\ + FreePage,\ + MapPage,\ + MapSpace,\ + MapIoMem,\ + GetPgAddr,\ + CommitPages,\ + ReleasePages,\ +\ + AllocKernelSpace,\ + FreeKernelSpace,\ + KernelAlloc,\ + KernelFree,\ + UserAlloc,\ + UserFree,\ + Kmalloc,\ + Kfree,\ + CreateRingBuffer,\ +\ + GetPid,\ + CreateObject,\ + DestroyObject,\ + CreateEvent,\ + RaiseEvent,\ + WaitEvent,\ + DestroyEvent,\ + ClearEvent,\ +\ + LoadCursor,\ + SelectHwCursor,\ + SetHwCursor,\ + HwCursorRestore,\ + HwCursorCreate,\ +\ + SysMsgBoardStr,\ + SysMsgBoardChar,\ + GetCurrentTask,\ + LoadFile,\ + SendEvent,\ + SetMouseData,\ + Sleep,\ + GetTimerTicks,\ +\ + strncat,\ + strncpy,\ + strncmp,\ + strnlen,\ + strchr,\ + strrchr,\ +\ + LFBAddress,\ + GetDisplay,\ + SetScreen,\ +\ + NetRegDev,\ + NetUnRegDev,\ + NetPtrToNum,\ + NetLinkChanged,\ + Eth_input,\ + IPv4_input diff --git a/drivers/mii.inc b/drivers/mii.inc new file mode 100644 index 0000000000..566d6a3f35 --- /dev/null +++ b/drivers/mii.inc @@ -0,0 +1,160 @@ +; Generic MII registers. + + MII_BMCR = 0x00 ; Basic mode control register + MII_BMSR = 0x01 ; Basic mode status register + MII_PHYSID1 = 0x02 ; PHYS ID 1 + MII_PHYSID2 = 0x03 ; PHYS ID 2 + MII_ADVERTISE = 0x04 ; Advertisement control reg + MII_LPA = 0x05 ; Link partner ability reg + MII_EXPANSION = 0x06 ; Expansion register + MII_CTRL1000 = 0x09 ; 1000BASE-T control + MII_STAT1000 = 0x0a ; 1000BASE-T status + MII_ESTATUS = 0x0f ; Extended Status + MII_DCOUNTER = 0x12 ; Disconnect counter + MII_FCSCOUNTER = 0x13 ; False carrier counter + MII_NWAYTEST = 0x14 ; N-way auto-neg test reg + MII_RERRCOUNTER = 0x15 ; Receive error counter + MII_SREVISION = 0x16 ; Silicon revision + MII_RESV1 = 0x17 ; Reserved... + MII_LBRERROR = 0x18 ; Lpback, rx, bypass error + MII_PHYADDR = 0x19 ; PHY address + MII_RESV2 = 0x1a ; Reserved... + MII_TPISTATUS = 0x1b ; TPI status for 10mbps + MII_NCONFIG = 0x1c ; Network interface config + +; Basic mode control register. + + BMCR_RESV = 0x003f ; Unused... + BMCR_SPEED1000 = 0x0040 ; MSB of Speed (1000) + BMCR_CTST = 0x0080 ; Collision test + BMCR_FULLDPLX = 0x0100 ; Full duplex + BMCR_ANRESTART = 0x0200 ; Auto negotiation restart + BMCR_ISOLATE = 0x0400 ; Disconnect DP83840 from MII + BMCR_PDOWN = 0x0800 ; Powerdown the DP83840 + BMCR_ANENABLE = 0x1000 ; Enable auto negotiation + BMCR_SPEED100 = 0x2000 ; Select 100Mbps + BMCR_LOOPBACK = 0x4000 ; TXD loopback bits + BMCR_RESET = 0x8000 ; Reset the DP83840 + +; Basic mode status register. + + BMSR_ERCAP = 0x0001 ; Ext-reg capability + BMSR_JCD = 0x0002 ; Jabber detected + BMSR_LSTATUS = 0x0004 ; Link status + BMSR_ANEGCAPABLE = 0x0008 ; Able to do auto-negotiation + BMSR_RFAULT = 0x0010 ; Remote fault detected + BMSR_ANEGCOMPLETE = 0x0020 ; Auto-negotiation complete + BMSR_RESV = 0x00c0 ; Unused... + BMSR_ESTATEN = 0x0100 ; Extended Status in R15 + BMSR_100HALF2 = 0x0200 ; Can do 100BASE-T2 HDX + BMSR_100FULL2 = 0x0400 ; Can do 100BASE-T2 FDX + BMSR_10HALF = 0x0800 ; Can do 10mbps, half-duplex + BMSR_10FULL = 0x1000 ; Can do 10mbps, full-duplex + BMSR_100HALF = 0x2000 ; Can do 100mbps, half-duplex + BMSR_100FULL = 0x4000 ; Can do 100mbps, full-duplex + BMSR_100BASE4 = 0x8000 ; Can do 100mbps, 4k packets + +; Advertisement control register. + + ADVERTISE_SLCT = 0x001f ; Selector bits + ADVERTISE_CSMA = 0x0001 ; Only selector supported + ADVERTISE_10HALF = 0x0020 ; Try for 10mbps half-duplex + ADVERTISE_1000XFULL = 0x0020 ; Try for 1000BASE-X full-duplex + ADVERTISE_10FULL = 0x0040 ; Try for 10mbps full-duplex + ADVERTISE_1000XHALF = 0x0040 ; Try for 1000BASE-X half-duplex + ADVERTISE_100HALF = 0x0080 ; Try for 100mbps half-duplex + ADVERTISE_1000XPAUSE = 0x0080 ; Try for 1000BASE-X pause + ADVERTISE_100FULL = 0x0100 ; Try for 100mbps full-duplex + ADVERTISE_1000XPSE_ASYM = 0x0100 ; Try for 1000BASE-X asym pause + ADVERTISE_100BASE4 = 0x0200 ; Try for 100mbps 4k packets + ADVERTISE_PAUSE_CAP = 0x0400 ; Try for pause + ADVERTISE_PAUSE_ASYM = 0x0800 ; Try for asymetric pause + ADVERTISE_RESV = 0x1000 ; Unused... + ADVERTISE_RFAULT = 0x2000 ; Say we can detect faults + ADVERTISE_LPACK = 0x4000 ; Ack link partners response + ADVERTISE_NPAGE = 0x8000 ; Next page bit + + ADVERTISE_FULL = (ADVERTISE_100FULL or ADVERTISE_10FULL or ADVERTISE_CSMA) + ADVERTISE_ALL = (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL) + +; Link partner ability register. + + LPA_SLCT = 0x001f ; Same as advertise selector + LPA_10HALF = 0x0020 ; Can do 10mbps half-duplex + LPA_1000XFULL = 0x0020 ; Can do 1000BASE-X full-duplex + LPA_10FULL = 0x0040 ; Can do 10mbps full-duplex + LPA_1000XHALF = 0x0040 ; Can do 1000BASE-X half-duplex + LPA_100HALF = 0x0080 ; Can do 100mbps half-duplex + LPA_1000XPAUSE = 0x0080 ; Can do 1000BASE-X pause + LPA_100FULL = 0x0100 ; Can do 100mbps full-duplex + LPA_1000XPAUSE_ASYM = 0x0100 ; Can do 1000BASE-X pause asym + LPA_100BASE4 = 0x0200 ; Can do 100mbps 4k packets + LPA_PAUSE_CAP = 0x0400 ; Can pause + LPA_PAUSE_ASYM = 0x0800 ; Can pause asymetrically + LPA_RESV = 0x1000 ; Unused... + LPA_RFAULT = 0x2000 ; Link partner faulted + LPA_LPACK = 0x4000 ; Link partner acked us + LPA_NPAGE = 0x8000 ; Next page bit + + LPA_DUPLEX = (LPA_10FULL or LPA_100FULL) + LPA_100 = (LPA_100FULL or LPA_100HALF or LPA_100BASE4) + +; Expansion register for auto-negotiation. + + EXPANSION_NWAY = 0x0001 ; Can do N-way auto-nego + EXPANSION_LCWP = 0x0002 ; Got new RX page code word + EXPANSION_ENABLENPAGE = 0x0004 ; This enables npage words + EXPANSION_NPCAPABLE = 0x0008 ; Link partner supports npage + EXPANSION_MFAULTS = 0x0010 ; Multiple faults detected + EXPANSION_RESV = 0xffe0 ; Unused... + + ESTATUS_1000_TFULL = 0x2000 ; Can do 1000BT Full + ESTATUS_1000_THALF = 0x1000 ; Can do 1000BT Half + +; N-way test register. + + NWAYTEST_RESV1 = 0x00ff ; Unused... + NWAYTEST_LOOPBACK = 0x0100 ; Enable loopback for N-way + NWAYTEST_RESV2 = 0xfe00 ; Unused... + +; 1000BASE-T Control register + + ADVERTISE_1000FULL = 0x0200 ; Advertise 1000BASE-T full duplex + ADVERTISE_1000HALF = 0x0100 ; Advertise 1000BASE-T half duplex + +; 1000BASE-T Status register + + LPA_1000LOCALRXOK = 0x2000 ; Link partner local receiver status + LPA_1000REMRXOK = 0x1000 ; Link partner remote receiver status + LPA_1000FULL = 0x0800 ; Link partner 1000BASE-T full duplex + LPA_1000HALF = 0x0400 ; Link partner 1000BASE-T half duplex + +; Flow control flags + + FLOW_CTRL_TX = 0x01 + FLOW_CTRL_RX = 0x02 + + + +if used mii_link_ok + +align 4 +mii_link_ok: + + DEBUGF 1, "mii_link_ok\n" + +; First do a dummy read to latch some MII phys + + mov ecx, MII_BMSR + call mdio_read + + mov ecx, MII_BMSR + call mdio_read + + and ax, BMSR_LSTATUS + + DEBUGF 1, "link status=0x%x\n", ax + + ret + +end if \ No newline at end of file diff --git a/drivers/netdrv.inc b/drivers/netdrv.inc new file mode 100644 index 0000000000..d074c1b5b9 --- /dev/null +++ b/drivers/netdrv.inc @@ -0,0 +1,150 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +include 'pci.inc' +include 'mii.inc' + +; Kernel variables + + PAGESIZE = 4096 + PG_SW = 0x003 + PG_NOCACHE = 0x018 + + +; network driver types + + NET_TYPE_ETH = 1 + NET_TYPE_SLIP = 2 + +; link state + + ETH_LINK_DOWN = 0 ; Link is down + ETH_LINK_UNKOWN = 1b ; There could be an active link + ETH_LINK_FD = 10b ; full duplex flag + ETH_LINK_10M = 100b ; 10 mbit + ETH_LINK_100M = 1000b ; 100 mbit + ETH_LINK_1G = 10000b ; gigabit + + + LAST_IO = 0 +macro set_io addr { + + if addr = 0 + mov edx, [device.io_addr] + else if addr = LAST_IO + else + add edx, addr - LAST_IO + end if + + LAST_IO = addr +} + +macro allocate_and_clear dest, size, err { + +; We need to allocate at least 8 pages, if we want a continuous memory in ram + push edx + if (size < 8*4096) & (size > 4096) + stdcall KernelAlloc, 8*4096 + else + stdcall KernelAlloc, size + end if + pop edx + + test eax, eax + jz err + mov dest, eax ; Save the address to it into the device struct + mov edi, eax ; look at last part of code! + +; Release the unused pages (if any) + if (size < 8*4096) & (size > 4096) + add eax, (size/4096+1)*4096 + mov ecx, 8-(size/4096+1) + push edx + call ReleasePages + pop edx + end if + +; Clear the allocated buffer + mov ecx, size/4 ; divide by 4 because of DWORD + xor eax, eax + rep stosd + +} + +struc IOCTL { + .handle dd ? + .io_code dd ? + .input dd ? + .inp_size dd ? + .output dd ? + .out_size dd ? +} + +virtual at edx + IOCTL IOCTL +end virtual + + +if used null_op +align 4 +null_op: + or eax, -1 + ret + +end if + + +macro GetRealAddr { ; input and output is eax + + push ax + call GetPgAddr + and word[esp], PAGESIZE - 1 + or ax, word[esp] + inc esp + inc esp + +} + +macro NET_DEVICE { + + .type dd ? ; Type field + .mtu dd ? ; Maximal Transmission Unit + .name dd ? ; Ptr to 0 terminated string + + .unload dd ? ; Ptrs to driver functions + .reset dd ? ; + .transmit dd ? ; + + .bytes_tx dq ? ; Statistics, updated by the driver + .bytes_rx dq ? ; + .packets_tx dd ? ; + .packets_rx dd ? ; + + .state dd ? ; link state (0 = no link) + .hwacc dd ? ; bitmask stating enabled HW accelerations + + .end: +} + + +macro ETH_DEVICE { + NET_DEVICE + + .mac dp ? + dw ? ; qword alignment + +} + + + +macro SLIP_DEVICE { + NET_DEVICE + +} \ No newline at end of file diff --git a/drivers/pci.inc b/drivers/pci.inc new file mode 100644 index 0000000000..577483d85a --- /dev/null +++ b/drivers/pci.inc @@ -0,0 +1,132 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +; PCI Bus defines + + PCI_HEADER_TYPE = 0x0e ; 8 bit + PCI_BASE_ADDRESS_0 = 0x10 ; 32 bit + PCI_BASE_ADDRESS_1 = 0x14 ; 32 bits + PCI_BASE_ADDRESS_2 = 0x18 ; 32 bits + PCI_BASE_ADDRESS_3 = 0x1c ; 32 bits + PCI_BASE_ADDRESS_4 = 0x20 ; 32 bits + PCI_BASE_ADDRESS_5 = 0x24 ; 32 bits + PCI_BASE_ADDRESS_SPACE_IO = 0x01 + PCI_BASE_ADDRESS_IO_MASK = 0xFFFFFFFC + PCI_BASE_ADDRESS_MEM_MASK = 0xFFFFFFF0 + +; PCI programming + + PCI_VENDOR_ID = 0x00 ; 16 bit + PCI_DEVICE_ID = 0x02 ; 16 bits + PCI_REG_COMMAND = 0x4 ; command register + PCI_REG_STATUS = 0x6 ; status register + PCI_REVISION_ID = 0x08 ; 8 bits + PCI_REG_LATENCY = 0xd ; latency timer register + PCI_REG_CAP_PTR = 0x34 ; capabilities pointer + PCI_REG_IRQ = 0x3c + PCI_REG_CAPABILITY_ID = 0x0 ; capapility ID in pm register block + PCI_REG_PM_STATUS = 0x4 ; power management status register + PCI_REG_PM_CTRL = 0x4 ; power management control register + PCI_BIT_PIO = 1 ; bit0: io space control + PCI_BIT_MMIO = 2 ; bit1: memory space control + PCI_BIT_MASTER = 4 ; bit2: device acts as a PCI master + + +macro PCI_find_io { + + local .check, .inc, .got + + xor eax, eax + mov esi, PCI_BASE_ADDRESS_0 + .check: + stdcall PciRead32, [device.pci_bus], [device.pci_dev], esi + + test eax, PCI_BASE_ADDRESS_IO_MASK + jz .inc + + test eax, PCI_BASE_ADDRESS_SPACE_IO + jz .inc + + and eax, PCI_BASE_ADDRESS_IO_MASK + jmp .got + + .inc: + add esi, 4 + cmp esi, PCI_BASE_ADDRESS_5 + jbe .check + xor eax, eax + + .got: + mov [device.io_addr], eax + +} + + +macro PCI_find_mmio32 { + + local .check, .inc, .got + + mov esi, PCI_BASE_ADDRESS_0 + .check: + stdcall PciRead32, [device.pci_bus], [device.pci_dev], esi + + test eax, PCI_BASE_ADDRESS_SPACE_IO ; mmio address? + jnz .inc + + test eax, 100b ; 64 bit? + jnz .inc + and eax, not 1111b + jmp .got + + .inc: + add esi, 4 + cmp esi, PCI_BASE_ADDRESS_5 + jbe .check + xor eax, eax + + .got: + mov [device.mmio_addr], eax +} + +macro PCI_find_irq { + + stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REG_IRQ + mov [device.irq_line], al + +} + +macro PCI_find_rev { + + stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REVISION_ID + mov [device.revision], al + +} + +macro PCI_make_bus_master bus, dev { + + stdcall PciRead32, [device.pci_bus], [device.pci_dev], PCI_REG_COMMAND + or al, PCI_BIT_MASTER + stdcall PciWrite32, [device.pci_bus], [device.pci_dev], PCI_REG_COMMAND, eax + +} + +macro PCI_adjust_latency min { + + local .not + + stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REG_LATENCY + cmp al, min + ja .not + mov al, min + stdcall PciWrite8, [device.pci_bus], [device.pci_dev], PCI_REG_LATENCY, eax + .not: + +} diff --git a/drivers/proc32.inc b/drivers/proc32.inc index 98a1bd3342..f20c7bc796 100644 --- a/drivers/proc32.inc +++ b/drivers/proc32.inc @@ -1,268 +1,268 @@ - -; Macroinstructions for defining and calling procedures - -macro stdcall proc,[arg] ; directly call STDCALL procedure - { common - if ~ arg eq - reverse - pushd arg - common - end if - call proc } - -macro invoke proc,[arg] ; indirectly call STDCALL procedure - { common - if ~ arg eq - reverse - pushd arg - common - end if - call [proc] } - -macro ccall proc,[arg] ; directly call CDECL procedure - { common - size@ccall = 0 - if ~ arg eq - reverse - pushd arg - size@ccall = size@ccall+4 - common - end if - call proc - if size@ccall - add esp,size@ccall - end if } - -macro cinvoke proc,[arg] ; indirectly call CDECL procedure - { common - size@ccall = 0 - if ~ arg eq - reverse - pushd arg - size@ccall = size@ccall+4 - common - end if - call [proc] - if size@ccall - add esp,size@ccall - end if } - -macro proc [args] ; define procedure - { common - match name params, args> - \{ define@proc name, \{ prologue name,flag,parmbytes,localbytes,reglist \} - macro locals - \{ virtual at ebp-localbytes+current - macro label . \\{ deflocal@proc .,:, \\} - struc db [val] \\{ \common deflocal@proc .,db,val \\} - struc dw [val] \\{ \common deflocal@proc .,dw,val \\} - struc dp [val] \\{ \common deflocal@proc .,dp,val \\} - struc dd [val] \\{ \common deflocal@proc .,dd,val \\} - struc dt [val] \\{ \common deflocal@proc .,dt,val \\} - struc dq [val] \\{ \common deflocal@proc .,dq,val \\} - struc rb cnt \\{ deflocal@proc .,rb cnt, \\} - struc rw cnt \\{ deflocal@proc .,rw cnt, \\} - struc rp cnt \\{ deflocal@proc .,rp cnt, \\} - struc rd cnt \\{ deflocal@proc .,rd cnt, \\} - struc rt cnt \\{ deflocal@proc .,rt cnt, \\} - struc rq cnt \\{ deflocal@proc .,rq cnt, \\} \} - macro endl - \{ purge label - restruc db,dw,dp,dd,dt,dq - restruc rb,rw,rp,rd,rt,rq - restruc byte,word,dword,pword,tword,qword - current = $-(ebp-localbytes) - end virtual \} - macro ret operand - \{ match any, operand \\{ retn operand \\} - match , operand \\{ match epilogue:reglist, epilogue@proc: - \\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \} - macro finish@proc \{ localbytes = (((current-1) shr 2)+1) shl 2 - end if \} } - -macro defargs@proc [arg] - { common - if ~ arg eq - forward - local ..arg,current@arg - match argname:type, arg - \{ current@arg equ argname - label ..arg type - argname equ ..arg - if dqword eq type - dd ?,?,?,? - else if tbyte eq type - dd ?,?,? - else if qword eq type | pword eq type - dd ?,? - else - dd ? - end if \} - match =current@arg,current@arg - \{ current@arg equ arg - arg equ ..arg - ..arg dd ? \} - common - args@proc equ current@arg - forward - restore current@arg - common - end if } - -macro deflocal@proc name,def,[val] - { common - match vars, all@vars \{ all@vars equ all@vars, \} - all@vars equ all@vars name - forward - local ..var,..tmp - ..var def val - match =?, val \{ ..tmp equ \} - match any =dup (=?), val \{ ..tmp equ \} - match tmp : value, ..tmp : val - \{ tmp: end virtual - initlocal@proc ..var,def value - virtual at tmp\} - common - match first rest, ..var, \{ name equ first \} } - -macro initlocal@proc name,def - { virtual at name - def - size@initlocal = $ - name - end virtual - position@initlocal = 0 - while size@initlocal > position@initlocal - virtual at name - def - if size@initlocal - position@initlocal < 2 - current@initlocal = 1 - load byte@initlocal byte from name+position@initlocal - else if size@initlocal - position@initlocal < 4 - current@initlocal = 2 - load word@initlocal word from name+position@initlocal - else - current@initlocal = 4 - load dword@initlocal dword from name+position@initlocal - end if - end virtual - if current@initlocal = 1 - mov byte [name+position@initlocal],byte@initlocal - else if current@initlocal = 2 - mov word [name+position@initlocal],word@initlocal - else - mov dword [name+position@initlocal],dword@initlocal - end if - position@initlocal = position@initlocal + current@initlocal - end while } - -macro endp - { purge ret,locals,endl - finish@proc - purge finish@proc - restore regs@proc - match all,args@proc \{ restore all \} - restore args@proc - match all,all@vars \{ restore all \} } - -macro local [var] - { common - locals - forward done@local equ - match varname[count]:vartype, var - \{ match =BYTE, vartype \\{ varname rb count - restore done@local \\} - match =WORD, vartype \\{ varname rw count - restore done@local \\} - match =DWORD, vartype \\{ varname rd count - restore done@local \\} - match =PWORD, vartype \\{ varname rp count - restore done@local \\} - match =QWORD, vartype \\{ varname rq count - restore done@local \\} - match =TBYTE, vartype \\{ varname rt count - restore done@local \\} - match =DQWORD, vartype \\{ label varname dqword - rq count+count - restore done@local \\} - match , done@local \\{ virtual - varname vartype - end virtual - rb count*sizeof.\#vartype - restore done@local \\} \} - match :varname:vartype, done@local:var - \{ match =BYTE, vartype \\{ varname db ? - restore done@local \\} - match =WORD, vartype \\{ varname dw ? - restore done@local \\} - match =DWORD, vartype \\{ varname dd ? - restore done@local \\} - match =PWORD, vartype \\{ varname dp ? - restore done@local \\} - match =QWORD, vartype \\{ varname dq ? - restore done@local \\} - match =TBYTE, vartype \\{ varname dt ? - restore done@local \\} - match =DQWORD, vartype \\{ label varname dqword - dq ?,? - restore done@local \\} - match , done@local \\{ varname vartype - restore done@local \\} \} - match ,done@local - \{ var - restore done@local \} - common - endl } + +; Macroinstructions for defining and calling procedures + +macro stdcall proc,[arg] ; directly call STDCALL procedure + { common + if ~ arg eq + reverse + pushd arg + common + end if + call proc } + +macro invoke proc,[arg] ; indirectly call STDCALL procedure + { common + if ~ arg eq + reverse + pushd arg + common + end if + call [proc] } + +macro ccall proc,[arg] ; directly call CDECL procedure + { common + size@ccall = 0 + if ~ arg eq + reverse + pushd arg + size@ccall = size@ccall+4 + common + end if + call proc + if size@ccall + add esp,size@ccall + end if } + +macro cinvoke proc,[arg] ; indirectly call CDECL procedure + { common + size@ccall = 0 + if ~ arg eq + reverse + pushd arg + size@ccall = size@ccall+4 + common + end if + call [proc] + if size@ccall + add esp,size@ccall + end if } + +macro proc [args] ; define procedure + { common + match name params, args> + \{ define@proc name, \{ prologue name,flag,parmbytes,localbytes,reglist \} + macro locals + \{ virtual at ebp-localbytes+current + macro label . \\{ deflocal@proc .,:, \\} + struc db [val] \\{ \common deflocal@proc .,db,val \\} + struc dw [val] \\{ \common deflocal@proc .,dw,val \\} + struc dp [val] \\{ \common deflocal@proc .,dp,val \\} + struc dd [val] \\{ \common deflocal@proc .,dd,val \\} + struc dt [val] \\{ \common deflocal@proc .,dt,val \\} + struc dq [val] \\{ \common deflocal@proc .,dq,val \\} + struc rb cnt \\{ deflocal@proc .,rb cnt, \\} + struc rw cnt \\{ deflocal@proc .,rw cnt, \\} + struc rp cnt \\{ deflocal@proc .,rp cnt, \\} + struc rd cnt \\{ deflocal@proc .,rd cnt, \\} + struc rt cnt \\{ deflocal@proc .,rt cnt, \\} + struc rq cnt \\{ deflocal@proc .,rq cnt, \\} \} + macro endl + \{ purge label + restruc db,dw,dp,dd,dt,dq + restruc rb,rw,rp,rd,rt,rq + restruc byte,word,dword,pword,tword,qword + current = $-(ebp-localbytes) + end virtual \} + macro ret operand + \{ match any, operand \\{ retn operand \\} + match , operand \\{ match epilogue:reglist, epilogue@proc: + \\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \} + macro finish@proc \{ localbytes = (((current-1) shr 2)+1) shl 2 + end if \} } + +macro defargs@proc [arg] + { common + if ~ arg eq + forward + local ..arg,current@arg + match argname:type, arg + \{ current@arg equ argname + label ..arg type + argname equ ..arg + if dqword eq type + dd ?,?,?,? + else if tbyte eq type + dd ?,?,? + else if qword eq type | pword eq type + dd ?,? + else + dd ? + end if \} + match =current@arg,current@arg + \{ current@arg equ arg + arg equ ..arg + ..arg dd ? \} + common + args@proc equ current@arg + forward + restore current@arg + common + end if } + +macro deflocal@proc name,def,[val] + { common + match vars, all@vars \{ all@vars equ all@vars, \} + all@vars equ all@vars name + forward + local ..var,..tmp + ..var def val + match =?, val \{ ..tmp equ \} + match any =dup (=?), val \{ ..tmp equ \} + match tmp : value, ..tmp : val + \{ tmp: end virtual + initlocal@proc ..var,def value + virtual at tmp\} + common + match first rest, ..var, \{ name equ first \} } + +macro initlocal@proc name,def + { virtual at name + def + size@initlocal = $ - name + end virtual + position@initlocal = 0 + while size@initlocal > position@initlocal + virtual at name + def + if size@initlocal - position@initlocal < 2 + current@initlocal = 1 + load byte@initlocal byte from name+position@initlocal + else if size@initlocal - position@initlocal < 4 + current@initlocal = 2 + load word@initlocal word from name+position@initlocal + else + current@initlocal = 4 + load dword@initlocal dword from name+position@initlocal + end if + end virtual + if current@initlocal = 1 + mov byte [name+position@initlocal],byte@initlocal + else if current@initlocal = 2 + mov word [name+position@initlocal],word@initlocal + else + mov dword [name+position@initlocal],dword@initlocal + end if + position@initlocal = position@initlocal + current@initlocal + end while } + +macro endp + { purge ret,locals,endl + finish@proc + purge finish@proc + restore regs@proc + match all,args@proc \{ restore all \} + restore args@proc + match all,all@vars \{ restore all \} } + +macro local [var] + { common + locals + forward done@local equ + match varname[count]:vartype, var + \{ match =BYTE, vartype \\{ varname rb count + restore done@local \\} + match =WORD, vartype \\{ varname rw count + restore done@local \\} + match =DWORD, vartype \\{ varname rd count + restore done@local \\} + match =PWORD, vartype \\{ varname rp count + restore done@local \\} + match =QWORD, vartype \\{ varname rq count + restore done@local \\} + match =TBYTE, vartype \\{ varname rt count + restore done@local \\} + match =DQWORD, vartype \\{ label varname dqword + rq count+count + restore done@local \\} + match , done@local \\{ virtual + varname vartype + end virtual + rb count*sizeof.\#vartype + restore done@local \\} \} + match :varname:vartype, done@local:var + \{ match =BYTE, vartype \\{ varname db ? + restore done@local \\} + match =WORD, vartype \\{ varname dw ? + restore done@local \\} + match =DWORD, vartype \\{ varname dd ? + restore done@local \\} + match =PWORD, vartype \\{ varname dp ? + restore done@local \\} + match =QWORD, vartype \\{ varname dq ? + restore done@local \\} + match =TBYTE, vartype \\{ varname dt ? + restore done@local \\} + match =DQWORD, vartype \\{ label varname dqword + dq ?,? + restore done@local \\} + match , done@local \\{ varname vartype + restore done@local \\} \} + match ,done@local + \{ var + restore done@local \} + common + endl } diff --git a/drivers/struct.inc b/drivers/struct.inc new file mode 100644 index 0000000000..909a4f72c0 --- /dev/null +++ b/drivers/struct.inc @@ -0,0 +1,240 @@ + +; Macroinstructions for defining data structures + +macro struct name + { virtual at 0 + fields@struct equ name + match child parent, name \{ fields@struct equ child,fields@\#parent \} + sub@struct equ + struc db [val] \{ \common define field@struct .,db, + fields@struct equ fields@struct,field@struct \} + struc dw [val] \{ \common define field@struct .,dw, + fields@struct equ fields@struct,field@struct \} + struc du [val] \{ \common define field@struct .,du, + fields@struct equ fields@struct,field@struct \} + struc dd [val] \{ \common define field@struct .,dd, + fields@struct equ fields@struct,field@struct \} + struc dp [val] \{ \common define field@struct .,dp, + fields@struct equ fields@struct,field@struct \} + struc dq [val] \{ \common define field@struct .,dq, + fields@struct equ fields@struct,field@struct \} + struc dt [val] \{ \common define field@struct .,dt, + fields@struct equ fields@struct,field@struct \} + struc rb count \{ define field@struct .,db,count dup (?) + fields@struct equ fields@struct,field@struct \} + struc rw count \{ define field@struct .,dw,count dup (?) + fields@struct equ fields@struct,field@struct \} + struc rd count \{ define field@struct .,dd,count dup (?) + fields@struct equ fields@struct,field@struct \} + struc rp count \{ define field@struct .,dp,count dup (?) + fields@struct equ fields@struct,field@struct \} + struc rq count \{ define field@struct .,dq,count dup (?) + fields@struct equ fields@struct,field@struct \} + struc rt count \{ define field@struct .,dt,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro db [val] \{ \common \local anonymous + define field@struct anonymous,db, + fields@struct equ fields@struct,field@struct \} + macro dw [val] \{ \common \local anonymous + define field@struct anonymous,dw, + fields@struct equ fields@struct,field@struct \} + macro du [val] \{ \common \local anonymous + define field@struct anonymous,du, + fields@struct equ fields@struct,field@struct \} + macro dd [val] \{ \common \local anonymous + define field@struct anonymous,dd, + fields@struct equ fields@struct,field@struct \} + macro dp [val] \{ \common \local anonymous + define field@struct anonymous,dp, + fields@struct equ fields@struct,field@struct \} + macro dq [val] \{ \common \local anonymous + define field@struct anonymous,dq, + fields@struct equ fields@struct,field@struct \} + macro dt [val] \{ \common \local anonymous + define field@struct anonymous,dt, + fields@struct equ fields@struct,field@struct \} + macro rb count \{ \local anonymous + define field@struct anonymous,db,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro rw count \{ \local anonymous + define field@struct anonymous,dw,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro rd count \{ \local anonymous + define field@struct anonymous,dd,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro rp count \{ \local anonymous + define field@struct anonymous,dp,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro rq count \{ \local anonymous + define field@struct anonymous,dq,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro rt count \{ \local anonymous + define field@struct anonymous,dt,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro union \{ fields@struct equ fields@struct,,union,< + sub@struct equ union \} + macro struct \{ fields@struct equ fields@struct,,substruct,< + sub@struct equ substruct \} } + +macro ends + { match , sub@struct \{ restruc db,dw,du,dd,dp,dq,dt + restruc rb,rw,rd,rp,rq,rt + purge db,dw,du,dd,dp,dq,dt + purge rb,rw,rd,rp,rq,rt + purge union,struct + match name tail,fields@struct, \\{ if $ + display 'Error: definition of ',\\`name,' contains illegal instructions.',0Dh,0Ah + err + end if \\} + match name=,fields,fields@struct \\{ fields@struct equ + make@struct name,fields + define fields@\\#name fields \\} + end virtual \} + match any, sub@struct \{ fields@struct equ fields@struct> \} + restore sub@struct } + +macro make@struct name,[field,type,def] + { common + local define + define equ name + forward + local sub + match , field \{ make@substruct type,name,sub def + define equ define,.,sub, \} + match any, field \{ define equ define,.#field,type, \} + common + match fields, define \{ define@struct fields \} } + +macro define@struct name,[field,type,def] + { common + virtual + db `name + load initial@struct byte from 0 + if initial@struct = '.' + display 'Error: name of structure should not begin with a dot.',0Dh,0Ah + err + end if + end virtual + local list + list equ + forward + if ~ field eq . + name#field type def + sizeof.#name#field = $ - name#field + else + label name#.#type + rb sizeof.#type + end if + local value + match any, list \{ list equ list, \} + list equ list + common + sizeof.#name = $ + restruc name + match values, list \{ + struc name value \\{ \\local \\..base + match any, fields@struct \\\{ fields@struct equ fields@struct,.,name, \\\} + match , fields@struct \\\{ label \\..base + forward + match , value \\\\{ field type def \\\\} + match any, value \\\\{ field type value + if ~ field eq . + rb sizeof.#name#field - ($-field) + end if \\\\} + common label . at \\..base \\\} + \\} + macro name value \\{ + match any, fields@struct \\\{ \\\local anonymous + fields@struct equ fields@struct,anonymous,name, \\\} + match , fields@struct \\\{ + forward + match , value \\\\{ type def \\\\} + match any, value \\\\{ \\\\local ..field + ..field = $ + type value + if ~ field eq . + rb sizeof.#name#field - ($-..field) + end if \\\\} + common \\\} \\} \} } + +macro enable@substruct + { macro make@substruct substruct,parent,name,[field,type,def] + \{ \common + \local define + define equ parent,name + \forward + \local sub + match , field \\{ match any, type \\\{ enable@substruct + make@substruct type,parent,sub def + purge make@substruct + define equ define,.,sub, \\\} \\} + match any, field \\{ define equ define,.\#field,type, \\} + \common + match fields, define \\{ define@\#substruct fields \\} \} } + +enable@substruct + +macro define@union parent,name,[field,type,def] + { common + virtual at parent#.#name + forward + if ~ field eq . + virtual at parent#.#name + parent#field type def + sizeof.#parent#field = $ - parent#field + end virtual + if sizeof.#parent#field > $ - parent#.#name + rb sizeof.#parent#field - ($ - parent#.#name) + end if + else + virtual at parent#.#name + label parent#.#type + type def + end virtual + label name#.#type at parent#.#name + if sizeof.#type > $ - parent#.#name + rb sizeof.#type - ($ - parent#.#name) + end if + end if + common + sizeof.#name = $ - parent#.#name + end virtual + struc name [value] \{ \common + label .\#name + last@union equ + forward + match any, last@union \\{ virtual at .\#name + field type def + end virtual \\} + match , last@union \\{ match , value \\\{ field type def \\\} + match any, value \\\{ field type value \\\} \\} + last@union equ field + common rb sizeof.#name - ($ - .\#name) \} + macro name [value] \{ \common \local ..anonymous + ..anonymous name value \} } + +macro define@substruct parent,name,[field,type,def] + { common + virtual at parent#.#name + forward + if ~ field eq . + parent#field type def + sizeof.#parent#field = $ - parent#field + else + label parent#.#type + rb sizeof.#type + end if + common + sizeof.#name = $ - parent#.#name + end virtual + struc name value \{ + label .\#name + forward + match , value \\{ field type def \\} + match any, value \\{ field type value + if ~ field eq . + rb sizeof.#parent#field - ($-field) + end if \\} + common \} + macro name value \{ \local ..anonymous + ..anonymous name \} } diff --git a/kernel/branches/net/applications/downloader/downloader.asm b/kernel/branches/net/applications/downloader/downloader.asm new file mode 100644 index 0000000000..7c92b1a8b4 --- /dev/null +++ b/kernel/branches/net/applications/downloader/downloader.asm @@ -0,0 +1,1201 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2009-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; downloader.asm - HTTP client for KolibriOS ;; +;; ;; +;; Based on HTTPC.asm for menuetos by ville turjanmaa ;; +;; ;; +;; Programmers: Barsuk, Clevermouse, Marat Zakiyanov, ;; +;; Kirill Lipatov, dunkaist, HidnPlayr ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +URLMAXLEN = 1024 +primary_buffer_size = 4096 + +__DEBUG__ = 1 +__DEBUG_LEVEL__ = 1 + +format binary as "" + +use32 + org 0x0 + + db 'MENUET01' ; header + dd 0x01 ; header version + dd START ; entry point + dd IM_END ; image size + dd I_END ; required memory + dd I_END ; esp + dd params ; I_PARAM + dd 0x0 ; I_Path + +include '../macros.inc' +include '../proc32.inc' +include '../network.inc' +include '../../../../../programs/develop/libraries/box_lib/trunk/box_lib.mac' +include '../dll.inc' +include '../debug-fdo.inc' + +START: + + mcall 68, 11 ; init heap so we can allocate memory dynamically + + mcall 40, EV_STACK + +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit + +; prepare webAddr area + + mov al, ' ' + mov edi, webAddr + mov ecx, URLMAXLEN + rep stosb + xor eax, eax + stosb + +; prepare document area + mov al, '/' + mov edi, document + stosb + mov al, ' ' + mov ecx, URLMAXLEN-1 + rep stosb + + call load_settings + cmp byte[params], 0 + je prepare_event ;red + +; we have an url + mov edi, document_user + mov al, ' ' + mov ecx, URLMAXLEN + rep stosb + + mov esi, params + mov edi, document_user + +; copy untill space or 0 + .copy_param: + mov al, [esi] + test al, al + jz .done + + cmp al, ' ' + jz .done_inc + + mov [edi], al + inc esi + inc edi + jmp .copy_param + + .done_inc: + +; url is followed by shared memory name. + inc esi + .done: + mov [shared_name], esi + + mov ah, 22 ; strange way to tell that socket should be opened... + call socket_commands + + jmp still + +prepare_event: +; Report events +; Stack 8 + defaults + mcall 40, 10100111b + +red: ; redraw + call draw_window + +still: + mcall 23, 1 ; wait here for event + cmp eax, 1 ; redraw request ? + je red + + cmp eax, 2 ; key in buffer ? + je key + + cmp eax, 3 ; button in buffer ? + je button + + cmp eax, 6 ; mouse in buffer ? + je mouse + +; Get the web page data from the remote server + cmp eax, 8 + jne still + + call read_incoming_data + + cmp [status], 4 + je .no_send + + mov [onoff], 1 + call send_request + + .no_send: + call print_status + + cmp [prev_status], 4 + jne no_close + cmp [status], 4 ; connection closed by server + jbe no_close ; respond to connection close command +; draw page + call read_incoming_data + mcall close, [socketnum] + mov [onoff], 0 + +no_close: + jmp still + +key: + mcall 2 ; read key + + stdcall [edit_box_key], dword edit1 + + shr eax, 8 + cmp eax, 13 + je retkey + + jmp still + + +button: + + mcall 17 ; get id + cmp ah, 26 + je save + cmp ah, 1 ; button id=1 ? + jne noclose +; DEBUGF 1, "Closing socket before exit...\n" + +close_end_exit: + +exit: + or eax, -1 ; close this program + mcall + +mouse: + stdcall [edit_box_mouse], edit1 + jmp still + +save: + DEBUGF 1, "file saved\n" + mcall 70, fileinfo + + mov ecx, [sc.work_text] + or ecx, 0x80000000 + mcall 4, <10, 93>, , download_complete + + jmp still + +noclose: + cmp ah, 31 + jne noup + sub [display_from], 20 + jmp still + +noup: + cmp ah, 32 + jne nourl + add [display_from], 20 + jmp still + + +retkey: + mov ah, 22 ; start load + +nourl: + call socket_commands ; opens or closes the connection + jmp still + + +;**************************************************************************** +; Function +; send_request +; +; Description +; Transmits the GET request to the server. +; This is done as GET then URL then HTTP/1.1', 13, 10, 13, 10 in 3 packets +; +;**************************************************************************** +send_request: + pusha + mov esi, string0 + mov edi, request + movsd +; If proxy is used, make absolute URI - prepend http:// + cmp byte[proxyAddr], 0 + jz .noproxy + mov dword[edi], 'http' + mov byte[edi+4], ':' + mov word[edi+5], '//' + add edi, 7 + mov esi, webAddr + + .copy_host_loop: + lodsb + cmp al, ' ' + jz .noproxy + stosb + jmp .copy_host_loop + + .noproxy: + xor edx, edx ; 0 + + .next_edx: +; Determine the length of the url to send in the GET request + mov al, [edx+document] + cmp al, ' ' + je .document_done + mov [edi], al + inc edi + inc edx + jmp .next_edx + + .document_done: + mov esi, stringh + mov ecx, stringh_end-stringh + rep movsb + xor edx, edx ; 0 + + .webaddr_next: + mov al, [webAddr + edx] + cmp al, ' ' + je .webaddr_done + mov [edi], al + inc edi + inc edx + jmp .webaddr_next + + .webaddr_done: + cmp byte[proxyUser], 0 + jz @f + call append_proxy_auth_header + @@: + mov esi, connclose + mov ecx, connclose_end-connclose + rep movsb + + pusha + mov eax, 63 + mov ebx, 1 + mov edx, request + @@: + mov cl, [edx] + cmp edx, edi + jz @f + mcall + inc edx + jmp @b + @@: + popa + + mov esi, edi + sub esi, request ; length + xor edi, edi ; flags +;;;;now write \r\nConnection: Close \r\n\r\n + mcall send, [socketnum], request ;' HTTP/1.1 .. ' + popa + ret + +;**************************************************************************** +; Function +; print_status +; +; Description +; displays the socket/data received status information +; +;**************************************************************************** +print_status: + pusha + mcall 26, 9 + cmp eax, [nextupdate] + jb status_return + + add eax, 25 + mov [nextupdate], eax + + mov ecx, [winys] + shl ecx, 16 + add ecx, -18 shl 16 + 10 + mcall 13, <5, 100>, , 0xffffff + + mov edx, 12 shl 16 - 18 + add edx, [winys] + xor esi, esi + mcall 47, <3, 0>, [status], , + + mov edx, 40 shl 16 - 18 + add edx, [winys] + mcall , <6, 0>, [pos] + +status_return: + popa + ret + +;**************************************************************************** +; Function +; read_incoming_data +; +; Description +; receive the web page from the server, storing it without processing +; +;**************************************************************************** +read_incoming_data: + cmp [onoff], 1 + je .rid + ret + + .rid: + push esi + push edi + DEBUGF 1, "rid\n" + + .read: + mcall recv, [socketnum], primary_buf, primary_buffer_size, 0 + inc eax ; -1 = error (socket closed?) + jz .no_more_data + dec eax ; 0 bytes... + jz .read + + mov edi, [pos] + add [pos], eax + push eax + mcall 68, 20, [pos], [buf_ptr] + mov [buf_ptr], eax + add edi, eax + mov esi, primary_buf + pop ecx ; number of recently read bytes + lea edx, [ecx - 3] + rep movsb + + .no_more_data: + +; mov [status], 4 ; connection closed by server + + call parse_result + mov ecx, [shared_name] + test ecx, ecx + jz @f + cmp [ecx], byte 0 + jnz save_in_shared + @@: + + mcall 70, fileinfo + + mov ecx, [sc.work_text] + or ecx, 0x80000000 + mcall 4, <10, 93>, , download_complete + DEBUGF 1, "file saved\n" + + pop edi + pop esi + +; if called from command line, then exit + cmp byte[params], 0 + jne exit + + ret + +save_in_shared: + + mov esi, 1 ; SHM_OPEN+SHM_WRITE + mcall 68, 22 + test eax, eax + jz save_in_shared_done + + sub edx, 4 + jbe save_in_shared_done + + mov ecx, [final_size] + cmp ecx, edx + jb @f + + mov ecx, edx + @@: + mov [eax], ecx + lea edi, [eax+4] + mov esi, [final_buffer] + mov edx, ecx + shr ecx, 2 + rep movsd + mov ecx, edx + and ecx, 3 + rep movsb + +save_in_shared_done: + pop edi + pop esi + jmp exit + +; this function cuts header, and removes chunk sizes if doc is chunked +; in: buf_ptr, pos; out: buf_ptr, pos. + +parse_result: +; close socket + mcall close, [socketnum] + + DEBUGF 1, "close socketnum: 0x%x\n", eax + mov edi, [buf_ptr] + mov edx, [pos] + mov [buf_size], edx +; mcall 70, fileinfo_tmp + DEBUGF 1, "pos = 0x%x\n", edx + +; first, find end of headers + .next_byte: + cmp dword[edi], 0x0d0a0d0a ; , + je .end_of_headers + cmp dword[edi], 0x0a0d0a0d + je .end_of_headers + inc edi + dec edx + jne .next_byte +; no end of headers. it's an error. let client see all those headers. + ret + + .end_of_headers: +; here we look at headers and search content-length or transfer-encoding headers +; DEBUGF 1, "eoh\n" + + sub edi, [buf_ptr] + add edi, 4 + mov [body_pos], edi ; store position where document body starts + mov [is_chunked], 0 +; find content-length in headers +; not good method, but should work for 'Content-Length:' + mov esi, [buf_ptr] + mov edi, s_contentlength + mov ebx, [body_pos] + xor edx, edx ; 0 + .cl_next: + mov al, [esi] + cmp al, [edi + edx] + jne .cl_fail + inc edx + cmp edx, len_contentlength + je .cl_found + jmp .cl_incr + .cl_fail: + xor edx, edx ; 0 + .cl_incr: + inc esi + dec ebx + je .cl_error + jmp .cl_next + .cl_error: +; DEBUGF 1, "content-length not found\n" + +; find 'chunked' +; , , , , +; + mov esi, [buf_ptr] + mov edi, s_chunked + mov ebx, [body_pos] + xor edx, edx ; 0 + + .ch_next: + mov al, [esi] + cmp al, [edi + edx] + jne .ch_fail + inc edx + cmp edx, len_chunked + je .ch_found + jmp .ch_incr + + .ch_fail: + xor edx, edx ; 0 + + .ch_incr: + inc esi + dec ebx + je .ch_error + jmp .ch_next + + .ch_error: +; if neither of the 2 headers is found, it's an error +; DEBUGF 1, "transfer-encoding: chunked not found\n" + mov eax, [pos] + sub eax, [body_pos] + jmp .write_final_size + + .ch_found: + mov [is_chunked], 1 + mov eax, [body_pos] + add eax, [buf_ptr] + sub eax, 2 + mov [prev_chunk_end], eax + jmp parse_chunks + + .cl_found: + call read_number ; eax = number from *esi + + .write_final_size: + mov [final_size], eax ; if this works, i will b very happy... + + mov ebx, [pos] ; we well check if it is right + sub ebx, [body_pos] + +; everything is ok, so we return + mov eax, [body_pos] + mov ebx, [buf_ptr] + add ebx, eax + mov [final_buffer], ebx +; mov ebx, [pos] +; sub ebx, eax +; mov [final_size], ebx + ret + +parse_chunks: +; DEBUGF 1, "parse chunks\n" + ; we have to look through the data and remove sizes of chunks we see + ; 1. read size of next chunk + ; 2. if 0, it's end. if not, continue. + ; 3. make a good buffer and copy a chunk there + xor eax, eax + mov [final_buffer], eax ; 0 + mov [final_size], eax ; 0 + +.read_size: + mov eax, [prev_chunk_end] + mov ebx, eax + sub ebx, [buf_ptr] + mov edx, eax +; DEBUGF 1, "rs " + cmp ebx, [pos] + jae chunks_end ; not good + + call read_hex ; in: eax=pointer to text. out:eax=hex number, ebx=end of text. + cmp eax, 0 + jz chunks_end + + add ebx, 1 + mov edx, ebx ; edx = size of size of chunk + + add ebx, eax + mov [prev_chunk_end], ebx + +; DEBUGF 1, "sz " + +; do copying: from buf_ptr+edx to final_buffer+prev_final_size count eax +; realloc final buffer + push eax + push edx + push dword [final_size] + add [final_size], eax + mcall 68, 20, [final_size], [final_buffer] + mov [final_buffer], eax +; DEBUGF 1, "re " + pop edi + pop esi + pop ecx +; add [pos], ecx + add edi, [final_buffer] +; DEBUGF 1, "cp " + + rep movsb + jmp .read_size + +chunks_end: +; free old buffer + DEBUGF 1, "chunks end\n" + + mcall 68, 13, [buf_ptr] +; done! + ret + +; reads content-length from [edi+ecx], result in eax +read_number: + push ebx + xor eax, eax + xor ebx, ebx + + .next: + mov bl, [esi] + + cmp bl, '0' + jb .not_number + cmp bl, '9' + ja .not_number + sub bl, '0' + shl eax, 1 + lea eax, [eax + eax * 4] ; eax *= 10 + add eax, ebx + + .not_number: + cmp bl, 13 + je .done + inc esi + jmp .next + + .done: + pop ebx + ret + +; reads hex from eax, result in eax, end of text in ebx +read_hex: + add eax, 2 + mov ebx, eax + mov eax, [ebx] + mov [deba], eax + + xor eax, eax + xor ecx, ecx +.next: + mov cl, [ebx] + inc ebx + + cmp cl, 0x0d + jz .done + + or cl, 0x20 + sub cl, '0' + jb .bad + + cmp cl, 0x9 + jbe .adding + + sub cl, 'a'-'0'-10 + cmp cl, 0x0a + jb .bad + + cmp cl, 0x0f + ja .bad + +.adding: + shl eax, 4 + or eax, ecx +; jmp .not_number +;.bad: +.bad: + jmp .next +.done: + + ret + +;**************************************************************************** +; Function +; socket_commands +; +; Description +; opens or closes the socket +; +;**************************************************************************** +socket_commands: + cmp ah, 22 ; open socket + jne tst3 + + DEBUGF 1, "opening socket\n" + +; Clear all page memory + xor eax, eax + mov [prev_chunk_end], eax ; 0 + cmp [buf_ptr], eax ; 0 + jz no_free + + mcall 68, 13, [buf_ptr] ; free buffer + +no_free: + xor eax, eax + mov [buf_size], eax ; 0 +; Parse the entered url + call parse_url + + mov edx, 80 + cmp byte [proxyAddr], 0 + jz @f + mov eax, [proxyPort] + xchg al, ah + mov [server_port], ax + @@: + + mcall socket, AF_INET4, SOCK_STREAM, 0 + mov [socketnum], eax + mcall connect, [socketnum], sockaddr1, 18 + mov [pagexs], 80 + + push eax + xor eax, eax ; 0 + mov [pos], eax + mov [pagex], eax + mov [pagey], eax + mov [command_on_off], eax + mov [is_body], eax + pop eax + ret + +tst3: + cmp ah, 24 ; close socket + jne no_24 + + mcall close, [socketnum] +no_24: + ret + +;**************************************************************************** +; Function +; parse_url +; +; Description +; parses the full url typed in by the user into a web address ( that +; can be turned into an IP address by DNS ) and the page to display +; DNS will be used to translate the web address into an IP address, if +; needed. +; url is at document_user and will be space terminated. +; web address goes to webAddr and is space terminated. +; ip address goes to server_ip +; page goes to document and is space terminated. +; +; Supported formats: +; address +; is optional, removed and ignored - only http supported +;
is required. It can be an ip address or web address +; is optional and must start with a leading / character +; +;**************************************************************************** +parse_url: +; First, reset destination variables + mov al, ' ' + mov edi, document + mov ecx, URLMAXLEN + rep stosb + mov edi, webAddr + mov ecx, URLMAXLEN + rep stosb + + mov al, '/' + mov [document], al + + mov esi, document_user +; remove any leading protocol text + mov ecx, URLMAXLEN + mov ax, '//' + +pu_000: + cmp [esi], byte ' ' ; end of text? + je pu_002 ; yep, so not found + cmp [esi], ax + je pu_001 ; Found it, so esi+2 is start + inc esi + loop pu_000 + +pu_002: +; not found, so reset esi to start + mov esi, document_user-2 + +pu_001: + add esi, 2 + mov ebx, esi ; save address of start of web address + mov edi, document_user + URLMAXLEN ; end of string +; look for page delimiter - it's a '/' character +pu_003: + cmp [esi], byte ' ' ; end of text? + je pu_004 ; yep, so none found + cmp esi, edi ; end of string? + je pu_004 ; yep, so none found + cmp [esi], byte '/' ; delimiter? + je pu_005 ; yep - process it + inc esi + jmp pu_003 + +pu_005: +; copy page to document address +; esi = delimiter + push esi + mov ecx, edi ; end of document_user + mov edi, document + +pu_006: + movsb + cmp esi, ecx + je pu_007 ; end of string? + cmp [esi], byte ' ' ; end of text +; je pu_007 ; - +; jmp pu_006 ; + jne pu_006 + +pu_007: + pop esi ; point esi to '/' delimiter + +pu_004: +; copy web address to webAddr +; start in ebx, end in esi-1 + mov ecx, esi + mov esi, ebx + mov edi, webAddr + +pu_008: + movsb + cmp esi, ecx +; je pu_009 ; - +; jmp pu_008 ; + jne pu_008 + +pu_009: +; For debugging, display resulting strings + DEBUGF 1, "%s", document_user + DEBUGF 1, "%s", webAddr + DEBUGF 1, "%s", document + +; Look up the ip address, or was it specified? + mov al, [proxyAddr] + cmp al, 0 + jnz pu_015 + mov al, [webAddr] +pu_015: + cmp al, '0' + jb pu_010 ; Resolve address + cmp al, '9' + ja pu_010 ; Resolve address + + DEBUGF 1, "GotIP\n" + +; Convert address +; If proxy is given, get proxy address instead of server + mov esi, proxyAddr-1 + cmp byte[esi+1], 0 + jne pu_020 + mov esi, webAddr-1 + +pu_020: + mov edi, server_ip + xor eax, eax + +ip1: + inc esi + cmp [esi], byte '0' + jb ip2 + cmp [esi], byte '9' + ja ip2 + imul eax, 10 + movzx ebx, byte [esi] + sub ebx, 48 + add eax, ebx + jmp ip1 + +ip2: + mov [edi], al + xor eax, eax + inc edi + cmp edi, server_ip+3 + jbe ip1 + jmp pu_011 + +pu_010: + DEBUGF 1, "Resolving...\n" + +; resolve name + push esp ; reserve stack place + push esp ; fourth parameter + push 0 ; third parameter + push 0 ; second parameter + push webAddr + call [getaddrinfo] + pop esi +; test for error + test eax, eax +; jnz .fail_dns + +; fill in ip in sockstruct + mov eax, [esi + addrinfo.ai_addr] + mov eax, [eax + sockaddr_in.sin_addr] + mov [server_ip], eax + + + DEBUGF 1, "Resolved\n" + +pu_011: + + ret + +;*************************************************************************** +; Function +; load_settings +; +; Description +; Load settings from configuration file network.ini +; +;*************************************************************************** +load_settings: + + invoke ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr + invoke ini.get_int, inifile, sec_proxy, key_proxyport, 80 + mov [proxyPort], eax + invoke ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser + invoke ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword + + ret + +;*************************************************************************** +; Function +; append_proxy_auth_header +; +; Description +; Append header to HTTP request for proxy authentification +; +;*************************************************************************** +append_proxy_auth_header: + mov esi, proxy_auth_basic + mov ecx, proxy_auth_basic_end - proxy_auth_basic + rep movsb +; base64-encode string : + mov esi, proxyUser + +apah000: + lodsb + test al, al + jz apah001 + call encode_base64_byte + jmp apah000 + +apah001: + mov al, ':' + call encode_base64_byte + mov esi, proxyPassword + +apah002: + lodsb + test al, al + jz apah003 + call encode_base64_byte + jmp apah002 + +apah003: + call encode_base64_final + ret + +encode_base64_byte: + inc ecx + shl edx, 8 + mov dl, al + cmp ecx, 3 + je ebb001 + ret + +ebb001: + shl edx, 8 + inc ecx + +ebb002: + rol edx, 6 + xor eax, eax + xchg al, dl + mov al, [base64_table+eax] + stosb + loop ebb002 + ret + +encode_base64_final: + mov al, 0 + test ecx, ecx + jz ebf000 + call encode_base64_byte + test ecx, ecx + jz ebf001 + call encode_base64_byte + mov byte [edi-2], '=' + +ebf001: + mov byte [edi-1], '=' + +ebf000: + ret + +; ********************************************* +; ******* WINDOW DEFINITIONS AND DRAW ******** +; ********************************************* + +draw_window: + + mcall 12, 1 + + mcall 48, 3, sc, 40 ;get system colors + + mov edx, [sc.work] + or edx, 0x34000000 + mcall 0, <50, 370>, <350, 140>, , 0, title ;draw window + + mov ecx, [sc.work_text] + or ecx, 80000000h + mcall 4, <14, 14>, , type_pls ;"URL:" + + edit_boxes_set_sys_color edit1, editboxes_end, sc + stdcall [edit_box_draw], edit1 + +; RELOAD + mcall 8, <90, 68>, <54, 16>, 22, [sc.work_button] +; STOP + mcall , <166, 50>, <54, 16>, 24 +; SAVE + mcall , <224, 54>, , 26 +; BUTTON TEXT + mov ecx, [sc.work_button_text] + or ecx, 80000000h + mcall 4, <102, 59>, , button_text + + mcall 12, 2 ; end window redraw + ret +;----------------------------------------------------------------------------- +; Data area +;----------------------------------------------------------------------------- +align 4 +@IMPORT: + +library libini, 'libini.obj', \ + box_lib, 'box_lib.obj', \ + network, 'network.obj' + +import libini, \ + ini.get_str, 'ini_get_str', \ + ini.get_int, 'ini_get_int' + +import box_lib, \ + edit_box_draw, 'edit_box', \ + edit_box_key, 'edit_box_key', \ + edit_box_mouse, 'edit_box_mouse' + +import network,\ + getaddrinfo, 'getaddrinfo',\ + freeaddrinfo, 'freeaddrinfo',\ + inet_ntoa, 'inet_ntoa' + +;--------------------------------------------------------------------- +fileinfo dd 2, 0, 0 +final_size dd 0 +final_buffer dd 0 + db '/rd/1/.download', 0 + +body_pos dd 0 + +buf_size dd 0 +buf_ptr dd 0 + +deba dd 0 + db 0 + +;--------------------------------------------------------------------- + +mouse_dd dd 0 +edit1 edit_box 295, 48, 10, 0xffffff, 0xff, 0x80ff, 0, 0x8000, URLMAXLEN, document_user, mouse_dd, ed_focus+ed_always_focus, 7, 7 +editboxes_end: + +;--------------------------------------------------------------------- + +include_debug_strings + +;--------------------------------------------------------------------- + +type_pls db 'URL:', 0 +button_text db 'DOWNLOAD STOP RESAVE', 0 +download_complete db 'File saved as /rd/1/.download', 0 +display_from dd 20 +pos dd 0 +pagex dd 0 +pagey dd 0 +pagexs dd 80 +command_on_off dd 0 +text_type db 1 +com2 dd 0 +script dd 0 +socketnum dd 0 + +addr dd 0 +ya dd 0 +len dd 0 + +title db 'HTTP Downloader', 0 + +;--------------------------------------------------------------------- +s_contentlength db 'Content-Length:' +len_contentlength = 15 + +s_chunked db 'Transfer-Encoding: chunked' +len_chunked = $ - s_chunked + +is_body dd 0 ; 0 if headers, 1 if content +is_chunked dd 0 +prev_chunk_end dd 0 +cur_chunk_size dd 0 + +string0: db 'GET ' + +stringh db ' HTTP/1.1', 13, 10, 'Host: ' +stringh_end: +proxy_auth_basic db 13, 10, 'Proxy-Authorization: Basic ' +proxy_auth_basic_end: +connclose db 13, 10, 'User-Agent: Kolibrios Downloader', 13, 10, 'Connection: Close', 13, 10, 13, 10 +connclose_end: + +base64_table db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + db '0123456789+/' + +inifile db '/sys/network.ini', 0 + +sec_proxy: +key_proxy db 'proxy', 0 +key_proxyport db 'port', 0 +key_user db 'user', 0 +key_password db 'password', 0 + +sockaddr1: + dw AF_INET4 +server_port dw 0x5000 ; 80 +server_ip dd 0 + rb 10 + +proxyPort dd 80 + +shared_name dd 0 + +status dd 0x0 +prev_status dd 0x0 + +onoff dd 0x0 + +nextupdate dd 0 +winys dd 400 + +;--------------------------------------------------------------------- +document_user db 'http://', 0 +;--------------------------------------------------------------------- +IM_END: +;--------------------------------------------------------------------- + rb URLMAXLEN-(IM_END - document_user) +;--------------------------------------------------------------------- + sc system_colors +;--------------------------------------------------------------------- +align 4 +document rb URLMAXLEN +;--------------------------------------------------------------------- +align 4 +webAddr rb URLMAXLEN+1 +;--------------------------------------------------------------------- + +align 4 +primary_buf rb primary_buffer_size + +params rb 1024 + +request rb 256 + +proxyAddr rb 256 +proxyUser rb 256 +proxyPassword rb 256 + + rb 4096 ; stack + +I_END: + + + diff --git a/kernel/branches/net/applications/ftpc/ftpc.asm b/kernel/branches/net/applications/ftpc/ftpc.asm new file mode 100644 index 0000000000..b50b415f28 --- /dev/null +++ b/kernel/branches/net/applications/ftpc/ftpc.asm @@ -0,0 +1,390 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ftpc.asm - FTP client for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format binary as "" + +__DEBUG__ = 0 +__DEBUG_LEVEL__ = 1 +BUFFERSIZE = 1024 + +STATUS_CONNECTING = 0 +STATUS_CONNECTED = 1 +STATUS_NEEDPASSWORD = 1 +STATUS_LOGGED_IN = 3 + +use32 +; standard header + db 'MENUET01' ; signature + dd 1 ; header version + dd start ; entry point + dd i_end ; initialized size + dd mem+0x1000 ; required memory + dd mem+0x1000 ; stack pointer + dd s ; parameters + dd 0 ; path + +include '../macros.inc' +purge mov,add,sub +include '../proc32.inc' +include '../dll.inc' +include '../debug-fdo.inc' +include '../network.inc' + +include 'usercommands.inc' +include 'servercommands.inc' + +; entry point +start: + + DEBUGF 1, "hello" +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit +; initialize console + push 1 + call [con_start] + push title + push 25 + push 80 + push 25 + push 80 + call [con_init] + +; Check for parameters + cmp byte [s], 0 + jne resolve + +main: + call [con_cls] +; Welcome user + push str1 + call [con_write_asciiz] + +; write prompt + push str2 + call [con_write_asciiz] +; read string + mov esi, s + push 256 + push esi + call [con_gets] +; check for exit + test eax, eax + jz done + cmp byte [esi], 10 + jz done + +resolve: + +; delete terminating '\n' + mov esi, s + @@: + lodsb + cmp al, 0x20 + ja @r + mov byte [esi-1], 0 + +; call [con_cls] + push str3 + call [con_write_asciiz] + push s + call [con_write_asciiz] + +; resolve name + push esp ; reserve stack place + push esp ; fourth parameter + push 0 ; third parameter + push 0 ; second parameter + push s ; first parameter + call [getaddrinfo] + pop esi +; test for error + test eax, eax + jnz fail + +; write results + push str8 + call [con_write_asciiz] +; mov edi, esi + +; convert IP address to decimal notation + mov eax, [esi+addrinfo.ai_addr] + mov eax, [eax+sockaddr_in.sin_addr] + mov [sockaddr1.ip], eax + push eax + call [inet_ntoa] +; write result + push eax + call [con_write_asciiz] +; free allocated memory + push esi + call [freeaddrinfo] + + push str9 + call [con_write_asciiz] + + mcall socket, AF_INET4, SOCK_STREAM, 0 + cmp eax, -1 + jz fail2 + mov [socketnum], eax + + mcall connect, [socketnum], sockaddr1, 18 + + mcall 40, 1 shl 7 + + mov [status], STATUS_CONNECTING + mov [offset], buffer_ptr + +wait_for_serverdata: + mcall 10 + + call [con_get_flags] + test eax, 0x200 ; con window closed? + jnz exit + +; receive socket data + mcall recv, [socketnum], [offset], BUFFERSIZE, 0 + inc eax + jz wait_for_serverdata + dec eax + jz wait_for_serverdata + +; extract commands, copy them to "s" buffer + add eax, buffer_ptr ; eax = end pointer + mov esi, buffer_ptr ; esi = current pointer + .nextcommand: + mov edi, s + .byteloop: + cmp esi, eax + jae wait_for_serverdata + lodsb + cmp al, 10 ; excellent, we might have a command + je .got_command + cmp al, 13 ; just ignore this crap + je .byteloop + stosb + jmp .byteloop + +; we have a newline check if its a command + .got_command: + xor al, al + stosb +; push esi eax + +; print it to the screen + pushd s + call [con_write_asciiz] + pushd str4 ; newline + call [con_write_asciiz] + +; cmp byte[s+2], " " +; jne .not_command + + lea ecx, [edi - s] + call server_parser + +; .not_command: +; pop eax esi +; jmp .nextcommand + + + + +wait_for_usercommand: + + cmp [status], STATUS_CONNECTED + je .connected + + cmp [status], STATUS_NEEDPASSWORD + je .needpass + + +; write prompt + push str2 + call [con_write_asciiz] +; read string + mov esi, s + push 256 + push esi + call [con_gets] + + call [con_get_flags] + test eax, 0x200 ; con window closed? + jnz exit + + cmp dword[s], "list" + je cmd_list + + cmp dword[s], "help" + je cmd_help + + push str_unkown + call [con_write_asciiz] + + jmp wait_for_usercommand + + + .connected: + + push str_user + call [con_write_asciiz] + + mov dword[s], "USER" + mov byte[s+4], " " + + jmp .send + + + .needpass: + push str_pass + call [con_write_asciiz] + + mov dword[s], "PASS" + mov byte[s+4], " " + + .send: +; read string + mov esi, s+5 + push 256 + push esi + call [con_gets] + + mov edi, s+5 + mov ecx, 256 + xor al, al + repne scasb + lea esi, [edi-s-1] + mcall send, [socketnum], s + + jmp wait_for_usercommand + + + + + + +open_dataconnection: + cmp [status], STATUS_LOGGED_IN + jne .fail + + mov dword[s], "PASV" + mov byte[s+4], 10 + mcall send, [socketnum], s, 5 + + ret + + .fail: + push str6 + call [con_write_asciiz] + + ret + + +fail2: + push str6 + call [con_write_asciiz] + + jmp fail.wait + +fail: + push str5 + call [con_write_asciiz] + .wait: + push str10 + call [con_write_asciiz] + call [con_getch2] + jmp main + +done: + push 1 + call [con_exit] +exit: + + mcall close, [socketnum] + mcall -1 + + + +; data +title db 'FTP client',0 +str1 db 'FTP client for KolibriOS v0.01',10,10,'Please enter ftp server address.',10,0 +str2 db '> ',0 +str3 db 'Connecting to ',0 +str4 db 10,0 +str5 db 10,'Name resolution failed.',10,0 +str6 db 10,'Socket error.',10,0 +str8 db ' (',0 +str9 db ')',10,0 +str10 db 'Push any key to continue.',0 +str_user db "username: ",0 +str_pass db "password: ",0 +str_unkown db "unkown command",10,0 +str_help db "available commands:",10,10 + db "help list",10,0 + +str_open db "opening data socket",10,0 + +sockaddr1: + dw AF_INET4 +.port dw 0x1500 ; 21 +.ip dd 0 + rb 10 + +sockaddr2: + dw AF_INET4 +.port dw 0 +.ip dd 0 + rb 10 + +include_debug_strings ; ALWAYS present in data section + + + +; import +align 4 +@IMPORT: + +library network, 'network.obj', console, 'console.obj' + +import network, \ + getaddrinfo, 'getaddrinfo', \ + freeaddrinfo, 'freeaddrinfo', \ + inet_ntoa, 'inet_ntoa' + +import console, \ + con_start, 'START', \ + con_init, 'con_init', \ + con_write_asciiz,'con_write_asciiz', \ + con_exit, 'con_exit', \ + con_gets, 'con_gets',\ + con_cls, 'con_cls',\ + con_getch2, 'con_getch2',\ + con_set_cursor_pos, 'con_set_cursor_pos',\ + con_write_string, 'con_write_string',\ + con_get_flags, 'con_get_flags' + + +i_end: + +active_passive db ? +socketnum dd ? +datasocket dd ? +buffer_ptr rb 2*BUFFERSIZE +status db ? +offset dd ? + +s rb 1024 + +mem: diff --git a/kernel/branches/net/applications/ftpc/servercommands.inc b/kernel/branches/net/applications/ftpc/servercommands.inc new file mode 100644 index 0000000000..5f06ab96d0 --- /dev/null +++ b/kernel/branches/net/applications/ftpc/servercommands.inc @@ -0,0 +1,114 @@ +server_parser: + +; Commands are always 3 numbers and followed by a space +; If a server decides it needs multiline output, +; first lines will have a dash instead of space after numbers, +; thus they are simply ignored. + + cmp dword[s], "150 " + je data_ok + + cmp dword[s], "220 " + je welcome + + cmp dword[s], "227 " + je pasv_ok + + cmp dword[s], "230 " + je login_ok + + cmp dword[s], "331 " + je pass + + ret + + +welcome: + + mov [status], STATUS_CONNECTED + ret + + +pass: + + mov [status], STATUS_NEEDPASSWORD + ret + + +login_ok: + + mov [status], STATUS_LOGGED_IN + ret + + +pasv_ok: + + sub ecx, 5 + jb .fail + mov al, "(" + mov edi, s + 5 + repne scasb + + mcall socket, AF_INET4, SOCK_STREAM, 0 + cmp eax, -1 + je fail + mov [datasocket], eax + + mov esi, edi + call ascii_dec + mov byte[sockaddr2.ip+0], bl + call ascii_dec + mov byte[sockaddr2.ip+1], bl + call ascii_dec + mov byte[sockaddr2.ip+2], bl + call ascii_dec + mov byte[sockaddr2.ip+3], bl + + call ascii_dec + mov byte[sockaddr2.port+1], bl + call ascii_dec + mov byte[sockaddr2.port+0], bl + + push str_open + call [con_write_asciiz] + + mcall connect, [datasocket], sockaddr2, 18 + + .fail: + ret + + +data_ok: + + mcall recv, [datasocket], buffer_ptr, BUFFERSIZE, 0 ; fixme: use other buffer + inc eax + jz .fail + dec eax + jz .fail + + mov byte[buffer_ptr + eax], 0 + pushd buffer_ptr + call [con_write_asciiz] + + .fail: + ret + + +ascii_dec: + + xor ebx, ebx + mov cl, 3 + .loop: + lodsb + sub al, '0' + jb .done + cmp al, 9 + ja .done + lea ebx, [ebx*4+ebx] + shl ebx, 1 + add bl, al + dec cl + jnz .loop + + .done: + ret \ No newline at end of file diff --git a/kernel/branches/net/applications/ftpc/usercommands.inc b/kernel/branches/net/applications/ftpc/usercommands.inc new file mode 100644 index 0000000000..57a4582459 --- /dev/null +++ b/kernel/branches/net/applications/ftpc/usercommands.inc @@ -0,0 +1,17 @@ +cmd_list: + + call open_dataconnection + + mov dword[s], "LIST" + mov word[s+4], 0x0d0a + mcall send, [socketnum], s, 6 + + jmp wait_for_serverdata + + +cmd_help: + + push str_help + call [con_write_asciiz] + + jmp wait_for_usercommand \ No newline at end of file diff --git a/kernel/branches/net/applications/ircc/window.inc b/kernel/branches/net/applications/ircc/window.inc index 4a9afb1650..5065b60cef 100644 --- a/kernel/branches/net/applications/ircc/window.inc +++ b/kernel/branches/net/applications/ircc/window.inc @@ -78,6 +78,21 @@ window_refresh: ret +window_updated: + + mov edi, [window_print] + test [edi + window.flags], FLAG_UPDATED + jnz .skip + + or [edi + window.flags], FLAG_UPDATED + +; now play a sound :) + + .skip: + + ret + + print_text: ; eax = start ptr ; dl = end char pusha diff --git a/kernel/branches/net/applications/libio.inc b/kernel/branches/net/applications/libio.inc index 8c78927ced..220203b24f 100644 --- a/kernel/branches/net/applications/libio.inc +++ b/kernel/branches/net/applications/libio.inc @@ -19,11 +19,11 @@ O_BINARY = 00000000b -O_READ = 00000001b +O_READ = 00000001b O_WRITE = 00000010b O_CREATE = 00000100b O_SHARE = 00001000b -O_TEXT = 00010000b +O_TEXT = 00010000b SEEK_SET = 0 SEEK_CUR = 1 @@ -54,7 +54,7 @@ struct FileInfoBlock Flags dd ? Count dd ? Buffer dd ? - db ? + db ? FileName dd ? ends @@ -62,7 +62,7 @@ struct FileInfoHeader Version dd ? FilesRead dd ? FilesCount dd ? - rd 5 + rd 5 ends struct FileInfoA @@ -78,7 +78,7 @@ struct FileInfoA FileSizeHigh dd ? ends ends - FileName rb 252 + FileName rb 264 ends struct FileInfoW @@ -94,12 +94,12 @@ struct FileInfoW FileSizeHigh dd ? ends ends - FileName rw 260 + FileName rw 264 ends virtual at 0 - FileInfo FileInfoA - FileInfo fix FileInfoA + FileInfo FileInfoA + FileInfo fix FileInfoA sizeof.FileInfo fix sizeof.FileInfoA end virtual @@ -109,4 +109,5 @@ FA_SYSTEM = 00000100b FA_LABEL = 00001000b FA_FOLDER = 00010000b FA_ARCHIVED = 00100000b -FA_ANY = 00111111b +FA_NORMAL = 01000000b +FA_ANY = 01111111b diff --git a/kernel/branches/net/data32.inc b/kernel/branches/net/data32.inc index 80be4c2455..c413332a0c 100644 --- a/kernel/branches/net/data32.inc +++ b/kernel/branches/net/data32.inc @@ -178,16 +178,16 @@ shmem_list: .fd dd shmem_list dll_list: - .bk dd dll_list - .fd dd dll_list - -pcidev_list: - .bk dd pcidev_list - .fd dd pcidev_list - -MAX_DEFAULT_DLL_ADDR = 0x80000000 -MIN_DEFAULT_DLL_ADDR = 0x70000000 -dll_cur_addr dd MIN_DEFAULT_DLL_ADDR + .bk dd dll_list + .fd dd dll_list + +pcidev_list: + .bk dd pcidev_list + .fd dd pcidev_list + +MAX_DEFAULT_DLL_ADDR = 0x80000000 +MIN_DEFAULT_DLL_ADDR = 0x70000000 +dll_cur_addr dd MIN_DEFAULT_DLL_ADDR ; supported videomodes @@ -500,4 +500,5 @@ BiosDisksData rb 200h BiosDiskCaches rb 80h*(cache_ide1-cache_ide0) BiosDiskPartitions rd 80h +tetten: IncludeUGlobals diff --git a/kernel/branches/net/gui/event.inc b/kernel/branches/net/gui/event.inc index 36e1b53711..a20ae5473d 100644 --- a/kernel/branches/net/gui/event.inc +++ b/kernel/branches/net/gui/event.inc @@ -527,7 +527,7 @@ align 4 cmp eax, 5 je .mouse_check ; eax=5, retvals=eax+1 (event 6) - ja .FlagAutoReset ; eax=[6..8], retvals=eax+1 (event 7...10) + ja .FlagAutoReset ; eax=[6..9], retvals=eax+1 (event 7...10) cmp eax, 1 jae .BtKy ; eax=[1,2], retvals=eax+1 (event 2,3) diff --git a/kernel/branches/net/kernel.asm b/kernel/branches/net/kernel.asm index ddd40ff159..74c526cb1a 100644 --- a/kernel/branches/net/kernel.asm +++ b/kernel/branches/net/kernel.asm @@ -77,11 +77,12 @@ $Revision $ USE_COM_IRQ equ 1 ; make irq 3 and irq 4 available for PCI devices ; Enabling the next line will enable serial output console -;debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used +debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used include "proc32.inc" include "kglobals.inc" -include "lang.inc" +;include "lang.inc" +lang fix en include "const.inc" max_processes equ 255 @@ -136,7 +137,7 @@ use16 if lang eq sp include "kernelsp.inc" ; spanish kernel messages else -version db 'Kolibri OS version 0.7.7.0+ ',13,10,13,10,0 +version db 'Kolibri OS network development ',13,10,13,10,0 end if include "boot/bootstr.inc" ; language-independent boot messages @@ -789,13 +790,13 @@ end if ; call build_scheduler; sys32.inc ; mov esi, boot_devices -; call boot_log - - mov [pci_access_enabled], 1 - call pci_enum - -; SET PRELIMINARY WINDOW STACK AND POSITIONS - +; call boot_log + + mov [pci_access_enabled], 1 + call pci_enum + +; SET PRELIMINARY WINDOW STACK AND POSITIONS + mov esi, boot_windefs call boot_log call set_window_defaults @@ -4615,16 +4616,16 @@ sys_msg_board_dword: pop eax pop ecx loop @b - popad - ret - -msg_board_data_size = 65536 ; Must be power of two - -uglobal - msg_board_data rb msg_board_data_size - msg_board_count dd 0x0 -endg - + popad + ret + +msg_board_data_size = 65536 ; Must be power of two + +uglobal + msg_board_data rb msg_board_data_size + msg_board_count dd 0x0 +endg + sys_msg_board: ; eax=1 : write : bl byte to write @@ -4651,13 +4652,13 @@ if defined debug_com_base pop ax dx end if - - mov [msg_board_data+ecx], bl - inc ecx - and ecx, msg_board_data_size - 1 - mov [msg_board_count], ecx - mov [check_idle_semaphore], 5 - ret + + mov [msg_board_data+ecx], bl + inc ecx + and ecx, msg_board_data_size - 1 + mov [msg_board_count], ecx + mov [check_idle_semaphore], 5 + ret .smbl1: cmp eax, 2 jne .smbl2 @@ -4744,14 +4745,14 @@ align 4 movzx ecx, cl lea ecx, [hotkey_scancodes+ecx*4] mov edx, [ecx] - mov [eax], edx - mov [ecx], eax - mov [eax+12], ecx - test edx, edx - jz @f - mov [edx+12], eax -@@: - and dword [esp+32], 0 + mov [eax], edx + mov [ecx], eax + mov [eax+12], ecx + test edx, edx + jz @f + mov [edx+12], eax +@@: + and dword [esp+32], 0 ret ;----------------------------------------------------------------------------- align 4 diff --git a/kernel/trunk/const.inc b/kernel/trunk/const.inc index f420bd388a..574a8362b5 100644 --- a/kernel/trunk/const.inc +++ b/kernel/trunk/const.inc @@ -399,7 +399,8 @@ EVENT_MOUSE equ 0x00000020 EVENT_IPC equ 0x00000040 EVENT_NETWORK equ 0x00000080 EVENT_DEBUG equ 0x00000100 -EVENT_EXTENDED equ 0x00000200 +EVENT_NETWORK2 equ 0x00000200 +EVENT_EXTENDED equ 0x00000400 EV_INTR equ 1 diff --git a/kernel/trunk/core/conf_lib.inc b/kernel/trunk/core/conf_lib.inc index be70368261..990c08617e 100644 --- a/kernel/trunk/core/conf_lib.inc +++ b/kernel/trunk/core/conf_lib.inc @@ -72,54 +72,7 @@ ugui_mouse_delay_def db '0x00A',0 udev_midibase db 'midibase',0 udev_midibase_def db '0x320',0 endg -;set up netvork configuration -proc set_network_conf -locals - par db 30 dup(?) -endl - pushad - ;[net] - ;active - lea eax, [par] - invoke ini.get_int, conf_fname, unet, unet_active, 0 - or eax, eax - jz .do_not_set_net - mov eax, [stack_config] - and eax, 0xFFFFFF80 - add eax, 3 - mov [stack_config], eax - call ash_eth_enable - - ;addr - lea eax, [par] - push eax - invoke ini.get_str, conf_fname, unet, unet_addr, eax, 30, unet_def - pop eax - stdcall do_inet_adr, eax - mov [stack_ip], eax - - ;mask - lea eax, [par] - push eax - invoke ini.get_str, conf_fname, unet, unet_mask, eax, 30, unet_def - pop eax - stdcall do_inet_adr, eax - mov [subnet_mask], eax - - ;gate - lea eax, [par] - push eax - invoke ini.get_str, conf_fname, unet, unet_gate, eax, 30, unet_def - pop eax - stdcall do_inet_adr, eax - mov [gateway_ip], eax -.do_not_set_net: - popad - ret - - -endp iglobal if lang eq sp include 'core/conf_lib-sp.inc' diff --git a/kernel/trunk/core/exports.inc b/kernel/trunk/core/exports.inc index 6b3bcdec06..33b70b90e7 100644 --- a/kernel/trunk/core/exports.inc +++ b/kernel/trunk/core/exports.inc @@ -101,6 +101,12 @@ iglobal szUSBNormalTransferAsync db 'USBNormalTransferAsync',0 szUSBControlTransferAsync db 'USBControlTransferAsync',0 + szNetRegDev db 'NetRegDev',0 + szNetUnRegDev db 'NetUnRegDev',0 + szNetPtrToNum db 'NetPtrToNum',0 + szNetLinkChanged db 'NetLinkChanged',0 + szEth_input db 'Eth_input',0 + align 16 kernel_export: dd szRegService , reg_service @@ -191,6 +197,12 @@ kernel_export: dd szUSBNormalTransferAsync, usb_normal_transfer_async dd szUSBControlTransferAsync, usb_control_async + dd szNetRegDev , NET_add_device + dd szNetUnRegDev , NET_remove_device + dd szNetPtrToNum , NET_ptr_to_num + dd szNetLinkChanged , NET_link_changed + dd szEth_input , ETH_input + exp_lfb: dd szLFBAddress , 0 dd 0 ;terminator, must be zero diff --git a/kernel/trunk/core/syscall.inc b/kernel/trunk/core/syscall.inc index b80930b298..364e8dc7a3 100644 --- a/kernel/trunk/core/syscall.inc +++ b/kernel/trunk/core/syscall.inc @@ -112,7 +112,7 @@ iglobal align 4 servetable: - dd socket ; 53-Socket interface + dd 0 dd 0 dd 0 dd 0 @@ -182,8 +182,8 @@ iglobal dd sys_apm ; 49-Advanced Power Management (APM) dd syscall_set_window_shape ; 50-Window shape & scale dd syscall_threads ; 51-Threads - dd stack_driver_stat ; 52-Stack driver status - dd cross_order ; 53-Socket interface + dd undefined_syscall ; 52-Stack driver status + dd undefined_syscall ; 53-Socket interface dd undefined_syscall ; 54-reserved dd sound_interface ; 55-Sound interface dd undefined_syscall ; 56-reserved @@ -204,9 +204,9 @@ iglobal dd syscall_window_settings ; 71-Window settings dd sys_sendwindowmsg ; 72-Send window message dd blit_32 ; 73-blitter; - dd undefined_syscall ; 74-reserved for new stack - dd undefined_syscall ; 75-reserved for new stack - dd undefined_syscall ; 76-reserved for new stack + dd sys_network ; 74-reserved for new stack + dd sys_socket ; 75-reserved for new stack + dd sys_protocols ; 76-reserved for new stack times 255 - ( ($-servetable2) /4 ) dd undefined_syscall dd sys_end ; -1-end application diff --git a/kernel/trunk/gui/event.inc b/kernel/trunk/gui/event.inc index e426645614..9fa10f4874 100644 --- a/kernel/trunk/gui/event.inc +++ b/kernel/trunk/gui/event.inc @@ -515,8 +515,8 @@ align 4 jz .no_events ; исчерпали все биты маски, но ничего не нашли ??? btr ecx, eax ; сбрасываем проверяемый бит маски ; переходим на обработчик этого (eax) бита - cmp eax, 9 - jae .loop ; eax=[9..31], ignored (event 10...32) + cmp eax, 10 + jae .loop ; eax=[10..31], ignored (event 10...32) cmp eax, 3 je .loop ; eax=3, ignored (event 4) @@ -527,7 +527,7 @@ align 4 cmp eax, 5 je .mouse_check ; eax=5, retvals=eax+1 (event 6) - ja .FlagAutoReset ; eax=[6..8], retvals=eax+1 (event 7...9) + ja .FlagAutoReset ; eax=[6..9], retvals=eax+1 (event 7...10) cmp eax, 1 jae .BtKy ; eax=[1,2], retvals=eax+1 (event 2,3) diff --git a/kernel/trunk/kernel.asm b/kernel/trunk/kernel.asm index 27952a0954..f037b6bc90 100644 --- a/kernel/trunk/kernel.asm +++ b/kernel/trunk/kernel.asm @@ -77,7 +77,7 @@ $Revision$ USE_COM_IRQ equ 1 ; make irq 3 and irq 4 available for PCI devices ; Enabling the next line will enable serial output console -;debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used +debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used ; The following constant, if nonzero, duplicates debug output to the screen. debug_direct_print equ 0 @@ -638,12 +638,6 @@ no_mode_0x12: mov dword [current_slot], SLOT_BASE + 256*2 mov dword [TASK_BASE], CURRENT_TASK + 32*2 - stdcall kernel_alloc, 0x10000/8 - mov edi, eax - mov [network_free_ports], eax - or eax, -1 - mov ecx, 0x10000/32 - rep stosd ; REDIRECT ALL IRQ'S TO INT'S 0x20-0x2f mov esi, boot_initirq @@ -883,12 +877,6 @@ end if stdcall map_page, tss._io_map_1, \ [SLOT_BASE+256+APPDATA.io_map+4], PG_MAP - mov ax, [OS_BASE+0x10000+bx_from_load] - cmp ax, 'r1'; if not rused ram disk - load network configuration from files {SPraid.simba} - je no_st_network - call set_network_conf - no_st_network: - ; LOAD FIRST APPLICATION cli @@ -2028,6 +2016,13 @@ sys_end: call restore_default_cursor_before_killing popa @@: +;-------------------------------------- +; kill all sockets this process owns + pusha + mov edx, [TASK_BASE] + mov edx, [edx+TASKDATA.pid] + call SOCKET_process_end + popa ;-------------------------------------- mov ecx, [current_slot] mov eax, [ecx+APPDATA.tls_base] @@ -2154,6 +2149,12 @@ sysfn_terminate: ; 18.2 = TERMINATE pop edx ecx test eax, eax jz noprocessterminate +;-------------------------------------- +; terminate all network sockets it used + pusha + mov eax, edx + call SOCKET_process_end + popa ;-------------------------------------- cmp [_display.select_cursor], 0 je .restore_end @@ -5366,28 +5367,6 @@ syscall_threads: ; CreateThreads align 4 -stack_driver_stat: - - call app_stack_handler ; Stack status - -; mov [check_idle_semaphore],5 ; enable these for zero delay -; call change_task ; between sent packet - - mov [esp+32], eax - ret - -align 4 - -socket: ; Socket interface - call app_socket_handler - -; mov [check_idle_semaphore],5 ; enable these for zero delay -; call change_task ; between sent packet - - mov [esp+36], eax - mov [esp+24], ebx - ret - paleholder: ret ;------------------------------------------------------------------------------ diff --git a/kernel/trunk/network/ARP.inc b/kernel/trunk/network/ARP.inc new file mode 100644 index 0000000000..070c3f1ada --- /dev/null +++ b/kernel/trunk/network/ARP.inc @@ -0,0 +1,645 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ARP.INC ;; +;; ;; +;; Part of the tcp/ip network stack for KolibriOS ;; +;; ;; +;; Based on the work of [Johnny_B] and [smb] ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June- 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 3386 $ + +ARP_NO_ENTRY = 0 +ARP_VALID_MAPPING = 1 +ARP_AWAITING_RESPONSE = 2 +ARP_RESPONSE_TIMEOUT = 3 + +ARP_REQUEST_TTL = 31 ; 20 s +ARP_ENTRY_TTL = 937 ; 600 s +ARP_STATIC_ENTRY = -1 + +ARP_REQ_OPCODE = 0x0100 ; request +ARP_REP_OPCODE = 0x0200 ; reply + +ARP_TABLE_SIZE = 20 ; Size of table + +struct ARP_entry + + IP dd ? + MAC dp ? + Status dw ? + TTL dw ? + +ends + +struct ARP_header + + HardwareType dw ? + ProtocolType dw ? + HardwareSize db ? + ProtocolSize db ? + Opcode dw ? + SenderMAC dp ? + SenderIP dd ? + TargetMAC dp ? + TargetIP dd ? + +ends + +align 4 +uglobal + + NumARP dd ? + + ARP_table rb ARP_TABLE_SIZE * sizeof.ARP_entry ; TODO: separate ARP table and stats per interface + + ARP_PACKETS_TX rd MAX_NET_DEVICES + ARP_PACKETS_RX rd MAX_NET_DEVICES + ARP_CONFLICTS rd MAX_NET_DEVICES + + +endg + + + +;----------------------------------------------------------------- +; +; ARP_init +; +; This function resets all ARP variables +; +;----------------------------------------------------------------- +macro ARP_init { + + xor eax, eax + mov [NumARP], eax + + mov edi, ARP_PACKETS_TX + mov ecx, 3*MAX_NET_DEVICES + rep stosd + +} + +;--------------------------------------------------------------------------- +; +; ARP_decrease_entry_ttls +; +;--------------------------------------------------------------------------- + +macro ARP_decrease_entry_ttls { + +local .loop +local .exit + +; The TTL field is decremented every second, and is deleted when it reaches 0. +; It is refreshed every time a packet is received. +; If the TTL field is 0xFFFF it is a static entry and is never deleted. +; The status field can be the following values: +; 0x0000 entry not used +; 0x0001 entry holds a valid mapping +; 0x0002 entry contains an IP address, awaiting ARP response +; 0x0003 No response received to ARP request. +; The last status value is provided to allow the network layer to delete +; a packet that is queued awaiting an ARP response + + mov ecx, [NumARP] + test ecx, ecx + jz .exit + + mov esi, ARP_table + .loop: + cmp [esi + ARP_entry.TTL], ARP_STATIC_ENTRY + je .next + + dec [esi + ARP_entry.TTL] + jz .time_out + + .next: + add esi, sizeof.ARP_entry + dec ecx + jnz .loop + jmp .exit + + .time_out: + cmp [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE + je .response_timeout + + push esi ecx + call ARP_del_entry + pop ecx esi + + jmp .next + + .response_timeout: + mov [esi + ARP_entry.Status], ARP_RESPONSE_TIMEOUT + mov [esi + ARP_entry.TTL], 10 + + jmp .next + + .exit: + +} + + +;----------------------------------------------------------------- +; +; ARP_input +; +; IN: Pointer to buffer in [esp] +; size of buffer in [esp+4] +; packet size (without ethernet header) in ecx +; packet ptr in edx +; device ptr in ebx +; OUT: / +; +;----------------------------------------------------------------- +align 4 +ARP_input: + +;----------------------------------------- +; Check validity and print some debug info + + cmp ecx, sizeof.ARP_header + jb .exit + + call NET_ptr_to_num + cmp edi, -1 + jz .exit + + inc [ARP_PACKETS_RX + 4*edi] ; update stats + + DEBUGF 1,"ARP_input: got packet from %u.%u.%u.%u through device %u\n",\ + [edx + ARP_header.SenderIP]:1, [edx + ARP_header.SenderIP + 1]:1,\ + [edx + ARP_header.SenderIP + 2]:1, [edx + ARP_header.SenderIP + 3]:1, edi + +;------------------------------ +; First, check for IP collision + + mov eax, [edx + ARP_header.SenderIP] + cmp eax, [IP_LIST + 4*edi] + je .collision + +;--------------------- +; Handle reply packets + + cmp [edx + ARP_header.Opcode], ARP_REP_OPCODE + jne .maybe_request + + DEBUGF 1,"ARP_input: It's a reply\n" + + mov ecx, [NumARP] + test ecx, ecx + jz .exit + + mov esi, ARP_table + .loop: + cmp [esi + ARP_entry.IP], eax + je .gotit + add esi, sizeof.ARP_entry + dec ecx + jnz .loop + + DEBUGF 1,"ARP_input: no matching entry found\n" + jmp .exit + + .gotit: + DEBUGF 1,"ARP_input: found matching entry\n" + + cmp [esi + ARP_entry.TTL], ARP_STATIC_ENTRY ; if it is a static entry, dont touch it + je .exit + + DEBUGF 1,"ARP_input: updating entry\n" + + mov [esi + ARP_entry.Status], ARP_VALID_MAPPING + mov [esi + ARP_entry.TTL], ARP_ENTRY_TTL + + mov eax, dword [edx + ARP_header.SenderMAC] + mov dword [esi + ARP_entry.MAC], eax + mov cx, word [edx + ARP_header.SenderMAC + 4] + mov word [esi + ARP_entry.MAC + 4], cx + + jmp .exit + +;----------------------- +; Handle request packets + + .maybe_request: + cmp [edx + ARP_header.Opcode], ARP_REQ_OPCODE + jne .exit + + DEBUGF 1,"ARP_input: its a request\n" + + mov eax, [IP_LIST + 4*edi] + cmp eax, [edx + ARP_header.TargetIP] ; Is it looking for my IP address? + jne .exit + + push eax + push edi + +; OK, it is a request for one of our MAC addresses. +; Build the frame and send it. We can reuse the buffer. (faster then using ARP_create_packet) + + lea esi, [edx + ARP_header.SenderMAC] + lea edi, [edx + ARP_header.TargetMAC] + movsd ; Move Sender Mac to Dest MAC + movsw ; + movsd ; Move sender IP to Dest IP + + pop esi + mov esi, [NET_DRV_LIST + 4*esi] + lea esi, [esi + ETH_DEVICE.mac] + lea edi, [edx + ARP_header.SenderMAC] + movsd ; Copy MAC address from in MAC_LIST + movsw ; + pop eax + stosd ; Write our IP + + mov [edx + ARP_header.Opcode], ARP_REP_OPCODE + +; Now, Fill in ETHERNET header + + mov edi, [esp] + lea esi, [edx + ARP_header.TargetMAC] + movsd + movsw + lea esi, [edx + ARP_header.SenderMAC] + movsd + movsw +; mov ax , ETHER_ARP ; It's already there, I'm sure of it! +; stosw + + DEBUGF 1,"ARP_input: Sending reply\n" + + call [ebx + NET_DEVICE.transmit] + ret + + .collision: + inc [ARP_CONFLICTS + 4*edi] + DEBUGF 1,"ARP_input: IP address conflict detected!\n" + + .exit: + call kernel_free + add esp, 4 ; pop (balance stack) + + DEBUGF 1,"ARP_input: exiting\n" + ret + + +;--------------------------------------------------------------------------- +; +; ARP_output_request +; +; IN: ip in eax +; device in edi +; OUT: / +; +;--------------------------------------------------------------------------- +align 4 +ARP_output_request: + + push eax ; DestIP + pushd [IP_LIST + edi] ; SenderIP + inc [ARP_PACKETS_TX + edi] ; assume we will succeed + + DEBUGF 1,"ARP_output_request: ip=%u.%u.%u.%u\n",\ + [esp + 4]:1, [esp + 5]:1, [esp + 6]:1, [esp + 7]:1 + + mov ebx, [NET_DRV_LIST + edi] ; device ptr + + lea eax, [ebx + ETH_DEVICE.mac] ; local device mac + mov edx, ETH_BROADCAST ; broadcast mac + mov ecx, sizeof.ARP_header + mov di, ETHER_ARP + call ETH_output + jz .exit + + mov ecx, eax + + mov [edi + ARP_header.HardwareType], 0x0100 ; Ethernet + mov [edi + ARP_header.ProtocolType], 0x0008 ; IP + mov [edi + ARP_header.HardwareSize], 6 ; MAC-addr length + mov [edi + ARP_header.ProtocolSize], 4 ; IP-addr length + mov [edi + ARP_header.Opcode], ARP_REQ_OPCODE ; Request + + add edi, ARP_header.SenderMAC + + lea esi, [ebx + ETH_DEVICE.mac] ; SenderMac + movsw ; + movsd ; + pop eax ; SenderIP + stosd ; + + mov eax, -1 ; DestMac + stosd ; + stosw ; + pop eax ; DestIP + stosd ; + + DEBUGF 1,"ARP_output_request: device=%x\n", ebx + + push edx ecx + call [ebx + NET_DEVICE.transmit] + ret + + .exit: + add esp, 4 + 4 + DEBUGF 1,"ARP_output_request: failed\n" + sub eax, eax + ret + + +;----------------------------------------------------------------- +; +; ARP_add_entry (or update) +; +; IN: esi = ptr to entry (can easily be made on the stack) +; OUT: eax = entry #, -1 on error +; edi = ptr to newly created entry +; +;----------------------------------------------------------------- ; TODO: use a mutex +align 4 +ARP_add_entry: + + DEBUGF 1,"ARP_add_entry: " + + mov ecx, [NumARP] + cmp ecx, ARP_TABLE_SIZE ; list full ? + jae .error + + xor eax, eax + mov edi, ARP_table + mov ecx, [esi + ARP_entry.IP] + .loop: + cmp [edi + ARP_entry.Status], ARP_NO_ENTRY ; is this slot empty? + je .add + + cmp [edi + ARP_entry.IP], ecx ; if not, check if it doesnt collide + jne .maybe_next + + cmp [edi + ARP_entry.TTL], ARP_STATIC_ENTRY ; ok, its the same IP, update it if not static + jne .add + + .maybe_next: ; try the next slot + add edi, sizeof.ARP_entry + inc eax + cmp eax, ARP_TABLE_SIZE + jae .error + jmp .loop + + .add: + mov ecx, sizeof.ARP_entry/2 + rep movsw + inc [NumARP] + sub edi, sizeof.ARP_entry + DEBUGF 1,"entry=%u\n", eax + + ret + + .error: + DEBUGF 1,"failed\n" + mov eax, -1 + ret + + +;----------------------------------------------------------------- +; +; ARP_del_entry +; +; IN: esi = ptr to arp entry +; OUT: / +; +;----------------------------------------------------------------- +align 4 +ARP_del_entry: + + DEBUGF 1,"ARP_del_entry: entry=%x entrys=%u\n", esi, [NumARP] + DEBUGF 1,"ARP_del_entry: IP=%u.%u.%u.%u\n", \ + [esi + ARP_entry.IP]:1, [esi + ARP_entry.IP + 1]:1, [esi + ARP_entry.IP + 2]:1, [esi + ARP_entry.IP + 3]:1 + + mov ecx, ARP_table + (ARP_TABLE_SIZE - 1) * sizeof.ARP_entry + sub ecx, esi + shr ecx, 1 + + mov edi, esi + add esi, sizeof.ARP_entry + rep movsw + + xor eax, eax + mov ecx, sizeof.ARP_entry/2 + rep stosw + + dec [NumARP] + DEBUGF 1,"ARP_del_entry: success\n" + + ret + + + + + +;----------------------------------------------------------------- +; +; ARP_IP_to_MAC +; +; This function translates an IP address to a MAC address +; +; IN: eax = IPv4 address +; edi = device number +; OUT: eax = -1 on error, -2 means request send +; else, ax = first two bytes of mac (high 16 bits of eax will be 0) +; ebx = last four bytes of mac +; edi = unchanged +; +;----------------------------------------------------------------- +align 4 +ARP_IP_to_MAC: + + DEBUGF 1,"ARP_IP_to_MAC: %u.%u", al, ah + rol eax, 16 + DEBUGF 1,".%u.%u\n", al, ah + rol eax, 16 + + cmp eax, 0xffffffff + je .broadcast + +;-------------------------------- +; Try to find the IP in ARP_table + + mov ecx, [NumARP] + test ecx, ecx + jz .not_in_list + mov esi, ARP_table + ARP_entry.IP + .scan_loop: + cmp [esi], eax + je .found_it + add esi, sizeof.ARP_entry + loop .scan_loop + + .not_in_list: + DEBUGF 1,"ARP_IP_to_MAC: preparing for ARP request\n" + +;-------------------- +; Send an ARP request + + push eax edi ; save IP for ARP_output_request + +; Now create the ARP entry + pushw ARP_REQUEST_TTL ; TTL + pushw ARP_AWAITING_RESPONSE ; status + pushd 0 ; mac + pushw 0 + pushd eax ; ip + mov esi, esp + call ARP_add_entry + add esp, sizeof.ARP_entry ; clear the entry from stack + + cmp eax, -1 ; did ARP_add_entry fail? + je .full + + mov esi, edi + pop edi eax ; IP in eax, device number in edi, for ARP_output_request + + push esi edi + call ARP_output_request ; And send a request + pop edi esi + +;----------------------------------------------- +; At this point, we got an ARP entry in the list + .found_it: + cmp [esi + ARP_entry.Status], ARP_VALID_MAPPING ; Does it have a MAC assigned? + je .valid + +if ARP_BLOCK + + cmp [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE ; Are we waiting for reply from remote end? + jne .give_up + push esi + mov esi, 10 ; wait 10 ms + call delay_ms + pop esi + jmp .found_it ; now check again + +else + + jmp .give_up + +end if + + .valid: + DEBUGF 1,"ARP_IP_to_MAC: found MAC\n" + movzx eax, word[esi + ARP_entry.MAC] + mov ebx, dword[esi + ARP_entry.MAC + 2] + ret + + .full: + DEBUGF 1,"ARP_IP_to_MAC: table is full!\n" + add esp, 8 + .give_up: + DEBUGF 1,"ARP_IP_to_MAC: entry has no valid mapping!\n" + mov eax, -1 + ret + + .broadcast: + mov eax, 0x0000ffff + mov ebx, 0xffffffff + ret + + +;----------------------------------------------------------------- +; +; ARP_API +; +; This function is called by system function 75 +; +; IN: subfunction number in bl +; device number in bh +; ecx, edx, .. depends on subfunction +; +; OUT: ? +; +;----------------------------------------------------------------- +align 4 +ARP_api: + + movzx eax, bh + shl eax, 2 + + and ebx, 0xff + cmp ebx, .number + ja .error + jmp dword [.table + 4*ebx] + + .table: + dd .packets_tx ; 0 + dd .packets_rx ; 1 + dd .entries ; 2 + dd .read ; 3 + dd .write ; 4 + dd .remove ; 5 + dd .send_announce ; 6 + dd .conflicts ; 7 + .number = ($ - .table) / 4 - 1 + + .error: + mov eax, -1 + ret + + .packets_tx: + mov eax, [ARP_PACKETS_TX + eax] + ret + + .packets_rx: + mov eax, [ARP_PACKETS_RX + eax] + ret + + .conflicts: + mov eax, [ARP_CONFLICTS + eax] + ret + + .entries: + mov eax, [NumARP] + ret + + .read: + cmp ecx, [NumARP] + jae .error + ; edi = pointer to buffer + ; ecx = # entry + imul ecx, sizeof.ARP_entry + add ecx, ARP_table + mov esi, ecx + mov ecx, sizeof.ARP_entry/2 + rep movsw + + xor eax, eax + ret + + .write: + ; esi = pointer to buffer + call ARP_add_entry ; out: eax = entry number, -1 on error + ret + + .remove: + ; ecx = # entry + cmp ecx, [NumARP] + jae .error + imul ecx, sizeof.ARP_entry + lea esi, [ARP_table + ecx] + call ARP_del_entry + ret + + .send_announce: + mov edi, eax + mov eax, [IP_LIST + eax] + call ARP_output_request ; now send a gratuitous ARP + ret + diff --git a/kernel/trunk/network/IPv4.inc b/kernel/trunk/network/IPv4.inc new file mode 100644 index 0000000000..2cc0449d52 --- /dev/null +++ b/kernel/trunk/network/IPv4.inc @@ -0,0 +1,1019 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; IPv4.INC ;; +;; ;; +;; Part of the TCP/IP network stack for KolibriOS ;; +;; ;; +;; Based on the work of [Johnny_B] and [smb] ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 3515 $ + +MAX_FRAGMENTS = 64 + +struct IPv4_header + + VersionAndIHL db ? ; Version[0-3 bits] and IHL(header length)[4-7 bits] + TypeOfService db ? ; precedence [7-5] minimize delay [4], maximize throughput [3], maximize riliability [2] minimize momentary cost [1] and zero [0] + TotalLength dw ? + Identification dw ? + FlagsAndFragmentOffset dw ? ; Flags[0-2] and FragmentOffset[3-15] + TimeToLive db ? ; + Protocol db ? + HeaderChecksum dw ? + SourceAddress dd ? + DestinationAddress dd ? + +ends + +struct FRAGMENT_slot + + ttl dw ? ; Time to live for this entry, 0 for empty slot's + id dw ? ; Identification field from IP header + SrcIP dd ? ; .. from IP header + DstIP dd ? ; .. from IP header + ptr dd ? ; Pointer to first packet + +ends + +struct FRAGMENT_entry ; This structure will replace the ethernet header in fragmented ip packets + + PrevPtr dd ? ; Pointer to previous fragment entry (-1 for first packet) + NextPtr dd ? ; Pointer to next fragment entry (-1 for last packet) + Owner dd ? ; Pointer to structure of driver + rb 2 ; to match ethernet header size ;;; FIXME + ; Ip header begins here (we will need the IP header to re-construct the complete packet) +ends + + +align 4 +uglobal + + IP_LIST rd MAX_NET_DEVICES + SUBNET_LIST rd MAX_NET_DEVICES + DNS_LIST rd MAX_NET_DEVICES + GATEWAY_LIST rd MAX_NET_DEVICES + BROADCAST_LIST rd MAX_NET_DEVICES + + IP_packets_tx rd MAX_NET_DEVICES + IP_packets_rx rd MAX_NET_DEVICES + IP_packets_dumped rd MAX_NET_DEVICES + + FRAGMENT_LIST rb MAX_FRAGMENTS * sizeof.FRAGMENT_slot +endg + + +;----------------------------------------------------------------- +; +; IPv4_init +; +; This function resets all IP variables +; +;----------------------------------------------------------------- +macro IPv4_init { + + xor eax, eax + mov edi, IP_LIST + mov ecx, 7*MAX_NET_DEVICES + (sizeof.FRAGMENT_slot*MAX_FRAGMENTS)/4 + rep stosd + +} + + +;----------------------------------------------------------------- +; +; Decrease TimeToLive of all fragment slots +; +;----------------------------------------------------------------- +macro IPv4_decrease_fragment_ttls { + +local .loop, .next + + mov esi, FRAGMENT_LIST + mov ecx, MAX_FRAGMENTS + .loop: + cmp [esi + FRAGMENT_slot.ttl], 0 + je .next + dec [esi + FRAGMENT_slot.ttl] + jz .died + .next: + add esi, sizeof.FRAGMENT_slot + dec ecx + jnz .loop + jmp .done + + .died: + DEBUGF 2,"IPv4 Fragment slot timed-out!\n" +;;; TODO: clear all entry's of timed-out slot + jmp .next + + .done: +} + + + +macro IPv4_checksum ptr { + +; This is the fast procedure to create or check an IP header without options +; To create a new checksum, the checksum field must be set to 0 before computation +; To check an existing checksum, leave the checksum as is, and it will be 0 after this procedure, if it was correct + + push ebx + xor ebx, ebx + add bl, [ptr+1] + adc bh, [ptr+0] + + adc bl, [ptr+3] + adc bh, [ptr+2] + + adc bl, [ptr+5] + adc bh, [ptr+4] + + adc bl, [ptr+7] + adc bh, [ptr+6] + + adc bl, [ptr+9] + adc bh, [ptr+8] + +; we skip 11th and 12th byte, they are the checksum bytes and should be 0 for re-calculation + + adc bl, [ptr+13] + adc bh, [ptr+12] + + adc bl, [ptr+15] + adc bh, [ptr+14] + + adc bl, [ptr+17] + adc bh, [ptr+16] + + adc bl, [ptr+19] + adc bh, [ptr+18] + + adc ebx, 0 + + push ecx + mov ecx, ebx + shr ecx, 16 + and ebx, 0xffff + add ebx, ecx + + mov ecx, ebx + shr ecx, 16 + add ebx, ecx + + not bx + jnz .not_zero + dec bx + .not_zero: + xchg bl, bh + pop ecx + + neg word [ptr+10] ; zero will stay zero so we just get the checksum + add word [ptr+10], bx ; , else we will get (new checksum - old checksum) in the end, wich should be 0 :) + pop ebx + +} + + + +;----------------------------------------------------------------- +; +; IPv4_input: +; +; Will check if IPv4 Packet isnt damaged +; and call appropriate handler. (TCP/UDP/ICMP/..) +; +; It will also re-construct fragmented packets +; +; IN: Pointer to buffer in [esp] +; size of buffer in [esp+4] +; pointer to device struct in ebx +; pointer to IPv4 header in edx +; size of IPv4 packet in ecx +; OUT: / +; +;----------------------------------------------------------------- +align 4 +IPv4_input: ; TODO: add IPv4 raw sockets support + + DEBUGF 2,"IPv4_input, packet from: %u.%u.%u.%u ",\ + [edx + IPv4_header.SourceAddress + 0]:1,[edx + IPv4_header.SourceAddress + 1]:1,\ + [edx + IPv4_header.SourceAddress + 2]:1,[edx + IPv4_header.SourceAddress + 3]:1 + DEBUGF 2,"to: %u.%u.%u.%u\n",\ + [edx + IPv4_header.DestinationAddress + 0]:1,[edx + IPv4_header.DestinationAddress + 1]:1,\ + [edx + IPv4_header.DestinationAddress + 2]:1,[edx + IPv4_header.DestinationAddress + 3]:1 + +;------------------------------- +; re-calculate the checksum + + IPv4_checksum edx + jnz .dump ; if checksum isn't valid then dump packet + + DEBUGF 1,"IPv4_input: Checksum ok\n" + +;----------------------------------- +; Check if destination IP is correct + + call NET_ptr_to_num + shl edi, 2 + + ; check if it matches local ip (Using RFC1122 strong end system model) + + mov eax, [edx + IPv4_header.DestinationAddress] + cmp eax, [IP_LIST + edi] + je .ip_ok + + ; check for broadcast (IP or (not SUBNET)) + + cmp eax, [BROADCAST_LIST + edi] + je .ip_ok + + ; or a special broadcast (255.255.255.255) + + cmp eax, 0xffffffff + je .ip_ok + + ; maybe it's a multicast (224.0.0.0/4) + + and eax, 0x0fffffff + cmp eax, 224 + je .ip_ok + + ; or a loopback address (127.0.0.0/8) + + and eax, 0x00ffffff + cmp eax, 127 + je .ip_ok + + ; or it's just not meant for us.. :( + + DEBUGF 2,"IPv4_input: Destination address does not match!\n" + jmp .dump + +;------------------------ +; Now we can update stats + + .ip_ok: + inc [IP_packets_rx + edi] + +;---------------------------------- +; Check if the packet is fragmented + + test [edx + IPv4_header.FlagsAndFragmentOffset], 1 shl 5 ; Is 'more fragments' flag set ? + jnz .has_fragments ; If so, we definately have a fragmented packet + + test [edx + IPv4_header.FlagsAndFragmentOffset], 0xff1f ; If flag is not set, but there is a fragment offset, the packet is last in series of fragmented packets + jnz .is_last_fragment + +;------------------------------------------------------------------- +; No, it's just a regular IP packet, pass it to the higher protocols + + .handle_it: ; We reach here if packet hasnt been fragmented, or when it already has been re-constructed + + movzx esi, [edx + IPv4_header.VersionAndIHL] ; Calculate Header length by using IHL field + and esi, 0x0000000f ; + shl esi, 2 ; + + movzx ecx, [edx + IPv4_header.TotalLength] ; Calculate length of encapsulated Packet + xchg cl, ch ; + sub ecx, esi ; + + lea edi, [edx + IPv4_header.SourceAddress] ; make edi ptr to source and dest IPv4 address + mov al, [edx + IPv4_header.Protocol] + add esi, edx ; make esi ptr to data + + cmp al, IP_PROTO_TCP + je TCP_input + + cmp al, IP_PROTO_UDP + je UDP_input + + cmp al, IP_PROTO_ICMP + je ICMP_input + + DEBUGF 2,"IPv4_input: unknown protocol %u\n", al + + .dump: + DEBUGF 1,"IPv4_input: dumping\n" + inc [IP_packets_dumped] ; FIXME: use correct interface + call kernel_free + add esp, 4 ; pop (balance stack) + ret + + +;--------------------------- +; Fragmented packet handler + + + .has_fragments: + movzx eax, [edx + IPv4_header.FlagsAndFragmentOffset] + xchg al, ah + shl ax, 3 + + DEBUGF 1,"IPv4_input: fragmented packet offset=%u id=%x\n", ax, [edx + IPv4_header.Identification]:4 + + test ax, ax ; Is this the first packet of the fragment? + jz .is_first_fragment + + +;------------------------------------------------------- +; We have a fragmented IP packet, but it's not the first + + DEBUGF 1,"IPv4_input: Middle fragment packet received!\n" + + call IPv4_find_fragment_slot + cmp esi, -1 + je .dump + + mov [esi + FRAGMENT_slot.ttl], 15 ; Reset the ttl + mov esi, [esi + FRAGMENT_slot.ptr] + or edi, -1 + .find_last_entry: ; The following routine will try to find the last entry + cmp edi, [esi + FRAGMENT_entry.PrevPtr] + jne .destroy_slot ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!) + mov edi, esi + mov esi, [esi + FRAGMENT_entry.NextPtr] + cmp esi, -1 + jne .find_last_entry + ; We found the last entry (pointer is now in edi) + ; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure + + pop eax ; pointer to packet + mov [edi + FRAGMENT_entry.NextPtr], eax ; update pointer of previous entry to the new entry + mov [eax + FRAGMENT_entry.NextPtr], -1 + mov [eax + FRAGMENT_entry.PrevPtr], edi + mov [eax + FRAGMENT_entry.Owner], ebx + + add esp, 4 + ret + + +;------------------------------------ +; We have received the first fragment + + .is_first_fragment: + DEBUGF 1,"IPv4_input: First fragment packet received!\n" + ; try to locate a free slot.. + mov ecx, MAX_FRAGMENTS + mov esi, FRAGMENT_LIST + .find_free_slot: + cmp word [esi + FRAGMENT_slot.ttl], 0 + je .found_free_slot + add esi, sizeof.FRAGMENT_slot + loop .find_free_slot + jmp .dump ; If no free slot was found, dump the packet + + .found_free_slot: ; We found a free slot, let's fill in the FRAGMENT_slot structure + mov [esi + FRAGMENT_slot.ttl], 15 ; RFC recommends 15 secs as ttl + mov ax, [edx + IPv4_header.Identification] + mov [esi + FRAGMENT_slot.id], ax + mov eax, [edx + IPv4_header.SourceAddress] + mov [esi + FRAGMENT_slot.SrcIP], eax + mov eax, [edx + IPv4_header.DestinationAddress] + mov [esi + FRAGMENT_slot.DstIP], eax + pop eax + mov [esi + FRAGMENT_slot.ptr], eax + ; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure + mov [eax + FRAGMENT_entry.NextPtr], -1 + mov [eax + FRAGMENT_entry.PrevPtr], -1 + mov [eax + FRAGMENT_entry.Owner], ebx + + add esp, 4 ; balance stack and exit + ret + + +;----------------------------------- +; We have received the last fragment + + .is_last_fragment: + DEBUGF 1,"IPv4_input: Last fragment packet received!\n" + + call IPv4_find_fragment_slot + cmp esi, -1 + je .dump + + mov esi, [esi + FRAGMENT_slot.ptr] ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer + push esi + xor eax, eax + or edi, -1 + + .count_bytes: + cmp [esi + FRAGMENT_entry.PrevPtr], edi + jne .destroy_slot_pop ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!) + mov cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.TotalLength] ; Add total length + xchg cl, ch + DEBUGF 1,"IPv4_input: Packet size=%u\n", cx + add ax, cx + movzx cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Sub Header length + and cx, 0x000F + shl cx, 2 + DEBUGF 1,"IPv4_input: Header size=%u\n", cx + sub ax, cx + mov edi, esi + mov esi, [esi + FRAGMENT_entry.NextPtr] + cmp esi, -1 + jne .count_bytes + + mov esi, [esp+4] + mov [edi + FRAGMENT_entry.NextPtr], esi ; Add this packet to the chain, this simplifies the following code + mov [esi + FRAGMENT_entry.NextPtr], -1 + mov [esi + FRAGMENT_entry.PrevPtr], edi + mov [esi + FRAGMENT_entry.Owner], ebx + + mov cx, [edx + IPv4_header.TotalLength] ; Note: This time we dont substract Header length + xchg cl, ch + DEBUGF 1,"IPv4_input: Packet size=%u\n", cx + add ax, cx + DEBUGF 1,"IPv4_input: Total Received data size=%u\n", eax + + push eax + mov ax, [edx + IPv4_header.FlagsAndFragmentOffset] + xchg al, ah + shl ax, 3 + add cx, ax + pop eax + DEBUGF 1,"IPv4_input: Total Fragment size=%u\n", ecx + + cmp ax, cx + jne .destroy_slot_pop + + push eax + push eax + call kernel_alloc + test eax, eax + je .destroy_slot_pop ; If we dont have enough space to allocate the buffer, discard all packets in slot + mov edx, [esp+4] ; Get pointer to first fragment entry back in edx + + .rebuild_packet_loop: + movzx ecx, [edx + sizeof.FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset + xchg cl, ch ; intel byte order + shl cx, 3 ; multiply by 8 and clear first 3 bits + DEBUGF 1,"IPv4_input: Fragment offset=%u\n", cx + + lea edi, [eax + ecx] ; Notice that edi will be equal to eax for first fragment + movzx ebx, [edx + sizeof.FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Find header size (in ebx) of fragment + and bx, 0x000F ; + shl bx, 2 ; + + lea esi, [edx + sizeof.FRAGMENT_entry] ; Set esi to the correct begin of fragment + movzx ecx, [edx + sizeof.FRAGMENT_entry + IPv4_header.TotalLength] ; Calculate total length of fragment + xchg cl, ch ; intel byte order + + cmp edi, eax ; Is this packet the first fragment ? + je .first_fragment + sub cx, bx ; If not, dont copy the header + add esi, ebx ; + .first_fragment: + + push cx ; First copy dword-wise, then byte-wise + shr cx, 2 ; + rep movsd ; + pop cx ; + and cx, 3 ; + rep movsb ; + + push eax + push edx ; Push pointer to fragment onto stack + mov ebx, [edx + FRAGMENT_entry.Owner] ; we need to remeber the owner, in case this is the last packet + mov edx, [edx + FRAGMENT_entry.NextPtr] ; Set edx to the next pointer + call kernel_free ; free the previous fragment buffer (this uses the value from stack) + pop eax + cmp edx, -1 ; Check if it is last fragment in chain + jne .rebuild_packet_loop + + pop ecx + xchg cl, ch + mov edx, eax + mov [edx + IPv4_header.TotalLength], cx + add esp, 8 + xchg cl, ch + push ecx + + push eax + jmp .handle_it ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr + + .destroy_slot_pop: + add esp, 4 + .destroy_slot: + DEBUGF 1,"IPv4_input: Destroy fragment slot!\n" + ; TODO! + jmp .dump + + + + + +;----------------------------------------------------------------- +; +; find fragment slot +; +; IN: pointer to fragmented packet in edx +; OUT: pointer to slot in esi, -1 on error +; +;----------------------------------------------------------------- +align 4 +IPv4_find_fragment_slot: + +;;; TODO: the RFC says we should check protocol number too + + push eax ebx ecx edx + mov ax, [edx + IPv4_header.Identification] + mov ecx, MAX_FRAGMENTS + mov esi, FRAGMENT_LIST + mov ebx, [edx + IPv4_header.SourceAddress] + mov edx, [edx + IPv4_header.DestinationAddress] + .find_slot: + cmp [esi + FRAGMENT_slot.id], ax + jne .try_next + cmp [esi + FRAGMENT_slot.SrcIP], ebx + jne .try_next + cmp [esi + FRAGMENT_slot.DstIP], edx + je .found_slot + .try_next: + add esi, sizeof.FRAGMENT_slot + loop .find_slot + + or esi, -1 + .found_slot: + pop edx ecx ebx eax + ret + + +;------------------------------------------------------------------ +; +; IPv4_output +; +; IN: eax = dest ip +; ebx = output device ptr/0 for automatic choice +; ecx = data length +; edx = source ip +; di = TTL shl 8 + protocol +; +; OUT: eax = pointer to buffer start +; ebx = pointer to device struct (needed for sending procedure) +; ecx = unchanged (packet size of embedded data) +; edx = size of complete buffer +; edi = pointer to start of data (0 on error) +; +;------------------------------------------------------------------ +align 4 +IPv4_output: + + DEBUGF 1,"IPv4_output: size=%u\n", ecx + + cmp ecx, 65500 ; Max IPv4 packet size + ja .too_large + + push ecx eax edx di + + cmp eax, 1 shl 24 + 127 + je .loopback + + call IPv4_route ; outputs device number in edi, dest ip in eax + call ARP_IP_to_MAC + test eax, 0xffff0000 ; error bits + jnz .arp_error + push ebx ; push the mac onto the stack + push ax + + inc [IP_packets_tx + edi] ; update stats + + mov ebx, [NET_DRV_LIST + edi] + lea eax, [ebx + ETH_DEVICE.mac] + mov edx, esp + mov ecx, [esp + 10 + 6] + add ecx, sizeof.IPv4_header + mov di, ETHER_IPv4 + call ETH_output + jz .eth_error + add esp, 6 ; pop the mac out of the stack + + .continue: + xchg cl, ch ; internet byte order + mov [edi + IPv4_header.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header) + mov [edi + IPv4_header.TypeOfService], 0 ; nothing special, just plain ip packet + mov [edi + IPv4_header.TotalLength], cx + mov [edi + IPv4_header.Identification], 0 ; fragment id: FIXME + mov [edi + IPv4_header.FlagsAndFragmentOffset], 0 + pop word [edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol +; [edi + IPv4_header.Protocol] + mov [edi + IPv4_header.HeaderChecksum], 0 + popd [edi + IPv4_header.SourceAddress] + popd [edi + IPv4_header.DestinationAddress] + + pop ecx + + IPv4_checksum edi + add edi, sizeof.IPv4_header + DEBUGF 2,"IPv4_output: success!\n" + ret + + .eth_error: + DEBUGF 2,"IPv4_output: ethernet error\n" + add esp, 3*4+2+6 + xor edi, edi + ret + + .arp_error: + DEBUGF 2,"IPv4_output: ARP error=%x\n", eax + add esp, 3*4+2 + xor edi, edi + ret + + .too_large: + DEBUGF 2,"IPv4_output: Packet too large!\n" + xor edi, edi + ret + + .loopback: + mov dword [esp + 2], eax + add ecx, sizeof.IPv4_header + mov di, ETHER_IPv4 + call LOOP_output + jmp .continue + + + + +;------------------------------------------------------------------ +; +; IPv4_output_raw +; +; IN: eax = socket ptr +; ecx = data length +; esi = data ptr +; +; OUT: / +; +;------------------------------------------------------------------ +align 4 +IPv4_output_raw: + + DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax + + cmp ecx, 1480 ;;;;; FIXME + ja .too_large + + sub esp, 8 + push esi eax + + call IPv4_route + call ARP_IP_to_MAC + + test eax, 0xffff0000 ; error bits + jnz .arp_error + + push ebx ; push the mac + push ax + + inc [IP_packets_tx + edi] + mov ebx, [NET_DRV_LIST + edi] + lea eax, [ebx + ETH_DEVICE.mac] + mov edx, esp + mov ecx, [esp + 6 + 4] + add ecx, sizeof.IPv4_header + mov di, ETHER_IPv4 + call ETH_output + jz .error + + add esp, 6 ; pop the mac + + mov dword[esp+4+4], edx + mov dword[esp+4+4+4], eax + + pop eax esi +;; todo: check socket options if we should add header, or just compute checksum + + push edi ecx + rep movsb + pop ecx edi + +; [edi + IPv4_header.VersionAndIHL] ; IPv4, normal length (no Optional header) +; [edi + IPv4_header.TypeOfService] ; nothing special, just plain ip packet +; [edi + IPv4_header.TotalLength] +; [edi + IPv4_header.TotalLength] ; internet byte order +; [edi + IPv4_header.FlagsAndFragmentOffset] + + mov [edi + IPv4_header.HeaderChecksum], 0 + +; [edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol +; [edi + IPv4_header.Protocol] +; [edi + IPv4_header.Identification] ; fragment id +; [edi + IPv4_header.SourceAddress] +; [edi + IPv4_header.DestinationAddress] + + IPv4_checksum edi ;;;; todo: checksum for IP packet with options! + add edi, sizeof.IPv4_header + DEBUGF 2,"IPv4_output_raw: device=%x\n", ebx + call [ebx + NET_DEVICE.transmit] + ret + + .error: + add esp, 6 + .arp_error: + add esp, 8+4+4 + .too_large: + DEBUGF 2,"IPv4_output_raw: Failed\n" + sub edi, edi + ret + + +;-------------------------------------------------------- +; +; +; IN: dword [esp] = pointer to buffer containing ipv4 packet to be fragmented +; dword [esp+4] = buffer size +; esi = pointer to ip header in that buffer +; ecx = max size of fragments +; +; OUT: / +; +;-------------------------------------------------------- + +align 4 +IPv4_fragment: + + DEBUGF 1,"IPv4_fragment\n" + + and ecx, not 111b ; align 4 + + cmp ecx, sizeof.IPv4_header + 8 ; must be able to put at least 8 bytes + jb .err2 + + push esi ecx + mov eax, [esi + IPv4_header.DestinationAddress] + call ARP_IP_to_MAC + pop ecx esi + cmp eax, -1 + jz .err2 + + push ebx + push ax + + mov ebx, [NET_DRV_LIST] + lea eax, [ebx + ETH_DEVICE.mac] + push eax + + + push esi ; ptr to ip header + sub ecx, sizeof.IPv4_header ; substract header size + push ecx ; max data size + push dword 0 ; offset + + .new_fragment: + DEBUGF 1,"Ipv4_fragment: new fragment" + + + mov eax, [esp + 3*4] + lea ebx, [esp + 4*4] + mov di , ETHER_IPv4 + call ETH_output + + cmp edi, -1 + jz .err + +; copy header + mov esi, [esp + 2*4] + mov ecx, 5 ; 5 dwords: TODO: use IHL field of the header! + rep movsd + +; copy data + mov esi, [esp + 2*4] + add esi, sizeof.IPv4_header + add esi, [esp] ; offset + + mov ecx, [esp + 1*4] + DEBUGF 1,"IPv4_fragment: copying %u bytes\n", ecx + rep movsb + +; now, correct header + mov ecx, [esp + 1*4] + add ecx, sizeof.IPv4_header + xchg cl, ch + mov [edi + IPv4_header.TotalLength], cx + + mov ecx, [esp] ; offset + xchg cl, ch + +; cmp dword[esp + 4*4], 0 ; last fragment?;<<<<<< +; je .last_fragment + or cx, 1 shl 2 ; more fragments +; .last_fragment: + mov [edi + IPv4_header.FlagsAndFragmentOffset], cx + + mov [edi + IPv4_header.HeaderChecksum], 0 + + ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet + mov ecx, [esp + 1*4] + + push edx eax + IPv4_checksum edi + + call [ebx + NET_DEVICE.transmit] + ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + mov ecx, [esp+4] + add [esp], ecx + + mov ecx, [esp+3*4+6+4] ; ptr to begin of buff + add ecx, [esp+3*4+6+4+4] ; buff size + sub ecx, [esp+2*4] ; ptr to ip header + add ecx, [esp] ; offset + + DEBUGF 1,"Ipv4_fragment: %u bytes remaining\n", ecx + + cmp ecx, [esp+1*4] + jae .new_fragment + + mov [esp+4], ecx ; set fragment size to remaining packet size + jmp .new_fragment + + .err: + DEBUGF 1,"Ipv4_fragment: failed\n" + .done: + add esp, 12 + 4 + 6 + .err2: + DEBUGF 1,"Ipv4_fragment: dumping\n" + call kernel_free + add esp, 4 + + ret + + + +;--------------------------------------------------------------------------- +; +; IPv4_route +; +; IN: eax = Destination IP +; OUT: edi = device id * 4 +; eax = ip of gateway if nescessary, unchanged otherwise +; +;--------------------------------------------------------------------------- +align 4 +IPv4_route: + + cmp eax, 0xffffffff + je .broadcast + + xor edi, edi + mov ecx, MAX_NET_DEVICES + .loop: + mov ebx, [IP_LIST+edi] + and ebx, [SUBNET_LIST+edi] + jz .next + mov edx, eax + and edx, [SUBNET_LIST+edi] + + cmp ebx, edx + je .found_it + .next: + add edi, 4 + dec ecx + jnz .loop + + .invalid: + xor edi, edi ; if none found, use device 0 as default + mov eax, [GATEWAY_LIST] + + .found_it: + DEBUGF 1,"IPv4_dest_to_dev: %u\n", edi + ret + + .broadcast: + xor edi, edi + ret + + + +;--------------------------------------------------------------------------- +; +; IPv4_get_frgmnt_num +; +; IN: / +; OUT: fragment number in ax +; +;--------------------------------------------------------------------------- +align 4 +IPv4_get_frgmnt_num: + xor ax, ax ;;; TODO: replace this with real code + + ret + + +;--------------------------------------------------------------------------- +; +; IPv4_API +; +; This function is called by system function 75 +; +; IN: subfunction number in bl +; device number in bh +; ecx, edx, .. depends on subfunction +; +; OUT: +; +;--------------------------------------------------------------------------- +align 4 +IPv4_api: + + movzx eax, bh + shl eax, 2 + + and ebx, 0x000000ff + cmp ebx, .number + ja .error + jmp dword [.table + 4*ebx] + + .table: + dd .packets_tx ; 0 + dd .packets_rx ; 1 + dd .read_ip ; 2 + dd .write_ip ; 3 + dd .read_dns ; 4 + dd .write_dns ; 5 + dd .read_subnet ; 6 + dd .write_subnet ; 7 + dd .read_gateway ; 8 + dd .write_gateway ; 9 + .number = ($ - .table) / 4 - 1 + + .error: + mov eax, -1 + ret + + .packets_tx: + mov eax, [IP_packets_tx + eax] + ret + + .packets_rx: + mov eax, [IP_packets_rx + eax] + ret + + .read_ip: + mov eax, [IP_LIST + eax] + ret + + .write_ip: + mov [IP_LIST + eax], ecx + mov edi, eax ; device number, we'll need it for ARP + + ; pre-calculate the local broadcast address + mov ebx, [SUBNET_LIST + eax] + not ebx + or ebx, ecx + mov [BROADCAST_LIST + eax], ebx + + mov eax, ecx + call ARP_output_request ; now send a gratuitous ARP + + call NET_send_event + xor eax, eax + ret + + .read_dns: + mov eax, [DNS_LIST + eax] + ret + + .write_dns: + mov [DNS_LIST + eax], ecx + call NET_send_event + xor eax, eax + ret + + .read_subnet: + mov eax, [SUBNET_LIST + eax] + ret + + .write_subnet: + mov [SUBNET_LIST + eax], ecx + + ; pre-calculate the local broadcast address + mov ebx, [IP_LIST + eax] + not ecx + or ecx, ebx + mov [BROADCAST_LIST + eax], ecx + + call NET_send_event + xor eax, eax + ret + + .read_gateway: + mov eax, [GATEWAY_LIST + eax] + ret + + .write_gateway: + mov [GATEWAY_LIST + eax], ecx + + call NET_send_event + xor eax, eax + ret \ No newline at end of file diff --git a/kernel/trunk/network/IPv6.inc b/kernel/trunk/network/IPv6.inc new file mode 100644 index 0000000000..1f28e5781b --- /dev/null +++ b/kernel/trunk/network/IPv6.inc @@ -0,0 +1,298 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2012-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; IPv6.INC ;; +;; ;; +;; Part of the tcp/ip network stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 3251 $ + + +struct IPv6_header + + VersionTrafficFlow dd ? ; Version[0-3], Traffic class[4-11], Flow Label [12-31] + PayloadLength dw ? ; 16 bits, unsigned length of payload (extension headers are part of this) + NextHeader db ? ; Values are same as in IPv4 'Protocol' field + HopLimit db ? ; Decremented by every node, packet is discarded when it reaches 0 + SourceAddress rd 4 ; 128-bit addresses + DestinationAddress rd 4 ; + Payload rb 0 + +ends + + +align 4 +uglobal + + IPv6: + .addresses rd 4*MAX_NET_DEVICES + .subnet rd 4*MAX_NET_DEVICES + .dns rd 4*MAX_NET_DEVICES + .gateway rd 4*MAX_NET_DEVICES + + .packets_tx rd MAX_NET_DEVICES + .packets_rx rd MAX_NET_DEVICES + +endg + + +;----------------------------------------------------------------- +; +; IPv6_init +; +; This function resets all IP variables +; +;----------------------------------------------------------------- +macro IPv6_init { + + xor eax, eax + mov edi, IPv6 + mov ecx, (4*4*4+2*4)MAX_IP + rep stosd + +} + + + +;----------------------------------------------------------------- +; +; IPv6_input: +; +; Will check if IPv6 Packet isnt damaged +; and call appropriate handler. (TCP/UDP/ICMP/..) +; +; It will also re-construct fragmented packets +; +; IN: Pointer to buffer in [esp] +; size of buffer in [esp+4] +; pointer to device struct in ebx +; pointer to IPv6 header in edx +; size of IPv6 packet in ecx +; OUT: / +; +;----------------------------------------------------------------- +align 4 +IPv6_input: + + DEBUGF 2,"IPv6_input from: %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x\n",\ + [edx + IPv6_header.SourceAddress + 0]:2,[edx + IPv6_header.SourceAddress + 1]:2,\ + [edx + IPv6_header.SourceAddress + 2]:2,[edx + IPv6_header.SourceAddress + 3]:2,\ + [edx + IPv6_header.SourceAddress + 4]:2,[edx + IPv6_header.SourceAddress + 5]:2,\ + [edx + IPv6_header.SourceAddress + 6]:2,[edx + IPv6_header.SourceAddress + 7]:2,\ + [edx + IPv6_header.SourceAddress + 8]:2,[edx + IPv6_header.SourceAddress + 9]:2,\ + [edx + IPv6_header.SourceAddress + 10]:2,[edx + IPv6_header.SourceAddress + 11]:2,\ + [edx + IPv6_header.SourceAddress + 12]:2,[edx + IPv6_header.SourceAddress + 13]:2,\ + [edx + IPv6_header.SourceAddress + 14]:2,[edx + IPv6_header.SourceAddress + 15]:2 + + DEBUGF 1,"IPv6_input to: %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x\n",\ + [edx + IPv6_header.DestinationAddress + 0]:2,[edx + IPv6_header.DestinationAddress + 1]:2,\ + [edx + IPv6_header.DestinationAddress + 2]:2,[edx + IPv6_header.DestinationAddress + 3]:2,\ + [edx + IPv6_header.DestinationAddress + 4]:2,[edx + IPv6_header.DestinationAddress + 5]:2,\ + [edx + IPv6_header.DestinationAddress + 6]:2,[edx + IPv6_header.DestinationAddress + 7]:2,\ + [edx + IPv6_header.DestinationAddress + 8]:2,[edx + IPv6_header.DestinationAddress + 9]:2,\ + [edx + IPv6_header.DestinationAddress + 10]:2,[edx + IPv6_header.DestinationAddress + 11]:2,\ + [edx + IPv6_header.DestinationAddress + 12]:2,[edx + IPv6_header.DestinationAddress + 13]:2,\ + [edx + IPv6_header.DestinationAddress + 14]:2,[edx + IPv6_header.DestinationAddress + 15]:2 + + sub ecx, sizeof.IPv6_header + jb .dump + + cmp cx, [edx + IPv6_header.PayloadLength] + jb .dump + +;------------------------------------------------------------------- +; No, it's just a regular IP packet, pass it to the higher protocols + + .handle_it: + movzx ecx, [edx + IPv6_header.PayloadLength] + lea edi, [edx + IPv6_header.SourceAddress] ; make edi ptr to source and dest IPv6 address + lea esi, [edx + IPv6_header.Payload] ; make esi ptr to data + mov al, [edx + IPv6_header.NextHeader] + + .scan: + cmp al, 59 ; no next + je .dump + + cmp al, 0 + je .hop_by_hop + + cmp al, 43 + je .routing + + cmp al, 44 + je .fragment + + cmp al, 60 + je .dest_opts + +; cmp al, IP_PROTO_TCP +; je TCP_input + +; cmp al, IP_PROTO_UDP +; je UDP_input + +; cmp al, 58 +; je ICMP6_input + + DEBUGF 2,"IPv6_input - unknown protocol: %u\n", al + + .dump: + DEBUGF 1,"IPv6_input - dumping\n" + call kernel_free + add esp, 4 + + ret + + .dump_options: + add esp, 2+4+4 + jmp .dump + + .nextheader: + pop esi + pop ecx + pop ax + jmp .scan + +;------------------------- +; Hop-by-Hop + + .hop_by_hop: + DEBUGF 1,"IPv6_input - hop by hop\n" + pushw [esi] ; 8 bit identifier for option type + movzx eax, byte[esi + 1] ; Hdr Ext Len + inc eax ; first 8 octets not counted + shl eax, 3 ; * 8 + sub ecx, eax + push ecx + add eax, esi + push eax + inc esi + inc esi + + mov al, [esi] + + cmp al, 0 + je .pad_1 + + cmp al, 1 + je .pad_n + + ; TODO: check with other known options + +; unknown option.. discard packet or not? +; check highest two bits + test al, 0xc0 ; discard packet + jnz .dump_options + + .pad_n: + movzx eax, byte[esi + 1] + DEBUGF 1,"IPv6_input - pad %u\n", eax + inc esi + inc esi + add esi, eax + sub ecx, eax + jmp .hop_by_hop + + .pad_1: + DEBUGF 1,"IPv6_input - pad 1\n" + inc esi + dec ecx + jmp .hop_by_hop + + + + .dest_opts: + DEBUGF 1,"IPv6_input - dest opts\n" + jmp .nextheader + + .routing: + DEBUGF 1,"IPv6_input - routing\n" + pushw [esi] ; 8 bit identifier for option type + movzx eax, byte[esi + 1] ; Hdr Ext Len + inc eax ; first 8 octets not counted + shl eax, 3 ; * 8 + sub ecx, eax + push ecx + add eax, esi + push eax + inc esi + inc esi + + cmp al, 0 + je .pad_1 + + cmp al, 1 + je .pad_n + + mov al, [esi] ; routing type + + jmp .nextheader + + .fragment: + DEBUGF 1,"IPv6_input - fragment\n" + + jmp .nextheader + + + + + + +;--------------------------------------------------------------------------- +; +; IPv6_API +; +; This function is called by system function 75 +; +; IN: subfunction number in bl +; device number in bh +; ecx, edx, .. depends on subfunction +; +; OUT: +; +;--------------------------------------------------------------------------- +align 4 +IPv6_api: + + movzx eax, bh + shl eax, 2 + + and ebx, 0x000000ff + cmp ebx, .number + ja .error + jmp dword [.table + 4*ebx] + + .table: + dd .packets_tx ; 0 + dd .packets_rx ; 1 +; dd .read_ip ; 2 +; dd .write_ip ; 3 +; dd .read_dns ; 4 +; dd .write_dns ; 5 +; dd .read_subnet ; 6 +; dd .write_subnet ; 7 +; dd .read_gateway ; 8 +; dd .write_gateway ; 9 + .number = ($ - .table) / 4 - 1 + + .error: + mov eax, -1 + ret + + .packets_tx: + mov eax, [IPv6.packets_tx + eax] + ret + + .packets_rx: + mov eax, [IPv6.packets_rx + eax] + ret + diff --git a/kernel/trunk/network/PPPoE.inc b/kernel/trunk/network/PPPoE.inc new file mode 100644 index 0000000000..f2ff64717e --- /dev/null +++ b/kernel/trunk/network/PPPoE.inc @@ -0,0 +1,340 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; PPPoE.INC ;; +;; ;; +;; Part of the tcp/ip network stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +struct PPPoE_frame + VersionAndType db ? + Code db ? + SessionID dw ? + Length dw ? ; Length of payload, does NOT include the length PPPoE header. + Payload rb 0 +ends + +uglobal + PPPoE_SID dw ? + PPPoE_MAC dp ? +endg + +;----------------------------------------------------------------- +; +; PPPoE_init +; +; This function resets all IP variables +; +;----------------------------------------------------------------- +macro PPPoE_init { + + call PPPoE_stop_connection + +} + + +;----------------------------------------------------------------- +; +; PPPoE discovery input +; +; Handler of received Ethernet packet with type = Discovery +; +; +; IN: Pointer to buffer in [esp] +; size of buffer in [esp+4] +; pointer to device struct in ebx +; pointer to PPP header in edx +; size of PPP packet in ecx +; OUT: / +; +;----------------------------------------------------------------- +align 4 +PPPoE_discovery_input: + + DEBUGF 2,"PPPoE_discovery_input\n" + +; First, find open PPPoE socket + + mov eax, net_sockets + + .next_socket: + mov eax, [eax + SOCKET.NextPtr] + or eax, eax + jz .dump + + cmp [eax + SOCKET.Domain], AF_PPP + jne .next_socket + + cmp [eax + SOCKET.Protocol], PPP_PROTO_ETHERNET + jne .next_socket + +; Now, send it to the this socket + + mov ecx, [esp + 4] + mov esi, [esp] + + jmp SOCKET_input + + .dump: + DEBUGF 1,'PPPoE_discovery_input: dumping\n' + call kernel_free + add esp, 4 + ret + + +;-------------------------------------- +; +; Send discovery packet +; +; IN: eax = socket pointer +; ecx = number of bytes to send +; esi = pointer to data +; +;-------------------------------------- + +align 4 +PPPoE_discovery_output: + + DEBUGF 2,"PPPoE_discovery_output: socket=%x buffer=%x size=%d\n", eax, esi, ecx + +; RFC2516: An entire PADI packet (including the PPPoE header) MUST NOT +; exceed 1484 octets. + cmp ecx, 1484 + 14 + ja .bad + +; Check that device exists and is ethernet device + mov ebx, [eax + SOCKET.device] + + cmp ebx, MAX_NET_DEVICES + ja .bad + + mov ebx, [NET_DRV_LIST + 4*ebx] + test ebx, ebx + jz .bad + + cmp [ebx + NET_DEVICE.type], NET_TYPE_ETH + jne .bad + + DEBUGF 2,"PPPoE_discovery_output: device=%x\n", ebx + +; Create packet. + push ecx esi + stdcall kernel_alloc, 1500 + pop esi ecx + test eax, eax + jz .bad + + mov edx, ecx + mov edi, eax + rep movsb + + cmp edx, 60 ; Min ETH size + ja @f + mov edx, 60 + @@: + + push edx eax ; size and packet ptr for driver send proc + +; Overwrite source MAC and protocol type + lea edi, [eax + ETH_header.SrcMAC] + lea esi, [ebx + ETH_DEVICE.mac] + movsd + movsw + cmp word[edi], ETHER_PPP_SESSION ; Allow only PPP_discovery, or LCP + je @f + mov ax, ETHER_PPP_DISCOVERY + stosw + @@: + +; And send the packet + call [ebx + NET_DEVICE.transmit] + + xor eax, eax + ret + + .bad: + or eax, -1 + ret + + +;----------------------------------------------------------------- +; +; PPPoE session input +; +; Handler of received Ethernet packet with type = Session +; +; +; IN: Pointer to buffer in [esp] +; size of buffer in [esp+4] +; pointer to device struct in ebx +; pointer to PPP header in edx +; size of PPP packet in ecx +; OUT: / +; +;----------------------------------------------------------------- +align 4 +PPPoE_session_input: + + cmp [edx + PPPoE_frame.VersionAndType], 0x11 + jne .dump + + cmp [edx + PPPoE_frame.Code], 0x00 + jne .dump + + movzx ecx, [edx + PPPoE_frame.Length] + xchg cl, ch + + mov ax, [edx + PPPoE_frame.SessionID] + DEBUGF 2,"PPPoE_input: session ID=%x, length=%u\n", ax, cx + cmp ax, [PPPoE_SID] + jne .dump + + mov ax, word [edx + PPPoE_frame.Payload] + add edx, PPPoE_frame.Payload + 2 + + cmp ax, PPP_IPv4 + je IPv4_input + +; cmp ax, PPP_IPv6 +; je IPv6_input + + jmp PPPoE_discovery_input ; Send LCP,CHAP,CBCP,... packets to the PPP dialer + DEBUGF 2,"PPPoE_input: Unknown protocol=%x\n", ax + + .dump: + DEBUGF 2,"PPPoE_input: dumping\n" + call kernel_free + add esp, 4 + ret + + + + +;----------------------------------------------------------------- +; +; PPPoE_output +; +; IN: +; ebx = device ptr +; ecx = packet size +; +; di = protocol +; +; OUT: edi = 0 on error, pointer to buffer otherwise +; eax = buffer start +; ebx = to device structure +; ecx = unchanged (packet size of embedded data) +; edx = size of complete buffer +; +;----------------------------------------------------------------- +align 4 +PPPoE_output: + + DEBUGF 1,"PPPoE_output: size=%u device=%x\n", ecx, ebx + + pushw di + pushw [PPPoE_SID] + + lea eax, [ebx + ETH_DEVICE.mac] + lea edx, [PPPoE_MAC] + add ecx, PPPoE_frame.Payload + 2 + mov di, ETHER_PPP_SESSION + call ETH_output + jz .eth_error + + sub ecx, PPPoE_frame.Payload + mov [edi + PPPoE_frame.VersionAndType], 0x11 + mov [edi + PPPoE_frame.Code], 0 + popw [edi + PPPoE_frame.SessionID] + xchg cl, ch + mov [edi + PPPoE_frame.Length], cx + xchg cl, ch + + pop word [edi + PPPoE_frame.Payload] + + sub ecx, 2 + add edi, PPPoE_frame.Payload + 2 + + DEBUGF 1,"PPPoE_output: success!\n" + ret + + + .eth_error: + add esp, 4 + xor edi, edi + + ret + + +PPPoE_start_connection: + + DEBUGF 2,"PPPoE_start_connection: %x\n", cx + + cmp [PPPoE_SID], 0 + jne .fail + + mov [PPPoE_SID], cx + mov dword [PPPoE_MAC], edx + mov word [PPPoE_MAC + 4], si + + xor eax, eax + ret + + .fail: + or eax, -1 + ret + + +align 4 +PPPoE_stop_connection: + + DEBUGF 2,"PPPoE_stop_connection\n" + + xor eax, eax + mov [PPPoE_SID], ax + mov dword [PPPoE_MAC], eax + mov word [PPPoE_MAC + 4], ax + + ret + + +;--------------------------------------------------------------------------- +; +; PPPoE API +; +; This function is called by system function 75 +; +; IN: subfunction number in bl +; device number in bh +; ecx, edx, .. depends on subfunction +; +; OUT: +; +;--------------------------------------------------------------------------- +align 4 +PPPoE_api: + + movzx eax, bh + shl eax, 2 + + and ebx, 0xff + cmp ebx, .number + ja .error + jmp dword [.table + 4*ebx] + + .table: + dd PPPoE_start_connection ; 0 + dd PPPoE_stop_connection ; 1 + .number = ($ - .table) / 4 - 1 + + .error: + mov eax, -1 + ret diff --git a/kernel/trunk/network/eth_drv/arp.inc b/kernel/trunk/network/eth_drv/arp.inc deleted file mode 100644 index 7f56ff5233..0000000000 --- a/kernel/trunk/network/eth_drv/arp.inc +++ /dev/null @@ -1,557 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; ARP.INC ;; -;; ;; -;; Address Resolution Protocol ;; -;; ;; -;; This file contains the following: ;; -;; arp_table_manager - Manages an ARPTable ;; -;; arp_request - Sends an ARP request on the ethernet ;; -;; arp_handler - Called when an ARP packet is received ;; -;; ;; -;; Changes history: ;; -;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net ;; -;; 11.11.2006 - [Johnny_B] and [smb] ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -ARP_NO_ENTRY equ 0 -ARP_VALID_MAPPING equ 1 -ARP_AWAITING_RESPONSE equ 2 -ARP_RESPONSE_TIMEOUT equ 3 - -struc ARP_ENTRY ;=14 bytes -{ .IP dd ? ;+00 - .MAC dp ? ;+04 - .Status dw ? ;+10 - .TTL dw ? ;+12 : ( in seconds ) -} - -virtual at 0 - ARP_ENTRY ARP_ENTRY -end virtual - -; The TTL field is decremented every second, and is deleted when it -; reaches 0. It is refreshed every time a packet is received -; If the TTL field is 0xFFFF it is a static entry and is never deleted -; The status field can be the following values: -; 0x0000 entry not used -; 0x0001 entry holds a valid mapping -; 0x0002 entry contains an IP address, awaiting ARP response -; 0x0003 No response received to ARP request. -; The last status value is provided to allow the network layer to delete -; a packet that is queued awaiting an ARP response - - -; The follow is the ARP Table. -; This table must be manually updated and the kernel recompilied if -; changes are made to it. -; Empty entries are filled with zeros - -ARP_ENTRY_SIZE equ 14 ; Number of bytes per entry -ARP_TABLE_SIZE equ 20 ; Size of table -ARP_TABLE_ENTRIES equ 0 ; Number of static entries in the table - -;TO ADD A STATIC ENTRY, DONT FORGET, PUT "ARPTable" from "uglobal" to "iglobal"!!! -;AND ALSO - IP and MAC have net byte-order, BUT STATUS AND TTL HAVE A MIRROR BYTE-ORDER!!! -uglobal - ARPTable: -;example, static entry -> db 11,22,33,44, 0x11,0x22,0x33,0x44,0x55,0x66, 0x01,0x00, 0xFF,0xFF - times ( ARP_TABLE_SIZE - ARP_TABLE_ENTRIES ) * ARP_ENTRY_SIZE db 0 -endg - -iglobal - NumARP: - dd ARP_TABLE_ENTRIES - ARPTable_ptr dd ARPTable ;pointer to ARPTable -endg - -ARP_REQ_OPCODE equ 0x0100 ;request -ARP_REP_OPCODE equ 0x0200 ;reply - -struc ARP_PACKET -{ .HardwareType dw ? ;+00 - .ProtocolType dw ? ;+02 - .HardwareSize db ? ;+04 - .ProtocolSize db ? ;+05 - .Opcode dw ? ;+06 - .SenderMAC dp ? ;+08 - .SenderIP dd ? ;+14 - .TargetMAC dp ? ;+18 - .TargetIP dd ? ;+24 -} - -virtual at 0 - ARP_PACKET ARP_PACKET -end virtual - - - -;*************************************************************************** -; Function -; arp_table_manager [by Johnny_B] -; -; Description -; Does a most required operations with ARP-table -; IN: -; Operation: see Opcode's constants below -; Index: Index of entry in the ARP-table -; Extra: Extra parameter for some Opcodes -; OUT: -; EAX = Returned value depends on opcodes, more detailed see below -; -;*************************************************************************** -;Opcode's constants -ARP_TABLE_ADD equ 1 -ARP_TABLE_DEL equ 2 -ARP_TABLE_GET equ 3 -ARP_TABLE_GET_ENTRIES_NUMBER equ 4 -ARP_TABLE_IP_TO_MAC equ 5 -ARP_TABLE_TIMER equ 6 - -;Index's constants -EXTRA_IS_ARP_PACKET_PTR equ 0 ;if Extra contain pointer to ARP_PACKET -EXTRA_IS_ARP_ENTRY_PTR equ -1 ;if Extra contain pointer to ARP_ENTRY - -align 4 -proc arp_table_manager stdcall uses ebx esi edi ecx edx,\ - Opcode:DWORD,Index:DWORD,Extra:DWORD - - mov ebx, dword[ARPTable_ptr];ARPTable base - mov ecx, dword[NumARP] ;ARP-entries counter - - mov eax, dword[Opcode] - cmp eax, ARP_TABLE_TIMER - je .timer - cmp eax, ARP_TABLE_ADD - je .add - cmp eax, ARP_TABLE_DEL - je .del - cmp eax, ARP_TABLE_GET - je .get - cmp eax, ARP_TABLE_IP_TO_MAC - je .ip_to_mac - cmp eax, ARP_TABLE_GET_ENTRIES_NUMBER - je .get_entries_number - jmp .exit ;if unknown opcode - - -;;BEGIN TIMER -;;Description: it must be callback every second. It is responsible for removing expired routes. -;;IN: Operation: ARP_TABLE_TIMER -;; Index: must be zero -;; Extra: must be zero -;;OUT: -;; EAX=not defined -;; -.timer: - test ecx, ecx - jz .exit;if NumARP=0 nothing to do - sub ecx, ARP_TABLE_ENTRIES;ecx=dynamic entries number - jz .exit;if NumARP=number of static entries then exit - - add ebx, ARP_TABLE_ENTRIES*ARP_ENTRY_SIZE;ebx=dynamic entries base - - .timer_loop: - movsx esi, word [ebx + ARP_ENTRY.TTL] - cmp esi, 0xFFFFFFFF - je .timer_loop_end;if TTL==0xFFFF then it's static entry - - test esi, esi - jnz .timer_loop_end_with_dec;if TTL!=0 - - ; Ok, TTL is 0 - ;if Status==AWAITING_RESPONSE and TTL==0 - ;then we have to change it to ARP_RESPONSE_TIMEOUT - cmp word [ebx + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE - jne @f - - mov word [ebx + ARP_ENTRY.Status], ARP_RESPONSE_TIMEOUT - mov word [ebx + ARP_ENTRY.TTL], word 0x000A;10 sec - jmp .timer_loop_end - - @@: - ;if TTL==0 and Status==VALID_MAPPING, we have to delete it - ;if TTL==0 and Status==RESPONSE_TIMEOUT, delete too - mov esi, dword[NumARP] - sub esi, ecx ;esi=index of entry, will be deleted - stdcall arp_table_manager, ARP_TABLE_DEL, esi, 0;opcode,index,extra - jmp .timer_loop_end - - - .timer_loop_end_with_dec: - dec word [ebx + ARP_ENTRY.TTL];decrease TTL - .timer_loop_end: - add ebx, ARP_ENTRY_SIZE - loop .timer_loop - - jmp .exit -;;END TIMER - -;;BEGIN ADD -;;Description: it adds an entry in the table. If ARP-table already -;; contains same IP, it will be updated. -;;IN: Operation: ARP_TABLE_ADD -;; Index: specifies what contains Extra-parameter -;; Extra: if Index==EXTRA_IS_ARP_PACKET_PTR, -;; then Extra contains pointer to ARP_PACKET, -;; otherwise Extra contains pointer to ARP_ENTRY -;;OUT: -;; EAX=index of entry, that has been added -;; -.add: - - sub esp, ARP_ENTRY_SIZE;Allocate ARP_ENTRY_SIZE byte in stack - - mov esi, [Extra];pointer - mov edi, [Index];opcode - - cmp edi, EXTRA_IS_ARP_PACKET_PTR - je .arp_packet_to_entry;if Extra contain ptr to ARP_PACKET and we have to form arp-entry - ;else it contain ptr to arp-entry - - cld - ; esi already has been loaded - mov edi, esp ;ebx + eax=ARPTable_base + ARP-entry_base(where we will add) - mov ecx, ARP_ENTRY_SIZE/2;ARP_ENTRY_SIZE must be even number!!! - rep movsw ;copy - jmp .search - - .arp_packet_to_entry: - mov edx, dword[esi + ARP_PACKET.SenderIP];esi=base of ARP_PACKET - mov [esp + ARP_ENTRY.IP], edx - - cld - lea esi, [esi + ARP_PACKET.SenderMAC] - lea edi, [esp + ARP_ENTRY.MAC] - movsd - movsw - mov word[esp + ARP_ENTRY.Status], ARP_VALID_MAPPING; specify the type - a valid entry - mov word[esp + ARP_ENTRY.TTL], 0x0E10; = 1 hour - - .search: - mov edx, dword[esp + ARP_ENTRY.IP];edx=IP-address, which we'll search - mov ecx, dword[NumARP] ;ecx=ARP-entries counter - jecxz .add_to_end ;if ARP-entries number == 0 - imul eax, ecx, ARP_ENTRY_SIZE ;eax=current table size(in bytes) - @@: - sub eax, ARP_ENTRY_SIZE - cmp dword[ebx + eax + ARP_ENTRY.IP], edx - loopnz @b - jz .replace ; found, replace existing entry, ptr to it is in eax - - .add_to_end: - ;else add to end - or eax, -1;set eax=0xFFFFFFFF if adding is impossible - mov ecx, dword[NumARP] - cmp ecx, ARP_TABLE_SIZE - je .add_exit;if arp-entries number is equal to arp-table maxsize - - imul eax, dword[NumARP], ARP_ENTRY_SIZE;eax=ptr to end of ARPTable - inc dword [NumARP];increase ARP-entries counter - - .replace: - cld - mov esi, esp ;esp=base of ARP-entry, that will be added - lea edi, [ebx + eax] ;ebx + eax=ARPTable_base + ARP-entry_base(where we will add) - mov ecx, ARP_ENTRY_SIZE/2;ARP_ENTRY_SIZE must be even number!!! - rep movsw - - mov ecx, ARP_ENTRY_SIZE - xor edx, edx;"div" takes operand from EDX:EAX - div ecx ;eax=index of entry, which has been added - -.add_exit: - add esp, ARP_ENTRY_SIZE;free stack - jmp .exit -;;END ADD - -;;BEGIN DEL -;;Description: it deletes an entry in the table. -;;IN: Operation: ARP_TABLE_DEL -;; Index: index of entry, that should be deleted -;; Extra: must be zero -;;OUT: -;; EAX=not defined -;; -.del: - mov esi, [Index] - imul esi, ARP_ENTRY_SIZE - - mov ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY_SIZE - sub ecx, esi - - lea edi, [ebx + esi] ;edi=ptr to entry that should be deleted - lea esi, [edi + ARP_ENTRY_SIZE];esi=ptr to next entry - - shr ecx, 1 ;ecx/2 => ARP_ENTRY_SIZE MUST BE EVEN NUMBER! - cld - rep movsw - - dec dword[NumARP];decrease arp-entries counter - jmp .exit -;;END DEL - -;;BEGIN GET -;;Description: it reads an entry of table into buffer. -;;IN: Operation: ARP_TABLE_GET -;; Index: index of entry, that should be read -;; Extra: pointer to buffer for reading(size must be equal to ARP_ENTRY_SIZE) -;;OUT: -;; EAX=not defined -;; -.get: - mov esi, [Index] - imul esi, ARP_ENTRY_SIZE;esi=ptr to required ARP_ENTRY - mov edi, [Extra] ;edi=buffer for reading - mov ecx, ARP_ENTRY_SIZE/2; must be even number!!! - cld - rep movsw - jmp .exit -;;END GET - -;;BEGIN IP_TO_MAC -;;Description: it gets an IP from Index, scans each entry in the table and writes -;; MAC, that relates to specified IP, into buffer specified in Extra. -;; And if it cannot find an IP-address in the table, it does an ARP-request of that. -;;IN: Operation: ARP_TABLE_IP_TO_MAC -;; Index: IP that should be transformed into MAC -;; Extra: pointer to buffer where will be written the MAC-address. -;;OUT: -;; EAX=ARP table entry status code. -;; If EAX==ARP_NO_ENTRY, IP isn't found in the table and we have sent the request. -;; If EAX==ARP_AWAITING_RESPONSE, we wait the response from remote system. -;; If EAX==ARP_RESPONSE_TIMEOUT, remote system not responds too long. -;; If EAX==ARP_VALID_MAPPING, all is ok, we've got a true MAC. -;; -;; If MAC will equal to a zero, in the buffer. It means, that IP-address was not yet -;; resolved, or that doesn't exist. I recommend you, to do at most 3-5 calls of this -;; function with 1sec delay. sure, only if it not return a valid MAC after a first call. -;; -.ip_to_mac: - - xor eax, eax - mov edi, dword[Extra] - cld - stosd - stosw - - - ; first, check destination IP to see if it is on 'this' network. - ; The test is: - ; if ( destIP & subnet_mask == stack_ip & subnet_mask ) - ; destination is local - ; else - ; destination is remote, so pass to gateway - - mov eax, [Index] ;eax=required IP - mov esi, eax - and esi, [subnet_mask] - mov ecx, [stack_ip] - and ecx, [subnet_mask] - cmp esi, ecx - je @f ;if we and target IP are located in the same network - mov eax, [gateway_ip] - mov [Index], eax - @@: - - cmp dword[NumARP], 0 - je .ip_to_mac_send_request;if ARP-table not contain an entries, we have to request IP. - ;EAX will be containing a zero, it's equal to ARP_NO_ENTRY - - mov ecx, dword[NumARP] - imul esi, ecx, ARP_ENTRY_SIZE;esi=current ARP-table size - - @@: - sub esi, ARP_ENTRY_SIZE - cmp [ebx + esi], eax ; ebx=ARPTable base - loopnz @b ; Return back if non match - jnz .ip_to_mac_send_request; and request IP->MAC if none found in the table - - ; Return the entry status in eax - movzx eax, word[ebx + esi + ARP_ENTRY.Status] - - ; esi holds index - cld - lea esi, [ebx + esi + ARP_ENTRY.MAC] - mov edi, [Extra];edi=ptr to buffer for write MAC - movsd - movsw - jmp .exit - - .ip_to_mac_send_request: - stdcall arp_request, [Index], stack_ip, node_addr;TargetIP,SenderIP_ptr,SenderMAC_ptr - mov eax, ARP_NO_ENTRY - jmp .exit - -;;END IP_TO_MAC - -;;BEGIN GET_ENTRIES_NUMBER -;;Description: returns an ARP-entries number in the ARPTable -;;IN: Operation: ARP_TABLE_GET_ENTRIES_NUMBER -;; Index: must be zero -;; Extra: must be zero -;;OUT: -;; EAX=ARP-entries number in the ARPTable - .get_entries_number: - mov eax, dword[NumARP] - jmp .exit -;;END GET_ENTRIES_NUMBER - -.exit: - ret -endp - - -;*************************************************************************** -; Function -; arp_handler -; -; Description -; Called when an ARP packet is received on the ethernet -; Header + Data is in Ether_buffer[] -; It looks to see if the packet is a request to resolve this Hosts -; IP address. If it is, send the ARP reply packet. -; This Hosts IP address is in dword [stack_ip] ( in network format ) -; This Hosts MAC address is in node_addr[6] -; All registers may be destroyed -; -;*************************************************************************** -arp_handler: - ; Is this a REQUEST? - ; Is this a request for My Host IP - ; Yes - So construct a response message. - ; Send this message to the ethernet card for transmission - - stdcall arp_table_manager, ARP_TABLE_ADD, EXTRA_IS_ARP_PACKET_PTR, ETH_FRAME.Data + ARP_PACKET - - inc dword[arp_rx_count];increase ARP-packets counter - - cmp word[ETH_FRAME.Data + ARP_PACKET.Opcode], ARP_REQ_OPCODE; Is this a request packet? - jne .exit ; No - so exit - - mov eax, [stack_ip] - cmp eax, dword[ETH_FRAME.Data + ARP_PACKET.TargetIP] ; Is it looking for my IP address? - jne .exit ; No - so quit now - - ; OK, it is a request for my MAC address. Build the frame and send it - ; We can reuse the packet. - - mov word[ETH_FRAME.Data + ARP_PACKET.Opcode], ARP_REP_OPCODE - - cld - mov esi, ETH_FRAME.Data + ARP_PACKET.SenderMAC - mov edi, ETH_FRAME.Data + ARP_PACKET.TargetMAC - movsd - movsw - - mov esi, ETH_FRAME.Data + ARP_PACKET.SenderIP - mov edi, ETH_FRAME.Data + ARP_PACKET.TargetIP - movsd - - mov esi, node_addr - mov edi, ETH_FRAME.Data + ARP_PACKET.SenderMAC - movsd - movsw - - mov esi, stack_ip - mov edi, ETH_FRAME.Data + ARP_PACKET.SenderIP - movsd - - ; Now, send it! - mov edi, ETH_FRAME.Data + ARP_PACKET.TargetMAC;ptr to destination MAC address - mov bx, ETHER_ARP ;type of protocol - mov ecx, 28 ;data size - mov esi, ETH_FRAME.Data + ARP_PACKET ;ptr to data - push ebp - call dword [drvr_transmit] ;transmit packet - pop ebp - - .exit: - ret - - -;*************************************************************************** -; Function -; arp_request [by Johnny_B] -; -; Description -; Sends an ARP request on the ethernet -; IN: -; TargetIP : requested IP address -; SenderIP_ptr : POINTER to sender's IP address(our system's address) -; SenderMAC_ptr : POINTER to sender's MAC address(our system's address) -; OUT: -; EAX=0 (if all is ok), otherwise EAX is not defined -; -; EBX,ESI,EDI will be saved -; -;*************************************************************************** -proc arp_request stdcall uses ebx esi edi,\ - TargetIP:DWORD, SenderIP_ptr:DWORD, SenderMAC_ptr:DWORD - - inc dword[arp_tx_count]; increase counter - - sub esp, 28; allocate memory for ARP_PACKET - - mov word[esp + ARP_PACKET.HardwareType], 0x0100;Ethernet - mov word[esp + ARP_PACKET.ProtocolType], 0x0008;IP - mov byte[esp + ARP_PACKET.HardwareSize], 0x06;MAC-addr length - mov byte[esp + ARP_PACKET.ProtocolSize], 0x04;IP-addr length - mov word[esp + ARP_PACKET.Opcode], 0x0100 ;Request - - cld - mov esi, [SenderMAC_ptr] - lea edi, [esp + ARP_PACKET.SenderMAC] ;Our MAC-addr - movsd - movsw - - mov esi, [SenderIP_ptr] - lea edi, [esp + ARP_PACKET.SenderIP] ;Our IP-addr - movsd - - xor eax, eax - lea edi, [esp + ARP_PACKET.TargetMAC] ;Required MAC-addr(zeroed) - stosd - stosw - - mov esi, dword[TargetIP] - mov dword[esp + ARP_PACKET.TargetIP], esi;Required IP-addr(we get it as function parameter) - - ; Now, send it! - mov edi, broadcast_add ; Pointer to 48 bit destination address - mov bx, ETHER_ARP ; Type of packet - mov ecx, 28 ; size of packet - lea esi, [esp + ARP_PACKET]; pointer to packet data - push ebp - call dword [drvr_transmit]; Call the drivers transmit function - pop ebp - - add esp, 28; free memory, allocated before for ARP_PACKET - - ; Add an entry in the ARP table, awaiting response - sub esp, ARP_ENTRY_SIZE;allocate memory for ARP-entry - - mov esi, dword[TargetIP] - mov dword[esp + ARP_ENTRY.IP], esi - - lea edi, [esp + ARP_ENTRY.MAC] - xor eax, eax - stosd - stosw - - mov word[esp + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE - mov word[esp + ARP_ENTRY.TTL], 0x000A; 10 seconds - - stdcall arp_table_manager, ARP_TABLE_ADD, EXTRA_IS_ARP_ENTRY_PTR, esp - add esp, ARP_ENTRY_SIZE; free memory - -.exit: - ret -endp diff --git a/kernel/trunk/network/eth_drv/drivers/3c59x.inc b/kernel/trunk/network/eth_drv/drivers/3c59x.inc deleted file mode 100644 index a4a3ddbf30..0000000000 --- a/kernel/trunk/network/eth_drv/drivers/3c59x.inc +++ /dev/null @@ -1,2404 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -;; Copyright (c) 2004, Endre Kozma -;; All rights reserved. -;; -;; Redistribution and use in source and binary forms, with or without -;; modification, are permitted provided that the following conditions are -;; met: -;; -;; 1. Redistributions of source code must retain the above copyright notice, -;; this list of conditions and the following disclaimer. -;; -;; 2. Redistributions in binary form must reproduce the above copyright -;; notice, this list of conditions and the following disclaimer in the -;; documentation and/or other materials provided with the distribution. -;; -;; 3. The name of the author may not be used to endorse or promote products -;; derived from this software without specific prior written permission. -;; -;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -;; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -;; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -;; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; 3C59X.INC ;; -;; ;; -;; Ethernet driver for Menuet OS ;; -;; ;; -;; Driver for 3Com fast etherlink 3c59x and ;; -;; etherlink XL 3c900 and 3c905 cards ;; -;; References: ;; -;; www.3Com.com - data sheets ;; -;; DP83840A.pdf - ethernet physical layer ;; -;; 3c59x.c - linux driver ;; -;; ethernet driver template by Mike Hibbett ;; -;; ;; -;; Credits ;; -;; Mike Hibbett, ;; -;; who kindly supplied me with a 3Com905C-TX-M card ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; History -;; ======= -;; $Log: 3C59X.INC,v $ -;; Revision 1.3 2004/07/11 12:21:12 kozma -;; Support of vortex chips (3c59x) added. -;; Support of 3c920 and 3c982 added. -;; Corrections. -;; -;; Revision 1.2 2004/06/12 19:40:20 kozma -;; Function e3c59x_set_available_media added in order to set -;; the default media in case auto detection finds no valid link. -;; Incorrect mii check removed (3c900 Cyclone works now). -;; Cleanups. -;; -;; Revision 1.1 2004/06/12 18:27:15 kozma -;; Initial revision -;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; comment the next line out if you don't want debug info printed -; on the debug board. This option adds a lot of bytes to the driver -; so it's worth to comment it out. -; E3C59X_DEBUG equ 1 - -; forcing full duplex mode makes sense at some cards and link types - E3C59X_FORCE_FD equ 1 - -macro virt_to_dma reg -{ - sub reg, OS_BASE -} - -macro dma_to_virt reg -{ - add reg, OS_BASE -} - -macro zero_to_virt reg -{ - -} - -macro virt_to_zero reg -{ - -} - -macro zero_to_dma reg -{ - sub reg, OS_BASE -} - -macro dma_to_zero reg -{ - add reg, OS_BASE -} - -macro strtbl name, [string] -{ -common - label name dword -forward - local label - dd label -forward - label db string, 0 -} - -; Ethernet frame symbols - ETH_ALEN equ 6 - ETH_HLEN equ (2*ETH_ALEN+2) - ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for - ; mininmum 64bytes frame length -; PCI programming - PCI_REG_COMMAND equ 0x4 ; command register - PCI_REG_STATUS equ 0x6 ; status register - PCI_REG_LATENCY equ 0xd ; latency timer register - PCI_REG_CAP_PTR equ 0x34 ; capabilities pointer - PCI_REG_CAPABILITY_ID equ 0x0 ; capapility ID in pm register block - PCI_REG_PM_STATUS equ 0x4 ; power management status register - PCI_REG_PM_CTRL equ 0x4 ; power management control register - PCI_BIT_PIO equ 0 ; bit0: io space control - PCI_BIT_MMIO equ 1 ; bit1: memory space control - PCI_BIT_MASTER equ 2 ; bit2: device acts as a PCI master -; Registers - E3C59X_REG_POWER_MGMT_CTRL equ 0x7c - E3C59X_REG_UP_LIST_PTR equ 0x38 - E3C59X_REG_UP_PKT_STATUS equ 0x30 - E3C59X_REG_TX_FREE_THRESH equ 0x2f - E3C59X_REG_DN_LIST_PTR equ 0x24 - E3C59X_REG_DMA_CTRL equ 0x20 - E3C59X_REG_TX_STATUS equ 0x1b - E3C59X_REG_RX_STATUS equ 0x18 - E3C59X_REG_TX_DATA equ 0x10 -; Common window registers - E3C59X_REG_INT_STATUS equ 0xe - E3C59X_REG_COMMAND equ 0xe -; Register window 7 - E3C59X_REG_MASTER_STATUS equ 0xc - E3C59X_REG_POWER_MGMT_EVENT equ 0xc - E3C59X_REG_MASTER_LEN equ 0x6 - E3C59X_REG_VLAN_ETHER_TYPE equ 0x4 - E3C59X_REG_VLAN_MASK equ 0x0 - E3C59X_REG_MASTER_ADDRESS equ 0x0 -; Register window 6 - E3C59X_REG_BYTES_XMITTED_OK equ 0xc - E3C59X_REG_BYTES_RCVD_OK equ 0xa - E3C59X_REG_UPPER_FRAMES_OK equ 0x9 - E3C59X_REG_FRAMES_DEFERRED equ 0x8 - E3C59X_REG_FRAMES_RCVD_OK equ 0x7 - E3C59X_REG_FRAMES_XMITTED_OK equ 0x6 - E3C59X_REG_RX_OVERRUNS equ 0x5 - E3C59X_REG_LATE_COLLISIONS equ 0x4 - E3C59X_REG_SINGLE_COLLISIONS equ 0x3 - E3C59X_REG_MULTIPLE_COLLISIONS equ 0x2 - E3C59X_REG_SQE_ERRORS equ 0x1 - E3C59X_REG_CARRIER_LOST equ 0x0 -; Register window 5 - E3C59X_REG_INDICATION_ENABLE equ 0xc - E3C59X_REG_INTERRUPT_ENABLE equ 0xa - E3C59X_REG_TX_RECLAIM_THRESH equ 0x9 - E3C59X_REG_RX_FILTER equ 0x8 - E3C59X_REG_RX_EARLY_THRESH equ 0x6 - E3C59X_REG_TX_START_THRESH equ 0x0 -; Register window 4 - E3C59X_REG_UPPER_BYTES_OK equ 0xe - E3C59X_REG_BAD_SSD equ 0xc - E3C59X_REG_MEDIA_STATUS equ 0xa - E3C59X_REG_PHYSICAL_MGMT equ 0x8 - E3C59X_REG_NETWORK_DIAGNOSTIC equ 0x6 - E3C59X_REG_FIFO_DIAGNOSTIC equ 0x4 - E3C59X_REG_VCO_DIAGNOSTIC equ 0x2 ; may not supported -; Bits in register window 4 - E3C59X_BIT_AUTOSELECT equ 24 -; Register window 3 - E3C59X_REG_TX_FREE equ 0xc - E3C59X_REG_RX_FREE equ 0xa - E3C59X_REG_MEDIA_OPTIONS equ 0x8 - E3C59X_REG_MAC_CONTROL equ 0x6 - E3C59X_REG_MAX_PKT_SIZE equ 0x4 - E3C59X_REG_INTERNAL_CONFIG equ 0x0 -; Register window 2 - E3C59X_REG_RESET_OPTIONS equ 0xc - E3C59X_REG_STATION_MASK_HI equ 0xa - E3C59X_REG_STATION_MASK_MID equ 0x8 - E3C59X_REG_STATION_MASK_LO equ 0x6 - E3C59X_REG_STATION_ADDRESS_HI equ 0x4 - E3C59X_REG_STATION_ADDRESS_MID equ 0x2 - E3C59X_REG_STATION_ADDRESS_LO equ 0x0 -; Register window 1 - E3C59X_REG_TRIGGER_BITS equ 0xc - E3C59X_REG_SOS_BITS equ 0xa - E3C59X_REG_WAKE_ON_TIMER equ 0x8 - E3C59X_REG_SMB_RXBYTES equ 0x7 - E3C59X_REG_SMB_DIAG equ 0x5 - E3C59X_REG_SMB_ARB equ 0x4 - E3C59X_REG_SMB_STATUS equ 0x2 - E3C59X_REG_SMB_ADDRESS equ 0x1 - E3C59X_REG_SMB_FIFO_DATA equ 0x0 -; Register window 0 - E3C59X_REG_EEPROM_DATA equ 0xc - E3C59X_REG_EEPROM_COMMAND equ 0xa - E3C59X_REG_BIOS_ROM_DATA equ 0x8 - E3C59X_REG_BIOS_ROM_ADDR equ 0x4 -; Physical management bits - E3C59X_BIT_MGMT_DIR equ 2 ; drive with the data written in mgmtData - E3C59X_BIT_MGMT_DATA equ 1 ; MII management data bit - E3C59X_BIT_MGMT_CLK equ 0 ; MII management clock -; MII commands - E3C59X_MII_CMD_MASK equ (1111b shl 10) - E3C59X_MII_CMD_READ equ (0110b shl 10) - E3C59X_MII_CMD_WRITE equ (0101b shl 10) -; MII registers - E3C59X_REG_MII_BMCR equ 0 ; basic mode control register - E3C59X_REG_MII_BMSR equ 1 ; basic mode status register - E3C59X_REG_MII_ANAR equ 4 ; auto negotiation advertisement register - E3C59X_REG_MII_ANLPAR equ 5 ; auto negotiation link partner ability register - E3C59X_REG_MII_ANER equ 6 ; auto negotiation expansion register -; MII bits - E3C59X_BIT_MII_AUTONEG_COMPLETE equ 5 ; auto-negotiation complete - E3C59X_BIT_MII_PREAMBLE_SUPPRESSION equ 6 -; eeprom bits and commands - E3C59X_EEPROM_CMD_READ equ 0x80 - E3C59X_EEPROM_BIT_BUSY equ 15 -; eeprom registers - E3C59X_EEPROM_REG_OEM_NODE_ADDR equ 0xa - E3C59X_EEPROM_REG_CAPABILITIES equ 0x10 -; Commands for command register - E3C59X_SELECT_REGISTER_WINDOW equ (1 shl 11) - - IS_VORTEX equ 0x1 - IS_BOOMERANG equ 0x2 - IS_CYCLONE equ 0x4 - IS_TORNADO equ 0x8 - EEPROM_8BIT equ 0x10 - HAS_PWR_CTRL equ 0x20 - HAS_MII equ 0x40 - HAS_NWAY equ 0x80 - HAS_CB_FNS equ 0x100 - INVERT_MII_PWR equ 0x200 - INVERT_LED_PWR equ 0x400 - MAX_COLLISION_RESET equ 0x800 - EEPROM_OFFSET equ 0x1000 - HAS_HWCKSM equ 0x2000 - EXTRA_PREAMBLE equ 0x4000 - -iglobal - align 4 -e3c59x_hw_versions: - dw 0x5900, IS_VORTEX ; 3c590 Vortex 10Mbps - dw 0x5920, IS_VORTEX ; 3c592 EISA 10Mbps Demon/Vortex - dw 0x5970, IS_VORTEX ; 3c597 EISA Fast Demon/Vortex - dw 0x5950, IS_VORTEX ; 3c595 Vortex 100baseTx - dw 0x5951, IS_VORTEX ; 3c595 Vortex 100baseT4 - dw 0x5952, IS_VORTEX ; 3c595 Vortex 100base-MII - dw 0x9000, IS_BOOMERANG ; 3c900 Boomerang 10baseT - dw 0x9001, IS_BOOMERANG ; 3c900 Boomerang 10Mbps Combo - dw 0x9004, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c900 Cyclone 10Mbps TPO - dw 0x9005, IS_CYCLONE or HAS_HWCKSM ; 3c900 Cyclone 10Mbps Combo - dw 0x9006, IS_CYCLONE or HAS_HWCKSM ; 3c900 Cyclone 10Mbps TPC - dw 0x900A, IS_CYCLONE or HAS_HWCKSM ; 3c900B-FL Cyclone 10base-FL - dw 0x9050, IS_BOOMERANG or HAS_MII ; 3c905 Boomerang 100baseTx - dw 0x9051, IS_BOOMERANG or HAS_MII ; 3c905 Boomerang 100baseT4 - dw 0x9055, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE ; 3c905B Cyclone 100baseTx - dw 0x9058, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c905B Cyclone 10/100/BNC - dw 0x905A, IS_CYCLONE or HAS_HWCKSM ; 3c905B-FX Cyclone 100baseFx - dw 0x9200, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c905C Tornado - dw 0x9800, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c980 Cyclone - dw 0x9805, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c982 Dual Port Server Cyclone - dw 0x7646, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3cSOHO100-TX Hurricane - dw 0x5055, IS_CYCLONE or EEPROM_8BIT or HAS_HWCKSM ; 3c555 Laptop Hurricane - dw 0x6055, IS_TORNADO or HAS_NWAY or EEPROM_8BIT or HAS_CB_FNS \ - or INVERT_MII_PWR or HAS_HWCKSM ; 3c556 Laptop Tornado - dw 0x6056, IS_TORNADO or HAS_NWAY or EEPROM_OFFSET or HAS_CB_FNS \ - or INVERT_MII_PWR or HAS_HWCKSM ; 3c556B Laptop Hurricane - dw 0x5b57, IS_BOOMERANG or HAS_MII or EEPROM_8BIT ; 3c575 [Megahertz] 10/100 LAN CardBus - dw 0x5057, IS_BOOMERANG or HAS_MII or EEPROM_8BIT ; 3c575 Boomerang CardBus - dw 0x5157, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT \ - or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFE575BT Cyclone CardBus - dw 0x5257, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \ - or MAX_COLLISION_RESET or HAS_HWCKSM ; 3CCFE575CT Tornado CardBus - dw 0x6560, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \ - or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFE656 Cyclone CardBus - dw 0x6562, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \ - or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFEM656B Cyclone+Winmodem CardBus - dw 0x6564, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \ - or MAX_COLLISION_RESET or HAS_HWCKSM ; 3CXFEM656C Tornado+Winmodem CardBus - dw 0x4500, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c450 HomePNA Tornado - dw 0x9201, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c920 Tornado - dw 0x1201, IS_TORNADO or HAS_HWCKSM or HAS_NWAY ; 3c982 Hydra Dual Port A - dw 0x1202, IS_TORNADO or HAS_HWCKSM or HAS_NWAY ; 3c982 Hydra Dual Port B - dw 0x9056, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE ; 3c905B-T4 - dw 0x9210, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c920B-EMB-WNM Tornado -E3C59X_HW_VERSIONS_SIZE= $-e3c59x_hw_versions -endg - -; RX/TX buffers sizes - E3C59X_MAX_ETH_PKT_SIZE equ 1536 ; max packet size - E3C59X_NUM_RX_DESC equ 4 ; a power of 2 number - E3C59X_NUM_TX_DESC equ 4 ; a power of 2 number - E3C59X_RX_BUFFER_SIZE equ (E3C59X_MAX_ETH_FRAME_SIZE*E3C59X_NUM_RX_DESC) - E3C59X_TX_BUFFER_SIZE equ (E3C59X_MAX_ETH_FRAME_SIZE*E3C59X_NUM_TX_DESC) -; Download Packet Descriptor - E3C59X_DPD_DN_NEXT_PTR equ 0 - E3C59X_DPD_FRAME_START_HDR equ 4 - E3C59X_DPD_DN_FRAG_ADDR equ 8 ; for packet data - E3C59X_DPD_DN_FRAG_LEN equ 12 ; for packet data - E3C59X_DPD_SIZE equ 16 ; a power of 2 number -; Upload Packet Descriptor - E3C59X_UPD_UP_NEXT_PTR equ 0 - E3C59X_UPD_PKT_STATUS equ 4 - E3C59X_UPD_UP_FRAG_ADDR equ 8 ; for packet data - E3C59X_UPD_UP_FRAG_LEN equ 12 ; for packet data - E3C59X_UPD_SIZE equ 16 - -; RX/TX buffers -if defined E3C59X_LINUX - E3C59X_MAX_ETH_FRAME_SIZE = 160 ; size of ethernet frame + bytes alignment - e3c59x_rx_buff = 0 -else - E3C59X_MAX_ETH_FRAME_SIZE = 1520 ; size of ethernet frame + bytes alignment - e3c59x_rx_buff = eth_data_start -end if - - e3c59x_tx_buff = e3c59x_rx_buff+E3C59X_RX_BUFFER_SIZE - e3c59x_dpd_buff = e3c59x_tx_buff+E3C59X_TX_BUFFER_SIZE - e3c59x_upd_buff = e3c59x_dpd_buff+(E3C59X_DPD_SIZE*E3C59X_NUM_TX_DESC) - -uglobal -e3c59x_curr_upd: - dd 0 -e3c59x_prev_dpd: - dd 0 -e3c59x_prev_tx_frame: - dd 0 -e3c59x_transmit_function: - dd 0 -e3c59x_receive_function: - dd 0 -endg - -iglobal -e3c59x_ver_id: - db 17 -endg - -uglobal -e3c59x_full_bus_master: - db 0 -e3c59x_has_hwcksm: - db 0 -e3c59x_preamble: - db 0 -e3c59x_dn_list_ptr_cleared: - db 0 -e3c59x_self_directed_packet: - rb 6 -endg - -if defined E3C59X_DEBUG -e3c59x_hw_type_str: - db "Detected hardware type : ", 0 -e3c59x_device_str: - db "Device ID : 0x" -e3c59x_device_id_str: - db "ffff", 13, 10, 0 -e3c59x_vendor_str: - db "Vendor ID : 0x" -e3c59x_vendor_id_str: - db "ffff", 13, 10, 0 -e3c59x_io_info_str: - db "IO address : 0x" -e3c59x_io_addr_str: - db "ffff", 13, 10, 0 -e3c59x_mac_info_str: - db "MAC address : " -e3c59x_mac_addr_str: - db "ff:ff:ff:ff:ff:ff", 13, 10, 0 -e3c59x_boomerang_str: - db " (boomerang)", 13, 10, 0 -e3c59x_vortex_str: - db " (vortex)", 13, 10, 0 -e3c59x_link_type_str: - db "Established link type : ", 0 -e3c59x_new_line_str: - db 13, 10, 0 -e3c59x_link_type: - dd 0 - -e3c59x_charset: - db '0123456789abcdef' - -strtbl e3c59x_link_str, \ - "No valid link type detected", \ - "10BASE-T half duplex", \ - "10BASE-T full-duplex", \ - "100BASE-TX half duplex", \ - "100BASE-TX full duplex", \ - "100BASE-T4", \ - "100BASE-FX", \ - "10Mbps AUI", \ - "10Mbps COAX (BNC)", \ - "miiDevice - not supported" - -strtbl e3c59x_hw_str, \ - "3c590 Vortex 10Mbps", \ - "3c592 EISA 10Mbps Demon/Vortex", \ - "3c597 EISA Fast Demon/Vortex", \ - "3c595 Vortex 100baseTx", \ - "3c595 Vortex 100baseT4", \ - "3c595 Vortex 100base-MII", \ - "3c900 Boomerang 10baseT", \ - "3c900 Boomerang 10Mbps Combo", \ - "3c900 Cyclone 10Mbps TPO", \ - "3c900 Cyclone 10Mbps Combo", \ - "3c900 Cyclone 10Mbps TPC", \ - "3c900B-FL Cyclone 10base-FL", \ - "3c905 Boomerang 100baseTx", \ - "3c905 Boomerang 100baseT4", \ - "3c905B Cyclone 100baseTx", \ - "3c905B Cyclone 10/100/BNC", \ - "3c905B-FX Cyclone 100baseFx", \ - "3c905C Tornado", \ - "3c980 Cyclone", \ - "3c982 Dual Port Server Cyclone", \ - "3cSOHO100-TX Hurricane", \ - "3c555 Laptop Hurricane", \ - "3c556 Laptop Tornado", \ - "3c556B Laptop Hurricane", \ - "3c575 [Megahertz] 10/100 LAN CardBus", \ - "3c575 Boomerang CardBus", \ - "3CCFE575BT Cyclone CardBus", \ - "3CCFE575CT Tornado CardBus", \ - "3CCFE656 Cyclone CardBus", \ - "3CCFEM656B Cyclone+Winmodem CardBus", \ - "3CXFEM656C Tornado+Winmodem CardBus", \ - "3c450 HomePNA Tornado", \ - "3c920 Tornado", \ - "3c982 Hydra Dual Port A", \ - "3c982 Hydra Dual Port B", \ - "3c905B-T4", \ - "3c920B-EMB-WNM Tornado" - -end if ; defined E3C59X_DEBUG - -;*************************************************************************** -; Function -; e3c59x_debug -; Description -; prints debug info to the debug board -; Parameters -; ebp - io_addr -; Return value -; Destroyed registers -; eax, ebx, ecx, edx, edi, esi -; -;*************************************************************************** -if defined E3C59X_DEBUG - align 4 -e3c59x_debug: - pushad -; print device type - mov esi, e3c59x_hw_type_str - call sys_msg_board_str - movzx ecx, byte [e3c59x_ver_id] - mov esi, [e3c59x_hw_str+ecx*4] - call sys_msg_board_str - mov esi, e3c59x_boomerang_str - cmp dword [e3c59x_transmit_function], e3c59x_boomerang_transmit - jz .boomerang - mov esi, e3c59x_vortex_str -.boomerang: - call sys_msg_board_str -; print device/vendor - mov ax, [pci_data+2] - mov cl, 2 - mov ebx, e3c59x_device_id_str - call e3c59x_print_hex - mov esi, e3c59x_device_str - call sys_msg_board_str - mov ax, [pci_data] - mov cl, 2 - mov ebx, e3c59x_vendor_id_str - call e3c59x_print_hex - mov esi, e3c59x_vendor_str - call sys_msg_board_str -; print io address - mov ax, [io_addr] - mov ebx, e3c59x_io_addr_str - mov cl, 2 - call e3c59x_print_hex - mov esi, e3c59x_io_info_str - call sys_msg_board_str -; print MAC address - mov ebx, e3c59x_mac_addr_str - xor ecx, ecx -.mac_loop: - push ecx - mov al, [node_addr+ecx] - mov cl, 1 - call e3c59x_print_hex - inc ebx - pop ecx - inc cl - cmp cl, 6 - jne .mac_loop - mov esi, e3c59x_mac_info_str - call sys_msg_board_str -; print link type - mov esi, e3c59x_link_type_str - call sys_msg_board_str - xor eax, eax - bsr ax, word [e3c59x_link_type] - jz @f - sub ax, 4 -@@: - mov esi, [e3c59x_link_str+eax*4] - call sys_msg_board_str - mov esi, e3c59x_new_line_str - call sys_msg_board_str - popad - ret - -;*************************************************************************** -; Function -; e3c59x_print_hex -; Description -; prints a hexadecimal value -; Parameters -; eax - value to be printed out -; ebx - where to print -; cl - value size (1, 2, 4) -; Return value -; ebx - end address after the print -; Destroyed registers -; eax, ebx -; -;*************************************************************************** - align 4 -e3c59x_print_hex: - cmp cl, 1 - je .print_byte - cmp cl, 2 - jz .print_word -.print_dword: - push eax - bswap eax - xchg ah, al - call .print_word - pop eax -.print_word: - push eax - xchg ah, al - call .print_byte - pop eax -.print_byte: - movzx eax, al - push eax - and al, 0xf0 - shr al, 4 - mov al, byte [eax+e3c59x_charset] - mov [ebx], al - inc ebx - pop eax - and al, 0x0f - mov al, byte [eax+e3c59x_charset] - mov [ebx], al - inc ebx - ret -end if ; defined E3C59X_DEBUG - -;*************************************************************************** -; Function -; e3c59x_try_link_detect -; Description -; e3c59x_try_link_detect checks if link exists -; Parameters -; ebp - io_addr -; Return value -; al - 0 ; no link detected -; al - 1 ; link detected -; Destroyed registers -; eax, ebx, ecx, edx, edi, esi -; -;*************************************************************************** - align 4 -e3c59x_try_link_detect: -; download self-directed packet - mov edi, node_addr - mov bx, 0x0608 ; packet type - mov esi, e3c59x_self_directed_packet - mov ecx, 6 ; 6 + 6 + 2 + 6 = 20 bytes - call dword [e3c59x_transmit_function] -; switch to register window 5 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+5 - out dx, ax -; program RxFilter for promiscuous operation - mov ax, (10000b shl 11) - lea edx, [ebp+E3C59X_REG_RX_FILTER] - in al, dx - or al, 1111b - lea edx, [ebp+E3C59X_REG_COMMAND] - out dx, ax -; switch to register window 4 - mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 - out dx, ax -; check loop - xor ebx, ebx - mov ecx, 0xffff ; 65535 tries -.loop: - push ecx ebx - call dword [e3c59x_receive_function] - pop ebx ecx - test al, al - jnz .finish -.no_packet_received: -; switch to register window 4 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 - out dx, ax -; read linkbeatdetect - lea edx, [ebp+E3C59X_REG_MEDIA_STATUS] - in ax, dx - test ah, 1000b ; test linkBeatDetect - jnz .link_detected - xor al, al - jmp .finish -.link_detected: -; test carrierSense - test al, 100000b - jz .no_carrier_sense - inc ebx -.no_carrier_sense: - dec ecx - jns .loop -; assume the link is good if 0 < ebx < 25 % - test ebx, ebx - setnz al - jz .finish - cmp ebx, 16384 ; 25% - setb al -.finish: -if defined E3C59X_DEBUG - test al, al - jz @f - or byte [e3c59x_link_type+1], 100b -@@: -end if ; defined E3C59X_DEBUG - ret - -;*************************************************************************** -; Function -; e3c59x_try_phy -; Description -; e3c59x_try_phy checks the auto-negotiation function -; in the PHY at PHY index. It can also be extended to -; include link detection for non-IEEE 802.3u -; auto-negotiation devices, for instance the BCM5000. -; Parameters -; ah - PHY index -; ebp - io_addr -; Return value -; al - 0 link is auto-negotiated -; al - 1 no link is auto-negotiated -; Destroyed registers -; eax, ebx, ecx, edx, esi -; -;*************************************************************************** - align 4 -e3c59x_try_phy: - mov al, E3C59X_REG_MII_BMCR - push eax - call e3c59x_mdio_read ; returns with window #4 - or ah, 0x80 ; software reset - mov ebx, eax - pop eax - push eax - call e3c59x_mdio_write ; returns with window #4 -; wait for reset to complete - mov esi, 2000 ; 2000ms = 2s - call delay_ms - pop eax - push eax - call e3c59x_mdio_read ; returns with window #4 - test ah, 0x80 - jnz .fail_finish - pop eax - push eax -; wait for a while after reset - mov esi, 20 ; 20ms - call delay_ms - pop eax - push eax - mov al, E3C59X_REG_MII_BMSR - call e3c59x_mdio_read ; returns with window #4 - test al, 1 ; extended capability supported? - jz .no_ext_cap -; auto-neg capable? - test al, 1000b - jz .fail_finish ; not auto-negotiation capable -; auto-neg complete? - test al, 100000b - jnz .auto_neg_ok -; restart auto-negotiation - pop eax - push eax - mov al, E3C59X_REG_MII_ANAR - push eax - call e3c59x_mdio_read ; returns with window #4 - or ax, (1111b shl 5) ; advertise only 10base-T and 100base-TX - mov ebx, eax - pop eax - call e3c59x_mdio_write ; returns with window #4 - pop eax - push eax - call e3c59x_mdio_read ; returns with window #4 - mov ebx, eax - or bh, 10010b ; restart auto-negotiation - pop eax - push eax - call e3c59x_mdio_write ; returns with window #4 - mov esi, 4000 ; 4000ms = 4 seconds - call delay_ms - pop eax - push eax - mov al, E3C59X_REG_MII_BMSR - call e3c59x_mdio_read ; returns with window #4 - test al, 100000b ; auto-neg complete? - jnz .auto_neg_ok - jmp .fail_finish -.auto_neg_ok: -; compare advertisement and link partner ability registers - pop eax - push eax - mov al, E3C59X_REG_MII_ANAR - call e3c59x_mdio_read ; returns with window #4 - xchg eax, [esp] - mov al, E3C59X_REG_MII_ANLPAR - call e3c59x_mdio_read ; returns with window #4 - pop ebx - and eax, ebx - and eax, 1111100000b - push eax -if defined E3C59X_DEBUG - mov word [e3c59x_link_type], ax -end if ; defined E3C59X_DEBUG -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax -; set full-duplex mode - lea edx, [ebp+E3C59X_REG_MAC_CONTROL] - in ax, dx - and ax, not 0x120 ; clear full duplex and flow control - pop ebx - test ebx, (1010b shl 5) ; check for full-duplex - jz .half_duplex - or ax, 0x120 ; set full duplex and flow control -.half_duplex: - out dx, ax - mov al, 1 - ret -.no_ext_cap: -; not yet implemented BCM5000 -.fail_finish: - pop eax - xor al, al - ret - -;*************************************************************************** -; Function -; e3c59x_try_mii -; Description -; e3c59x_try_MII checks the on-chip auto-negotiation logic -; or an off-chip MII PHY, depending upon what is set in -; xcvrSelect by the caller. -; It exits when it finds the first device with a good link. -; Parameters -; ebp - io_addr -; Return value -; al - 0 -; al - 1 -; Destroyed registers -; eax, ebx, ecx, edx, esi -; -;*************************************************************************** - align 4 -e3c59x_try_mii: -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax - lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] - in eax, dx - and eax, (1111b shl 20) - cmp eax, (1000b shl 20) ; is auto-negotiation set? - jne .mii_device -; auto-negotiation is set -; switch to register window 4 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 - out dx, ax -; PHY==24 is the on-chip auto-negotiation logic -; it supports only 10base-T and 100base-TX - mov ah, 24 - call e3c59x_try_phy - test al, al - jz .fail_finish - mov cl, 24 - jmp .check_preamble -.mii_device: - cmp eax, (0110b shl 20) - jne .fail_finish - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 - out dx, ax - lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT] - in ax, dx - and al, (1 shl E3C59X_BIT_MGMT_DIR) or (1 shl E3C59X_BIT_MGMT_DATA) - cmp al, (1 shl E3C59X_BIT_MGMT_DATA) - je .serch_for_phy - xor al, al - ret -.serch_for_phy: -; search for PHY - mov cl, 31 -.search_phy_loop: - cmp cl, 24 - je .next_phy - mov ah, cl ; ah = phy - mov al, E3C59X_REG_MII_BMCR ; al = Basic Mode Status Register - push ecx - call e3c59x_mdio_read - pop ecx - test ax, ax - jz .next_phy - cmp ax, 0xffff - je .next_phy - mov ah, cl ; ah = phy - push ecx - call e3c59x_try_phy - pop ecx - test al, al - jnz .check_preamble -.next_phy: - dec cl - jns .search_phy_loop -.fail_finish: - xor al, al - ret -; epilog -.check_preamble: - push eax ; eax contains the return value of e3c59x_try_phy -; check hard coded preamble forcing - movzx eax, byte [e3c59x_ver_id] - test word [eax*4+e3c59x_hw_versions+2], EXTRA_PREAMBLE - setnz [e3c59x_preamble] ; force preamble - jnz .finish -; check mii for preamble suppression - mov ah, cl - mov al, E3C59X_REG_MII_BMSR - call e3c59x_mdio_read - test al, 1000000b ; preamble suppression? - setz [e3c59x_preamble] ; no -.finish: - pop eax - ret - -;*************************************************************************** -; Function -; e3c59x_test_packet -; Description -; e3c59x_try_loopback try a loopback packet for 10BASE2 or AUI port -; Parameters -; ebp - io_addr -; Return value -; al - 0 -; al - 1 -; Destroyed registers -; eax, ebx, ecx, edx, edi, esi -; -;*************************************************************************** - align 4 -e3c59x_test_packet: -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax -; set fullDuplexEnable in MacControl register - lea edx, [ebp+E3C59X_REG_MAC_CONTROL] - in ax, dx - or ax, 0x120 - out dx, ax -; switch to register window 5 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+5 - out dx, ax -; set RxFilter to enable individual address matches - mov ax, (10000b shl 11) - lea edx, [ebp+E3C59X_REG_RX_FILTER] - in al, dx - or al, 1 - lea edx, [ebp+E3C59X_REG_COMMAND] - out dx, ax -; issue RxEnable and TxEnable - call e3c59x_rx_reset - call e3c59x_tx_reset -; download a self-directed test packet - mov edi, node_addr - mov bx, 0x0608 ; packet type - mov esi, e3c59x_self_directed_packet - mov ecx, 6 ; 6 + 6 + 2 + 6 = 20 bytes - call dword [e3c59x_transmit_function] -; wait for 2s - mov esi, 2000 ; 2000ms = 2s - call delay_ms -; check if self-directed packet is received - call dword [e3c59x_receive_function] - test al, al - jnz .finish -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax -; clear fullDuplexEnable in MacControl register - lea edx, [ebp+E3C59X_REG_MAC_CONTROL] - in ax, dx - and ax, not 0x120 - out dx, ax - xor al, al -.finish: - ret - -;*************************************************************************** -; Function -; e3c59x_try_loopback -; Description -; tries a loopback packet for 10BASE2 or AUI port -; Parameters -; al - 0: 10Mbps AUI connector -; 1: 10BASE-2 -; ebp - io_addr -; Return value -; al - 0 -; al - 1 -; Destroyed registers -; eax, ebx, ecx, edx, edi, esi -; -;*************************************************************************** - align 4 -e3c59x_try_loopback: - push eax -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax - pop eax - push eax -if defined E3C59X_DEBUG - mov bl, al - inc bl - shl bl, 3 - or byte [e3c59x_link_type+1], bl -end if ; defined E3C59X_DEBUG - test al, al ; aui or coax? - jz .complete_loopback -; enable 100BASE-2 DC-DC converter - mov ax, (10b shl 11) ; EnableDcConverter - out dx, ax -.complete_loopback: - mov cl, 2 ; give a port 3 chances to complete a loopback -.next_try: - push ecx - call e3c59x_test_packet - pop ecx - test al, al - jnz .finish - dec cl - jns .next_try -.finish: - xchg eax, [esp] - test al, al - jz .aui_finish -; issue DisableDcConverter command - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, (10111b shl 11) - out dx, ax -.aui_finish: - pop eax ; al contains the result of operation -if defined E3C59X_DEBUG - test al, al - jnz @f - and byte [e3c59x_link_type+1], not 11000b -@@: -end if ; defined E3C59X_DEBUG - ret - -;*************************************************************************** -; Function -; e3c59x_set_available_media -; Description -; sets the first available media -; Parameters -; ebp - io_addr -; Return value -; al - 0 -; al - 1 -; Destroyed registers -; eax, edx -; -;*************************************************************************** - align 4 -e3c59x_set_available_media: -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax - lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] - in eax, dx - push eax - lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] - in ax, dx - test al, 10b - jz @f -; baseTXAvailable - pop eax - and eax, not (1111b shl 20) - or eax, (100b shl 20) -if defined E3C59X_DEBUG & defined E3C59X_FORCE_FD - mov word [e3c59x_link_type], (1 shl 8) -else if defined E3C59X_DEBUG - mov word [e3c59x_link_type], (1 shl 7) -end if - jmp .set_media -@@: - test al, 100b - jz @f -; baseFXAvailable - pop eax - and eax, not (1111b shl 20) - or eax, (101b shl 20) -if defined E3C59X_DEBUG - mov word [e3c59x_link_type], (1 shl 10) -end if - jmp .set_media -@@: - test al, 1000000b - jz @f -; miiDevice - pop eax - and eax, not (1111b shl 20) - or eax, (0110b shl 20) -if defined E3C59X_DEBUG - mov word [e3c59x_link_type], (1 shl 13) -end if - jmp .set_media -@@: - test al, 1000b - jz @f -.set_default: -; 10bTAvailable - pop eax - and eax, not (1111b shl 20) -if defined E3C59X_DEBUG & defined E3C59X_FORCE_FD - mov word [e3c59x_link_type], (1 shl 6) -else if defined E3C59X_DEBUG - mov word [e3c59x_link_type], (1 shl 5) -end if ; E3C59X_FORCE_FD - jmp .set_media -@@: - test al, 10000b - jz @f -; coaxAvailable - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, (10b shl 11) ; EnableDcConverter - out dx, ax - pop eax - and eax, not (1111b shl 20) - or eax, (11b shl 20) -if defined E3C59X_DEBUG - mov word [e3c59x_link_type], (1 shl 12) -end if ; defined E3C59X_DEBUG - jmp .set_media -@@: - test al, 10000b - jz .set_default -; auiAvailable - pop eax - and eax, not (1111b shl 20) - or eax, (1 shl 20) -if defined E3C59X_DEBUG - mov word [e3c59x_link_type], (1 shl 11) -end if ; defined E3C59X_DEBUG -.set_media: - lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] - out dx, eax -if defined E3C59X_FORCE_FD -; set fullDuplexEnable in MacControl register - lea edx, [ebp+E3C59X_REG_MAC_CONTROL] - in ax, dx - or ax, 0x120 - out dx, ax -end if ; E3C59X_FORCE_FD - mov al, 1 - ret - -;*************************************************************************** -; Function -; e3c59x_set_active_port -; Description -; It selects the media port (transceiver) to be used -; Parameters: -; ebp - io_addr -; Return value: -; Destroyed registers -; eax, ebx, ecx, edx, edi, esi -; -;*************************************************************************** - align 4 -e3c59x_set_active_port: -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax - lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] - in eax, dx - test eax, (1 shl 24) ; check if autoselect enable - jz .set_first_available_media -; check 100BASE-TX and 10BASE-T - lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] - in ax, dx - test al, 1010b ; check whether 100BASE-TX or 10BASE-T available - jz .mii_device ; they are not available -; set auto-negotiation - lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] - in eax, dx - and eax, not (1111b shl 20) - or eax, (1000b shl 20) - out dx, eax - call e3c59x_try_mii - test al, al - jz .mii_device - ret -.mii_device: -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax -; check for off-chip mii device - lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] - in ax, dx - test al, 1000000b ; check miiDevice - jz .base_fx - lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] - in eax, dx - and eax, not (1111b shl 20) - or eax, (0110b shl 20) ; set MIIDevice - out dx, eax - call e3c59x_try_mii - test al, al - jz .base_fx - ret -.base_fx: -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax -; check for 100BASE-FX - lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] - in ax, dx ; read media option register - test al, 100b ; check 100BASE-FX - jz .aui_enable - lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] - in eax, dx - and eax, not (1111b shl 20) - or eax, (0101b shl 20) ; set 100base-FX - out dx, eax - call e3c59x_try_link_detect - test al, al - jz .aui_enable - ret -.aui_enable: -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax -; check for 10Mbps AUI connector - lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] - in ax, dx ; read media option register - test al, 100000b ; check 10Mbps AUI connector - jz .coax_available - lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] - in eax, dx - and eax, not (1111b shl 20) - or eax, (0001b shl 20) ; set 10Mbps AUI connector - out dx, eax - xor al, al ; try 10Mbps AUI connector - call e3c59x_try_loopback - test al, al - jz .coax_available - ret -.coax_available: -; switch to register window 3 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 - out dx, ax -; check for coaxial 10BASE-2 port - lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] - in ax, dx ; read media option register - test al, 10000b ; check 10BASE-2 - jz .set_first_available_media - lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] - in eax, dx - and eax, not (1111b shl 20) - or eax, (0011b shl 20) ; set 10BASE-2 - out dx, eax - mov al, 1 - call e3c59x_try_loopback - test al, al - jz .set_first_available_media - ret -.set_first_available_media: - jmp e3c59x_set_available_media - -;*************************************************************************** -; Function -; e3c59x_wake_up -; Description -; set the power state to D0 -; Destroyed registers -; eax, ebx, ecx, edx, edi, esi -; -;*************************************************************************** - align 4 -e3c59x_wake_up: -; wake up - we directly do it by programming PCI -; check if the device is power management capable - mov al, 2 - mov ah, [pci_bus] - mov bl, PCI_REG_STATUS - mov bh, [pci_dev] - push eax ebx - call pci_read_reg - test al, 10000b ; is there "new capabilities" linked list? - pop ebx eax - jz .device_awake -; search for power management register - mov al, 1 - mov bl, PCI_REG_CAP_PTR - push eax ebx - call pci_read_reg - mov cl, al - cmp cl, 0x3f - pop ebx eax - jbe .device_awake -; traverse the list - mov al, 2 -.pm_loop: - mov bl, cl - push eax ebx - call pci_read_reg - cmp al, 1 - je .set_pm_state - test ah, ah - mov cl, ah - pop ebx eax - jnz .pm_loop - jmp .device_awake -; waku up the device if necessary -.set_pm_state: - pop ebx eax - add bl, PCI_REG_PM_CTRL - push eax ebx - call pci_read_reg - mov cx, ax - test cl, 3 - pop ebx eax - jz .device_awake - and cl, not 11b ; set state to D0 - call pci_write_reg -.device_awake: - ret - -;*************************************************************************** -; Function -; e3c59x_probe -; Description -; Searches for an ethernet card, enables it and clears the rx buffer -; If a card was found, it enables the ethernet -> TCPIP link -; Destroyed registers -; eax, ebx, ecx, edx, edi, esi -; -;*************************************************************************** - align 4 -e3c59x_probe: - movzx ebp, word [io_addr] - mov al, 2 - mov ah, [pci_bus] - mov bh, [pci_dev] - mov bl, PCI_REG_COMMAND - push ebp eax ebx - call pci_read_reg - mov cx, ax - or cl, (1 shl PCI_BIT_MASTER) or (1 shl PCI_BIT_PIO) - and cl, not (1 shl PCI_BIT_MMIO) - pop ebx eax - call pci_write_reg -; wake up the card - call e3c59x_wake_up - pop ebp -; get chip version - mov ax, [pci_data+2] - mov ecx, E3C59X_HW_VERSIONS_SIZE/4-1 -.chip_ver_loop: - cmp ax, [e3c59x_hw_versions+ecx*4] - jz .chip_ver_found - dec ecx - jns .chip_ver_loop - xor ecx, ecx -.chip_ver_found: - mov [e3c59x_ver_id], cl - test word [e3c59x_hw_versions+2+ecx*4], HAS_HWCKSM - setnz [e3c59x_has_hwcksm] -; set pci latency for vortex cards - test word [e3c59x_hw_versions+2+ecx*4], IS_VORTEX - jz .not_vortex - mov cx, 11111000b ; 248 = max latency - mov al, 1 - mov ah, [pci_bus] - mov bl, PCI_REG_LATENCY - mov bh, [pci_dev] - call pci_write_reg -.not_vortex: -; set RX/TX functions - mov ax, E3C59X_EEPROM_REG_CAPABILITIES - call e3c59x_read_eeprom - test al, 100000b ; full bus master? - setnz [e3c59x_full_bus_master] - jnz .boomerang_func - mov dword [e3c59x_transmit_function], e3c59x_vortex_transmit - mov dword [e3c59x_receive_function], e3c59x_vortex_poll - jmp @f -.boomerang_func: ; full bus master, so use boomerang functions - mov dword [e3c59x_transmit_function], e3c59x_boomerang_transmit - mov dword [e3c59x_receive_function], e3c59x_boomerang_poll -@@: -; read MAC from eeprom - mov ecx, 2 -.mac_loop: - lea ax, [E3C59X_EEPROM_REG_OEM_NODE_ADDR+ecx] - call e3c59x_read_eeprom - xchg ah, al ; htons - mov [node_addr+ecx*2], ax - dec ecx - jns .mac_loop - test byte [e3c59x_full_bus_master], 0xff - jz .set_preamble -; switch to register window 2 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+2 - out dx, ax -; activate xcvr by setting some magic bits - lea edx, [ebp+E3C59X_REG_RESET_OPTIONS] - in ax, dx - and ax, not 0x4010 - movzx ebx, byte [e3c59x_ver_id] - test word [ebx*4+e3c59x_hw_versions+2], INVERT_LED_PWR - jz @f - or al, 0x10 -@@: - test word [ebx*4+e3c59x_hw_versions+2], INVERT_MII_PWR - jz @f - or ah, 0x40 -@@: - out dx, ax -.set_preamble: -; use preamble as default - mov byte [e3c59x_preamble], 1 ; enable preamble - -;*************************************************************************** -; Function -; e3c59x_reset -; Description -; Place the chip (ie, the ethernet card) into a virgin state -; Destroyed registers -; eax, ebx, ecx, edx, edi, esi -; -;*************************************************************************** -e3c59x_reset: -; issue global reset - call e3c59x_global_reset -; disable interrupts - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, (1110b shl 11) - out dx, ax -; enable Statistics - mov ax, (10101b shl 11) - out dx, ax -; set indication - mov ax, (1111b shl 11) or 0x6c6 - out dx, ax -; acknowledge (clear) every interrupt indicator - mov ax, (1101b shl 11) or 0x661 - out dx, ax -; switch to register window 2 - mov ax, E3C59X_SELECT_REGISTER_WINDOW+2 - out dx, ax -; write MAC addres back into the station address registers - lea edx, [ebp+E3C59X_REG_STATION_ADDRESS_LO] - mov esi, node_addr - cld - outsw - add edx, 2 - outsw - add edx, 2 - outsw - add edx, 2 -; clear station mask - xor eax, eax - out dx, ax - add edx, 2 - out dx, ax - add edx, 2 - out dx, ax -; switch to register window 6 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+6 - out dx, ax -; clear all statistics by reading - lea edx, [ebp+E3C59X_REG_CARRIER_LOST] - mov cl, 9 -.stat_clearing_loop: - in al, dx - inc edx - dec cl - jns .stat_clearing_loop - in ax, dx - add dx, 2 - in ax, dx -; switch to register window 4 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 - out dx, ax -; clear BadSSD - lea edx, [ebp+E3C59X_REG_BAD_SSD] - in al, dx -; clear extra statistics bit in NetworkDiagnostic - lea edx, [ebp+E3C59X_REG_NETWORK_DIAGNOSTIC] - in ax, dx - or ax, 0x0040 - out dx, ax -; SetRxEarlyThreshold - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, (10001b shl 11)+(E3C59X_MAX_ETH_PKT_SIZE shr 2) - out dx, ax - test byte [e3c59x_full_bus_master], 0xff - jz .skip_boomerang_setting -; set upRxEarlyEnable - lea edx, [ebp+E3C59X_REG_DMA_CTRL] - in eax, dx - or eax, 0x20 - out dx, eax -; TxFreeThreshold - lea edx, [ebp+E3C59X_REG_TX_FREE_THRESH] - mov al, (E3C59X_MAX_ETH_PKT_SIZE / 256) - out dx, al -; program DnListPtr - lea edx, [ebp+E3C59X_REG_DN_LIST_PTR] - xor eax, eax - out dx, eax -.skip_boomerang_setting: -; initialization - call e3c59x_rx_reset - call e3c59x_tx_reset - call e3c59x_set_active_port - call e3c59x_rx_reset - call e3c59x_tx_reset -; switch to register window 5 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+5 - out dx, ax -; program RxFilter for promiscuous operation - mov ax, (10000b shl 11) - lea edx, [ebp+E3C59X_REG_RX_FILTER] - in al, dx - or al, 1111b - lea edx, [ebp+E3C59X_REG_COMMAND] - out dx, ax -; switch to register window 4 - mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 - out dx, ax -; wait for linkDetect - lea edx, [ebp+E3C59X_REG_MEDIA_STATUS] - mov cl, 20 ; wait for max 2s - mov esi, 100 ; 100ms -.link_detect_loop: - call delay_ms - in ax, dx - test ah, 1000b ; linkDetect - jnz @f - dec cl - jnz .link_detect_loop -@@: -; Indicate that we have successfully reset the card - mov eax, [pci_data] - mov [eth_status], eax -if defined E3C59X_DEBUG - call e3c59x_debug -end if ; defined E3C59X_DEBUG - ret - -;*************************************************************************** -; Function -; e3c59x_global_reset -; Description -; resets the device -; Parameters: -; ebp - io_addr -; Return value: -; Destroyed registers -; ax, ecx, edx, esi -; -;*************************************************************************** - align 4 -e3c59x_global_reset: -; GlobalReset - lea edx, [ebp+E3C59X_REG_COMMAND] - xor eax, eax -; or al, 0x14 - out dx, ax -; wait for GlobalReset to complete - mov ecx, 64000 -.global_reset_loop: - in ax, dx - test ah, 10000b ; check CmdInProgress - jz .finish - dec ecx - jnz .global_reset_loop -.finish: -; wait for 2 seconds for NIC to boot - mov esi, 2000 ; 2000ms = 2s - push ebp - call delay_ms - pop ebp - ret - -;*************************************************************************** -; Function -; e3c59x_tx_reset -; Description -; resets and enables transmitter engine -; Parameters: -; ebp - io_addr -; Return value: -; Destroyed registers -; ax, ecx, edx -; -;*************************************************************************** - align 4 -e3c59x_tx_reset: -; TxReset - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, (01011b shl 11) - out dx, ax -; Wait for TxReset to complete - mov ecx, 200000 -.tx_reset_loop: - in ax, dx - test ah, 10000b ; check CmdInProgress - jz .tx_set_prev - dec ecx - jns .tx_reset_loop -.tx_set_prev: - test byte [e3c59x_full_bus_master], 0xff - jz .tx_enable -; init last_dpd - mov dword [e3c59x_prev_dpd], e3c59x_dpd_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_DPD_SIZE - mov dword [e3c59x_prev_tx_frame], e3c59x_tx_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_MAX_ETH_FRAME_SIZE -.tx_enable: - mov ax, (01001b shl 11) ; TxEnable - out dx, ax - ret - -;*************************************************************************** -; Function -; e3c59x_rx_reset -; Description -; resets and enables receiver engine -; Parameters: -; ebp - io_addr -; Return value: -; Destroyed registers -; eax, ebx, ecx, edx, edi, esi -; -;*************************************************************************** - align 4 -e3c59x_rx_reset: - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, (0101b shl 11) or 0x4 ; RxReset - out dx, ax -; wait for RxReset to complete - mov ecx, 200000 -.rx_reset_loop: - in ax, dx - test ah, 10000b ; check CmdInProgress - jz .setup_upd - dec ecx - jns .rx_reset_loop -.setup_upd: -; check if full bus mastering - test byte [e3c59x_full_bus_master], 0xff - jz .rx_enable -; create upd ring - mov eax, e3c59x_upd_buff - zero_to_virt eax - mov [e3c59x_curr_upd], eax - mov esi, eax - virt_to_dma esi - mov edi, e3c59x_rx_buff - zero_to_dma edi - mov ebx, e3c59x_upd_buff+(E3C59X_NUM_RX_DESC-1)*E3C59X_UPD_SIZE - zero_to_virt ebx - mov cl, E3C59X_NUM_RX_DESC-1 -.upd_loop: - mov [ebx+E3C59X_UPD_UP_NEXT_PTR], esi - and dword [eax+E3C59X_UPD_PKT_STATUS], 0 - mov [eax+E3C59X_UPD_UP_FRAG_ADDR], edi - mov dword [eax+E3C59X_UPD_UP_FRAG_LEN], E3C59X_MAX_ETH_FRAME_SIZE or (1 shl 31) - add edi, E3C59X_MAX_ETH_FRAME_SIZE - add esi, E3C59X_UPD_SIZE - mov ebx, eax - add eax, E3C59X_UPD_SIZE - dec cl - jns .upd_loop - mov eax, e3c59x_upd_buff - zero_to_dma eax - lea edx, [ebp+E3C59X_REG_UP_LIST_PTR] - out dx, eax ; write E3C59X_REG_UP_LIST_PTR - lea edx, [ebp+E3C59X_REG_COMMAND] -.rx_enable: - mov ax, (00100b shl 11) ; RxEnable - out dx, ax - ret - -;*************************************************************************** -; Function -; e3c59x_write_eeprom -; Description -; reads eeprom -; Note : the caller must switch to the register window 0 -; before calling this function -; Parameters: -; ax - register to be read (only the first 63 words can be read) -; cx - value to be read into the register -; Return value: -; ax - word read -; Destroyed registers -; ax, ebx, edx -; -;*************************************************************************** -; align 4 -;e3c59x_write_eeprom: -; mov edx, [io_addr] -; add edx, E3C59X_REG_EEPROM_COMMAND -; cmp ah, 11b -; ja .finish ; address may have a value of maximal 1023 -; shl ax, 2 -; shr al, 2 -; push eax -;; wait for busy -; mov ebx, 0xffff -;@@: -; in ax, dx -; test ah, 0x80 -; jz .write_enable -; dec ebx -; jns @r -;; write enable -;.write_enable: -; xor eax, eax -; mov eax, (11b shl 4) -; out dx, ax -;; wait for busy -; mov ebx, 0xffff -;@@: -; in ax, dx -; test ah, 0x80 -; jz .erase_loop -; dec ebx -; jns @r -;.erase_loop: -; pop eax -; push eax -; or ax, (11b shl 6) ; erase register -; out dx, ax -; mov ebx, 0xffff -;@@: -; in ax, dx -; test ah, 0x80 -; jz .write_reg -; dec ebx -; jns @r -;.write_reg: -; add edx, E3C59X_REG_EEPROM_DATA-E3C59X_REG_EEPROM_COMMAND -; mov eax, ecx -; out dx, ax -;; write enable -; add edx, E3C59X_REG_EEPROM_COMMAND-E3C59X_REG_EEPROM_DATA -; xor eax, eax -; mov eax, (11b shl 4) -; out dx, ax -; wait for busy -; mov ebx, 0xffff -;@@: -; in ax, dx -; test ah, 0x80 -; jz .issue_write_reg -; dec ebx -; jns @r -;.issue_write_reg: -; pop eax -; or ax, 01b shl 6 -; out dx, ax -;.finish: -; ret -;*************************************************************************** -; Function -; e3c59x_read_eeprom -; Description -; reads eeprom -; Parameters: -; ax - register to be read (only the first 63 words can be read) -; ebp - io_addr -; Return value: -; ax - word read -; Destroyed registers -; ax, ebx, edx, ebp -; -;*************************************************************************** - align 4 -e3c59x_read_eeprom: - push eax -; switch to register window 0 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+0 - out dx, ax - pop eax - and ax, 111111b ; take only the first 6 bits into account - movzx ebx, byte [e3c59x_ver_id] - test word [ebx*4+e3c59x_hw_versions+2], EEPROM_8BIT - jz @f - add ax, 0x230 ; hardware constant - jmp .read -@@: - add ax, E3C59X_EEPROM_CMD_READ - test word [ebx*4+e3c59x_hw_versions+2], EEPROM_OFFSET - jz .read - add ax, 0x30 -.read: - lea edx, [ebp+E3C59X_REG_EEPROM_COMMAND] - out dx, ax - mov ebx, 0xffff ; duration of about 162 us ;-) -.wait_for_reading: - in ax, dx - test ah, 0x80 ; check bit eepromBusy - jz .read_data - dec ebx - jns .wait_for_reading -.read_data: - lea edx, [ebp+E3C59X_REG_EEPROM_DATA] - in ax, dx - ret - -;*************************************************************************** -; Function -; e3c59x_mdio_sync -; Description -; initial synchronization -; Parameters -; ebp - io_addr -; Return value -; Destroyed registers -; ax, edx, cl -; -;*************************************************************************** - align 4 -e3c59x_mdio_sync: -; switch to register window 4 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 - out dx, ax - cmp byte [e3c59x_preamble], 0 - je .no_preamble -; send 32 logic ones - lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT] - mov cl, 31 -.loop: - mov ax, (1 shl E3C59X_BIT_MGMT_DATA) or (1 shl E3C59X_BIT_MGMT_DIR) - out dx, ax - in ax, dx ; delay - mov ax, (1 shl E3C59X_BIT_MGMT_DATA) \ - or (1 shl E3C59X_BIT_MGMT_DIR) \ - or (1 shl E3C59X_BIT_MGMT_CLK) - out dx, ax - in ax, dx ; delay - dec cl - jns .loop -.no_preamble: - ret - -;*************************************************************************** -; Function -; e3c59x_mdio_read -; Description -; read MII register -; see page 16 in D83840A.pdf -; Parameters -; ah - PHY addr -; al - register addr -; ebp - io_addr -; Return value -; ax - register read -; Destroyed registers -; eax, ebx, cx, edx -; -;*************************************************************************** - align 4 -e3c59x_mdio_read: - push eax - call e3c59x_mdio_sync ; returns with window #4 - pop eax - lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT] - shl al, 3 - shr ax, 3 - and ax, not E3C59X_MII_CMD_MASK - or ax, E3C59X_MII_CMD_READ - mov ebx, eax - xor ecx, ecx - mov cl, 13 -.cmd_loop: - mov ax, (1 shl E3C59X_BIT_MGMT_DIR) ; write mii - bt ebx, ecx - jnc .zero_bit - or al, (1 shl E3C59X_BIT_MGMT_DATA) -.zero_bit: - out dx, ax - push eax - in ax, dx ; delay - pop eax - or al, (1 shl E3C59X_BIT_MGMT_CLK) ; write - out dx, ax - in ax, dx ; delay - dec cl - jns .cmd_loop -; read data (18 bits with the two transition bits) - mov cl, 17 - xor ebx, ebx -.read_loop: - shl ebx, 1 - xor eax, eax ; read comand - out dx, ax - in ax, dx ; delay - in ax, dx - test al, (1 shl E3C59X_BIT_MGMT_DATA) - jz .dont_set - inc ebx -.dont_set: - mov ax, (1 shl E3C59X_BIT_MGMT_CLK) - out dx, ax - in ax, dx ; delay - dec cl - jns .read_loop - mov eax, ebx - ret - -;*************************************************************************** -; Function -; e3c59x_mdio_write -; Description -; write MII register -; see page 16 in D83840A.pdf -; Parameters -; ah - PHY addr -; al - register addr -; bx - word to be written -; ebp - io_addr -; Return value -; ax - register read -; Destroyed registers -; eax, ebx, cx, edx -; -;*************************************************************************** - align 4 -e3c59x_mdio_write: - push eax - call e3c59x_mdio_sync - pop eax - lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT] - shl al, 3 - shr ax, 3 - and ax, not E3C59X_MII_CMD_MASK - or ax, E3C59X_MII_CMD_WRITE - shl eax, 2 - or eax, 10b ; transition bits - shl eax, 16 - mov ax, bx - mov ebx, eax - mov ecx, 31 -.cmd_loop: - mov ax, (1 shl E3C59X_BIT_MGMT_DIR) ; write mii - bt ebx, ecx - jnc .zero_bit - or al, (1 shl E3C59X_BIT_MGMT_DATA) -.zero_bit: - out dx, ax - push eax - in ax, dx ; delay - pop eax - or al, (1 shl E3C59X_BIT_MGMT_CLK) ; write - out dx, ax - in ax, dx ; delay - dec ecx - jns .cmd_loop - ret - -;*************************************************************************** -; Function -; e3c59x_transmit -; Description -; Transmits a packet of data via the ethernet card -; edi - Pointer to 48 bit destination address -; bx - Type of packet -; ecx - size of packet -; esi - pointer to packet data -; ebp - io_addr -; Destroyed registers -; eax, ecx, edx, ebp -; -;*************************************************************************** - align 4 -e3c59x_transmit: - jmp dword [e3c59x_transmit_function] - -;*************************************************************************** -; Function -; e3c59x_check_tx_status -; Description -; Checks TxStatus queue. -; Return value -; al - 0 no error was found -; al - 1 error was found TxReset is needed -; Destroyed registers -; eax, ecx, edx, ebp -; -;*************************************************************************** -e3c59x_check_tx_status: - movzx ebp, word [io_addr] ; to be implemented in ETHERNET.INC -; clear TxStatus queue - lea edx, [ebp+E3C59X_REG_TX_STATUS] - mov cl, 31 ; max number of queue entries -.tx_status_loop: - in al, dx - test al, al - jz .finish ; no error - test al, 0x3f - jnz .finish ; error -.no_error_found: -; clear current TxStatus entry which advances the next one - xor al, al - out dx, al - dec cl - jns .tx_status_loop -.finish: - ret - -;*************************************************************************** -; Function -; e3c59x_vortex_transmit -; Description -; Transmits a packet of data via the ethernet card -; edi - Pointer to 48 bit destination address -; bx - Type of packet -; ecx - size of packet -; esi - pointer to packet data -; ebp - io_addr -; Destroyed registers -; eax, edx, ecx, edi, esi, ebp -; -;*************************************************************************** - align 4 -e3c59x_vortex_transmit: - push ecx - call e3c59x_check_tx_status - pop ecx - test al, al - jz .no_error_found - jmp e3c59x_tx_reset -.no_error_found: -; switch to register window 7 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+7 - out dx, ax -; check for master operation in progress - lea edx, [ebp+E3C59X_REG_MASTER_STATUS] - in ax, dx - test ah, 0x80 - jnz .finish ; no DMA for sending -; dword boundary correction - cmp ecx, E3C59X_MAX_ETH_FRAME_SIZE - ja .finish ; packet is too long -; write Frame Start Header - mov eax, ecx -; add header length and extend the complete length to dword boundary - add eax, ETH_HLEN+3 - and eax, not 3 - lea edx, [ebp+E3C59X_REG_TX_DATA] - out dx, eax -; prepare the complete frame - push esi - mov esi, edi - mov edi, e3c59x_tx_buff - zero_to_virt edi - cld -; copy destination address - movsd - movsw -; copy source address - mov esi, node_addr - movsd - movsw -; copy packet type - mov [edi], bx - add edi, 2 -; copy packet data - pop esi - push ecx - shr ecx, 2 - rep movsd - pop ecx - and ecx, 3 - rep movsb - mov ecx, eax -; program frame address to be sent - lea edx, [ebp+E3C59X_REG_MASTER_ADDRESS] - mov eax, e3c59x_tx_buff - zero_to_dma eax - out dx, eax -; program frame length - lea edx, [ebp+E3C59X_REG_MASTER_LEN] - mov eax, ecx - out dx, ax -; start DMA Down - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, (10100b shl 11) + 1 ; StartDMADown - out dx, ax -.finish: - ret - -;*************************************************************************** -; Function -; e3c59x_boomerang_transmit -; Description -; Transmits a packet of data via the ethernet card -; edi - Pointer to 48 bit destination address -; bx - Type of packet -; ecx - size of packet -; esi - pointer to packet data -; ebp - io_addr -; Destroyed registers -; eax, ebx, ecx, edx, esi, edi, ebp -; -;*************************************************************************** - align 4 -e3c59x_boomerang_transmit: - push ecx - call e3c59x_check_tx_status - pop ecx - test al, al - jz .no_error_found - jmp e3c59x_tx_reset -.no_error_found: - cmp ecx, E3C59X_MAX_ETH_FRAME_SIZE - ja .finish ; packet is too long -; calculate descriptor address - mov eax, [e3c59x_prev_dpd] - cmp eax, e3c59x_dpd_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_DPD_SIZE - jb @f -; wrap around - mov eax, e3c59x_dpd_buff-E3C59X_DPD_SIZE -@@: - add eax, E3C59X_DPD_SIZE - zero_to_virt eax - push eax -; check DnListPtr - lea edx, [ebp+E3C59X_REG_DN_LIST_PTR] - in eax, dx -; mark if Dn_List_Ptr is cleared - test eax, eax - setz [e3c59x_dn_list_ptr_cleared] -; finish if no more free descriptor is available - FIXME! - cmp eax, [esp] - pop eax - jz .finish - push eax esi - mov esi, edi -; calculate tx_buffer address - mov edi, [e3c59x_prev_tx_frame] - cmp edi, e3c59x_tx_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_MAX_ETH_FRAME_SIZE - jb @f -; wrap around - mov edi, e3c59x_tx_buff-E3C59X_MAX_ETH_FRAME_SIZE -@@: - add edi, E3C59X_MAX_ETH_FRAME_SIZE - zero_to_virt edi - mov eax, edi - cld -; copy destination address - movsd - movsw -; copy source address - mov esi, node_addr - movsd - movsw -; copy packet type - mov [edi], bx - add edi, 2 -; copy packet data - pop esi - push ecx - shr ecx, 2 - rep movsd - pop ecx - push ecx - and ecx, 3 - rep movsb -; padding, do we really need it? - pop ecx - add ecx, ETH_HLEN - cmp ecx, ETH_ZLEN - jae @f - mov ecx, ETH_ZLEN -@@: -; calculate - mov ebx, ecx - ;test byte [e3c59x_has_hwcksm], 0xff - ;jz @f - ;or ebx, (1 shl 26) ; set AddTcpChecksum -;@@: - or ebx, 0x8000 ; transmission complete notification - or ecx, 0x80000000 ; last fragment -; program DPD - mov edi, eax - pop eax - and dword [eax+E3C59X_DPD_DN_NEXT_PTR], 0 - mov dword [eax+E3C59X_DPD_FRAME_START_HDR], ebx - virt_to_dma edi - mov dword [eax+E3C59X_DPD_DN_FRAG_ADDR], edi - mov [eax+E3C59X_DPD_DN_FRAG_LEN], ecx -; calculate physical address - virt_to_dma eax - push eax - cmp byte [e3c59x_dn_list_ptr_cleared], 0 - jz .add_to_list -; write Dn_List_Ptr - out dx, eax - jmp .finish -.add_to_list: -; DnStall - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, ((110b shl 11)+2) - out dx, ax -; wait for DnStall to complete - mov ecx, 6000 -.wait_for_stall: - in ax, dx ; read E3C59X_REG_INT_STATUS - test ah, 10000b - jz .dnstall_ok - dec ecx - jnz .wait_for_stall -.dnstall_ok: - pop eax - push eax - mov ebx, [e3c59x_prev_dpd] - zero_to_virt ebx - mov [ebx], eax - lea edx, [ebp+E3C59X_REG_DN_LIST_PTR] - in eax, dx - test eax, eax - jnz .dnunstall -; if Dn_List_Ptr has been cleared fill it up - pop eax - push eax - out dx, eax -.dnunstall: -; DnUnStall - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, ((110b shl 11)+3) - out dx, ax -.finish: - pop eax - dma_to_zero eax - mov [e3c59x_prev_dpd], eax - dma_to_zero edi - mov [e3c59x_prev_tx_frame], edi - ret - -;*************************************************************************** -; Function -; e3c59x_poll -; Description -; Polls the ethernet card for a received packet -; Received data, if any, ends up in Ether_buffer -; Destroyed registers -; eax, ebx, edx, ecx, edi, esi, ebp -; -;*************************************************************************** - align 4 -e3c59x_poll: - jmp dword [e3c59x_receive_function] - -;*************************************************************************** -; Function -; e3c59x_vortex_poll -; Description -; Polls the ethernet card for a received packet -; Received data, if any, ends up in Ether_buffer -; Parameters -; ebp - io_addr -; Return value -; al - 0 ; no packet received -; al - 1 ; packet received -; Destroyed registers -; eax, ebx, edx, ecx, edi, esi, ebp -; -;*************************************************************************** - align 4 -e3c59x_vortex_poll: - and word [eth_rx_data_len], 0 ; assume no packet received - movzx ebp, word [io_addr] ; to be implemented in ETHERNET.INC -.rx_status_loop: -; examine RxStatus - lea edx, [ebp+E3C59X_REG_RX_STATUS] - in ax, dx - test ax, ax - jz .finish - test ah, 0x80 ; rxIncomplete - jz .check_error - jmp .finish -.check_error: - test ah, 0x40 - jz .check_length -; discard the top frame received advancing the next one - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, (01000b shl 11) - out dx, ax - jmp .rx_status_loop -.check_length: - and eax, 0x1fff - cmp eax, E3C59X_MAX_ETH_PKT_SIZE - ja .discard_frame ; frame is too long discard it -.check_dma: - push eax -; switch to register window 7 - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, E3C59X_SELECT_REGISTER_WINDOW+7 - out dx, ax -; check for master operation in progress - lea edx, [ebp+E3C59X_REG_MASTER_STATUS] - in ax, dx - test ah, 0x80 - jz .read_frame ; no DMA for receiving - pop eax - jmp .finish -.read_frame: -; program buffer address to read in - lea edx, [ebp+E3C59X_REG_MASTER_ADDRESS] -if defined E3C59X_LINUX - mov eax, e3c59x_rx_buff - zero_to_dma eax -else - mov eax, Ether_buffer -end if - out dx, eax -; program frame length - lea edx, [ebp+E3C59X_REG_MASTER_LEN] - mov ax, 1560 - out dx, ax -; start DMA Up - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, (10100b shl 11) ; StartDMAUp - out dx, ax -; check for master operation in progress -.dma_loop: - lea edx, [ebp+E3C59X_REG_MASTER_STATUS] - in ax, dx - test ah, 0x80 - jnz .dma_loop -; registrate the received packet length - pop eax - mov word [eth_rx_data_len], ax -; discard the top frame received -.discard_frame: - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, (01000b shl 11) - out dx, ax -.finish: -; set return value - cmp word [eth_rx_data_len], 0 - setne al - ret - -;*************************************************************************** -; Function -; e3c59x_boomerang_poll -; Description -; Polls the ethernet card for a received packet -; Received data, if any, ends up in Ether_buffer -; Parameters -; ebp - io_addr -; Return value -; al - 0 ; no packet received -; al - 1 ; packet received -; Destroyed registers -; eax, edx, ecx, edi, esi, ebp -; -;*************************************************************************** - align 4 -e3c59x_boomerang_poll: - and word [eth_rx_data_len], 0 ; assume no packet received - movzx ebp, word [io_addr] ; to be implemented in ETHERNET.INC -; check if packet is uploaded - mov eax, [e3c59x_curr_upd] - test byte [eax+E3C59X_UPD_PKT_STATUS+1], 0x80 ; upPktComplete - jnz .check_error - jmp .finish -; packet is uploaded check for any error -.check_error: - test byte [eax+E3C59X_UPD_PKT_STATUS+1], 0x40 ; upError - jz .copy_packet_length - and dword [eax+E3C59X_UPD_PKT_STATUS], 0 - jmp .finish -.copy_packet_length: - mov ecx, [eax+E3C59X_UPD_PKT_STATUS] - and ecx, 0x1fff - cmp ecx, E3C59X_MAX_ETH_PKT_SIZE - jbe .copy_packet - and dword [eax+E3C59X_UPD_PKT_STATUS], 0 - jmp .finish -.copy_packet: - push ecx - mov word [eth_rx_data_len], cx - mov esi, [eax+E3C59X_UPD_UP_FRAG_ADDR] - dma_to_virt esi - mov edi, Ether_buffer - shr ecx, 2 ; first copy dword-wise - cld - rep movsd ; copy the dwords - pop ecx - and ecx, 3 - rep movsb ; copy the rest bytes - mov eax, [e3c59x_curr_upd] - and dword [eax+E3C59X_UPD_PKT_STATUS], 0 - virt_to_zero eax - cmp eax, e3c59x_upd_buff+(E3C59X_NUM_RX_DESC-1)*E3C59X_UPD_SIZE - jb .no_wrap -; wrap around - mov eax, e3c59x_upd_buff-E3C59X_UPD_SIZE -.no_wrap: - add eax, E3C59X_UPD_SIZE - zero_to_virt eax - mov [e3c59x_curr_upd], eax -.finish: -; check if the NIC is in the upStall state - lea edx, [ebp+E3C59X_REG_UP_PKT_STATUS] - in eax, dx - test ah, 0x20 ; UpStalled - jz .noUpUnStall -; issue upUnStall command - lea edx, [ebp+E3C59X_REG_COMMAND] - mov ax, ((110b shl 11)+1) ; upUnStall - out dx, ax -.noUpUnStall: -; set return value - cmp word [eth_rx_data_len], 0 - setnz al - ret diff --git a/kernel/trunk/network/eth_drv/drivers/forcedeth.inc b/kernel/trunk/network/eth_drv/drivers/forcedeth.inc deleted file mode 100644 index 2bd678e5e0..0000000000 --- a/kernel/trunk/network/eth_drv/drivers/forcedeth.inc +++ /dev/null @@ -1,2696 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; FORCEDETH.INC ;; -;; ;; -;; Ethernet driver for Kolibri OS ;; -;; ;; -;; Version 0.1 24 June 2008 - 23 Sep 2008 ;; -;; ;; -;; Driver for chips of NVIDIA nForce2 ;; -;; References: ;; -;; forcedeth.c - linux driver (etherboot project) ;; -;; ethernet driver template by Mike Hibbett ;; -;; ;; -;; The copyright statement is ;; -;; ;; -;; GNU GENERAL PUBLIC LICENSE ;; -;; Version 2, June 1991 ;; -;; ;; -;; Copyright 2008 shurf, ;; -;; cit.utc@gmail.com ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - -;******************************************************************** -; Interface -; forcedeth_reset -; forcedeth_probe -; forcedeth_poll -; forcedeth_transmit -; forcedeth_cable -; -;******************************************************************** - -;************************************************************************** -; forcedeth Register Definitions -;************************************************************************** - -PCI_REG_COMMAND equ 0x04 ; command register - -PCI_COMMAND_IO equ 0x01 ; Enable response in I/O space -PCI_COMMAND_MASTER equ 0x04 ; Enable bus mastering -PCI_LATENCY_TIMER equ 0x0d ; 8 bits - -PCI_VENDOR_ID equ 0x00 ; 16 bit -PCI_REVISION_ID equ 0x08 ; 8 bits - -PCI_BASE_ADDRESS_0 equ 0x10 ; 32 bits -PCI_BASE_ADDRESS_1 equ 0x14 ; 32 bits -PCI_BASE_ADDRESS_2 equ 0x18 ; 32 bits -PCI_BASE_ADDRESS_3 equ 0x1c ; 32 bits -PCI_BASE_ADDRESS_4 equ 0x20 ; 32 bits -PCI_BASE_ADDRESS_5 equ 0x24 ; 32 bits - -PCI_BASE_ADDRESS_SPACE_IO equ 0x01 -PCI_BASE_ADDRESS_IO_MASK equ (not 0x03) -PCI_BASE_ADDRESS_MEM_MASK equ (not 0x0f) - -PCI_BASE_ADDRESS_MEM_TYPE_MASK equ 0x06 -PCI_BASE_ADDRESS_MEM_TYPE_32 equ 0x00 ; 32 bit address -PCI_BASE_ADDRESS_MEM_TYPE_1M equ 0x02 ; Below 1M [obsolete] -PCI_BASE_ADDRESS_MEM_TYPE_64 equ 0x04 ; 64 bit address - -; NIC specific static variables go here -PCI_DEVICE_ID_NVIDIA_NVENET_1 equ 0x01c3 -PCI_DEVICE_ID_NVIDIA_NVENET_2 equ 0x0066 -PCI_DEVICE_ID_NVIDIA_NVENET_4 equ 0x0086 -PCI_DEVICE_ID_NVIDIA_NVENET_5 equ 0x008c -PCI_DEVICE_ID_NVIDIA_NVENET_3 equ 0x00d6 -PCI_DEVICE_ID_NVIDIA_NVENET_7 equ 0x00df -PCI_DEVICE_ID_NVIDIA_NVENET_6 equ 0x00e6 -PCI_DEVICE_ID_NVIDIA_NVENET_8 equ 0x0056 -PCI_DEVICE_ID_NVIDIA_NVENET_9 equ 0x0057 -PCI_DEVICE_ID_NVIDIA_NVENET_10 equ 0x0037 -PCI_DEVICE_ID_NVIDIA_NVENET_11 equ 0x0038 -PCI_DEVICE_ID_NVIDIA_NVENET_12 equ 0x0268 -PCI_DEVICE_ID_NVIDIA_NVENET_13 equ 0x0269 -PCI_DEVICE_ID_NVIDIA_NVENET_14 equ 0x0372 -PCI_DEVICE_ID_NVIDIA_NVENET_15 equ 0x0373 - -ETH_DATA_LEN equ 1500 - -; rx/tx mac addr + type + vlan + align + slack -RX_NIC_BUFSIZE equ (ETH_DATA_LEN + 64) -; even more slack -RX_ALLOC_BUFSIZE equ (ETH_DATA_LEN + 128) - -NvRegIrqStatus equ 0x00 -NvRegIrqMask equ 0x04 -NvRegUnknownSetupReg6 equ 0x08 -NvRegPollingInterval equ 0x0c -NvRegMacReset equ 0x3c -NvRegMisc1 equ 0x80 -NvRegTransmitterControl equ 0x84 -NvRegTransmitterStatus equ 0x88 -NvRegPacketFilterFlags equ 0x8c -NvRegOffloadConfig equ 0x90 -NvRegReceiverControl equ 0x94 -NvRegReceiverStatus equ 0x98 -NvRegRandomSeed equ 0x9c -NvRegUnknownSetupReg1 equ 0xA0 -NvRegUnknownSetupReg2 equ 0xA4 -NvRegMacAddrA equ 0xA8 ; MAC address low -NvRegMacAddrB equ 0xAC ; MAC address high -NvRegMulticastAddrA equ 0xB0 -NvRegMulticastAddrB equ 0xB4 -NvRegMulticastMaskA equ 0xB8 -NvRegMulticastMaskB equ 0xBC -NvRegPhyInterface equ 0xC0 -NvRegTxRingPhysAddr equ 0x100 -NvRegRxRingPhysAddr equ 0x104 -NvRegRingSizes equ 0x108 -NvRegUnknownTransmitterReg equ 0x10c -NvRegLinkSpeed equ 0x110 -NvRegUnknownSetupReg5 equ 0x130 -NvRegUnknownSetupReg3 equ 0x13c -NvRegTxRxControl equ 0x144 -NvRegMIIStatus equ 0x180 -NvRegUnknownSetupReg4 equ 0x184 -NvRegAdapterControl equ 0x188 -NvRegMIISpeed equ 0x18c -NvRegMIIControl equ 0x190 -NvRegMIIData equ 0x194 -NvRegWakeUpFlags equ 0x200 -NvRegPowerState equ 0x26c -NvRegPowerState2 equ 0x600 - -NVREG_UNKSETUP1_VAL equ 0x16070f -NVREG_UNKSETUP2_VAL equ 0x16 -NVREG_UNKSETUP3_VAL1 equ 0x200010 -NVREG_UNKSETUP4_VAL equ 8 -NVREG_UNKSETUP5_BIT31 equ (1 shl 31) -NVREG_UNKSETUP6_VAL equ 3 - -NVREG_TXRXCTL_RXCHECK equ 0x0400 -NVREG_MIISTAT_ERROR equ 0x0001 -NVREG_MIISTAT_MASK equ 0x000f -NVREG_MIISTAT_MASK2 equ 0x000f -NVREG_MIICTL_INUSE equ 0x08000 -NVREG_MIICTL_WRITE equ 0x00400 -NVREG_MIICTL_ADDRSHIFT equ 5 - -NVREG_MIISPEED_BIT8 equ (1 shl 8) -NVREG_MIIDELAY equ 5 - -NVREG_IRQ_RX_ERROR equ 0x0001 -NVREG_IRQ_RX equ 0x0002 -NVREG_IRQ_RX_NOBUF equ 0x0004 -NVREG_IRQ_LINK equ 0x0040 -NVREG_IRQ_TIMER equ 0x0020 -NVREG_IRQMASK_WANTED_2 equ 0x0147 - -NVREG_IRQ_RX_ALL equ (NVREG_IRQ_RX_ERROR or NVREG_IRQ_RX or NVREG_IRQ_RX_NOBUF) -NVREG_IRQ_TX_ALL equ 0 ; ??????????? -NVREG_IRQ_OTHER_ALL equ (NVREG_IRQ_LINK or NVREG_IRQ_TIMER) - -NVREG_IRQSTAT_MASK equ 0x1ff - -NVREG_TXRXCTL_KICK equ 0x0001 -NVREG_TXRXCTL_BIT1 equ 0x0002 -NVREG_TXRXCTL_BIT2 equ 0x0004 -NVREG_TXRXCTL_IDLE equ 0x0008 -NVREG_TXRXCTL_RESET equ 0x0010 -NVREG_TXRXCTL_RXCHECK equ 0x0400 - -NVREG_MCASTADDRA_FORCE equ 0x01 - -NVREG_MAC_RESET_ASSERT equ 0x0F3 - -NVREG_MISC1_HD equ 0x02 -NVREG_MISC1_FORCE equ 0x3b0f3c - -NVREG_PFF_ALWAYS equ 0x7F0008 -NVREG_PFF_PROMISC equ 0x80 -NVREG_PFF_MYADDR equ 0x20 - -NVREG_OFFLOAD_HOMEPHY equ 0x601 -NVREG_OFFLOAD_NORMAL equ RX_NIC_BUFSIZE - -NVREG_RNDSEED_MASK equ 0x00ff -NVREG_RNDSEED_FORCE equ 0x7f00 -NVREG_RNDSEED_FORCE2 equ 0x2d00 -NVREG_RNDSEED_FORCE3 equ 0x7400 - -; NVREG_POLL_DEFAULT is the interval length of the timer source on the nic -; NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms -NVREG_POLL_DEFAULT equ 970 - -NVREG_ADAPTCTL_START equ 0x02 -NVREG_ADAPTCTL_LINKUP equ 0x04 -NVREG_ADAPTCTL_PHYVALID equ 0x40000 -NVREG_ADAPTCTL_RUNNING equ 0x100000 -NVREG_ADAPTCTL_PHYSHIFT equ 24 - -NVREG_WAKEUPFLAGS_VAL equ 0x7770 - -NVREG_POWERSTATE_POWEREDUP equ 0x8000 -NVREG_POWERSTATE_VALID equ 0x0100 -NVREG_POWERSTATE_MASK equ 0x0003 -NVREG_POWERSTATE_D0 equ 0x0000 -NVREG_POWERSTATE_D1 equ 0x0001 -NVREG_POWERSTATE_D2 equ 0x0002 -NVREG_POWERSTATE_D3 equ 0x0003 - -NVREG_POWERSTATE2_POWERUP_MASK equ 0x0F11 -NVREG_POWERSTATE2_POWERUP_REV_A3 equ 0x0001 - -NVREG_RCVCTL_START equ 0x01 -NVREG_RCVSTAT_BUSY equ 0x01 - -NVREG_XMITCTL_START equ 0x01 - -NVREG_LINKSPEED_FORCE equ 0x10000 -NVREG_LINKSPEED_10 equ 1000 -NVREG_LINKSPEED_100 equ 100 -NVREG_LINKSPEED_1000 equ 50 - -NVREG_RINGSZ_TXSHIFT equ 0 -NVREG_RINGSZ_RXSHIFT equ 16 - -LPA_1000FULL equ 0x0800 - -; Link partner ability register. -LPA_SLCT equ 0x001f ; Same as advertise selector -LPA_10HALF equ 0x0020 ; Can do 10mbps half-duplex -LPA_10FULL equ 0x0040 ; Can do 10mbps full-duplex -LPA_100HALF equ 0x0080 ; Can do 100mbps half-duplex -LPA_100FULL equ 0x0100 ; Can do 100mbps full-duplex -LPA_100BASE4 equ 0x0200 ; Can do 100mbps 4k packets -LPA_RESV equ 0x1c00 ; Unused... -LPA_RFAULT equ 0x2000 ; Link partner faulted -LPA_LPACK equ 0x4000 ; Link partner acked us -LPA_NPAGE equ 0x8000 ; Next page bit - -MII_READ equ (-1) -MII_PHYSID1 equ 0x02 ; PHYS ID 1 -MII_PHYSID2 equ 0x03 ; PHYS ID 2 -MII_BMCR equ 0x00 ; Basic mode control register -MII_BMSR equ 0x01 ; Basic mode status register -MII_ADVERTISE equ 0x04 ; Advertisement control reg -MII_LPA equ 0x05 ; Link partner ability reg -MII_SREVISION equ 0x16 ; Silicon revision -MII_RESV1 equ 0x17 ; Reserved... -MII_NCONFIG equ 0x1c ; Network interface config - -; PHY defines -PHY_OUI_MARVELL equ 0x5043 -PHY_OUI_CICADA equ 0x03f1 -PHYID1_OUI_MASK equ 0x03ff -PHYID1_OUI_SHFT equ 6 -PHYID2_OUI_MASK equ 0xfc00 -PHYID2_OUI_SHFT equ 10 -PHY_INIT1 equ 0x0f000 -PHY_INIT2 equ 0x0e00 -PHY_INIT3 equ 0x01000 -PHY_INIT4 equ 0x0200 -PHY_INIT5 equ 0x0004 -PHY_INIT6 equ 0x02000 -PHY_GIGABIT equ 0x0100 - -PHY_TIMEOUT equ 0x1 -PHY_ERROR equ 0x2 - -PHY_100 equ 0x1 -PHY_1000 equ 0x2 -PHY_HALF equ 0x100 - -PHY_RGMII equ 0x10000000 - -; desc_ver values: -; This field has two purposes: -; - Newer nics uses a different ring layout. The layout is selected by -; comparing np->desc_ver with DESC_VER_xy. -; - It contains bits that are forced on when writing to NvRegTxRxControl. -DESC_VER_1 equ 0x0 -DESC_VER_2 equ (0x02100 or NVREG_TXRXCTL_RXCHECK) - -MAC_ADDR_LEN equ 6 - -NV_TX_LASTPACKET equ (1 shl 16) -NV_TX_RETRYERROR equ (1 shl 19) -NV_TX_LASTPACKET1 equ (1 shl 24) -NV_TX_DEFERRED equ (1 shl 26) -NV_TX_CARRIERLOST equ (1 shl 27) -NV_TX_LATECOLLISION equ (1 shl 28) -NV_TX_UNDERFLOW equ (1 shl 29) -NV_TX_ERROR equ (1 shl 30) -NV_TX_VALID equ (1 shl 31) - -NV_TX2_LASTPACKET equ (1 shl 29) -NV_TX2_RETRYERROR equ (1 shl 18) -NV_TX2_LASTPACKET1 equ (1 shl 23) -NV_TX2_DEFERRED equ (1 shl 25) -NV_TX2_CARRIERLOST equ (1 shl 26) -NV_TX2_LATECOLLISION equ (1 shl 27) -NV_TX2_UNDERFLOW equ (1 shl 28) -; error and valid are the same for both -NV_TX2_ERROR equ (1 shl 30) -NV_TX2_VALID equ (1 shl 31) - -NV_RX_DESCRIPTORVALID equ (1 shl 16) -NV_RX_AVAIL equ (1 shl 31) - -NV_RX2_DESCRIPTORVALID equ (1 shl 29) - -RX_RING equ 4 -TX_RING equ 2 - -FLAG_MASK_V1 equ 0xffff0000 -FLAG_MASK_V2 equ 0xffffc000 -LEN_MASK_V1 equ (0xffffffff xor FLAG_MASK_V1) -LEN_MASK_V2 equ (0xffffffff xor FLAG_MASK_V2) - -; Miscelaneous hardware related defines: -NV_PCI_REGSZ_VER1 equ 0x270 -NV_PCI_REGSZ_VER2 equ 0x604 -; various timeout delays: all in usec -NV_TXRX_RESET_DELAY equ 4 -NV_TXSTOP_DELAY1 equ 10 -NV_TXSTOP_DELAY1MAX equ 500000 -NV_TXSTOP_DELAY2 equ 100 -NV_RXSTOP_DELAY1 equ 10 -NV_RXSTOP_DELAY1MAX equ 500000 -NV_RXSTOP_DELAY2 equ 100 -NV_SETUP5_DELAY equ 5 -NV_SETUP5_DELAYMAX equ 50000 -NV_POWERUP_DELAY equ 5 -NV_POWERUP_DELAYMAX equ 5000 -NV_MIIBUSY_DELAY equ 50 -NV_MIIPHY_DELAY equ 10 -NV_MIIPHY_DELAYMAX equ 10000 -NV_MAC_RESET_DELAY equ 64 -NV_WAKEUPPATTERNS equ 5 -NV_WAKEUPMASKENTRIES equ 4 - -; Advertisement control register. -ADVERTISE_SLCT equ 0x001f ; Selector bits -ADVERTISE_CSMA equ 0x0001 ; Only selector supported -ADVERTISE_10HALF equ 0x0020 ; Try for 10mbps half-duplex -ADVERTISE_10FULL equ 0x0040 ; Try for 10mbps full-duplex -ADVERTISE_100HALF equ 0x0080 ; Try for 100mbps half-duplex -ADVERTISE_100FULL equ 0x0100 ; Try for 100mbps full-duplex -ADVERTISE_100BASE4 equ 0x0200 ; Try for 100mbps 4k packets -ADVERTISE_RESV equ 0x1c00 ; Unused... -ADVERTISE_RFAULT equ 0x2000 ; Say we can detect faults -ADVERTISE_LPACK equ 0x4000 ; Ack link partners response -ADVERTISE_NPAGE equ 0x8000 ; Next page bit - -ADVERTISE_FULL equ (ADVERTISE_100FULL or ADVERTISE_10FULL or ADVERTISE_CSMA) -ADVERTISE_ALL equ (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL) - -MII_1000BT_CR equ 0x09 -MII_1000BT_SR equ 0x0a -ADVERTISE_1000FULL equ 0x0200 -ADVERTISE_1000HALF equ 0x0100 - -BMCR_ANRESTART equ 0x0200 ; Auto negotiation restart -BMCR_ANENABLE equ 0x1000 ; Enable auto negotiation -BMCR_SPEED100 equ 0x2000 ; Select 100Mbps -BMCR_LOOPBACK equ 0x4000 ; TXD loopback bits -BMCR_RESET equ 0x8000 ; Reset the DP83840 - -; Basic mode status register. -BMSR_ERCAP equ 0x0001 ; Ext-reg capability -BMSR_JCD equ 0x0002 ; Jabber detected -BMSR_LSTATUS equ 0x0004 ; Link status -BMSR_ANEGCAPABLE equ 0x0008 ; Able to do auto-negotiation -BMSR_RFAULT equ 0x0010 ; Remote fault detected -BMSR_ANEGCOMPLETE equ 0x0020 ; Auto-negotiation complete -BMSR_RESV equ 0x07c0 ; Unused... -BMSR_10HALF equ 0x0800 ; Can do 10mbps, half-duplex -BMSR_10FULL equ 0x1000 ; Can do 10mbps, full-duplex -BMSR_100HALF equ 0x2000 ; Can do 100mbps, half-duplex -BMSR_100FULL equ 0x4000 ; Can do 100mbps, full-duplex -BMSR_100BASE4 equ 0x8000 ; Can do 100mbps, 4k packets - -ETH_ALEN equ 6 -ETH_HLEN equ (2 * ETH_ALEN + 2) -ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for - ; mininmum 64bytes frame length - -uglobal -forcedeth_mmio_addr dd 0 ; memory map physical address -forcedeth_mmio_size dd 0 ; size of memory bar -forcedeth_vendor_id dw 0 ; Vendor ID -forcedeth_device_id dw 0 ; Device ID -forcedeth_orig_mac0 dd 0 ; MAC -forcedeth_orig_mac1 dd 0 ; MAC -forcedeth_mapio_addr dd 0 ; mapped IO address -forcedeth_txflags dd 0 ; -forcedeth_desc_ver dd 0 ; -forcedeth_irqmask dd 0 ; IRQ-mask -forcedeth_wolenabled dd 0 ; WOL -forcedeth_in_shutdown dd 0 ; -forcedeth_cur_rx dd 0 ; -forcedeth_refill_rx dd 0 ; -forcedeth_phyaddr dd 0 ; -forcedeth_phy_oui dd 0 ; -forcedeth_gigabit dd 0 ; -forcedeth_needs_mac_reset dd 0 ; -forcedeth_linkspeed dd 0 ; -forcedeth_duplex dd 0 ; -forcedeth_next_tx dd 0 ; next TX descriptor number -forcedeth_nic_tx dd 0 ; ??? d'nt used ??? -forcedeth_packetlen dd 0 ; -forcedeth_nocable dd 0 ; no cable present -endg - -struc forcedeth_TxDesc { - .PacketBuffer dd ? - .FlagLen dd ? -} -virtual at 0 - forcedeth_TxDesc forcedeth_TxDesc - sizeof.forcedeth_TxDesc = $ - forcedeth_TxDesc -end virtual - -struc forcedeth_RxDesc { - .PacketBuffer dd ? - .FlagLen dd ? -} -virtual at 0 - forcedeth_RxDesc forcedeth_RxDesc - sizeof.forcedeth_RxDesc = $ - forcedeth_RxDesc -end virtual - -virtual at eth_data_start - ; Define the TX Descriptor - align 256 - forcedeth_tx_ring rb TX_RING * sizeof.forcedeth_TxDesc - ; Create a static buffer of size RX_BUF_SZ for each - ; TX Descriptor. All descriptors point to a - ; part of this buffer - align 256 - forcedeth_txb rb TX_RING * RX_NIC_BUFSIZE - - ; Define the RX Descriptor - align 256 - forcedeth_rx_ring rb RX_RING * sizeof.forcedeth_RxDesc - ; Create a static buffer of size RX_BUF_SZ for each - ; RX Descriptor. All descriptors point to a - ; part of this buffer - align 256 - forcedeth_rxb rb RX_RING * RX_NIC_BUFSIZE -end virtual - - -;*************************************************************************** -; Function -; forcedeth_reset -; Description -; Place the chip (ie, the ethernet card) into a virgin state -; No inputs -; All registers destroyed -; -;*************************************************************************** -forcedeth_reset: - - ; 1) erase previous misconfiguration - ; 4.1-1: stop adapter: ignored, 4.3 seems to be overkill - - ; writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA) - mov edi, dword [forcedeth_mapio_addr] - mov dword [edi+NvRegMulticastAddrA], NVREG_MCASTADDRA_FORCE - - ; writel(0, base + NvRegMulticastAddrB) - mov dword [edi+NvRegMulticastAddrB], 0 - - ; writel(0, base + NvRegMulticastMaskA) - mov dword [edi+NvRegMulticastMaskA], 0 - - ; writel(0, base + NvRegMulticastMaskB) - mov dword [edi+NvRegMulticastMaskB], 0 - - ; writel(0, base + NvRegPacketFilterFlags) - mov dword [edi+NvRegPacketFilterFlags], 0 - - ; writel(0, base + NvRegTransmitterControl) - mov dword [edi+NvRegTransmitterControl], 0 - - ; writel(0, base + NvRegReceiverControl) - mov dword [edi+NvRegReceiverControl], 0 - - ; writel(0, base + NvRegAdapterControl) - mov dword [edi+NvRegAdapterControl], 0 - - - ; 2) initialize descriptor rings - ; init_ring(nic) - call forcedeth_init_ring - - ; writel(0, base + NvRegLinkSpeed) - mov dword [edi+NvRegLinkSpeed], 0 - - ; writel(0, base + NvRegUnknownTransmitterReg) - mov dword [edi+NvRegUnknownTransmitterReg], 0 - - ; txrx_reset(nic) - call forcedeth_txrx_reset - - ; writel(0, base + NvRegUnknownSetupReg6) - mov dword [edi+NvRegUnknownSetupReg6], 0 - - ; np->in_shutdown = 0 - mov dword [forcedeth_in_shutdown], 0 - - - ; 3) set mac address - ; writel(mac[0], base + NvRegMacAddrA) - mov eax, dword [forcedeth_orig_mac0] - mov dword [edi+NvRegMacAddrA], eax - - ; writel(mac[1], base + NvRegMacAddrB) - mov eax, dword [forcedeth_orig_mac1] - mov dword [edi+NvRegMacAddrB], eax - - - ; 4) give hw rings - ; writel((u32) virt_to_le32desc(&rx_ring[0]), base + NvRegRxRingPhysAddr) - mov eax, forcedeth_rx_ring - -;DEBUGF 1," K : FORCEDETH: rx_ring at 0x%x\n", eax - - sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - mov dword [edi+NvRegRxRingPhysAddr], eax - - ; writel((u32) virt_to_le32desc(&tx_ring[0]), base + NvRegTxRingPhysAddr) - mov eax, forcedeth_tx_ring - sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - mov dword [edi+NvRegTxRingPhysAddr], eax - - ; writel(((RX_RING - 1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING - 1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes) - mov dword [edi+NvRegRingSizes], (((RX_RING - 1) shl NVREG_RINGSZ_RXSHIFT) + ((TX_RING - 1) shl NVREG_RINGSZ_TXSHIFT)) - - ; 5) continue setup - ; np->linkspeed = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10 - mov dword [forcedeth_linkspeed], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) - - ; np->duplex = 0 - mov dword [forcedeth_duplex], 0 - - ; writel(np->linkspeed, base + NvRegLinkSpeed) - mov dword [edi+NvRegLinkSpeed], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) - - ; writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3) - mov dword [edi+NvRegUnknownSetupReg3], NVREG_UNKSETUP3_VAL1 - - ; writel(np->desc_ver, base + NvRegTxRxControl) - mov eax, dword [forcedeth_desc_ver] - mov dword [edi+NvRegTxRxControl], eax - - ; pci_push(base) - call forcedeth_pci_push - - ; writel(NVREG_TXRXCTL_BIT1 | np->desc_ver, base + NvRegTxRxControl) - or eax, NVREG_TXRXCTL_BIT1 - mov dword [edi+NvRegTxRxControl], eax - - ; reg_delay(NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, "open: SetupReg5, Bit 31 remained off\n") - push ebx edx edi ;;;;;;;;;;;;;;;;;;;;;; - stdcall forcedeth_reg_delay, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, 0 - pop edi edx ebx ;;;;;;;;;;;;;;;;;;;;;; - - ; writel(0, base + NvRegUnknownSetupReg4) - mov dword [edi+NvRegUnknownSetupReg4], 0 - - ; writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus) - mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK2 - - - ; printf("%d-Mbs Link, %s-Duplex\n", np->linkspeed & NVREG_LINKSPEED_10 ? 10 : 100, np->duplex ? "Full" : "Half") -;;;;;;;;;;; DEBUGF - - ; 6) continue setup - - ; writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1) - mov dword [edi+NvRegMisc1], (NVREG_MISC1_FORCE or NVREG_MISC1_HD) - - ; writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus) - mov eax, dword [edi+NvRegTransmitterStatus] - mov dword [edi+NvRegTransmitterStatus], eax - - ; writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags) - mov dword [edi+NvRegPacketFilterFlags], NVREG_PFF_ALWAYS - - ; writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig) - mov dword [edi+NvRegOffloadConfig], NVREG_OFFLOAD_NORMAL - - ; writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus) - mov eax, dword [edi+NvRegReceiverStatus] - mov dword [edi+NvRegReceiverStatus], eax - - ; Get a random number - ; i = random() - push edi - stdcall sys_clock ; eax = 0x00SSMMHH (current system time) - pop edi - - ; writel(NVREG_RNDSEED_FORCE | (i & NVREG_RNDSEED_MASK), base + NvRegRandomSeed) - and eax, NVREG_RNDSEED_MASK - or eax, NVREG_RNDSEED_FORCE - mov dword [edi+NvRegRandomSeed], eax - - ; writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1) - mov dword [edi+NvRegUnknownSetupReg1], NVREG_UNKSETUP1_VAL - - ; writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2) - mov dword [edi+NvRegUnknownSetupReg2], NVREG_UNKSETUP2_VAL - - ; writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval) - mov dword [edi+NvRegPollingInterval], NVREG_POLL_DEFAULT - - ; writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6) - mov dword [edi+NvRegUnknownSetupReg6], NVREG_UNKSETUP6_VAL - - ; writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT) | NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING, - ; base + NvRegAdapterControl) - mov eax, dword [forcedeth_phyaddr] - shl eax, NVREG_ADAPTCTL_PHYSHIFT - or eax, (NVREG_ADAPTCTL_PHYVALID or NVREG_ADAPTCTL_RUNNING) - mov dword [edi+NvRegAdapterControl], eax - - ; writel(NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, base + NvRegMIISpeed) - mov dword [edi+NvRegMIISpeed], (NVREG_MIISPEED_BIT8 or NVREG_MIIDELAY) - - ; writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4) - mov dword [edi+NvRegUnknownSetupReg4], NVREG_UNKSETUP4_VAL - - ; writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags) - mov dword [edi+NvRegWakeUpFlags], NVREG_WAKEUPFLAGS_VAL - - ; i = readl(base + NvRegPowerState) - mov eax, dword [edi+NvRegPowerState] - - ; if ((i & NVREG_POWERSTATE_POWEREDUP) == 0) - test eax, NVREG_POWERSTATE_POWEREDUP - jnz @f - ; writel(NVREG_POWERSTATE_POWEREDUP | i, base + NvRegPowerState) - or eax, NVREG_POWERSTATE_POWEREDUP - mov dword [edi+NvRegPowerState], eax - -@@: - - ; pci_push(base) - call forcedeth_pci_push - - ; nv_udelay(10) - mov esi, 10 - call forcedeth_nv_udelay - - ; writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState) - mov eax, dword [edi+NvRegPowerState] - or eax, NVREG_POWERSTATE_VALID - mov dword [edi+NvRegPowerState], eax - - ; ??? disable all interrupts ??? - ; writel(0, base + NvRegIrqMask) - mov dword [edi+NvRegIrqMask], 0 - -;;; ; ??? Mask RX interrupts -;;; mov dword [edi+NvRegIrqMask], NVREG_IRQ_RX_ALL -;;; ; ??? Mask TX interrupts -;;; ;mov dword [edi+NvRegIrqMask], NVREG_IRQ_TX_ALL -;;; ; ??? Mask OTHER interrupts -;;; mov dword [edi+NvRegIrqMask], NVREG_IRQ_OTHER_ALL - - ; pci_push(base) - call forcedeth_pci_push - - ; writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus) - mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK2 - - ; writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus) - mov dword [edi+NvRegIrqStatus], NVREG_IRQSTAT_MASK - - ; pci_push(base) - call forcedeth_pci_push - - - ; writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA) - mov dword [edi+NvRegMulticastAddrA], NVREG_MCASTADDRA_FORCE - - ; writel(0, base + NvRegMulticastAddrB) - mov dword [edi+NvRegMulticastAddrB], 0 - - ; writel(0, base + NvRegMulticastMaskA) - mov dword [edi+NvRegMulticastMaskA], 0 - - ; writel(0, base + NvRegMulticastMaskB) - mov dword [edi+NvRegMulticastMaskB], 0 - - ; writel(NVREG_PFF_ALWAYS | NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags) - mov dword [edi+NvRegPacketFilterFlags], (NVREG_PFF_ALWAYS or NVREG_PFF_MYADDR) - - ; set_multicast(nic) - call forcedeth_set_multicast - - ; One manual link speed update: Interrupts are enabled, future link - ; speed changes cause interrupts and are handled by nv_link_irq(). - - ; miistat = readl(base + NvRegMIIStatus) - mov eax, dword [edi+NvRegMIIStatus] - - ; writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); - mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK - - ; dprintf(("startup: got 0x%hX.\n", miistat)); -;;; DEBUGF 1," K : FORCEDETH: startup: got 0x%x\n", eax - - - ; ret = update_linkspeed(nic) - call forcedeth_update_linkspeed - push eax - - ; start_tx(nic) - call forcedeth_start_tx - - pop eax - -; if (ret) { -; //Start Connection netif_carrier_on(dev); -; } else { -; printf("no link during initialization.\n"); -; } - - ;*** added by shurf (21.09.2008) - mov dword [forcedeth_nocable], 0 - ;*** - - test eax, eax - jnz .return - DEBUGF 1," K : FORCEDETH: no link during initialization.\n" - - ;*** added by shurf (21.09.2008) - mov dword [forcedeth_nocable], 1 - ;*** - -.return: - -; Indicate that we have successfully reset the card - mov eax, dword [pci_data] - mov dword [eth_status], eax - ret - - - -;*************************************************************************** -; Function -; forcedeth_probe -; Description -; Searches for an ethernet card, enables it and clears the rx buffer -; If a card was found, it enables the ethernet -> TCPIP link -; -;*************************************************************************** -forcedeth_probe: - -; DEBUGF 1," K : FORCEDETH: 0x%x 0x%x, 0x%x\n", [io_addr]:8,[pci_bus]:2,[pci_dev]:2 - - mov dword [forcedeth_needs_mac_reset], 0 - -; BEGIN of adjust_pci_device() - ; read word from PCI-device - mov al, 1 ;;;;;;;;;;;;;;2 - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_REG_COMMAND - call pci_read_reg - mov bx, ax ; new command - or bx, PCI_COMMAND_MASTER - or bx, PCI_COMMAND_IO - cmp bx, ax - je @f - ; Enabling PCI-device (make card as bus master) - DEBUGF 1," K : FORCEDETH: Updating PCI command 0x%x->0x%x\n", ax, bx - mov cx, bx - mov al, 1 ;;;;;;;;;;;;2 - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_REG_COMMAND - call pci_write_reg - - ; Check latency settings -@@: - ; Get current latency settings from Latency timer register (byte) - mov al, 0 ;;;;;;;;;1 - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_LATENCY_TIMER - call pci_read_reg - - ; see if its at least 32 - cmp al, 32 - jge @f - ; set latency to 32 - DEBUGF 1, "K : FORCEDETH: PCI latency timer (CFLT) is unreasonably low at %d.\n", al - DEBUGF 1, "K : FORCEDETH: Setting to 32 clocks.\n" - mov cl, 32 - mov al, 0 ;;;;;;;1 - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_LATENCY_TIMER - call pci_write_reg -; END of adjust_pci_device() - -@@: -; BEGIN of pci_bar_start (addr = pci_bar_start(pci, PCI_BASE_ADDRESS_0)) - mov al, 2 ; dword - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_BASE_ADDRESS_0 - call pci_read_reg - test eax, PCI_BASE_ADDRESS_SPACE_IO - jz @f - and eax, PCI_BASE_ADDRESS_IO_MASK - jmp .next -@@: - push eax - and eax, PCI_BASE_ADDRESS_MEM_TYPE_MASK - cmp eax, PCI_BASE_ADDRESS_MEM_TYPE_64 - jne .not64 - mov al, 2 ; dword - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_BASE_ADDRESS_0 + 4 - call pci_read_reg - or eax, eax - jz .not64 - DEBUGF 1,"K : FORCEDETH: pci_bar_start: Unhandled 64bit BAR\n" - or eax, -1 - jmp .next -.not64: - pop eax - and eax, PCI_BASE_ADDRESS_MEM_MASK -.next: -; END of pci_bar_start -; addr = eax - mov dword [forcedeth_mmio_addr], eax - - -; BEGIN of pci_bar_size (sz = pci_bar_size(pci, PCI_BASE_ADDRESS_0)) - - ; Save original bar - mov al, 2 ; dword - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_BASE_ADDRESS_0 - call pci_read_reg - mov dword [forcedeth_tmp_start], eax - ; Compute which bits can be set - ; (ecx - value to write) - mov al, 2 ; dword - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_BASE_ADDRESS_0 - mov ecx, (not 0) - call pci_write_reg - mov al, 2 ; dword - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_BASE_ADDRESS_0 - call pci_read_reg - push eax - ; Restore the original size - mov al, 2 ; dword - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_BASE_ADDRESS_0 - mov ecx, dword [forcedeth_tmp_start] - call pci_write_reg - ; Find the significant bits - pop eax - test dword [forcedeth_tmp_start], PCI_BASE_ADDRESS_SPACE_IO - jz @f - and eax, PCI_BASE_ADDRESS_IO_MASK - jmp .next2 -@@: - and eax, PCI_BASE_ADDRESS_MEM_MASK -.next2: - ; Find the lowest bit set - mov ecx, eax - sub eax, 1 - not eax - and ecx, eax - -; END of pci_bar_start - mov dword [forcedeth_mmio_size], ecx - - DEBUGF 1," K : FORCEDETH: mmio_addr= 0x%x [mmio_size= 0x%x]\n", [forcedeth_mmio_addr]:8, [forcedeth_mmio_size]:8 - - ; Get Vendor and Device ID - mov al, 2 - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_VENDOR_ID - call pci_read_reg - mov word [forcedeth_vendor_id], ax - shr eax, 16 - mov word [forcedeth_device_id], ax - - DEBUGF 1," K : FORCEDETH: vendor_id= 0x%x device_id= 0x%x\n", [forcedeth_vendor_id]:4, [forcedeth_device_id]:4 - - ; handle different descriptor versions - mov eax, dword [forcedeth_device_id] - cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_1 - je .ver1 - cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_2 - je .ver1 - cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_3 - je .ver1 - mov dword [forcedeth_desc_ver], DESC_VER_2 - jmp @f -.ver1: - mov dword [forcedeth_desc_ver], DESC_VER_1 -@@: - ; read the mac address - ; map memory - stdcall map_io_mem, [forcedeth_mmio_addr], [forcedeth_mmio_size], (PG_SW+PG_NOCACHE) - test eax, eax - jz .fail - - mov dword [forcedeth_mapio_addr], eax - mov edi, eax - mov eax, dword [edi+NvRegMacAddrA] - mov dword [forcedeth_orig_mac0], eax - mov edx, dword [edi+NvRegMacAddrB] - mov dword [forcedeth_orig_mac1], edx - - ; save MAC-address to global variable node_addr - mov dword [node_addr], eax - mov word [node_addr+4], dx - - ; reverse if desired - cmp word [forcedeth_device_id], 0x03E5 - jae .no_reverse_mac - mov al, byte [node_addr] - xchg al, byte [node_addr+5] - mov byte [node_addr], al - mov al, byte [node_addr+1] - xchg al, byte [node_addr+4] - mov byte [node_addr+4], al - mov al, byte [node_addr+2] - xchg al, byte [node_addr+3] - mov byte [node_addr+3], al -.no_reverse_mac: - -; DEBUGF 1," K : FORCEDETH: orig_mac0= 0x%x\n", [forcedeth_orig_mac0]:8 -; DEBUGF 1," K : FORCEDETH: orig_mac1= 0x%x\n", [forcedeth_orig_mac1]:8 - DEBUGF 1," K : FORCEDETH: MAC = %x-%x-%x-%x-%x-%x\n", [node_addr+0]:2,[node_addr+1]:2,[node_addr+2]:2,[node_addr+3]:2,[node_addr+4]:2,[node_addr+5]:2, - - ; disable WOL - mov edi, dword [forcedeth_mapio_addr] - mov dword [edi+NvRegWakeUpFlags], 0 - mov dword [forcedeth_wolenabled], 0 - - mov dword [forcedeth_txflags], (NV_TX2_LASTPACKET or NV_TX2_VALID) - cmp dword [forcedeth_desc_ver], DESC_VER_1 - jne @f - mov dword [forcedeth_txflags], (NV_TX_LASTPACKET or NV_TX_VALID) -@@: - -; BEGIN of switch (pci->dev_id) - - cmp word [forcedeth_device_id], 0x01C3 - jne .next_0x0066 - ; nforce - mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER) - jmp .end_switch - -.next_0x0066: - cmp word [forcedeth_device_id], 0x0066 - je @f - cmp word [forcedeth_device_id], 0x00D6 - je @f - jmp .next_0x0086 -@@: - mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER) - cmp dword [forcedeth_desc_ver], DESC_VER_1 - jne @f - or dword [forcedeth_txflags], NV_TX_LASTPACKET1 - jmp .end_switch -@@: - or dword [forcedeth_txflags], NV_TX2_LASTPACKET1 - jmp .end_switch - -.next_0x0086: - cmp word [forcedeth_device_id], 0x0086 - je @f - cmp word [forcedeth_device_id], 0x008c - je @f - cmp word [forcedeth_device_id], 0x00e6 - je @f - cmp word [forcedeth_device_id], 0x00df - je @f - cmp word [forcedeth_device_id], 0x0056 - je @f - cmp word [forcedeth_device_id], 0x0057 - je @f - cmp word [forcedeth_device_id], 0x0037 - je @f - cmp word [forcedeth_device_id], 0x0038 - je @f - jmp .next_0x0268 -@@: - ; np->irqmask = NVREG_IRQMASK_WANTED_2; - ; np->irqmask |= NVREG_IRQ_TIMER; - mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER) - - ; if (np->desc_ver == DESC_VER_1) - cmp dword [forcedeth_desc_ver], DESC_VER_1 - jne @f - ; np->tx_flags |= NV_TX_LASTPACKET1; - or dword [forcedeth_txflags], NV_TX_LASTPACKET1 - jmp .end_switch - ; else -@@: - ; np->tx_flags |= NV_TX2_LASTPACKET1; - or dword [forcedeth_txflags], NV_TX2_LASTPACKET1 - - ; break; - jmp .end_switch - -.next_0x0268: -; cmp word [forcedeth_device_id], 0x0268 -; je @f -; cmp word [forcedeth_device_id], 0x0269 -; je @f -; cmp word [forcedeth_device_id], 0x0372 -; je @f -; cmp word [forcedeth_device_id], 0x0373 -; je @f -; jmp .default_switch -;@@: - cmp word [forcedeth_device_id], 0x0268 - jb .default_switch - ; pci_read_config_byte(pci, PCI_REVISION_ID, &revision_id); - mov al, 0 ; byte - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, PCI_REVISION_ID - call pci_read_reg - mov ecx, eax ; cl = revision_id - - ; take phy and nic out of low power mode - ; powerstate = readl(base + NvRegPowerState2); - mov edi, dword [forcedeth_mapio_addr] - mov eax, dword [edi+NvRegPowerState2] ; eax = powerstate - - ; powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK; - and eax, not NVREG_POWERSTATE2_POWERUP_MASK - - ; if ((pci->dev_id==PCI_DEVICE_ID_NVIDIA_NVENET_12||pci->dev_id==PCI_DEVICE_ID_NVIDIA_NVENET_13)&&revision_id>=0xA3) - cmp dword [forcedeth_device_id], PCI_DEVICE_ID_NVIDIA_NVENET_12 - je @f - cmp dword [forcedeth_device_id], PCI_DEVICE_ID_NVIDIA_NVENET_13 - je @f - jmp .end_if -@@: - cmp cl, 0xA3 - jl .end_if - ; powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3; - or eax, NVREG_POWERSTATE2_POWERUP_REV_A3 - -.end_if: - - ; writel(powerstate, base + NvRegPowerState2); - mov dword [edi+NvRegPowerState2], eax - - ; //DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ - ; np->irqmask = NVREG_IRQMASK_WANTED_2; - ; np->irqmask |= NVREG_IRQ_TIMER; - mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER) - - ; needs_mac_reset = 1; - mov dword [forcedeth_needs_mac_reset], 1 - - ; if (np->desc_ver == DESC_VER_1) - cmp dword [forcedeth_desc_ver], DESC_VER_1 - jne @f - ; np->tx_flags |= NV_TX_LASTPACKET1; - or dword [forcedeth_txflags], NV_TX_LASTPACKET1 - jmp .end_if2 -@@: - ; else - ; np->tx_flags |= NV_TX2_LASTPACKET1; - or dword [forcedeth_txflags], NV_TX2_LASTPACKET1 - -.end_if2: - ; break; - jmp .end_switch - -.default_switch: - DEBUGF 1," K : FORCEDETH: Your card was undefined in this driver.\n" - DEBUGF 1," K : FORCEDETH: Review driver_data in Kolibri driver and send a patch\n" - -.end_switch: - -; END of switch (pci->dev_id) - - - ; Find a suitable phy - mov dword [forcedeth_tmp_i], 1 -.for_loop: - ; for (i = 1; i <= 32; i++) - ; phyaddr = i & 0x1f - mov ebx, dword [forcedeth_tmp_i] - and ebx, 0x1f - - ; id1 = mii_rw(phyaddr, MII_PHYSID1, MII_READ) - ;EBX - addr, EAX - miireg, ECX - value - mov eax, MII_PHYSID1 - mov ecx, MII_READ - call forcedeth_mii_rw ; id1 = eax - - ; if (id1 < 0 || id1 == 0xffff) - cmp eax, 0xffffffff - je .continue_for - test eax, 0x80000000 - jnz .continue_for - mov dword [forcedeth_tmp_id1], eax - - ; id2 = mii_rw(nic, phyaddr, MII_PHYSID2, MII_READ) - mov eax, MII_PHYSID2 - mov ecx, MII_READ - call forcedeth_mii_rw ; id2 = eax - - ; if (id2 < 0 || id2 == 0xffff) - cmp eax, 0xffffffff - je .continue_for - test eax, 0x80000000 - jnz .continue_for - mov dword [forcedeth_tmp_id2], eax - - jmp .break_for -.continue_for: - inc dword [forcedeth_tmp_i] - cmp dword [forcedeth_tmp_i], 32 - jle .for_loop - jmp .end_for - -.break_for: - -;;;; DEBUGF 1," K : FORCEDETH: id1=0x%x id2=0x%x\n", [forcedeth_tmp_id1]:8, [forcedeth_tmp_id2]:8 - - ; id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT - mov eax, dword [forcedeth_tmp_id1] - and eax, PHYID1_OUI_MASK - shl eax, PHYID1_OUI_SHFT - mov dword [forcedeth_tmp_id1], eax - - ; id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT - mov eax, dword [forcedeth_tmp_id2] - and eax, PHYID2_OUI_MASK - shr eax, PHYID2_OUI_SHFT - mov dword [forcedeth_tmp_id2], eax - - DEBUGF 1," K : FORCEDETH: Found PHY 0x%x:0x%x at address 0x%x\n", [forcedeth_tmp_id1]:8, [forcedeth_tmp_id2]:8, ebx - - ; np->phyaddr = phyaddr; - mov dword [forcedeth_phyaddr], ebx - - ; np->phy_oui = id1 | id2; - mov eax, dword [forcedeth_tmp_id1] - or eax, dword [forcedeth_tmp_id2] - mov dword [forcedeth_phy_oui], eax - -.end_for: - - ; if (i == 33) - cmp dword [forcedeth_tmp_i], 33 - jne @f - ; PHY in isolate mode? No phy attached and user wants to - ; test loopback? Very odd, but can be correct. - - DEBUGF 1," K : FORCEDETH: Could not find a valid PHY.\n" - - jmp .next3 - -@@: - - ; if (i != 33) - ; reset it - call forcedeth_phy_init - -.next3: - -; dprintf(("%s: forcedeth.c: subsystem: %hX:%hX bound to %s\n", -; pci->name, pci->vendor, pci->dev_id, pci->name)); - DEBUGF 1," K : FORCEDETH: subsystem: 0x%x:0x%x bound to forcedeth\n", [forcedeth_vendor_id]:4, [forcedeth_device_id]:4 - - -; if(needs_mac_reset) mac_reset(nic); - cmp dword [forcedeth_needs_mac_reset], 0 - je @f - call forcedeth_mac_reset - -@@: - - ; if(!forcedeth_reset(nic)) return 0; // no valid link - call forcedeth_reset - test eax, eax - jnz @f - mov eax, 0 - jmp .return - -@@: - - ; point to NIC specific routines - ; dev->disable = forcedeth_disable; - ; nic->poll = forcedeth_poll; - ; nic->transmit = forcedeth_transmit; - ; nic->irq = forcedeth_irq; - ;;;;;;;;;stdcall attach_int_handler, 11, forcedeth_int_handler, 0 - - ; return 1 - mov eax, 1 - jmp .return - -.fail: - mov eax, 0 - -.return: - ret - -uglobal -forcedeth_tmp_start dd ? -forcedeth_tmp_reg dd ? -forcedeth_tmp_i dd ? -forcedeth_tmp_id1 dd ? -forcedeth_tmp_id2 dd ? -forcedeth_tmp_phyinterface dd ? -forcedeth_tmp_newls dd ? -forcedeth_tmp_newdup dd ? -forcedeth_tmp_retval dd ? -forcedeth_tmp_control_1000 dd ? -forcedeth_tmp_lpa dd ? -forcedeth_tmp_adv dd ? -forcedeth_tmp_len dd ? -forcedeth_tmp_valid dd ? -forcedeth_tmp_nr dd ? -forcedeth_tmp_ptxb dd ? -endg - -;*************************************************************************** -; Function -; forcedeth_poll -; -; Description -; Polls the ethernet card for a received packet -; Received data, if any, ends up in Ether_buffer -; -;*************************************************************************** -forcedeth_poll: - - mov word [eth_rx_data_len], 0 - - ; ???????????????????????????? - ; ??? Clear events? ??? - mov edi, dword [forcedeth_mapio_addr] - mov dword [edi+NvRegIrqStatus], NVREG_IRQSTAT_MASK - ; ???????????????????????????? - -.top: - - ; i = np->cur_rx % RX_RING - mov eax, dword [forcedeth_cur_rx] - and eax, (RX_RING-1) - mov dword [forcedeth_tmp_i], eax - - ; Flags = le32_to_cpu(rx_ring[i].FlagLen) - ; Flags = rx_ring[i].FlagLen - mov cl, sizeof.forcedeth_RxDesc - mul cl - add eax, forcedeth_rx_ring - mov ebx, eax - mov eax, [ebx + forcedeth_RxDesc.FlagLen] - - - ; if (Flags & NV_RX_AVAIL) - test eax, NV_RX_AVAIL - ; return 0; /* still owned by hardware, */ - ; still owned by hardware - jnz .return0 - -;;;;; DEBUGF 1,"poll: FlagLen = %x\n", eax - - ; if (np->desc_ver == DESC_VER_1) { - cmp dword [forcedeth_desc_ver], DESC_VER_1 - jne @f - ; if (!(Flags & NV_RX_DESCRIPTORVALID)) - test eax, NV_RX_DESCRIPTORVALID - ; return 0; - jz .return0 - jmp .next - ; } else { -@@: - ; if (!(Flags & NV_RX2_DESCRIPTORVALID)) - test eax, NV_RX2_DESCRIPTORVALID - ; return 0; - jz .return0 - ; } - -.next: - - ; len = nv_descr_getlength(&rx_ring[i], np->desc_ver) - ; len = rx_ring[i].FlagLen & ((np->desc_ver == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2); - ; eax = FlagLen - cmp dword [forcedeth_desc_ver], DESC_VER_1 - jne @f - and eax, LEN_MASK_V1 - jmp .next2 -@@: - and eax, LEN_MASK_V2 - -.next2: - - ; mov dword [forcedeth_tmp_len], eax - - ; valid = 1 - mov dword [forcedeth_tmp_valid], 1 - - ; got a valid packet - forward it to the network core - ; nic->packetlen = len; - mov dword [forcedeth_packetlen], eax - ; - mov word [eth_rx_data_len], ax -;;;;;;;;; DEBUGF 1,"poll: packet len = 0x%x\n", [forcedeth_packetlen] - - - ; memcpy(nic->packet, rxb + (i * RX_NIC_BUFSIZE), nic->packetlen); - ; Copy packet to system buffer (Ether_buffer) - ;???? ecx = (len-4) - mov ecx, eax - push ecx - shr ecx, 2 - - ; rxb + (i * RX_NIC_BUFSIZE) - mov eax, dword [forcedeth_tmp_i] - mov bx, RX_NIC_BUFSIZE - mul bx - add eax, forcedeth_rxb - - mov esi, eax - mov edi, Ether_buffer - cld ; set to increment - rep movsd ; mov dword from [esi++] to [edi++] - pop ecx - and ecx, 3 ; copy rest 1-3 bytes - rep movsb - - ; wmb(); - ; ??? - - ; np->cur_rx++; - inc dword [forcedeth_cur_rx] - - ; if (!valid) - cmp dword [forcedeth_tmp_valid], 0 - jne @f - ; goto top; - jmp .top -@@: - ; alloc_rx(nic); - call forcedeth_alloc_rx - - ; return 1; - jmp .return1 - -;;;;; DEBUGF 1,"K : FORCEDETH: poll: ...\n" - - -.return0: - mov eax, 0 - jmp .return -.return1: - mov eax, 1 -.return: - ;;push eax - - ; ???????????????????????????????????????????????? - ; ????? clear interrupt mask/status - ; read IRQ status - ;;mov edi, dword [forcedeth_mapio_addr] - ;;mov eax, dword [edi+NvRegIrqStatus] - - ; clear events - ;;and eax, not (NVREG_IRQ_RX_ERROR or NVREG_IRQ_RX or NVREG_IRQ_RX_NOBUF or NVREG_IRQ_LINK or NVREG_IRQ_TIMER) - - ; write IRQ status - ;;mov dword [edi+NvRegIrqStatus], eax - ; ???????????????????????????????????????????????? - - ;;pop eax - ret - - -;*************************************************************************** -; Function -; forcedeth_transmit -; -; Description -; Transmits a packet of data via the ethernet card -; Pointer to 48 bit destination address in edi -; Type of packet in bx -; size of packet in ecx -; pointer to packet data in esi -; -;*************************************************************************** -forcedeth_transmit: - - ; send the packet to destination -;pusha -;DEBUGF 1,"K : FORCEDETH: transmit: packet type = 0x%x\n", ebx -;DEBUGF 1,"K : FORCEDETH: transmit: packet len = 0x%x\n", ecx -;mov eax, dword [edi] -;DEBUGF 1,"K : FORCEDETH: transmit: dest adr = 0x%x\n", eax -;mov eax, dword [edi+4] -;DEBUGF 1,"K : FORCEDETH: transmit: dest adr2 = 0x%x\n", eax -;mov eax, dword [node_addr] -;DEBUGF 1,"K : FORCEDETH: transmit: src adr = 0x%x\n", eax -;mov eax, dword [node_addr+4] -;DEBUGF 1,"K : FORCEDETH: transmit: src adr2 = 0x%x\n", eax -;popa - - ; int nr = np->next_tx % TX_RING - mov eax, dword [forcedeth_next_tx] - and eax, (TX_RING-1) - mov dword [forcedeth_tmp_nr], eax - - ; point to the current txb incase multiple tx_rings are used - ; ptxb = txb + (nr * RX_NIC_BUFSIZE) - push ecx - mov cx, RX_NIC_BUFSIZE - mul cx ; AX*CX, result to DX:AX - add eax, forcedeth_txb - mov dword [forcedeth_tmp_ptxb], eax - push esi - mov esi, edi ; dst MAC - mov edi, eax ; packet buffer - cld ; set to increment - - ; copy the packet to ring buffer - ; memcpy(ptxb, d, ETH_ALEN); /* dst */ - movsd - movsw - - ; memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ - mov esi, node_addr - movsd - movsw - - ; nstype = htons((u16) t); /* type */ - ; memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); /* type */ - mov word [edi], bx - add edi, 2 - - ; memcpy(ptxb + ETH_HLEN, p, s); - pop esi - pop ecx - push ecx - shr ecx, 2 ; count in dwords - rep movsd ; copy dwords from [esi+=4] to [edi+=4] - pop ecx - push ecx - and ecx, 3 ; copy rest 1-3 bytes - rep movsb ; copy bytess from [esi++] to [edi++] - - - ; s += ETH_HLEN; - ; while (s < ETH_ZLEN) /* pad to min length */ - ; ptxb[s++] = '\0'; - ; pad to min length - pop ecx - add ecx, ETH_HLEN - push ecx ; header length + data length - cmp ecx, ETH_ZLEN - jge @f - mov eax, ETH_ZLEN - sub eax, ecx - xchg eax, ecx - mov al, 0 - rep stosb ; copy byte from al to [edi++] - -@@: - - ; tx_ring[nr].PacketBuffer = (u32) virt_to_le32desc(ptxb); - mov eax, dword [forcedeth_tmp_nr] - mov cl, sizeof.forcedeth_TxDesc - mul cl - add eax, forcedeth_tx_ring - mov ebx, eax - mov eax, dword [forcedeth_tmp_ptxb] - sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - mov [ebx + forcedeth_TxDesc.PacketBuffer], eax - -;DEBUGF 1,"K : FORCEDETH: transmit: PacketBuffer = 0x%x\n", eax -;DEBUGF 1,"K : FORCEDETH: transmit: txflags = 0x%x\n", [forcedeth_txflags]:8 - - ; wmb(); - ; tx_ring[nr].FlagLen = cpu_to_le32((s - 1) | np->tx_flags); - pop eax ; header length + data length - mov ecx, dword [forcedeth_txflags] - or eax, ecx - mov [ebx + forcedeth_TxDesc.FlagLen], eax - - ; writel(NVREG_TXRXCTL_KICK | np->desc_ver, base + NvRegTxRxControl); - mov edi, dword [forcedeth_mapio_addr] - mov eax, dword [forcedeth_desc_ver] - or eax, NVREG_TXRXCTL_KICK - mov dword [edi+NvRegTxRxControl], eax - - ; pci_push(base); - call forcedeth_pci_push - - ; np->next_tx++ - inc dword [forcedeth_next_tx]; may be need to reset? Overflow? - - ret - -;*************************************************************************** -; Function -; forcedeth_cable -; -; Description -; Return AL=0, if cable is not connected -; Returm AL=1, if cable is connected -; -;*************************************************************************** -forcedeth_cable: - - mov al, 1 - cmp dword [forcedeth_nocable], 1 - jne .return - mov al, 0 - -.return: - ret - -;*************************************************************************** - - -; read/write a register on the PHY. -; Caller must guarantee serialization -; Input: EAX - miireg, EBX - addr, ECX - value -; Output: EAX - retval -forcedeth_mii_rw: - push ebx - push eax ; save miireg - ; writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus) - mov edi, dword [forcedeth_mapio_addr] - mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK - - ; reg = readl(base + NvRegMIIControl) - mov eax, dword [edi+NvRegMIIControl] - test eax, NVREG_MIICTL_INUSE - jz @f - ; writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl) - mov dword [edi+NvRegMIIControl], NVREG_MIICTL_INUSE - ; nv_udelay(NV_MIIBUSY_DELAY) - mov esi, NV_MIIBUSY_DELAY - call forcedeth_nv_udelay -@@: - ; reg = (addr << NVREG_MIICTL_ADDRSHIFT) | miireg - pop edx ; restore miireg - mov eax, ebx - shl eax, NVREG_MIICTL_ADDRSHIFT - or eax, edx - mov dword [forcedeth_tmp_reg], eax - - cmp ecx, MII_READ - je @f - ; writel(value, base + NvRegMIIData) - mov dword [edi+NvRegMIIData], ecx - ; reg |= NVREG_MIICTL_WRITE - or dword [forcedeth_tmp_reg], NVREG_MIICTL_WRITE -@@: - ; writel(reg, base + NvRegMIIControl) - mov eax, dword [forcedeth_tmp_reg] - mov dword [edi+NvRegMIIControl], eax - - push ebx edx edi ;;;;;;;;;;;;;;;;;;;;;; - - ; reg_delay(NvRegMIIControl, NVREG_MIICTL_INUSE, 0, NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL) - stdcall forcedeth_reg_delay, NvRegMIIControl, NVREG_MIICTL_INUSE, 0, NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, 0 - - pop edi edx ebx ;;;;;;;;;;;;;;;;;;;;;; - - test eax, eax - jz @f -;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw of reg %d at PHY %d timed out.\n", edx, ebx - mov eax, 0xffffffff - jmp .return -@@: - cmp ecx, MII_READ - je @f - ;it was a write operation - fewer failures are detectable -;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw wrote 0x%x to reg %d at PHY %d\n", ecx, edx, ebx - mov eax, 0 - jmp .return -@@: - ; readl(base + NvRegMIIStatus) - mov eax, dword [edi+NvRegMIIStatus] - test eax, NVREG_MIISTAT_ERROR - jz @f -;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw of reg %d at PHY %d failed.\n", edx, ebx - mov eax, 0xffffffff - jmp .return -@@: - ; retval = readl(base + NvRegMIIData) - mov eax, dword [edi+NvRegMIIData] -;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw read from reg %d at PHY %d: 0x%x.\n", edx, ebx, eax -.return: - pop ebx - ret - - - -; Input: ESI - delay -; Output: none -forcedeth_nv_udelay: - - push ebx - cmp dword [forcedeth_in_shutdown], 0 - jne @f - call forcedeth_udelay ; delay on ESI - jmp .return -@@: - -.loop: - cmp esi, 0 - je .return - ; Don't allow an rx_ring overflow to happen - ; while shutting down the NIC it will - ; kill the receive function. - - call forcedeth_drop_rx - mov ebx, 3 ; sleep = 3 - cmp ebx, esi ; if(sleep > delay) - jle @f - mov ebx, esi ; sleep = delay -@@: - push esi - mov esi, ebx - ; udelay(sleep) - call forcedeth_udelay ; delay on ESI - pop esi - sub esi, ebx ; delay -= sleep - jmp .loop - -.return: - pop ebx - ret - - -; Input: none -; Output: none -forcedeth_drop_rx: - - push eax ebx ecx edi - - ; events = readl(base + NvRegIrqStatus) - mov edi, dword [forcedeth_mapio_addr] - mov eax, dword [edi+NvRegIrqStatus] - - test eax, eax - jz @f - ; writel(events, base + NvRegIrqStatus) - mov dword [edi+NvRegIrqStatus], eax -@@: - ;if (!(events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF))) - test eax, (NVREG_IRQ_RX_ERROR or NVREG_IRQ_RX or NVREG_IRQ_RX_NOBUF) - jz .return - -.loop: - ; i = np->cur_rx % RX_RING - mov eax, dword [forcedeth_cur_rx] - and eax, (RX_RING-1) - ; //Flags = le32_to_cpu(rx_ring[i].FlagLen) - ; Flags = rx_ring[i].FlagLen - mov cl, sizeof.forcedeth_RxDesc - mul cl - add eax, forcedeth_rx_ring - mov ebx, eax - mov eax, [ebx + forcedeth_RxDesc.FlagLen] - ; len = nv_descr_getlength(&rx_ring[i], np->desc_ver) - ; > len = Flags & ((np->desc_ver == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2) - ; ??? len don't used later !!! ??? - ; ... - test eax, NV_RX_AVAIL - jnz .return ; still owned by hardware, - ; wmb() - ; ??? may be empty function ??? - ; np->cur_rx++ - inc dword [forcedeth_cur_rx] - ; alloc_rx(NULL) - call forcedeth_alloc_rx -.return: - pop edi ecx ebx eax - ret - - -; Fill rx ring entries. -; Return 1 if the allocations for the skbs failed and the -; rx engine is without Available descriptors -; Input: none -; Output: none -forcedeth_alloc_rx: - - push eax ebx ecx edx - ; refill_rx = np->refill_rx - mov ecx, dword [forcedeth_refill_rx] -.loop: - cmp dword [forcedeth_cur_rx], ecx - je .loop_end - ; nr = refill_rx % RX_RING - mov eax, ecx - and eax, (RX_RING-1) ; nr - ; rx_ring[nr].PacketBuffer = &rxb[nr * RX_NIC_BUFSIZE] - push ecx - push eax - mov cl, sizeof.forcedeth_RxDesc - mul cl - add eax, forcedeth_rx_ring - mov ebx, eax - pop eax - mov cx, RX_NIC_BUFSIZE - mul cx - pop ecx - add eax, forcedeth_rxb - sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - mov [ebx + forcedeth_RxDesc.PacketBuffer], eax - ; wmb() - ; ... - ; rx_ring[nr].FlagLen = RX_NIC_BUFSIZE | NV_RX_AVAIL - mov [ebx + forcedeth_RxDesc.FlagLen], (RX_NIC_BUFSIZE or NV_RX_AVAIL) - inc ecx - jmp .loop - -.loop_end: - ; np->refill_rx = refill_rx - mov [forcedeth_refill_rx], ecx -.return: - pop edx ecx ebx eax - ret - - -; Delay in millisec -; Input: ESI - delay in ms -; Output: none -forcedeth_udelay: - call delay_ms - ret - -; Input: offset:word, mask:dword, target:dword, delay:word, delaymax:word, msg:dword -; Output: EAX - 0|1 -;;;;proc forcedeth_reg_delay,offset:word,mask:dword,target:dword,delay:word,delaymax:word,msg:dword -proc forcedeth_reg_delay,offset:dword,mask:dword,target:dword,delay:dword,delaymax:dword,msg:dword - - push ebx esi edi - ; pci_push(base) - call forcedeth_pci_push -.loop: - ; nv_udelay(delay) - mov esi, dword [delay] - call forcedeth_nv_udelay ; delay in esi - mov eax, dword [delaymax] - sub eax, dword [delay] - mov dword [delaymax], eax - ; if (delaymax < 0) - test dword [delaymax], 0x80000000 - jz @f - ; return 1 - mov eax, 1 - jmp .return -@@: - ; while ((readl(base + offset) & mask) != target) - mov edi, dword [forcedeth_mapio_addr] - mov ebx, dword [offset] - mov eax, dword [edi+ebx] - and eax, dword [mask] - cmp eax, dword [target] - jne .loop - xor eax, eax -.return: - pop edi esi ebx - ret -endp - - -; Input: none -; Output: none -forcedeth_pci_push: - push eax edi - ;force out pending posted writes - mov edi, dword [forcedeth_mapio_addr] - mov eax, dword [edi] - pop edi eax - ret - - -; Input: none -; Output: EAX - result (0 = OK, other = error) -forcedeth_phy_init: - - push ebx ecx - - ; set advertise register - ; reg = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ); - ; EBX - addr, EAX - miireg, ECX - value - mov ebx, dword [forcedeth_phyaddr] - mov eax, MII_ADVERTISE - mov ecx, MII_READ - call forcedeth_mii_rw ; reg = eax - - ; reg |= - ; (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | - ; ADVERTISE_100FULL | 0x800 | 0x400); - or eax, (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL or 0x800 or 0x400) - - ; if (mii_rw(nic, np->phyaddr, MII_ADVERTISE, reg)) - ; EBX - addr, EAX - miireg, ECX - value - mov ecx, eax ; reg - mov eax, MII_ADVERTISE - call forcedeth_mii_rw ; eax -> return - - test eax, eax - jz @f - ; printf("phy write to advertise failed.\n"); - DEBUGF 1," K : FORCEDETH: phy write to advertise failed.\n" - - ; return PHY_ERROR; - mov eax, PHY_ERROR - jmp .return -@@: - ; get phy interface type - ; phyinterface = readl(base + NvRegPhyInterface); - mov edi, dword [forcedeth_mapio_addr] - mov eax, dword [edi+NvRegPhyInterface] ; phyinterface = eax - mov dword [forcedeth_tmp_phyinterface], eax - -;;;;;;;;;;;;;;;;;;;;;;;;; -DEBUGF 1," K : FORCEDETH: phy interface type = 0x%x\n", [forcedeth_tmp_phyinterface]:8 -;;;;;;;;;;;;;;;;;;;;;;;;; - - ; see if gigabit phy - ; mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ); - ; EBX - addr, EAX - miireg, ECX - value - mov eax, MII_BMSR - mov ecx, MII_READ - call forcedeth_mii_rw ; mii_status = eax - - ; if (mii_status & PHY_GIGABIT) - test eax, PHY_GIGABIT - jnz .gigabit - ; np->gigabit = 0; - mov dword [forcedeth_gigabit], 0 - jmp .next_if - -.gigabit: - ; np->gigabit = PHY_GIGABIT; - mov dword [forcedeth_gigabit], PHY_GIGABIT - - ; mii_control_1000 = mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ); - ; EBX - addr, EAX - miireg, ECX - value - mov eax, MII_1000BT_CR - mov ecx, MII_READ - call forcedeth_mii_rw ; mii_control_1000 = eax - - ; mii_control_1000 &= ~ADVERTISE_1000HALF; - and eax, (not ADVERTISE_1000HALF) - - ; if (phyinterface & PHY_RGMII) - test dword [forcedeth_tmp_phyinterface], PHY_RGMII - jz @f - ; mii_control_1000 |= ADVERTISE_1000FULL - or eax, ADVERTISE_1000FULL - jmp .next -@@: - ; mii_control_1000 &= ~ADVERTISE_1000FULL - and eax, (not ADVERTISE_1000FULL) - -.next: - ; if (mii_rw(nic, np->phyaddr, MII_1000BT_CR, mii_control_1000)) - ; EBX - addr, EAX - miireg, ECX - value - mov ecx, eax - mov eax, MII_1000BT_CR - call forcedeth_mii_rw ; eax -> return - - test eax, eax - jz .next_if - - ; printf("phy init failed.\n"); - DEBUGF 1," K : FORCEDETH: phy init failed.\n" - - ; return PHY_ERROR; - mov eax, PHY_ERROR - jmp .return - -.next_if: - - ; reset the phy - ; if (phy_reset(nic)) - call forcedeth_phy_reset - test eax, eax - jz @f - ; printf("phy reset failed\n") - DEBUGF 1," K : FORCEDETH: phy reset failed.\n" - ; return PHY_ERROR - mov eax, PHY_ERROR - jmp .return -@@: - - ; phy vendor specific configuration - ; if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII)) - cmp dword [forcedeth_phy_oui], PHY_OUI_CICADA - jne .next_if2 - test dword [forcedeth_tmp_phyinterface], PHY_RGMII - jz .next_if2 - - ; phy_reserved = mii_rw(nic, np->phyaddr, MII_RESV1, MII_READ) - ; EBX - addr, EAX - miireg, ECX - value - mov eax, MII_RESV1 - mov ecx, MII_READ - call forcedeth_mii_rw ; phy_reserved = eax - - ; phy_reserved &= ~(PHY_INIT1 | PHY_INIT2) - and eax, (not (PHY_INIT1 or PHY_INIT2)) - ; phy_reserved |= (PHY_INIT3 | PHY_INIT4) - or eax, (PHY_INIT3 or PHY_INIT4) - - ; if (mii_rw(nic, np->phyaddr, MII_RESV1, phy_reserved)) - ; EBX - addr, EAX - miireg, ECX - value - mov ecx, eax - mov eax, MII_RESV1 - call forcedeth_mii_rw ; eax -> return - test eax, eax - jz @f - ; printf("phy init failed.\n") - DEBUGF 1," K : FORCEDETH: phy init failed.\n" - ; return PHY_ERROR - mov eax, PHY_ERROR - jmp .return -@@: - ; phy_reserved = mii_rw(nic, np->phyaddr, MII_NCONFIG, MII_READ); - ; EBX - addr, EAX - miireg, ECX - value - mov eax, MII_NCONFIG - mov ecx, MII_READ - call forcedeth_mii_rw ; phy_reserved = eax - - ; phy_reserved |= PHY_INIT5 - or eax, PHY_INIT5 - - ; if (mii_rw(nic, np->phyaddr, MII_NCONFIG, phy_reserved)) - ; EBX - addr, EAX - miireg, ECX - value - mov ecx, eax - mov eax, MII_NCONFIG - call forcedeth_mii_rw ; eax -> return - test eax, eax - jz .next_if2 - ; printf("phy init failed.\n") - DEBUGF 1," K : FORCEDETH: phy init failed.\n" - ; return PHY_ERROR - mov eax, PHY_ERROR - jmp .return - -.next_if2: - - ; if (np->phy_oui == PHY_OUI_CICADA) - cmp dword [forcedeth_phy_oui], PHY_OUI_CICADA - jne .restart - - ; phy_reserved = mii_rw(nic, np->phyaddr, MII_SREVISION, MII_READ) - ; EBX - addr, EAX - miireg, ECX - value - mov eax, MII_SREVISION - mov ecx, MII_READ - call forcedeth_mii_rw ; phy_reserved = eax - - ; phy_reserved |= PHY_INIT6 - or eax, PHY_INIT6 - - ; if (mii_rw(nic, np->phyaddr, MII_SREVISION, phy_reserved)) - mov ecx, eax - mov eax, MII_SREVISION - call forcedeth_mii_rw ; eax -> return - test eax, eax - jz .restart - ; printf("phy init failed.\n"); - DEBUGF 1," K : FORCEDETH: phy init failed.\n" - ; return PHY_ERROR; - jmp .return - -.restart: - ; restart auto negotiation - ; mii_control = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ) - ; EBX - addr, EAX - miireg, ECX - value - mov eax, MII_BMCR - mov ecx, MII_READ - call forcedeth_mii_rw ; mii_control = eax - - ; mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE) - or eax, (BMCR_ANRESTART or BMCR_ANENABLE) - - ; if (mii_rw(nic, np->phyaddr, MII_BMCR, mii_control)) - mov ecx, eax - mov eax, MII_BMCR - call forcedeth_mii_rw ; eax -> return - test eax, eax - jz .ok - - ; return PHY_ERROR; - mov eax, PHY_ERROR - jmp .return - -.ok: - mov eax, 0 -.return: - pop ecx ebx - ret - - -; Input: none -; Output: EAX - result (0 = OK, other = error) -forcedeth_phy_reset: - - push ebx ecx edx - - ; miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ); - ; EBX - addr, EAX - miireg, ECX - value - mov ebx, dword [forcedeth_phyaddr] - mov eax, MII_BMCR - mov ecx, MII_READ - call forcedeth_mii_rw ; miicontrol = eax - - ; miicontrol |= BMCR_RESET; - or eax, BMCR_RESET - push eax - - ; if (mii_rw(nic, np->phyaddr, MII_BMCR, miicontrol)) - ; EBX - addr, EAX - miireg, ECX - value - mov ecx, eax - mov eax, MII_BMCR - call forcedeth_mii_rw ; miicontrol = eax - - test eax, eax - jz @f - pop eax - mov eax, 0xffffffff - jmp .return -@@: - pop eax - - ; wait for 500ms - ; mdelay(500) - mov esi, 500 - call forcedeth_udelay - - ; must wait till reset is deasserted - ; while (miicontrol & BMCR_RESET) { - mov edx, 100 -.while_loop: - test eax, BMCR_RESET - jz .while_loop_exit - - ; mdelay(10); - mov esi, 10 - call forcedeth_udelay - - ; miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ); - ; EBX - addr, EAX - miireg, ECX - value - mov eax, MII_BMCR - mov ecx, MII_READ - call forcedeth_mii_rw ; miicontrol = eax - - ; FIXME: 100 tries seem excessive - ; if (tries++ > 100) - dec edx - jnz .while_loop - ; return -1; - mov eax, 0xffffffff - jmp .return -.while_loop_exit: - ; return 0 - mov eax, 0 -.return: - pop edx ecx ebx - ret - -; Input: none -; Output: none -forcedeth_mac_reset: - push esi edi - - ; dprintf("mac_reset\n") - DEBUGF 1," K : FORCEDETH: mac_reset.\n" - - ; writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl) - mov edi, dword [forcedeth_mapio_addr] - mov eax, dword [forcedeth_desc_ver] - or eax, (NVREG_TXRXCTL_BIT2 or NVREG_TXRXCTL_RESET) - mov dword [edi+NvRegTxRxControl], eax - - ; pci_push(base) - call forcedeth_pci_push - - ; writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset) - mov dword [edi+NvRegMacReset], NVREG_MAC_RESET_ASSERT - - ; pci_push(base) - call forcedeth_pci_push - - ; udelay(NV_MAC_RESET_DELAY) - mov esi, NV_MAC_RESET_DELAY - call forcedeth_nv_udelay - - ; writel(0, base + NvRegMacReset) - mov dword [edi+NvRegMacReset], 0 - - ; pci_push(base) - call forcedeth_pci_push - - ; udelay(NV_MAC_RESET_DELAY) - mov esi, NV_MAC_RESET_DELAY - call forcedeth_nv_udelay - - ; writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl) - mov eax, dword [forcedeth_desc_ver] - or eax, NVREG_TXRXCTL_BIT2 - mov dword [edi+NvRegTxRxControl], eax - - ; pci_push(base) - call forcedeth_pci_push - - pop edi esi - ret - -; Input: none -; Output: none -forcedeth_init_ring: - push eax ebx ecx - - ; np->next_tx = np->nic_tx = 0 - mov dword[forcedeth_next_tx], 0 - mov dword[forcedeth_nic_tx], 0 - - ; for (i = 0; i < TX_RING; i++) - mov ecx, TX_RING - -.for_loop: - ; tx_ring[i].FlagLen = 0; - mov eax, ecx - dec eax - mov bl, sizeof.forcedeth_TxDesc - mul bl - add eax, forcedeth_tx_ring - mov ebx, eax - mov dword [ebx + forcedeth_TxDesc.FlagLen], 0 - loop .for_loop - - ; np->cur_rx = RX_RING; - mov dword [forcedeth_cur_rx], RX_RING - ; np->refill_rx = 0; - mov dword [forcedeth_refill_rx], 0 - - ;for (i = 0; i < RX_RING; i++) - mov ecx, RX_RING - -.for_loop2: - ; rx_ring[i].FlagLen = 0; - mov eax, ecx - dec eax - mov bl, sizeof.forcedeth_RxDesc - mul bl - add eax, forcedeth_rx_ring - mov ebx, eax - mov dword [ebx + forcedeth_RxDesc.FlagLen], 0 - loop .for_loop2 - - ; alloc_rx(nic); - call forcedeth_alloc_rx - -.return: - pop ecx ebx eax - ret - -; Input: none -; Output: none -forcedeth_txrx_reset: - push eax esi edi - - ; dprintf(("txrx_reset\n")) - DEBUGF 1," K : FORCEDETH: txrx_reset.\n" - - ; writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl) - mov edi, dword [forcedeth_mapio_addr] - mov eax, dword [forcedeth_desc_ver] - or eax, (NVREG_TXRXCTL_BIT2 or NVREG_TXRXCTL_RESET) - mov dword [edi+NvRegTxRxControl], eax - - ; pci_push(base) - call forcedeth_pci_push - - ; nv_udelay(NV_TXRX_RESET_DELAY) - mov esi, NV_TXRX_RESET_DELAY - call forcedeth_nv_udelay - - ; writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl) - mov eax, dword [forcedeth_desc_ver] - or eax, NVREG_TXRXCTL_BIT2 - mov dword [edi+NvRegTxRxControl], eax - - ; pci_push(base) - call forcedeth_pci_push - -.return: - pop edi esi eax - ret - -; Input: none -; Output: none -forcedeth_set_multicast: - push edi - - ; u32 addr[2]; - ; u32 mask[2]; - ; u32 pff; - ; u32 alwaysOff[2]; - ; u32 alwaysOn[2]; - ; - ; memset(addr, 0, sizeof(addr)); - ; memset(mask, 0, sizeof(mask)); - ; - ; pff = NVREG_PFF_MYADDR; - ; - ; alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0; - ; - ; addr[0] = alwaysOn[0]; - ; addr[1] = alwaysOn[1]; - ; mask[0] = alwaysOn[0] | alwaysOff[0]; - ; mask[1] = alwaysOn[1] | alwaysOff[1]; - ; - ; addr[0] |= NVREG_MCASTADDRA_FORCE; - ; pff |= NVREG_PFF_ALWAYS; - ; stop_rx(); - call forcedeth_stop_rx - ; writel(addr[0], base + NvRegMulticastAddrA); - mov edi, dword [forcedeth_mapio_addr] - mov dword [edi+NvRegMulticastAddrA], NVREG_MCASTADDRA_FORCE - ; writel(addr[1], base + NvRegMulticastAddrB); - mov dword [edi+NvRegMulticastAddrB], 0 - ; writel(mask[0], base + NvRegMulticastMaskA); - mov dword [edi+NvRegMulticastMaskA], 0 - ; writel(mask[1], base + NvRegMulticastMaskB); - mov dword [edi+NvRegMulticastMaskB], 0 - ; writel(pff, base + NvRegPacketFilterFlags); - mov dword [edi+NvRegPacketFilterFlags], (NVREG_PFF_MYADDR or NVREG_PFF_ALWAYS) - ; start_rx(nic); - call forcedeth_start_rx - -.return: - pop edi - ret - -; Input: none -; Output: none -forcedeth_start_rx: - push edi - - ; dprintf(("start_rx\n")) - DEBUGF 1," K : FORCEDETH: start_rx.\n" - - ; Already running? Stop it. - ; if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { - mov edi, dword [forcedeth_mapio_addr] - mov eax, dword [edi+NvRegReceiverControl] - test eax, NVREG_RCVCTL_START - jz @f - ; writel(0, base + NvRegReceiverControl) - mov dword [edi+NvRegReceiverControl], 0 - ; pci_push(base) - call forcedeth_pci_push - -@@: - - ; writel(np->linkspeed, base + NvRegLinkSpeed); - mov eax, dword [forcedeth_linkspeed] - mov dword [edi+NvRegLinkSpeed], eax - ; pci_push(base); - call forcedeth_pci_push - ; writel(NVREG_RCVCTL_START, base + NvRegReceiverControl); - mov dword [edi+NvRegReceiverControl], NVREG_RCVCTL_START - ; pci_push(base); - call forcedeth_pci_push - -.return: - pop edi - ret - -; Input: none -; Output: none -forcedeth_stop_rx: - push esi edi - - ; dprintf(("stop_rx\n")) - DEBUGF 1," K : FORCEDETH: stop_rx.\n" - - ; writel(0, base + NvRegReceiverControl) - mov edi, dword [forcedeth_mapio_addr] - mov dword [edi+NvRegReceiverControl], 0 - - push ebx edx edi ;;;;;;;;;;;;;;;;;;;;;; - ; reg_delay(NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, "stop_rx: ReceiverStatus remained busy"); - stdcall forcedeth_reg_delay, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, 0 - pop edi edx ebx ;;;;;;;;;;;;;;;;;;;;;; - - - ; nv_udelay(NV_RXSTOP_DELAY2) - mov esi, NV_RXSTOP_DELAY2 - call forcedeth_nv_udelay - - ; writel(0, base + NvRegLinkSpeed) - mov dword [edi+NvRegLinkSpeed], 0 - -.return: - pop edi esi - ret - -; Input: none -; Output: EAX -forcedeth_update_linkspeed: - push ebx ecx esi edi - - ; BMSR_LSTATUS is latched, read it twice: - ; we want the current value. - - ; mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ) - ;EBX - addr, EAX - miireg, ECX - value - mov ebx, dword [forcedeth_phyaddr] - mov eax, MII_BMSR - mov ecx, MII_READ - call forcedeth_mii_rw - - - ; mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ) - ;EBX - addr, EAX - miireg, ECX - value - mov ebx, dword [forcedeth_phyaddr] - mov eax, MII_BMSR - mov ecx, MII_READ - call forcedeth_mii_rw ; mii_status = eax - - ; yhlu - - ; for(i=0;i<30;i++) { - mov ecx, 30 -.for_loop: - push ecx - - ; mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ); - ;EBX - addr, EAX - miireg, ECX - value - ;mov ebx, dword [forcedeth_phyaddr] - mov eax, MII_BMSR - mov ecx, MII_READ - call forcedeth_mii_rw ; mii_status = eax - - ; if((mii_status & BMSR_LSTATUS) && (mii_status & BMSR_ANEGCOMPLETE)) break; - test eax, BMSR_LSTATUS - jz @f - test eax, BMSR_ANEGCOMPLETE - jz @f - ; break - pop ecx - jmp .break - -@@: - - ; mdelay(100); - push eax ; ??? - mov esi, 100 - call forcedeth_udelay - pop eax ; ??? - - pop ecx - loop .for_loop - -.break: - - ; if (!(mii_status & BMSR_LSTATUS)) { - test eax, BMSR_LSTATUS - jnz @f - - ; printf("no link detected by phy - falling back to 10HD.\n") - DEBUGF 1," K : FORCEDETH: update_linkspeed: no link detected by phy - falling back to 10HD.\n" - - ; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10 - mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) - - ; newdup = 0; - mov dword [forcedeth_tmp_newdup], 0 - ; retval = 0; - mov dword [forcedeth_tmp_retval], 0 - - ; goto set_speed; - jmp .set_speed - -@@: - - ; check auto negotiation is complete - ; if (!(mii_status & BMSR_ANEGCOMPLETE)) { - test eax, BMSR_ANEGCOMPLETE - jnz @f - - ; still in autonegotiation - configure nic for 10 MBit HD and wait. - ; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10 - mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) - - ; newdup = 0 - mov dword [forcedeth_tmp_newdup], 0 - - ; retval = 0 - mov dword [forcedeth_tmp_retval], 0 - - ; printf("autoneg not completed - falling back to 10HD.\n") - DEBUGF 1," K : FORCEDETH: update_linkspeed: autoneg not completed - falling back to 10HD.\n" - - ; goto set_speed - jmp .set_speed - -@@: - - ; retval = 1 - mov dword [forcedeth_tmp_retval], 1 - - ; if (np->gigabit == PHY_GIGABIT) { - cmp dword [forcedeth_gigabit], PHY_GIGABIT - jne .end_if - ; control_1000 = mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ) - ;EBX - addr, EAX - miireg, ECX - value - ;mov ebx, dword [forcedeth_phyaddr] - mov eax, MII_1000BT_CR - mov ecx, MII_READ - call forcedeth_mii_rw ; control_1000 = eax - mov dword [forcedeth_tmp_control_1000], eax - - ; status_1000 = mii_rw(nic, np->phyaddr, MII_1000BT_SR, MII_READ) - ;EBX - addr, EAX - miireg, ECX - value - ;mov ebx, dword [forcedeth_phyaddr] - mov eax, MII_1000BT_SR - mov ecx, MII_READ - call forcedeth_mii_rw ; status_1000 = eax - ;mov dword [forcedeth_tmp_status_1000], eax - - ; if ((control_1000 & ADVERTISE_1000FULL) && - ; (status_1000 & LPA_1000FULL)) { - test eax, LPA_1000FULL - jz .end_if - test dword [forcedeth_tmp_control_1000], ADVERTISE_1000FULL - jz .end_if - - ; printf ("update_linkspeed: GBit ethernet detected.\n") - DEBUGF 1," K : FORCEDETH: update_linkspeed: GBit ethernet detected.\n" - - ; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_1000 - mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_1000) - - ; newdup = 1 - mov dword [forcedeth_tmp_newdup], 1 - - ; goto set_speed - jmp .set_speed - -.end_if: - - ; adv = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ); - ;EBX - addr, EAX - miireg, ECX - value - ;mov ebx, dword [forcedeth_phyaddr] - mov eax, MII_ADVERTISE - mov ecx, MII_READ - call forcedeth_mii_rw ; adv = eax - mov dword [forcedeth_tmp_adv], eax - - ; lpa = mii_rw(nic, np->phyaddr, MII_LPA, MII_READ); - ;EBX - addr, EAX - miireg, ECX - value - ;mov ebx, dword [forcedeth_phyaddr] - mov eax, MII_LPA - mov ecx, MII_READ - call forcedeth_mii_rw ; lpa = eax - mov dword [forcedeth_tmp_lpa], eax - - ; dprintf(("update_linkspeed: PHY advertises 0x%hX, lpa 0x%hX.\n", adv, lpa)); - DEBUGF 1," K : FORCEDETH: update_linkspeed: PHY advertises 0x%x, lpa 0x%x.\n", [forcedeth_tmp_adv]:8, [forcedeth_tmp_lpa]:8 - - ; FIXME: handle parallel detection properly, handle gigabit ethernet - ; lpa = lpa & adv - mov eax, dword [forcedeth_tmp_adv] - and dword [forcedeth_tmp_lpa], eax - - mov eax, dword [forcedeth_tmp_lpa] - - ; if (lpa & LPA_100FULL) { - test eax, LPA_100FULL - jz @f - ; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_100 - mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_100) - ; newdup = 1 - mov dword [forcedeth_tmp_newdup], 1 - jmp .set_speed -@@: - ; } else if (lpa & LPA_100HALF) { - test eax, LPA_100HALF - jz @f - ; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_100 - mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_100) - ; newdup = 0 - mov dword [forcedeth_tmp_newdup], 0 - jmp .set_speed -@@: - ; } else if (lpa & LPA_10FULL) { - test eax, LPA_10FULL - jz @f - ; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10 - mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) - ; newdup = 1 - mov dword [forcedeth_tmp_newdup], 1 - jmp .set_speed -@@: - ; } else if (lpa & LPA_10HALF) { - test eax, LPA_10HALF - ; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10; - mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) - ; newdup = 0; - mov dword [forcedeth_tmp_newdup], 0 - jmp .set_speed -@@: - ; } else { - ; printf("bad ability %hX - falling back to 10HD.\n", lpa) - DEBUGF 1," K : FORCEDETH: update_linkspeed: bad ability 0x%x - falling back to 10HD.\n", eax - - ; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10 - mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) - ; newdup = 0 - mov dword [forcedeth_tmp_newdup], 0 - ; } - -.set_speed: - - ; if (np->duplex == newdup && np->linkspeed == newls) - mov eax, dword [forcedeth_tmp_newdup] - cmp eax, dword [forcedeth_duplex] - jne .end_if2 - mov eax, dword [forcedeth_tmp_newls] - cmp eax, dword [forcedeth_linkspeed] - jne .end_if2 - ; return retval; - jmp .return - -.end_if2: - - ; dprintf(("changing link setting from %d/%s to %d/%s.\n", - ; np->linkspeed, np->duplex ? "Full-Duplex": "Half-Duplex", newls, newdup ? "Full-Duplex": "Half-Duplex")) - DEBUGF 1," K : FORCEDETH: update_linkspeed: changing link from %x/XD to %x/XD.\n", [forcedeth_linkspeed]:8, [forcedeth_tmp_newls]:8 ; !!!!!!!!!!!!!!!!!!!!!!!!!!!! - - ; np->duplex = newdup - mov eax, dword [forcedeth_tmp_newdup] - mov dword [forcedeth_duplex], eax - - ; np->linkspeed = newls - mov eax, [forcedeth_tmp_newls] - mov dword [forcedeth_linkspeed], eax - - ; if (np->gigabit == PHY_GIGABIT) { - cmp dword [forcedeth_gigabit], PHY_GIGABIT - jne .end_if3 - - ; phyreg = readl(base + NvRegRandomSeed); - mov edi, dword [forcedeth_mapio_addr] - mov eax, dword [edi+NvRegRandomSeed] - - ; phyreg &= ~(0x3FF00); - and eax, not (0x3FF00) - mov ecx, eax ; phyreg = ecx - - ; if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10) - mov eax, dword [forcedeth_linkspeed] - and eax, 0xFFF - cmp eax, NVREG_LINKSPEED_10 - jne @f - ; phyreg |= NVREG_RNDSEED_FORCE3 - or ecx, NVREG_RNDSEED_FORCE3 - jmp .end_if4 -@@: - ; else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100) - cmp eax, NVREG_LINKSPEED_100 - jne @f - ; phyreg |= NVREG_RNDSEED_FORCE2 - or ecx, NVREG_RNDSEED_FORCE2 - jmp .end_if4 -@@: - ; else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000) - cmp eax, NVREG_LINKSPEED_1000 - jne .end_if4 - ; phyreg |= NVREG_RNDSEED_FORCE - or ecx, NVREG_RNDSEED_FORCE -.end_if4: - ; writel(phyreg, base + NvRegRandomSeed) - mov dword [edi+NvRegRandomSeed], ecx - -.end_if3: - - ; phyreg = readl(base + NvRegPhyInterface) - mov ecx, dword [edi+NvRegPhyInterface] - - ; phyreg &= ~(PHY_HALF | PHY_100 | PHY_1000) - and ecx, not (PHY_HALF or PHY_100 or PHY_1000) - - ; if (np->duplex == 0) - cmp dword [forcedeth_duplex], 0 - jne @f - ; phyreg |= PHY_HALF - or ecx, PHY_HALF -@@: - ; if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100) - mov eax, dword [forcedeth_linkspeed] - and eax, 0xFFF - cmp eax, NVREG_LINKSPEED_100 - jne @f - ; phyreg |= PHY_100 - or ecx, PHY_100 - jmp .end_if5 -@@: - ; else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000) - cmp eax, NVREG_LINKSPEED_1000 - jne .end_if5 - ; phyreg |= PHY_1000 - or ecx, PHY_1000 - -.end_if5: - - ; writel(phyreg, base + NvRegPhyInterface) - mov dword [edi+NvRegPhyInterface], ecx - - ; writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD), base + NvRegMisc1); - cmp dword [forcedeth_duplex], 0 - je @f - mov ecx, 0 - jmp .next -@@: - mov ecx, NVREG_MISC1_HD -.next: - or ecx, NVREG_MISC1_FORCE - mov dword [edi+NvRegMisc1], ecx - - ; pci_push(base) - call forcedeth_pci_push - - ; writel(np->linkspeed, base + NvRegLinkSpeed) - mov eax, dword [forcedeth_linkspeed] - mov dword [edi+NvRegLinkSpeed], eax - - ; pci_push(base) - call forcedeth_pci_push - -.return: - ; return retval - mov eax, dword [forcedeth_tmp_retval] - pop edi esi ecx ebx - ret - - -; Input: none -; Output: none -forcedeth_start_tx: - push edi - ; dprintf(("start_tx\n")) - DEBUGF 1," K : FORCEDETH: start_tx.\n" - - ; writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl) - mov edi, dword [forcedeth_mapio_addr] - mov dword [edi+NvRegTransmitterControl], NVREG_XMITCTL_START - - ; pci_push(base) - call forcedeth_pci_push - -.return: - pop edi - ret - -; Interrupt handler -forcedeth_int_handler: - DEBUGF 1," K : FORCEDETH: interrupt handler.\n" - - ret - diff --git a/kernel/trunk/network/eth_drv/drivers/i8255x.inc b/kernel/trunk/network/eth_drv/drivers/i8255x.inc deleted file mode 100644 index d4202a8d44..0000000000 --- a/kernel/trunk/network/eth_drv/drivers/i8255x.inc +++ /dev/null @@ -1,794 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; ;; -;; I8255X.INC ;; -;; ;; -;; Ethernet driver for Menuet OS ;; -;; ;; -;; Version 0.3 11 August 2003 ;; -;; ;; -;; This driver is based on the eepro100 driver from ;; -;; the etherboot 5.0.6 project. The copyright statement is ;; -;; ;; -;; GNU GENERAL PUBLIC LICENSE ;; -;; Version 2, June 1991 ;; -;; ;; -;; remaining parts Copyright 2002 Mike Hibbett, ;; -;; mikeh@oceanfree.net ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -;******************************************************************** -; Interface -; I8255x_reset -; I8255x_probe -; I8255x_poll -; I8255x_transmit -; -; These functions are referenced in ethernet.inc -; -;******************************************************************** - - -rxfd_status equ eth_data_start -rxfd_command equ eth_data_start + 2 -rxfd_link equ eth_data_start + 4 -rxfd_rx_buf_addr equ eth_data_start + 8 -rxfd_count equ eth_data_start + 12 -rxfd_size equ eth_data_start + 14 -rxfd_packet equ eth_data_start + 16 - - - -uglobal -eeprom_data: - times 16 dd 0 - -align 4 - -lstats: -tx_good_frames: - dd 0 -tx_coll16_errs: - dd 0 -tx_late_colls: - dd 0 -tx_underruns: - dd 0 -tx_lost_carrier: - dd 0 -tx_deferred: - dd 0 -tx_one_colls: - dd 0 -tx_multi_colls: - dd 0 -tx_total_colls: - dd 0 -rx_good_frames: - dd 0 -rx_crc_errs: - dd 0 -rx_align_errs: - dd 0 -rx_resource_errs: - dd 0 -rx_overrun_errs: - dd 0 -rx_colls_errs: - dd 0 -rx_runt_errs: - dd 0 -done_marker: - dd 0 - -align 4 - -confcmd: -confcmd_status: - dw 0 -confcmd_command: - dw 0 -confcmd_link: - dd 0 -endg - -iglobal -confcmd_data: - db 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1 - db 0, 0x2e, 0, 0x60, 0, 0xf2, 0x48, 0, 0x40, 0xf2 - db 0x80, 0x3f, 0x05 -endg - -uglobal -align 4 - -txfd: -txfd_status: - dw 0 -txfd_command: - dw 0 -txfd_link: - dd 0 -txfd_tx_desc_addr: - dd 0 -txfd_count: - dd 0 -txfd_tx_buf_addr0: - dd 0 -txfd_tx_buf_size0: - dd 0 -txfd_tx_buf_addr1: - dd 0 -txfd_tx_buf_size1: - dd 0 - -align 4 - -hdr: -hdr_dst_addr: - times 6 db 0 -hdr_src_addr: - times 6 db 0 -hdr_type: - dw 0 -endg - - -;*************************************************************************** -; Function -; wait_for_cmd_done -; -; Description -; waits for the hardware to complete a command -; port address in edx -; -; al destroyed -;*************************************************************************** -wait_for_cmd_done: - in al, dx - cmp al, 0 - jne wait_for_cmd_done - ret - - - -;*************************************************************************** -; Function -; mdio_read -; -; Description -; This probably reads a register in the "physical media interface chip" -; Phy_id in ebx -; location in ecx -; -; Data returned in eax -; -;*************************************************************************** -mdio_read: - mov edx, [io_addr] - add edx, 16 ; SCBCtrlMDI - - mov eax, 0x08000000 - shl ecx, 16 - or eax, ecx - shl ebx, 21 - or eax, ebx - - out dx, eax - -mrlp: - call delay_us - in eax, dx - mov ecx, eax - and ecx, 0x10000000 - jz mrlp - - and eax, 0xffff - ret - - - -;*************************************************************************** -; Function -; mdio_write -; -; Description -; This probably writes a register in the "physical media interface chip" -; Phy_id in ebx -; location in ecx -; data in edx -; Data returned in eax -; -;*************************************************************************** -mdio_write: - mov eax, 0x04000000 - shl ecx, 16 - or eax, ecx - shl ebx, 21 - or eax, ebx - or eax, edx - - mov edx, [io_addr] - add edx, 16 ; SCBCtrlMDI - out dx, eax - -mwlp: - call delay_us - in eax, dx - mov ecx, eax - and ecx, 0x10000000 - jz mwlp - - and eax, 0xffff - ret - - - -;/***********************************************************************/ -;/* I82557 related defines */ -;/***********************************************************************/ - -; Serial EEPROM section. -; A "bit" grungy, but we work our way through bit-by-bit :->. -; EEPROM_Ctrl bits. -EE_SHIFT_CLK equ 0x01 ; EEPROM shift clock. -EE_CS equ 0x02 ; EEPROM chip select. -EE_DATA_WRITE equ 0x04 ; EEPROM chip data in. -EE_DATA_READ equ 0x08 ; EEPROM chip data out. -EE_WRITE_0 equ 0x4802 -EE_WRITE_1 equ 0x4806 -EE_ENB equ 0x4802 - - -; The EEPROM commands include the alway-set leading bit. -EE_READ_CMD equ 6 - -; The SCB accepts the following controls for the Tx and Rx units: -CU_START equ 0x0010 -CU_RESUME equ 0x0020 -CU_STATSADDR equ 0x0040 -CU_SHOWSTATS equ 0x0050 ; Dump statistics counters. -CU_CMD_BASE equ 0x0060 ; Base address to add to add CU commands. -CU_DUMPSTATS equ 0x0070 ; Dump then reset stats counters. - -RX_START equ 0x0001 -RX_RESUME equ 0x0002 -RX_ABORT equ 0x0004 -RX_ADDR_LOAD equ 0x0006 -RX_RESUMENR equ 0x0007 -INT_MASK equ 0x0100 -DRVR_INT equ 0x0200 ; Driver generated interrupt. - - -;*************************************************************************** -; Function -; do_eeprom_cmd -; -; Description -; writes a cmd to the ethernet cards eeprom, by bit bashing -; cmd in ebx -; cmd length in ecx -; return in eax -;*************************************************************************** -do_eeprom_cmd: - mov edx, [io_addr]; We only require the value in dx - add dx, 14 ; the value SCBeeprom - - mov ax, EE_ENB - out dx, ax - call delay_us - - mov ax, 0x4803 ; EE_ENB | EE_SHIFT_CLK - out dx, ax - call delay_us - - ; dx holds ee_addr - ; ecx holds count - ; eax holds cmd - xor edi, edi ; this will be the receive data - -dec_001: - mov esi, 1 - - dec ecx - shl esi, cl - inc ecx - and esi, ebx - mov eax, EE_WRITE_0; I am assuming this doesnt affect the flags.. - cmp esi, 0 - jz dec_002 - mov eax, EE_WRITE_1 - -dec_002: - out dx, ax - call delay_us - - or ax, EE_SHIFT_CLK - out dx, ax - call delay_us - - shl edi, 1 - - in ax, dx - and ax, EE_DATA_READ - cmp ax, 0 - jz dec_003 - inc edi - -dec_003: - loop dec_001 - - mov ax, EE_ENB - out dx, ax - call delay_us - - mov ax, 0x4800 - out dx, ax - call delay_us - - mov eax, edi - - ret - - -;*************************************************************************** -; Function -; I8255x_probe -; Description -; Searches for an ethernet card, enables it and clears the rx buffer -; If a card was found, it enables the ethernet -> TCPIP link -; -;*************************************************************************** -I8255x_probe: - DEBUGF 1," K : Probing i8255x device \n" - mov eax, [io_addr] - - mov ebx, [pci_bus] - mov ecx, [pci_dev] - mov edx, 0x04 ; PCI_COMMAND - call pcibios_read_config_word - - or ax, 0x05 - mov ebx, [pci_bus] - mov ecx, [pci_dev] - mov edx, 0x04 ; PCI_COMMAND - call pcibios_write_config_word - - mov ebx, 0x6000000 - mov ecx, 27 - call do_eeprom_cmd - and eax, 0xffe0000 - cmp eax, 0xffe0000 - je bige - - mov ebx, 0x1800000 - mov ecx, 0x40 - jmp doread - -bige: - mov ebx, 0x6000000 - mov ecx, 0x100 - -doread: - ; do-eeprom-cmd will destroy all registers - ; we have eesize in ecx - ; read_cmd in ebx - - ; Ignore full eeprom - just load the mac address - mov ecx, 0 - -drlp: - push ecx ; save count - push ebx - mov eax, ecx - shl eax, 16 - or ebx, eax - mov ecx, 27 - call do_eeprom_cmd - - pop ebx - pop ecx - - mov edx, ecx - shl edx, 2 - mov esi, eeprom_data - add esi, edx - mov [esi], eax - - inc ecx - cmp ecx, 16 - jne drlp - - ; OK, we have the MAC address. - ; Now reset the card - - mov edx, [io_addr] - add dx, 8 ; SCBPort - xor eax, eax ; The reset cmd == 0 - out dx, eax - - mov esi, 10 - call delay_ms ; Give the card time to warm up. - - mov eax, lstats - mov edx, [io_addr] - add edx, 4 ; SCBPointer - out dx, eax - - mov eax, 0x0140 ; INT_MASK | CU_STATSADDR - mov edx, [io_addr] - add edx, 2 ; SCBCmd - out dx, ax - - call wait_for_cmd_done - - mov eax, 0 - mov edx, [io_addr] - add edx, 4 ; SCBPointer - out dx, eax - - mov eax, 0x0106 ; INT_MASK | RX_ADDR_LOAD - mov edx, [io_addr] - add edx, 2 ; SCBCmd - out dx, ax - - call wait_for_cmd_done - - ; build rxrd structure - mov ax, 0x0001 - mov [rxfd_status], ax - mov ax, 0x0000 - mov [rxfd_command], ax - - mov eax, rxfd_status - sub eax, OS_BASE - mov [rxfd_link], eax - - mov eax, Ether_buffer - sub eax, OS_BASE - mov [rxfd_rx_buf_addr], eax - - mov ax, 0 - mov [rxfd_count], ax - - mov ax, 1528 - mov [rxfd_size], ax - - mov edx, [io_addr] - add edx, 4 ; SCBPointer - - mov eax, rxfd_status - sub eax, OS_BASE - out dx, eax - - mov edx, [io_addr] - add edx, 2 ; SCBCmd - - mov ax, 0x0101 ; INT_MASK | RX_START - out dx, ax - - call wait_for_cmd_done - - ; start the reciver - - mov ax, 0 - mov [rxfd_status], ax - - mov ax, 0xc000 - mov [rxfd_command], ax - - mov edx, [io_addr] - add edx, 4 ; SCBPointer - - mov eax, rxfd_status - sub eax, OS_BASE - out dx, eax - - mov edx, [io_addr] - add edx, 2 ; SCBCmd - - mov ax, 0x0101 ; INT_MASK | RX_START - out dx, ax - - ; Init TX Stuff - - mov edx, [io_addr] - add edx, 4 ; SCBPointer - - mov eax, 0 - out dx, eax - - mov edx, [io_addr] - add edx, 2 ; SCBCmd - - mov ax, 0x0160 ; INT_MASK | CU_CMD_BASE - out dx, ax - - call wait_for_cmd_done - - ; Set TX Base address - - ; First, set up confcmd values - - mov ax, 2 - mov [confcmd_command], ax - mov eax, txfd - sub eax, OS_BASE - mov [confcmd_link], eax - - mov ax, 1 - mov [txfd_command], ax ; CmdIASetup - - mov ax, 0 - mov [txfd_status], ax - - mov eax, confcmd - sub eax, OS_BASE - mov [txfd_link], eax - - - - ; ETH_ALEN is 6 bytes - - mov esi, eeprom_data - mov edi, node_addr - mov ecx, 3 -drp000: - mov eax, [esi] - mov [edi], al - shr eax, 8 - inc edi - mov [edi], al - inc edi - add esi, 4 - loop drp000 - - ; Hard code your MAC address into node_addr at this point, - ; If you cannot read the MAC address from the eeprom in the previous step. - ; You also have to write the mac address into txfd_tx_desc_addr, rather - ; than taking data from eeprom_data - - mov esi, eeprom_data - mov edi, txfd_tx_desc_addr - mov ecx, 3 -drp001: - mov eax, [esi] - mov [edi], al - shr eax, 8 - inc edi - mov [edi], al - inc edi - add esi, 4 - loop drp001 - - - mov esi, eeprom_data + (6 * 4) - mov eax, [esi] - shr eax, 8 - and eax, 0x3f - cmp eax, 4 ; DP83840 - je drp002 - cmp eax, 10 ; DP83840A - je drp002 - jmp drp003 - -drp002: - mov ebx, [esi] - and ebx, 0x1f - push ebx - mov ecx, 23 - call mdio_read - pop ebx - or eax, 0x0422 - mov ecx, 23 - mov edx, eax - call mdio_write - -drp003: - mov ax, 0x4002 ; Cmdsuspend | CmdConfigure - mov [confcmd_command], ax - mov ax, 0 - mov [confcmd_status], ax - mov eax, txfd - mov [confcmd_link], eax - mov ebx, confcmd_data - mov al, 0x88 ; fifo of 8 each - mov [ebx + 1], al - mov al, 0 - mov [ebx + 4], al - mov al, 0x80 - mov [ebx + 5], al - mov al, 0x48 - mov [ebx + 15], al - mov al, 0x80 - mov [ebx + 19], al - mov al, 0x05 - mov [ebx + 21], al - - mov eax, txfd - sub eax, OS_BASE - mov edx, [io_addr] - add edx, 4 ; SCBPointer - out dx, eax - - mov eax, 0x0110 ; INT_MASK | CU_START - mov edx, [io_addr] - add edx, 2 ; SCBCmd - out dx, ax - - call wait_for_cmd_done - jmp skip - - ; wait for thing to start -drp004: - mov ax, [txfd_status] - cmp ax, 0 - je drp004 - -skip: - ; Indicate that we have successfully reset the card - mov eax, [pci_data] - mov [eth_status], eax - -I8255x_exit: - ret - - - -;*************************************************************************** -; Function -; I8255x_reset -; Description -; Place the chip (ie, the ethernet card) into a virgin state -; No inputs -; All registers destroyed -; -;*************************************************************************** -I8255x_reset: - ret - - - -;*************************************************************************** -; Function -; I8255x_poll -; -; Description -; Polls the ethernet card for a received packet -; Received data, if any, ends up in Ether_buffer -; -;*************************************************************************** -I8255x_poll: - mov ax, 0 ; assume no data - mov [eth_rx_data_len], ax - - mov ax, [rxfd_status] - cmp ax, 0 - je i8p_exit - - mov ax, 0 - mov [rxfd_status], ax - - mov ax, 0xc000 - mov [rxfd_command], ax - - mov edx, [io_addr] - add edx, 4 ; SCBPointer - - mov eax, rxfd_status - sub eax, OS_BASE - out dx, eax - - mov edx, [io_addr] - add edx, 2 ; SCBCmd - - mov ax, 0x0101 ; INT_MASK | RX_START - out dx, ax - - call wait_for_cmd_done - - mov esi, rxfd_packet - mov edi, Ether_buffer - mov ecx, 1518 - cld - rep movsb - - mov ax, [rxfd_count] - and ax, 0x3fff - mov [eth_rx_data_len], ax - -i8p_exit: - ret - - - -;*************************************************************************** -; Function -; I8255x_transmit -; -; Description -; Transmits a packet of data via the ethernet card -; Pointer to 48 bit destination address in edi -; Type of packet in bx -; size of packet in ecx -; pointer to packet data in esi -; -;*************************************************************************** -I8255x_transmit: - - mov [hdr_type], bx - - mov eax, [edi] - mov [hdr_dst_addr], eax - mov ax, [edi+4] - mov [hdr_dst_addr+4], ax - - mov eax, [node_addr] - mov [hdr_src_addr], eax - mov ax, [node_addr+4] - mov [hdr_src_addr+4], ax - - mov edx, [io_addr] - in ax, dx - and ax, 0xfc00 - out dx, ax - - xor ax, ax - mov [txfd_status], ax - mov ax, 0x400C ; Cmdsuspend | CmdTx | CmdTxFlex - mov [txfd_command], ax - mov eax, txfd - mov [txfd_link], eax - mov eax, 0x02208000 - mov [txfd_count], eax - mov eax, txfd_tx_buf_addr0 - sub eax, OS_BASE - mov [txfd_tx_desc_addr], eax - mov eax, hdr - sub eax, OS_BASE - mov [txfd_tx_buf_addr0], eax - mov eax, 14; sizeof hdr - mov [txfd_tx_buf_size0], eax - - ; Copy the buffer address and size in - mov eax, esi - sub eax, OS_BASE - mov [txfd_tx_buf_addr1], eax - mov eax, ecx - mov [txfd_tx_buf_size1], eax - - mov eax, txfd - sub eax, OS_BASE - mov edx, [io_addr] - add edx, 4 ; SCBPointer - out dx, eax - - mov ax, 0x0110 ; INT_MASK | CU_START - mov edx, [io_addr] - add edx, 2 ; SCBCmd - out dx, ax - - call wait_for_cmd_done - - mov edx, [io_addr] - in ax, dx - -I8t_001: - mov ax, [txfd_status] - cmp ax, 0 - je I8t_001 - - mov edx, [io_addr] - in ax, dx - - ret diff --git a/kernel/trunk/network/eth_drv/drivers/pcnet32.inc b/kernel/trunk/network/eth_drv/drivers/pcnet32.inc deleted file mode 100644 index ee3ef61f62..0000000000 --- a/kernel/trunk/network/eth_drv/drivers/pcnet32.inc +++ /dev/null @@ -1,848 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; PCNET32.INC ;; -;; ;; -;; Ethernet driver for Menuet OS ;; -;; ;; -;; - Version 1.0 31 July 2004: ;; -;; Initial release ;; -;; ;; -;; - Version 1.01 29 March 2008: ;; -;; Adapted to work with kolibrios flat kernel ;; -;; Debug info is updated, and now uses DEBUGF macro ;; -;; by hidnplayr@kolibrios.org ;; -;; ;; -;; This driver is based on the PCNet32 driver from ;; -;; the etherboot 5.0.6 project. The copyright statement is ;; -;; ;; -;; GNU GENERAL PUBLIC LICENSE ;; -;; Version 2, June 1991 ;; -;; ;; -;; remaining parts Copyright 2004 Jarek Pelczar, ;; -;; jpelczar@interia.pl ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -PCNET32_PORT_AUI equ 0x00 -PCNET32_PORT_10BT equ 0x01 -PCNET32_PORT_GPSI equ 0x02 -PCNET32_PORT_MII equ 0x03 -PCNET32_PORT_PORTSEL equ 0x03 -PCNET32_PORT_ASEL equ 0x04 -PCNET32_PORT_100 equ 0x40 -PCNET32_PORT_FD equ 0x80 -PCNET32_DMA_MASK equ 0xffffffff - -PCNET32_LOG_TX_BUFFERS equ 1 -PCNET32_LOG_RX_BUFFERS equ 2 - -PCNET32_TX_RING_SIZE equ (1 shl PCNET32_LOG_TX_BUFFERS) -PCNET32_TX_RING_MOD_MASK equ (PCNET32_TX_RING_SIZE-1) -PCNET32_TX_RING_LEN_BITS equ 0 -PCNET32_RX_RING_SIZE equ (1 shl PCNET32_LOG_RX_BUFFERS) -PCNET32_RX_RING_MOD_MASK equ (PCNET32_RX_RING_SIZE-1) -PCNET32_RX_RING_LEN_BITS equ (PCNET32_LOG_RX_BUFFERS shl 4) -PCNET32_PKT_BUF_SZ equ 1544 -PCNET32_PKT_BUF_SZ_NEG equ 0xf9f8 - -pcnet32_txb equ (eth_data_start) -pcnet32_rxb equ ((pcnet32_txb+(PCNET32_PKT_BUF_SZ*PCNET32_TX_RING_SIZE)+0xf) and 0xfffffff0) -pcnet32_tx_ring equ ((pcnet32_rxb+(PCNET32_PKT_BUF_SZ*PCNET32_RX_RING_SIZE)+0xf) and 0xfffffff0) -pcnet32_rx_ring equ ((pcnet32_tx_ring+(16*PCNET32_TX_RING_SIZE)+0xf) and 0xfffffff0) - -virtual at ((pcnet32_rx_ring+(16*PCNET32_RX_RING_SIZE)+0xf) and 0xfffffff0) -pcnet32_private: -.mode dw ? -.tlen_rlen dw ? -.phys_addr db ?,?,?,?,?,? -.reserved dw ? -.filter dd ?,? -.rx_ring dd ? -.tx_ring dd ? -.cur_rx dd ? -.cur_tx dd ? -.dirty_rx dd ? -.dirty_tx dd ? -.tx_full db ? -.options dd ? -.full_duplex db ? -.chip_version dd ? -.mii db ? -.ltint db ? -.dxsuflo db ? -.fset db ? -.fdx db ? -end virtual - -virtual at 0 -pcnet32_rx_head: -.base dd ? -.buf_length dw ? -.status dw ? -.msg_length dd ? -.reserved dd ? -end virtual - -virtual at 0 -pcnet32_tx_head: -.base dd ? -.length dw ? -.status dw ? -.misc dd ? -.reserved dd ? -end virtual - -uglobal -pcnet32_access: -.read_csr dd ? -.write_csr dd ? -.read_bcr dd ? -.write_bcr dd ? -.read_rap dd ? -.write_rap dd ? -.reset dd ? -endg - -iglobal -pcnet32_options_mapping: -dd PCNET32_PORT_ASEL ; 0 Auto-select -dd PCNET32_PORT_AUI ; 1 BNC/AUI -dd PCNET32_PORT_AUI ; 2 AUI/BNC -dd PCNET32_PORT_ASEL ; 3 not supported -dd PCNET32_PORT_10BT or PCNET32_PORT_FD ; 4 10baseT-FD -dd PCNET32_PORT_ASEL ; 5 not supported -dd PCNET32_PORT_ASEL ; 6 not supported -dd PCNET32_PORT_ASEL ; 7 not supported -dd PCNET32_PORT_ASEL ; 8 not supported -dd PCNET32_PORT_MII ; 9 MII 10baseT -dd PCNET32_PORT_MII or PCNET32_PORT_FD ; 10 MII 10baseT-FD -dd PCNET32_PORT_MII ; 11 MII (autosel) -dd PCNET32_PORT_10BT ; 12 10BaseT -dd PCNET32_PORT_MII or PCNET32_PORT_100 ; 13 MII 100BaseTx -dd PCNET32_PORT_MII or PCNET32_PORT_100 or PCNET32_PORT_FD ; 14 MII 100BaseTx-FD -dd PCNET32_PORT_ASEL ; 15 not supported -endg - -PCNET32_WIO_RDP equ 0x10 -PCNET32_WIO_RAP equ 0x12 -PCNET32_WIO_RESET equ 0x14 -PCNET32_WIO_BDP equ 0x16 -PCNET32_DWIO_RDP equ 0x10 -PCNET32_DWIO_RAP equ 0x14 -PCNET32_DWIO_RESET equ 0x18 -PCNET32_DWIO_BDP equ 0x1C -PCNET32_TOTAL_SIZE equ 0x20 -; ebx - index -; return: -; eax - data -pcnet32_wio_read_csr: - push edx - lea edx, [ebp+PCNET32_WIO_RAP] - mov ax, bx - out dx, ax - lea edx, [ebp+PCNET32_WIO_RDP] - in ax, dx - and eax, 0xffff - pop edx - ret -; eax - data -; ebx - index -pcnet32_wio_write_csr: - push edx - lea edx, [ebp+PCNET32_WIO_RAP] - xchg eax, ebx - out dx, ax - xchg eax, ebx - lea edx, [ebp+PCNET32_WIO_RDP] - out dx, ax - pop edx - ret -; ebx - index -; return: -; eax - data -pcnet32_wio_read_bcr: - push edx - lea edx, [ebp+PCNET32_WIO_RAP] - mov ax, bx - out dx, ax - lea edx, [ebp+PCNET32_WIO_BDP] - in ax, dx - and eax, 0xffff - pop edx - ret -; eax - data -; ebx - index -pcnet32_wio_write_bcr: - push edx - lea edx, [ebp+PCNET32_WIO_RAP] - xchg eax, ebx - out dx, ax - xchg eax, ebx - lea edx, [ebp+PCNET32_WIO_BDP] - out dx, ax - pop edx - ret -pcnet32_wio_read_rap: - push edx - lea edx, [ebp+PCNET32_WIO_RAP] - in ax, dx - and eax, 0xffff - pop edx - ret -; eax - val -pcnet32_wio_write_rap: - push edx - lea edx, [ebp+PCNET32_WIO_RAP] - out dx, ax - pop edx - ret -pcnet32_wio_reset: - push edx - push eax - lea edx, [ebp+PCNET32_WIO_RESET] - in ax, dx - pop eax - pop edx - ret -pcnet32_wio_check: - push edx - mov ax, 88 - lea edx, [ebp+PCNET32_WIO_RAP] - out dx, ax - nop - nop - in ax, dx - cmp ax, 88 - sete al - pop edx - ret - -iglobal -pcnet32_wio: - dd pcnet32_wio_read_csr - dd pcnet32_wio_write_csr - dd pcnet32_wio_read_bcr - dd pcnet32_wio_write_bcr - dd pcnet32_wio_read_rap - dd pcnet32_wio_write_rap - dd pcnet32_wio_reset -endg - -; ebx - index -; return: -; eax - data -pcnet32_dwio_read_csr: - push edx - lea edx, [ebp+PCNET32_DWIO_RAP] - mov eax, ebx - out dx, eax - lea edx, [ebp+PCNET32_DWIO_RDP] - in eax, dx - and eax, 0xffff - pop edx - ret -; ebx - index -; eax - data -pcnet32_dwio_write_csr: - push edx - lea edx, [ebp+PCNET32_DWIO_RAP] - xchg eax, ebx - out dx, eax - lea edx, [ebp+PCNET32_DWIO_RDP] - xchg eax, ebx - out dx, eax - pop edx - ret -; ebx - index -; return: -; eax - data -pcnet32_dwio_read_bcr: - push edx - lea edx, [ebp+PCNET32_DWIO_RAP] - mov eax, ebx - out dx, eax - lea edx, [ebp+PCNET32_DWIO_BDP] - in eax, dx - and eax, 0xffff - pop edx - ret -; ebx - index -; eax - data -pcnet32_dwio_write_bcr: - push edx - lea edx, [ebp+PCNET32_DWIO_RAP] - xchg eax, ebx - out dx, eax - lea edx, [ebp+PCNET32_DWIO_BDP] - xchg eax, ebx - out dx, eax - pop edx - ret -pcnet32_dwio_read_rap: - push edx - lea edx, [ebp+PCNET32_DWIO_RAP] - in eax, dx - and eax, 0xffff - pop edx - ret -; eax - val -pcnet32_dwio_write_rap: - push edx - lea edx, [ebp+PCNET32_DWIO_RAP] - out dx, eax - pop edx - ret -pcnet32_dwio_reset: - push edx - push eax - lea edx, [ebp+PCNET32_DWIO_RESET] - in eax, dx - pop eax - pop edx - ret -pcnet32_dwio_check: - push edx - lea edx, [PCNET32_DWIO_RAP] - mov eax, 88 - out dx, eax - nop - nop - in eax, dx - and eax, 0xffff - cmp eax, 88 - sete al - pop edx - ret - -iglobal -pcnet32_dwio: - dd pcnet32_dwio_read_csr - dd pcnet32_dwio_write_csr - dd pcnet32_dwio_read_bcr - dd pcnet32_dwio_write_bcr - dd pcnet32_dwio_read_rap - dd pcnet32_dwio_write_rap - dd pcnet32_dwio_reset -endg - - - -pcnet32_init_ring: - mov [pcnet32_private.tx_full], 0 - mov [pcnet32_private.cur_rx], 0 - mov [pcnet32_private.cur_tx], 0 - mov [pcnet32_private.dirty_rx], 0 - mov [pcnet32_private.dirty_tx], 0 - mov edi, pcnet32_rx_ring - mov ecx, PCNET32_RX_RING_SIZE - mov ebx, pcnet32_rxb - sub ebx, OS_BASE -.rx_init: - mov [edi+pcnet32_rx_head.base], ebx - mov [edi+pcnet32_rx_head.buf_length], word PCNET32_PKT_BUF_SZ_NEG - mov [edi+pcnet32_rx_head.status], word 0x8000 - add ebx, PCNET32_PKT_BUF_SZ -; inc ebx - add edi, 16 - loop .rx_init - mov edi, pcnet32_tx_ring - mov ecx, PCNET32_TX_RING_SIZE -.tx_init: - mov [edi+pcnet32_tx_head.base], dword 0 - mov [edi+pcnet32_tx_head.status], word 0 - add edi, 16 - loop .tx_init - mov [pcnet32_private.tlen_rlen], (PCNET32_TX_RING_LEN_BITS or PCNET32_RX_RING_LEN_BITS) - mov esi, node_addr - mov edi, pcnet32_private.phys_addr - cld - movsd - movsw - mov eax, pcnet32_rx_ring - sub eax, OS_BASE - mov dword [pcnet32_private.rx_ring], eax - - mov eax, pcnet32_tx_ring - sub eax, OS_BASE - mov dword [pcnet32_private.tx_ring], eax - ret - - - -pcnet32_reset: - ; Reset PCNET32 - mov ebp, [io_addr] - call dword [pcnet32_access.reset] - ; set 32bit mode - mov ebx, 20 - mov eax, 2 - call dword [pcnet32_access.write_bcr] - ; set/reset autoselect bit - mov ebx, 2 - call dword [pcnet32_access.read_bcr] - and eax, not 2 - test [pcnet32_private.options], PCNET32_PORT_ASEL - jz .L1 - or eax, 2 -.L1: - call dword [pcnet32_access.write_bcr] - ; Handle full duplex setting - cmp byte [pcnet32_private.full_duplex], 0 - je .L2 - mov ebx, 9 - call dword [pcnet32_access.read_bcr] - and eax, not 3 - test [pcnet32_private.options], PCNET32_PORT_FD - jz .L3 - or eax, 1 - cmp [pcnet32_private.options], PCNET32_PORT_FD or PCNET32_PORT_AUI - jne .L4 - or eax, 2 - jmp .L4 -.L3: - test [pcnet32_private.options], PCNET32_PORT_ASEL - jz .L4 - cmp [pcnet32_private.chip_version], 0x2627 - jne .L4 - or eax, 3 -.L4: - mov ebx, 9 - call dword [pcnet32_access.write_bcr] -.L2: - ; set/reset GPSI bit - mov ebx, 124 - call dword [pcnet32_access.read_csr] - mov ecx, [pcnet32_private.options] - and ecx, PCNET32_PORT_PORTSEL - cmp ecx, PCNET32_PORT_GPSI - jne .L5 - or eax, 0x10 -.L5: - call dword [pcnet32_access.write_csr] - cmp [pcnet32_private.mii], 0 - je .L6 - test [pcnet32_private.options], PCNET32_PORT_ASEL - jnz .L6 - mov ebx, 32 - call dword [pcnet32_access.read_bcr] - and eax, not 0x38 - test [pcnet32_private.options], PCNET32_PORT_FD - jz .L7 - or eax, 0x10 -.L7: - test [pcnet32_private.options], PCNET32_PORT_100 - jz .L8 - or eax, 0x08 -.L8: - call dword [pcnet32_access.write_bcr] - jmp .L9 -.L6: - test [pcnet32_private.options], PCNET32_PORT_ASEL - jz .L9 - mov ebx, 32 -; DEBUGF 1," K : ASEL, enable auto-negotiation\n" - call dword [pcnet32_access.read_bcr] - and eax, not 0x98 - or eax, 0x20 - call dword [pcnet32_access.write_bcr] -.L9: - cmp [pcnet32_private.ltint], 0 - je .L10 - mov ebx, 5 - call dword [pcnet32_access.read_csr] - or eax, (1 shl 14) - call dword [pcnet32_access.write_csr] -.L10: - mov eax, [pcnet32_private.options] - and eax, PCNET32_PORT_PORTSEL - shl eax, 7 - mov [pcnet32_private.mode], ax - mov [pcnet32_private.filter], dword 0xffffffff - mov [pcnet32_private.filter+4], dword 0xffffffff - call pcnet32_init_ring - mov ebx, 1 - mov eax, pcnet32_private - sub eax, OS_BASE - and eax, 0xffff - call dword [pcnet32_access.write_csr] - mov eax, pcnet32_private - sub eax, OS_BASE - mov ebx, 2 - shr eax, 16 - call dword [pcnet32_access.write_csr] - mov ebx, 4 - mov eax, 0x0915 - call dword [pcnet32_access.write_csr] - mov ebx, 0 - mov eax, 1 - call dword [pcnet32_access.write_csr] - mov ecx, 100 -.L11: - xor ebx, ebx - call dword [pcnet32_access.read_csr] - test ax, 0x100 - jnz .L12 - loop .L11 -.L12: -; DEBUGF 1," K : hardware reset\n" - xor ebx, ebx - mov eax, 0x0002 - call dword [pcnet32_access.write_csr] - xor ebx, ebx - call dword [pcnet32_access.read_csr] -; DEBUGF 1," K : PCNET reset complete\n" - ret - - - -pcnet32_adjust_pci_device: - ;*******Get current setting************************ - mov al, 2 ;read a word - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, 0x04 ;from command Register - call pci_read_reg - ;******see if its already set as bus master******** - mov bx, ax - and bx, 5 - cmp bx, 5 - je pcnet32_adjust_pci_device_Latency - ;******Make card a bus master******* - mov cx, ax ;value to write - mov bh, [pci_dev] - mov al, 2 ;write a word - or cx, 5 - mov ah, [pci_bus] - mov bl, 0x04 ;to command register - call pci_write_reg - ;******Check latency setting*********** -pcnet32_adjust_pci_device_Latency: - ;*******Get current latency setting************************ -; mov al, 1 ;read a byte -; mov bh, [pci_dev] -; mov ah, [pci_bus] -; mov bl, 0x0D ;from Lantency Timer Register -; call pci_read_reg - ;******see if its aat least 64 clocks******** -; cmp ax,64 -; jge pcnet32_adjust_pci_device_Done - ;******Set latency to 32 clocks******* -; mov cx, 64 ;value to write -; mov bh, [pci_dev] -; mov al, 1 ;write a byte -; mov ah, [pci_bus] -; mov bl, 0x0D ;to Lantency Timer Register -; call pci_write_reg - ;******Check latency setting*********** -pcnet32_adjust_pci_device_Done: - ret - - - - -pcnet32_probe: - mov ebp, [io_addr] - call pcnet32_wio_reset - xor ebx, ebx - call pcnet32_wio_read_csr - cmp eax, 4 - jne .try_dwio - call pcnet32_wio_check - and al, al - jz .try_dwio -; DEBUGF 1," K : Using WIO\n" - mov esi, pcnet32_wio - jmp .L1 -.try_dwio: - call pcnet32_dwio_reset - xor ebx, ebx - call pcnet32_dwio_read_csr - cmp eax, 4 - jne .no_dev - call pcnet32_dwio_check - and al, al - jz .no_dev -; DEBUGF 1," K : Using DWIO\n" - mov esi, pcnet32_dwio - jmp .L1 -.no_dev: - DEBUGF 1," K : PCNET32 not found\n" - ret -.L1: - mov edi, pcnet32_access - mov ecx, 7 - cld - rep movsd - mov ebx, 88 - call dword [pcnet32_access.read_csr] - mov ecx, eax - mov ebx, 89 - call dword [pcnet32_access.read_csr] - shl eax, 16 - or eax, ecx - mov ecx, eax - and ecx, 0xfff - cmp ecx, 3 - jne .no_dev - shr eax, 12 - and eax, 0xffff - mov [pcnet32_private.chip_version], eax -; DEBUGF 1," K : PCNET32 chip version OK\n" - mov [pcnet32_private.fdx], 0 - mov [pcnet32_private.mii], 0 - mov [pcnet32_private.fset], 0 - mov [pcnet32_private.dxsuflo], 0 - mov [pcnet32_private.ltint], 0 - mov eax, [pcnet32_private.chip_version] - cmp eax, 0x2420 - je .L2 - cmp eax, 0x2430 - je .L3 - cmp eax, 0x2621 - je .L4 - cmp eax, 0x2623 - je .L5 - cmp eax, 0x2624 - je .L6 - cmp eax, 0x2625 - je .L7 - cmp eax, 0x2626 - je .L8 - cmp eax, 0x2627 - je .L9 - DEBUGF 1," K : Invalid chip rev\n" - jmp .no_dev -.L2: -; DEBUGF 1," K : PCnet/PCI 79C970\n" - jmp .L10 -.L3: -; DEBUGF 1," K : PCnet/PCI 79C970\n" - jmp .L10 -.L4: -; DEBUGF 1," K : PCnet/PCI II 79C970A\n" - mov [pcnet32_private.fdx], 1 - jmp .L10 -.L5: -; DEBUGF 1," K : PCnet/FAST 79C971\n" - mov [pcnet32_private.fdx], 1 - mov [pcnet32_private.mii], 1 - mov [pcnet32_private.fset], 1 - mov [pcnet32_private.ltint], 1 - jmp .L10 -.L6: -; DEBUGF 1," K : PCnet/FAST+ 79C972\n" - mov [pcnet32_private.fdx], 1 - mov [pcnet32_private.mii], 1 - mov [pcnet32_private.fset], 1 - jmp .L10 -.L7: -; DEBUGF 1," K : PCnet/FAST III 79C973\n" - mov [pcnet32_private.fdx], 1 - mov [pcnet32_private.mii], 1 - jmp .L10 -.L8: -; DEBUGF 1," K : PCnet/Home 79C978\n" - mov [pcnet32_private.fdx], 1 - mov ebx, 49 - call dword [pcnet32_access.read_bcr] - call dword [pcnet32_access.write_bcr] - jmp .L10 -.L9: -; DEBUGF 1," K : PCnet/FAST III 79C975\n" - mov [pcnet32_private.fdx], 1 - mov [pcnet32_private.mii], 1 -.L10: - cmp [pcnet32_private.fset], 1 - jne .L11 - mov ebx, 18 - call dword [pcnet32_access.read_bcr] - or eax, 0x800 - call dword [pcnet32_access.write_bcr] - mov ebx, 80 - call dword [pcnet32_access.read_csr] - and eax, 0xc00 - or eax, 0xc00 - call dword [pcnet32_access.write_csr] - mov [pcnet32_private.dxsuflo], 1 - mov [pcnet32_private.ltint], 1 -.L11: - ; read MAC - mov edi, node_addr - mov edx, ebp - mov ecx, 6 -.Lmac: - in al, dx - stosb - inc edx - loop .Lmac -; DEBUGF 1," K : MAC read\n" - call pcnet32_adjust_pci_device -; DEBUGF 1," K : PCI done\n" - mov eax, PCNET32_PORT_ASEL - mov [pcnet32_private.options], eax - mov [pcnet32_private.mode], word 0x0003 - mov [pcnet32_private.tlen_rlen], word (PCNET32_TX_RING_LEN_BITS or PCNET32_RX_RING_LEN_BITS) - mov esi, node_addr - mov edi, pcnet32_private.phys_addr - cld - movsd - movsw - mov [pcnet32_private.filter], dword 0 - mov [pcnet32_private.filter+4], dword 0 - mov eax, pcnet32_rx_ring - sub eax, OS_BASE - mov dword [pcnet32_private.rx_ring], eax - - mov eax, pcnet32_tx_ring - sub eax, OS_BASE - mov dword [pcnet32_private.tx_ring], eax -; DEBUGF 1," K : Switching to 32\n" - mov ebx, 20 - mov eax, 2 - call dword [pcnet32_access.write_bcr] - mov ebx, 1 - mov eax, ((pcnet32_private - OS_BASE) and 0xffff) - call dword [pcnet32_access.write_csr] - mov ebx, 2 - mov eax, ((pcnet32_private - OS_BASE) shr 16) and 0xffff - call dword [pcnet32_access.write_csr] - mov ebx, 0 - mov eax, 1 - call dword [pcnet32_access.write_csr] - mov esi, 1 - call delay_ms - call pcnet32_reset - mov eax, [pci_data] - mov [eth_status], eax - ret - - - -pcnet32_poll: - xor ax, ax - mov [eth_rx_data_len], ax - mov eax, [pcnet32_private.cur_rx] - and eax, PCNET32_RX_RING_MOD_MASK - mov ebx, eax - imul esi, eax, PCNET32_PKT_BUF_SZ - add esi, pcnet32_rxb - shl ebx, 4 - add ebx, pcnet32_rx_ring - mov cx, [ebx+pcnet32_rx_head.status] - test cx, 0x8000 - jnz .L1 - cmp ch, 3 - jne .L1 - mov ecx, [ebx+pcnet32_rx_head.msg_length] - and ecx, 0xfff - sub ecx, 4 - mov [eth_rx_data_len], cx -; DEBUGF 1," K : PCNETRX: %ub\n",cx - push ecx - shr ecx, 2 - mov edi, Ether_buffer - cld - rep movsd - pop ecx - and ecx, 3 - rep movsb - mov [ebx+pcnet32_rx_head.buf_length], word PCNET32_PKT_BUF_SZ_NEG - or [ebx+pcnet32_rx_head.status], word 0x8000 - inc [pcnet32_private.cur_rx] -.L1: - ret - - - - -; Pointer to 48 bit destination address in edi -; Type of packet in bx -; size of packet in ecx -; pointer to packet data in esi -pcnet32_xmit: - push edi - push esi - push ebx - push ecx -; DEBUGF 1," K : PCNETTX\n" - mov esi, edi - mov edi, [pcnet32_private.cur_tx] - imul edi, PCNET32_PKT_BUF_SZ - add edi, pcnet32_txb; edi=ptxb - mov eax, edi - cld ; copy MAC - movsd - movsw - mov esi, node_addr - cld - movsd - movsw - mov [edi], bx - add edi, 2 - mov esi, [esp+8] - mov ecx, [esp] - push ecx - shr ecx, 2 - cld - rep movsd - pop ecx - and ecx, 3 - rep movsb -; mov ecx,[esp] -; add ecx,14 ; ETH_HLEN -; xor eax,eax -; pad to min length (60=ETH_ZLEN) -; cmp ecx,60 -; jae .L1 -; sub ecx,60 -; cld -; rep stosb -;.L1: - mov edi, pcnet32_tx_ring+0; entry=0 - mov ecx, [esp] - add ecx, 14 - cmp cx, 60 - jae .L1 - mov cx, 60 -.L1: - neg cx - mov [edi+pcnet32_tx_head.length], cx - mov [edi+pcnet32_tx_head.misc], dword 0 - sub eax, OS_BASE - mov [edi+pcnet32_tx_head.base], eax - mov [edi+pcnet32_tx_head.status], word 0x8300 - ; trigger an immediate send poll - mov ebx, 0 - mov eax, 0x0008; 0x0048 - mov ebp, [io_addr] - call dword [pcnet32_access.write_csr] - mov dword [pcnet32_private.cur_tx], 0 - ; wait for TX to complete - mov ecx, [timer_ticks];[0xfdf0] - add ecx, 100 -.L2: - mov ax, [edi+pcnet32_tx_head.status] - test ax, 0x8000 - jz .L3 - cmp ecx, [timer_ticks];[0xfdf0] - jb .L4 - mov esi, 10 - call delay_ms - jnz .L2 -.L4: - DEBUGF 1," K : PCNET: Send timeout\n" -.L3: - mov dword [edi+pcnet32_tx_head.base], 0 - pop ecx - pop ebx - pop esi - pop edi - ret diff --git a/kernel/trunk/network/eth_drv/drivers/r6040.inc b/kernel/trunk/network/eth_drv/drivers/r6040.inc deleted file mode 100644 index 7480fce93f..0000000000 --- a/kernel/trunk/network/eth_drv/drivers/r6040.inc +++ /dev/null @@ -1,813 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; R6040 driver for KolibriOS ;; -;; ;; -;; based on R6040.c from linux ;; -;; ;; -;; Written by Asper (asper.85@mail.ru) ;; -;; and hidnplayr (hidnplayr@gmail.com) ;; -;; ;; -;; GNU GENERAL PUBLIC LICENSE ;; -;; Version 2, June 1991 ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - - -;******************************************************************** -; Interface -; r6040_reset -; r6040_probe -; r6040_poll -; r6040_transmit -; -; These functions are referenced in ethernet.inc -; -;******************************************************************** - -;; A few user-configurable values. - -TX_RING_SIZE equ 4 -RX_RING_SIZE equ 4 - -; ethernet address length -ETH_ALEN equ 6 -ETH_HLEN equ (2 * ETH_ALEN + 2) -ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for - ; mininmum 64bytes frame length -; system timer frequency -HZ equ 1000 - -; max time out delay time -W_MAX_TIMEOUT equ 0x0FFF - -;; Size of the in-memory receive ring. -RX_BUF_LEN_IDX equ 3 ;; 0==8K, 1==16K, 2==32K, 3==64K -RX_BUF_LEN equ (8192 << RX_BUF_LEN_IDX) - -;-; Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). -;-TX_BUF_SIZE equ 1536 -;-RX_BUF_SIZE equ 1536 - -;; PCI Tuning Parameters -; Threshold is bytes transferred to chip before transmission starts. -TX_FIFO_THRESH equ 256 ;; In bytes, rounded down to 32 byte units. - -;; The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. -RX_FIFO_THRESH equ 4 ;; Rx buffer level before first PCI xfer. -RX_DMA_BURST equ 4 ;; Maximum PCI burst, '4' is 256 bytes -TX_DMA_BURST equ 4 - -;; Operational parameters that usually are not changed. -PHY1_ADDR equ 1 ;For MAC1 -PHY2_ADDR equ 3 ;For MAC2 -PHY_MODE equ 0x3100 ;PHY CHIP Register 0 -PHY_CAP equ 0x01E1 ;PHY CHIP Register 4 - -;; Time in jiffies before concluding the transmitter is hung. -TX_TIMEOUT equ ((6000*HZ)/1000) - -R6040_IO_SIZE equ 256 ; RDC MAC I/O Size -MAX_MAC equ 2 ; MAX RDC MAC - -;************************************************************************** -; RDC R6040 Register Definitions -;************************************************************************** -MCR0 equ 0x00 ;Control register 0 -MCR1 equ 0x01 ;Control register 1 -MAC_RST equ 0x0001 ;Reset the MAC -MBCR equ 0x08 ;Bus control -MT_ICR equ 0x0C ;TX interrupt control -MR_ICR equ 0x10 ;RX interrupt control -MTPR equ 0x14 ;TX poll command register -MR_BSR equ 0x18 ;RX buffer size -MR_DCR equ 0x1A ;RX descriptor control -MLSR equ 0x1C ;Last status -MMDIO equ 0x20 ;MDIO control register -MDIO_WRITE equ 0x4000 ;MDIO write -MDIO_READ equ 0x2000 ;MDIO read -MMRD equ 0x24 ;MDIO read data register -MMWD equ 0x28 ;MDIO write data register -MTD_SA0 equ 0x2C ;TX descriptor start address 0 -MTD_SA1 equ 0x30 ;TX descriptor start address 1 -MRD_SA0 equ 0x34 ;RX descriptor start address 0 -MRD_SA1 equ 0x38 ;RX descriptor start address 1 -MISR equ 0x3C ;Status register -MIER equ 0x40 ;INT enable register -MSK_INT equ 0x0000 ;Mask off interrupts -RX_FINISH equ 0x0001 ;RX finished -RX_NO_DESC equ 0x0002 ;No RX descriptor available -RX_FIFO_FULL equ 0x0004 ;RX FIFO full -RX_EARLY equ 0x0008 ;RX early -TX_FINISH equ 0x0010 ;TX finished -TX_EARLY equ 0x0080 ;TX early -EVENT_OVRFL equ 0x0100 ;Event counter overflow -LINK_CHANGED equ 0x0200 ;PHY link changed -ME_CISR equ 0x44 ;Event counter INT status -ME_CIER equ 0x48 ;Event counter INT enable -MR_CNT equ 0x50 ;Successfully received packet counter -ME_CNT0 equ 0x52 ;Event counter 0 -ME_CNT1 equ 0x54 ;Event counter 1 -ME_CNT2 equ 0x56 ;Event counter 2 -ME_CNT3 equ 0x58 ;Event counter 3 -MT_CNT equ 0x5A ;Successfully transmit packet counter -ME_CNT4 equ 0x5C ;Event counter 4 -MP_CNT equ 0x5E ;Pause frame counter register -MAR0 equ 0x60 ;Hash table 0 -MAR1 equ 0x62 ;Hash table 1 -MAR2 equ 0x64 ;Hash table 2 -MAR3 equ 0x66 ;Hash table 3 -MID_0L equ 0x68 ;Multicast address MID0 Low -MID_0M equ 0x6A ;Multicast address MID0 Medium -MID_0H equ 0x6C ;Multicast address MID0 High -MID_1L equ 0x70 ;MID1 Low -MID_1M equ 0x72 ;MID1 Medium -MID_1H equ 0x74 ;MID1 High -MID_2L equ 0x78 ;MID2 Low -MID_2M equ 0x7A ;MID2 Medium -MID_2H equ 0x7C ;MID2 High -MID_3L equ 0x80 ;MID3 Low -MID_3M equ 0x82 ;MID3 Medium -MID_3H equ 0x84 ;MID3 High -PHY_CC equ 0x88 ;PHY status change configuration register -PHY_ST equ 0x8A ;PHY status register -MAC_SM equ 0xAC ;MAC status machine -MAC_ID equ 0xBE ;Identifier register - -MAX_BUF_SIZE equ 0x600 ;1536 - -MBCR_DEFAULT equ 0x012A ;MAC Bus Control Register -MCAST_MAX equ 3 ;Max number multicast addresses to filter - -;Descriptor status -DSC_OWNER_MAC equ 0x8000 ;MAC is the owner of this descriptor -DSC_RX_OK equ 0x4000 ;RX was successfull -DSC_RX_ERR equ 0x0800 ;RX PHY error -DSC_RX_ERR_DRI equ 0x0400 ;RX dribble packet -DSC_RX_ERR_BUF equ 0x0200 ;RX length exceeds buffer size -DSC_RX_ERR_LONG equ 0x0100 ;RX length > maximum packet length -DSC_RX_ERR_RUNT equ 0x0080 ;RX packet length < 64 byte -DSC_RX_ERR_CRC equ 0x0040 ;RX CRC error -DSC_RX_BCAST equ 0x0020 ;RX broadcast (no error) -DSC_RX_MCAST equ 0x0010 ;RX multicast (no error) -DSC_RX_MCH_HIT equ 0x0008 ;RX multicast hit in hash table (no error) -DSC_RX_MIDH_HIT equ 0x0004 ;RX MID table hit (no error) -DSC_RX_IDX_MID_MASK equ 3 ;RX mask for the index of matched MIDx - -;PHY settings -ICPLUS_PHY_ID equ 0x0243 - -RX_INTS equ RX_FIFO_FULL or RX_NO_DESC or RX_FINISH -TX_INTS equ TX_FINISH -INT_MASK equ RX_INTS or TX_INTS - - -r6040_txb equ (eth_data_start) -r6040_rxb equ ((r6040_txb+(MAX_BUF_SIZE*TX_RING_SIZE)+32) and 0xfffffff0) -r6040_tx_ring equ ((r6040_rxb+(MAX_BUF_SIZE*RX_RING_SIZE)+32) and 0xfffffff0) -r6040_rx_ring equ ((r6040_tx_ring+(r6040_x_head.sizeof*TX_RING_SIZE)+32) and 0xfffffff0) - -virtual at ((r6040_rx_ring+(r6040_x_head.sizeof*RX_RING_SIZE)+32) and 0xfffffff0) -r6040_private: - .rx_ring dd ? - .tx_ring dd ? - .cur_rx dw ? - .cur_tx dw ? - .phy_addr dw ? - .phy_mode dw ? - .mcr0 dw ? - .mcr1 dw ? - .switch_sig dw ? -end virtual - -virtual at 0 -r6040_x_head: - .status dw ? ;0-1 - .len dw ? ;2-3 - .buf dd ? ;4-7 - .ndesc dd ? ;8-B - .rev1 dd ? ;C-F - .vbufp dd ? ;10-13 - .vndescp dd ? ;14-17 - .skb_ptr dd ? ;18-1B - .rev2 dd ? ;1C-1F - .sizeof: -end virtual - - - -; Read a word data from PHY Chip -proc r6040_phy_read stdcall, phy_addr:dword, reg:dword - push ecx edx - mov eax, [phy_addr] - shl eax, 8 - add eax, [reg] - add eax, MDIO_READ - mov edx, [io_addr] - add edx, MMDIO - out dx, ax - ;Wait for the read bit to be cleared. - mov ecx, 2048 ;limit - xor eax, eax - .read: - in ax, dx - test ax, MDIO_READ - jz @f - dec ecx - test ecx, ecx - jnz .read - @@: - mov edx, [io_addr] - add edx, MMRD - in ax, dx - and eax, 0xFFFF - pop edx ecx - ret -endp - -; Write a word data to PHY Chip -proc r6040_phy_write stdcall, phy_addr:dword, reg:dword, val:dword - push eax ecx edx - mov eax, [val] - mov edx, [io_addr] - add edx, MMWD - out dx, ax - ;Write the command to the MDIO bus - mov eax, [phy_addr] - shl eax, 8 - add eax, [reg] - add eax, MDIO_WRITE - mov edx, [io_addr] - add edx, MMDIO - out dx, ax - ;Wait for the write bit to be cleared. - mov ecx, 2048 ;limit - xor eax, eax - .write: - in ax, dx - test ax, MDIO_WRITE - jz @f - dec ecx - test ecx, ecx - jnz .write - @@: - pop edx ecx eax - ret -endp - -macro r6040_mdio_write reg, val { - stdcall r6040_phy_read, [io_addr], [r6040_private.phy_addr], reg -} - -macro r6040_mdio_write reg, val { - stdcall r6040_phy_write, [io_addr], [r6040_private.phy_addr], reg, val -} - - -proc r6040_init_ring_desc stdcall, desc_ring:dword, size:dword - push eax ecx esi - mov ecx, [size] - test ecx, ecx - jz .out - - mov esi, [desc_ring] - mov eax, esi - .next_desc: - add eax, r6040_x_head.sizeof - OS_BASE - mov [esi+r6040_x_head.ndesc], eax - add eax, OS_BASE - mov [esi+r6040_x_head.vndescp], eax - mov esi, eax - dec ecx - jnz .next_desc - - sub esi, r6040_x_head.sizeof - mov eax, [desc_ring] - mov [esi+r6040_x_head.vndescp], eax - sub eax, OS_BASE - mov [esi+r6040_x_head.ndesc], eax - .out: - pop esi ecx eax - ret -endp - - - - -r6040_init_rxbufs: - - stdcall r6040_init_ring_desc, r6040_rx_ring, RX_RING_SIZE - - ; Allocate skbs for the rx descriptors - mov esi, r6040_rx_ring - mov ebx, r6040_rxb - mov ecx, RX_RING_SIZE - mov eax, r6040_rx_ring - .next_desc: - mov [esi+r6040_x_head.skb_ptr], ebx - mov [esi+r6040_x_head.buf], ebx - sub [esi+r6040_x_head.buf], OS_BASE - mov [esi+r6040_x_head.status], DSC_OWNER_MAC - - mov eax, [esi+r6040_x_head.vndescp] - mov esi, eax - - add ebx, MAX_BUF_SIZE - dec ecx - jnz .next_desc - - xor eax, eax - .out: - - ret - - -r6040_probe: - - DEBUGF 1, "Probing r6040\n" - - call adjust_pci_device - - - ; If PHY status change register is still set to zero - ; it means the bootloader didn't initialize it - mov edx, [io_addr] - add edx, PHY_CC - in ax, dx - test ax, ax - jnz @f - mov eax, 0x9F07 - out dx, ax - @@: - ; Set MAC address - mov ecx, 3 - mov edi, node_addr - mov edx, [io_addr] - add edx, MID_0L - .mac: - in ax, dx - stosw - add edx, 2 - dec ecx - jnz .mac - ; Some bootloaders/BIOSes do not initialize - ; MAC address, warn about that - and eax, 0xFF - or eax, [node_addr] - test eax, eax - jnz @f - DEBUGF 1, "K : MAC address not initialized\n" ;, generating random" - ;Asper: Add here generate function call! - ; Temporary workaround: init by constant adress - mov dword [node_addr], 0x00006000 - mov word [node_addr+4], 0x0001 - @@: - ; Init RDC private data - mov [r6040_private.mcr0], 0x1002 - ;mov [r6040_private.phy_addr], 1 ; Asper: Only one network card is supported now. - mov [r6040_private.switch_sig], 0 - - ; Check the vendor ID on the PHY, if 0xFFFF assume none attached - stdcall r6040_phy_read, 1, 2 - cmp ax, 0xFFFF - jne @f - DEBUGF 1, "K : Failed to detect an attached PHY\n" ;, generating random" - mov eax, -1 - ret - @@: - - ; Set MAC address - call r6040_mac_address - - - ; Initialize and alloc RX/TX buffers - stdcall r6040_init_ring_desc, r6040_tx_ring, TX_RING_SIZE - call r6040_init_rxbufs ;r6040_alloc_rxbufs - test eax, eax - jnz .out - - ; Read the PHY ID - mov [r6040_private.phy_mode], 0x8000 - stdcall r6040_phy_read, 0, 2 - mov [r6040_private.switch_sig], ax - cmp ax, ICPLUS_PHY_ID - jne @f - stdcall r6040_phy_write, 29, 31, 0x175C ; Enable registers - jmp .phy_readen - @@: - - ; PHY Mode Check - movzx eax, [r6040_private.phy_addr] - stdcall r6040_phy_write, eax, 4, PHY_CAP - stdcall r6040_phy_write, eax, 0, PHY_MODE -; if PHY_MODE = 0x3100 - call r6040_phy_mode_chk - mov [r6040_private.phy_mode], ax - jmp .phy_readen -; end if -; if not (PHY_MODE and 0x0100) - mov [r6040_private.phy_mode], 0 -; end if - .phy_readen: - - ; Set duplex mode - mov ax, [r6040_private.phy_mode] - or [r6040_private.mcr0], ax - - ; improve performance (by RDC guys) - stdcall r6040_phy_read, 30, 17 - or ax, 0x4000 - stdcall r6040_phy_write, 30, 17, eax - - stdcall r6040_phy_read, 30, 17 - xor ax, -1 - or ax, 0x2000 - xor ax, -1 - stdcall r6040_phy_write, 30, 17, eax - - stdcall r6040_phy_write, 0, 19, 0x0000 - stdcall r6040_phy_write, 0, 30, 0x01F0 - - ; Initialize all Mac registers - call r6040_reset - - xor eax, eax - .out: - ret - - - - - - -align 4 -r6040_reset: - - DEBUGF 1, "Resetting r6040\n" - - push eax ecx edx - ; Mask off Interrupt - mov eax, MSK_INT - mov edx, [io_addr] - add edx, MIER - out dx, ax - - ;Reset RDC MAC - mov eax, MAC_RST - mov edx, [io_addr] - add edx, MCR1 - out dx, ax - - mov ecx, 2048 ;limit - .read: - in ax, dx - test ax, 0x1 - jnz @f - dec ecx - test ecx, ecx - jnz .read - @@: - ;Reset internal state machine - mov ax, 2 - mov edx, [io_addr] - add edx, MAC_SM - out dx, ax - xor ax, ax - out dx, ax - mov esi, 5 - call delay_ms - - ;MAC Bus Control Register - mov ax, MBCR_DEFAULT - mov edx, [io_addr] - add edx, MBCR - out dx, ax - - ;Buffer Size Register - mov ax, MAX_BUF_SIZE - mov edx, [io_addr] - add edx, MR_BSR - out dx, ax - - ;Write TX ring start address - mov eax, r6040_tx_ring - OS_BASE ;Asper: Maybe we can just write dword? Hidnplayr: better use word, as described in datasheet. - mov edx, [io_addr] - add edx, MTD_SA0 - out dx, ax - shr eax, 16 - add edx, MTD_SA1 - MTD_SA0 - out dx, ax - - ;Write RX ring start address - mov eax, r6040_rx_ring - OS_BASE ;Asper: Maybe we can just write dword? - mov edx, [io_addr] - add edx, MRD_SA0 - out dx, ax - shr eax, 16 - add edx, MRD_SA1 - MRD_SA0 - out dx, ax - - ;Set interrupt waiting time and packet numbers - xor ax, ax - mov edx, [io_addr] - add edx, MT_ICR - out dx, ax - - ;Asper: ~ Disable ints ;Enable interrupts - ;mov ax, MSK_INT ;INT_MASK ;Asper ~ - ;mov edx, [io_addr] - ;add edx, MIER - ;out dx, ax - - ;Enable TX and RX - mov ax, [r6040_private.mcr0] - or ax, 0x0002 - mov edx, [io_addr] - out dx, ax - - ;Let TX poll the descriptors - ;we may got called by r6040_tx_timeout which has left - ;some unset tx buffers - xor ax, ax - inc ax - mov edx, [io_addr] - add edx, MTPR - out dx, ax - - pop edx ecx eax - - DEBUGF 1, "reset ok!\n" - - ; Indicate that we have successfully reset the card - mov eax, [pci_data] - mov [eth_status], eax - ret - - - -proc r6040_tx_timeout - push eax edx - ;... - inc [stats.tx_errors] - ;Reset MAC and re-init all registers - call r6040_init_mac_regs - pop edx eax - ret -endp - -proc r6040_get_stats - push eax edx - mov edx, [io_addr] - add edx, ME_CNT1 - in al, dx - add [stats.rx_crc_errors], al - mov edx, [io_addr] - add edx, ME_CNT0 - in al, dx - add [stats.multicast], al - pop edx eax - ret -endp - -;... - -proc r6040_phy_mode_chk - push ebx - ;PHY Link Status Check - movzx eax, [r6040_private.phy_addr] - stdcall r6040_phy_read, eax, 1 - test eax, 0x4 - jnz @f - mov eax, 0x8000 ;Link Failed, full duplex - @@: - ;PHY Chip Auto-Negotiation Status - movzx eax, [r6040_private.phy_addr] - stdcall r6040_phy_read, eax, 1 - test eax, 0x0020 - jz .force_mode - ;Auto Negotuiation Mode - movzx eax, [r6040_private.phy_addr] - stdcall r6040_phy_read, eax, 5 - mov ebx, eax - movzx eax, [r6040_private.phy_addr] - stdcall r6040_phy_read, eax, 4 - and eax, ebx - test eax, 0x140 - jz .ret_0 - jmp .ret_0x8000 - .force_mode: - ;Force Mode - movzx eax, [r6040_private.phy_addr] - stdcall r6040_phy_read, eax, 0 - test eax, 0x100 - jz .ret_0 - .ret_0x8000: - mov eax, 0x8000 - pop ebx - ret - .ret_0: - xor eax, eax - pop ebx - ret -endp - - - -;*************************************************************************** -; Function -; r6040_rx -; Description -; polls card to see if there is a packet waiting -; -; Currently only supports one descriptor per packet, if packet is fragmented -; between multiple descriptors you will lose part of the packet -;*************************************************************************** -r6040_poll: - push ebx ecx esi edi - - xor eax, eax - mov [eth_rx_data_len], ax - - movzx eax, [r6040_private.cur_rx] - mov ebx, eax - shl ebx, 5 - - mov cx, [ebx+r6040_rx_ring+r6040_x_head.status] ; Read the descriptor status - test cx, DSC_OWNER_MAC - jnz .out - - test cx, DSC_RX_ERR ; Global error status set - jz .no_dsc_rx_err - ;... - jmp .out - - .no_dsc_rx_err: - ; Packet successfully received - movzx ecx, [ebx+r6040_rx_ring+r6040_x_head.len] - and ecx, 0xFFF - sub ecx, 4 ; Do not count the CRC - mov [eth_rx_data_len], cx - mov esi, [ebx+r6040_rx_ring+r6040_x_head.skb_ptr] - - push ecx - shr ecx, 2 - mov edi, Ether_buffer - cld - rep movsd - pop ecx - and ecx, 3 - rep movsb - - or [ebx+r6040_rx_ring+r6040_x_head.status], DSC_OWNER_MAC - - inc [r6040_private.cur_rx] - and [r6040_private.cur_rx], RX_RING_SIZE-1 - - xor eax, eax - .out: - pop edi esi ecx ebx - ret - - - -;*************************************************************************** -; Function -; r6040_transmit -; Description -; Transmits a packet of data via the ethernet card -; Pointer to 48 bit destination address in edi -; Type of packet in bx -; size of packet in ecx -; pointer to packet data in esi -; -;*************************************************************************** -r6040_transmit: - cmp ecx, MAX_BUF_SIZE - jg .out ; packet is too long - - push edi esi ebx ecx - - movzx eax, [r6040_private.cur_tx] - shl eax, 5 - -; DEBUGF 1,"R6040: TX buffer status: 0x%x, eax=%u\n", [eax + r6040_tx_ring + r6040_x_head.status]:4, eax - - test [r6040_tx_ring + eax + r6040_x_head.status], 0x8000 ; check if buffer is available - jz .l3 - - push ecx esi - mov ecx, [timer_ticks] - add ecx, 100 - .l2: - test [r6040_tx_ring + eax + r6040_x_head.status], 0x8000 - jz .l5 - cmp ecx, [timer_ticks] - jb .l4 - mov esi, 10 - call delay_ms - jmp .l2 - - .l4: - pop esi ecx - DEBUGF 1,"R6040: Send timeout\n" - jmp .out - - .l5: - pop esi ecx - .l3: - push eax - - mov esi, edi - -; point to the current tx buffer - movzx edi, [r6040_private.cur_tx] - imul edi, MAX_BUF_SIZE - add edi, r6040_txb - lea eax, [edi - OS_BASE] ; real buffer address in eax - -; copy destination address - movsd - movsw -; copy source address - mov esi, node_addr - movsd - movsw -; copy packet type - mov [edi], bx - add edi, 2 - - mov esi, [esp+8+4] - mov ecx, [esp+4] -; copy the packet data - push ecx - shr ecx, 2 - rep movsd - pop ecx - and ecx, 3 - rep movsb - - pop edi - - mov ecx, [esp] - add ecx, ETH_HLEN - cmp cx, ETH_ZLEN - jae @f - mov cx, ETH_ZLEN - @@: - - mov [r6040_tx_ring + edi + r6040_x_head.len], cx - mov [r6040_tx_ring + edi + r6040_x_head.buf], eax - mov [r6040_tx_ring + edi + r6040_x_head.status], 0x8000 - - ; Trigger the MAC to check the TX descriptor - mov ax, 0x01 - mov edx, [io_addr] - add edx, MTPR - out dx, ax - - inc [r6040_private.cur_tx] - and [r6040_private.cur_tx], TX_RING_SIZE-1 - xor eax, eax - - pop ecx ebx esi edi - .out: - ret - - - -r6040_mac_address: - push eax ecx edx esi edi - ; MAC operation register - mov ax, 1 - mov edx, [io_addr] - add edx, MCR1 - out dx, ax - ; Reset MAC - mov ax, 2 - mov edx, [io_addr] - add edx, MAC_SM - out dx, ax - ; Reset internal state machine - xor ax, ax - out dx, ax - mov esi, 5 - call delay_ms - - ; Restore MAC Address - mov ecx, 3 - mov edi, node_addr - mov edx, [io_addr] - add edx, MID_0L - .mac: - in ax, dx - stosw - add edx, 2 - dec ecx - jnz .mac - - pop edi esi edx ecx eax - ret - diff --git a/kernel/trunk/network/eth_drv/drivers/rtl8029.inc b/kernel/trunk/network/eth_drv/drivers/rtl8029.inc deleted file mode 100644 index 897eaeeb82..0000000000 --- a/kernel/trunk/network/eth_drv/drivers/rtl8029.inc +++ /dev/null @@ -1,976 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; RTL8029.INC ;; -;; ;; -;; Ethernet driver for Menuet OS ;; -;; ;; -;; Version 0.2 31 July 2002 ;; -;; ;; -;; This driver is based on the ns8390 driver from ;; -;; the etherboot 5.0.6 project. The copyright statement is ;; -;; ;; -;; GNU GENERAL PUBLIC LICENSE ;; -;; Version 2, June 1991 ;; -;; ;; -;; remaining parts Copyright 2002 Mike Hibbett, ;; -;; mikeh@oceanfree.net ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;; While this implementation handles only PCI bus RTL8029 ;; -;; hardware, it can be easily adapted to other NE2000 clone ;; -;; products. I just dont have any to try! ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -;******************************************************************** -; Interface -; rtl8029_reset -; rtl8029_probe -; rtl8029_poll -; rtl8029_transmit -; -;******************************************************************** - - - - -;************************************************************************** -; 8390 Register Definitions -;************************************************************************** -D8390_P0_COMMAND equ 0x00 -D8390_P0_PSTART equ 0x01 -D8390_P0_PSTOP equ 0x02 -D8390_P0_BOUND equ 0x03 -D8390_P0_TSR equ 0x04 -D8390_P0_TPSR equ 0x04 -D8390_P0_TBCR0 equ 0x05 -D8390_P0_TBCR1 equ 0x06 -D8390_P0_ISR equ 0x07 -D8390_P0_RSAR0 equ 0x08 -D8390_P0_RSAR1 equ 0x09 -D8390_P0_RBCR0 equ 0x0A -D8390_P0_RBCR1 equ 0x0B -D8390_P0_RSR equ 0x0C -D8390_P0_RCR equ 0x0C -D8390_P0_TCR equ 0x0D -D8390_P0_DCR equ 0x0E -D8390_P0_IMR equ 0x0F -D8390_P1_COMMAND equ 0x00 -D8390_P1_PAR0 equ 0x01 -D8390_P1_PAR1 equ 0x02 -D8390_P1_PAR2 equ 0x03 -D8390_P1_PAR3 equ 0x04 -D8390_P1_PAR4 equ 0x05 -D8390_P1_PAR5 equ 0x06 -D8390_P1_CURR equ 0x07 -D8390_P1_MAR0 equ 0x08 - -D8390_COMMAND_PS0 equ 0x0 ; Page 0 select -D8390_COMMAND_PS1 equ 0x40 ; Page 1 select -D8390_COMMAND_PS2 equ 0x80 ; Page 2 select -D8390_COMMAND_RD2 equ 0x20 ; Remote DMA control -D8390_COMMAND_RD1 equ 0x10 -D8390_COMMAND_RD0 equ 0x08 -D8390_COMMAND_TXP equ 0x04 ; transmit packet -D8390_COMMAND_STA equ 0x02 ; start -D8390_COMMAND_STP equ 0x01 ; stop - -D8390_COMMAND_RD2_STA equ 0x22 -D8390_COMMAND_RD2_STP equ 0x21 -D8390_COMMAND_RD1_STA equ 0x12 -D8390_COMMAND_RD0_STA equ 0x0A -D8390_COMMAND_PS0_RD2_STP equ 0x21 -D8390_COMMAND_PS1_RD2_STP equ 0x61 -D8390_COMMAND_PS0_RD2_STA equ 0x22 -D8390_COMMAND_PS0_TXP_RD2_STA equ 0x26 - -D8390_RCR_MON equ 0x20 ; monitor mode - -D8390_DCR_FT1 equ 0x40 -D8390_DCR_LS equ 0x08 ; Loopback select -D8390_DCR_WTS equ 0x01 ; Word transfer select - -D8390_DCR_FT1_LS equ 0x48 -D8390_DCR_WTS_FT1_LS equ 0x49 - -D8390_ISR_PRX equ 0x01 ; successful recv -D8390_ISR_PTX equ 0x02 ; successful xmit -D8390_ISR_RXE equ 0x04 ; receive error -D8390_ISR_TXE equ 0x08 ; transmit error -D8390_ISR_OVW equ 0x10 ; Overflow -D8390_ISR_CNT equ 0x20 ; Counter overflow -D8390_ISR_RDC equ 0x40 ; Remote DMA complete -D8390_ISR_RST equ 0x80 ; reset - -D8390_RSTAT_PRX equ 0x01 ; successful recv -D8390_RSTAT_CRC equ 0x02 ; CRC error -D8390_RSTAT_FAE equ 0x04 ; Frame alignment error -D8390_RSTAT_OVER equ 0x08 ; FIFO overrun - -D8390_TXBUF_SIZE equ 6 -D8390_RXBUF_END equ 32 -D8390_PAGE_SIZE equ 256 - -ETH_ALEN equ 6 -ETH_HLEN equ 14 -ETH_ZLEN equ 60 -ETH_FRAME_LEN equ 1514 - -FLAG_PIO equ 0x01 -FLAG_16BIT equ 0x02 -ASIC_PIO equ 0 - -VENDOR_NONE equ 0 -VENDOR_WD equ 1 -VENDOR_NOVELL equ 2 -VENDOR_3COM equ 3 - -NE_ASIC_OFFSET equ 0x10 -NE_RESET equ 0x0F ; Used to reset card -NE_DATA equ 0x00 ; Used to read/write NIC mem - -MEM_8192 equ 32 -MEM_16384 equ 64 -MEM_32768 equ 128 - -ISA_MAX_ADDR equ 0x400 - -uglobal -eth_flags: - db 0 -eth_vendor: - db 0 -eth_nic_base: - dw 0 -eth_asic_base: - dw 0 -eth_memsize: - db 0 -eth_rx_start: - db 0 -eth_tx_start: - db 0 -eth_bmem: - dd 0 -eth_rmem: - dd 0 -romdata: - db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -endg - -iglobal -test_data: - db 'NE*000 memory',0 -test_buffer: - db ' ',0 -endg - -uglobal -eth_type: - dw 0 -pkthdr: - db 0,0,0,0 ; status, next, (short) len -pktoff: - dw 0 -eth_rx_data_ptr: - dd 0 -eth_tmp_len: - dw 0 -endg - - - -;*************************************************************************** -; Function -; eth_pio_read -; -; Description -; Read a frame from the ethernet card via Programmed I/O -; src in ebx -; cnt in ecx -; dst in edi -;*************************************************************************** -eth_pio_read: - mov al, [eth_flags] - and al, FLAG_16BIT - cmp al, 0 - je epr_001 - - inc ecx - and ecx, 0xFFFFFFFE - -epr_001: - mov al, D8390_COMMAND_RD2_STA - mov dx, [eth_nic_base] - add dx, D8390_P0_COMMAND - out dx, al - - mov al, cl - mov dx, [eth_nic_base] - add dx, D8390_P0_RBCR0 - out dx, al - - mov al, ch - mov dx, [eth_nic_base] - add dx, D8390_P0_RBCR1 - out dx, al - - mov al, bl - mov dx, [eth_nic_base] - add dx, D8390_P0_RSAR0 - out dx, al - - mov al, bh - mov dx, [eth_nic_base] - add dx, D8390_P0_RSAR1 - out dx, al - - mov al, D8390_COMMAND_RD0_STA - mov dx, [eth_nic_base] - add dx, D8390_P0_COMMAND - out dx, al - - mov dx, [eth_asic_base] - add dx, ASIC_PIO - - mov al, [eth_flags] - and al, FLAG_16BIT - cmp al, 0 - je epr_003 - - shr ecx, 1 - -epr_002: - ; 2 bytes at a time - in ax, dx - mov [edi], ax - add edi, 2 - loop epr_002 - ret - -epr_003: - ; 1 byte at a time - in al, dx - mov [edi], al - inc edi - loop epr_003 - ret - - - - -;*************************************************************************** -; Function -; eth_pio_write -; -; Description -; writes a frame to the ethernet card via Programmed I/O -; dst in ebx -; cnt in ecx -; src in esi -;*************************************************************************** -eth_pio_write: - mov al, [eth_flags] - and al, FLAG_16BIT - cmp al, 0 - je epw_001 - - inc ecx - and ecx, 0xFFFFFFFE - -epw_001: - mov al, D8390_COMMAND_RD2_STA - mov dx, [eth_nic_base] - add dx, D8390_P0_COMMAND - out dx, al - - mov al, D8390_ISR_RDC - mov dx, [eth_nic_base] - add dx, D8390_P0_ISR - out dx, al - - - mov al, cl - mov dx, [eth_nic_base] - add dx, D8390_P0_RBCR0 - out dx, al - - mov al, ch - mov dx, [eth_nic_base] - add dx, D8390_P0_RBCR1 - out dx, al - - mov al, bl - mov dx, [eth_nic_base] - add dx, D8390_P0_RSAR0 - out dx, al - - mov al, bh - mov dx, [eth_nic_base] - add dx, D8390_P0_RSAR1 - out dx, al - - mov al, D8390_COMMAND_RD1_STA - mov dx, [eth_nic_base] - add dx, D8390_P0_COMMAND - out dx, al - - mov dx, [eth_asic_base] - add dx, ASIC_PIO - - mov al, [eth_flags] - and al, FLAG_16BIT - cmp al, 0 - je epw_003 - - shr ecx, 1 - -epw_002: - ; 2 bytes at a time - mov ax, [esi] - add esi, 2 - out dx, ax - - loop epw_002 - jmp epw_004 - -epw_003: - ; 1 byte at a time - mov al, [esi] - inc esi - out dx, al - loop epw_003 - -epw_004: - mov dx, [eth_nic_base] - add dx, D8390_P0_ISR - -epw_005: - in al, dx - and al, D8390_ISR_RDC - cmp al, D8390_ISR_RDC - jne epw_005 - - ret - - - -;*************************************************************************** -; Function -; rtl8029_reset -; Description -; Place the chip (ie, the ethernet card) into a virgin state -; No inputs -; All registers destroyed -; -;*************************************************************************** -rtl8029_reset: - mov bx, [eth_nic_base] - - mov dx, bx - add dx, D8390_P0_COMMAND - mov al, D8390_COMMAND_PS0_RD2_STP - out dx, al - - mov dx, bx - add dx, D8390_P0_DCR - mov al, [eth_flags] - and al, FLAG_16BIT - cmp al, FLAG_16BIT - jne nsr_001 - - mov al, 0x49 - jmp nsr_002 - -nsr_001: - mov al, 0x48 - -nsr_002: - out dx, al - - xor al, al - - mov dx, bx - add dx, D8390_P0_RBCR0 - out dx, al - - mov dx, bx - add dx, D8390_P0_RBCR1 - out dx, al - - mov dx, bx - add dx, D8390_P0_RCR - mov al, 0x20 - out dx, al - - mov dx, bx - add dx, D8390_P0_TCR - mov al, 2 - out dx, al - - mov dx, bx - add dx, D8390_P0_TPSR - mov al, [eth_tx_start] - out dx, al - - mov dx, bx - add dx, D8390_P0_PSTART - mov al, [eth_rx_start] - out dx, al - - mov dx, bx - add dx, D8390_P0_PSTOP - mov al, [eth_memsize] - out dx, al - - mov dx, bx - add dx, D8390_P0_BOUND - mov al, [eth_memsize] - dec al - out dx, al - - mov dx, bx - add dx, D8390_P0_ISR - mov al, 0xff - out dx, al - - mov dx, bx - add dx, D8390_P0_IMR - xor al, al - out dx, al - - mov dx, bx - add dx, D8390_P0_COMMAND - mov al, D8390_COMMAND_PS1_RD2_STP - out dx, al - - mov dx, bx - add dx, D8390_P1_PAR0 - mov esi, node_addr - mov ecx, ETH_ALEN - -nsr_003: - mov al, [esi] - out dx, al - - inc esi - inc dx - loop nsr_003 - - mov dx, bx - add dx, D8390_P1_MAR0 - mov ecx, ETH_ALEN - - mov al, 0xff - -nsr_004: - out dx, al - inc dx - loop nsr_004 - - mov dx, bx - add dx, D8390_P1_CURR - mov al, [eth_rx_start] - out dx, al - - mov dx, bx - add dx, D8390_P0_COMMAND - mov al, D8390_COMMAND_PS0_RD2_STA - out dx, al - - mov dx, bx - add dx, D8390_P0_ISR - mov al, 0xff - out dx, al - - mov dx, bx - add dx, D8390_P0_TCR - mov al, 0 - out dx, al - - mov dx, bx - add dx, D8390_P0_RCR - mov al, 4 - out dx, al - - ret - - - -;*************************************************************************** -; Function -; rtl8029_probe -; Description -; Searches for an ethernet card, enables it and clears the rx buffer -; If a card was found, it enables the ethernet -> TCPIP link -; -;*************************************************************************** -rtl8029_probe: - mov eax, [io_addr] - mov [eth_nic_base], ax ; The IO address space is 16 bit only - - mov al, VENDOR_NONE - mov [eth_vendor], al - - mov al, [eth_vendor] - cmp al, VENDOR_NONE - - jne ep_check_have_vendor - xor eax, eax - mov [eth_bmem], eax - - mov al, FLAG_PIO - mov [eth_flags], al - - mov ax, [eth_nic_base] - add ax, NE_ASIC_OFFSET - mov [eth_asic_base], ax - - mov al, MEM_16384 - mov [eth_memsize], al - - mov al, 32 - mov [eth_tx_start], al - - add al, D8390_TXBUF_SIZE - mov [eth_rx_start], al - - mov dx, [eth_asic_base] - add dx, NE_RESET - - in al, dx - out dx, al - - in al, 0x84 - - mov bx, [eth_nic_base] - - mov dx, bx - add dx, D8390_P0_COMMAND - mov al, D8390_COMMAND_RD2_STP - out dx, al - - mov dx, bx - add dx, D8390_P0_RCR - mov al, D8390_RCR_MON - out dx, al - - mov dx, bx - add dx, D8390_P0_DCR - mov al, D8390_DCR_FT1_LS - out dx, al - - mov dx, bx - add dx, D8390_P0_PSTART - mov al, MEM_8192 - out dx, al - - mov dx, bx - add dx, D8390_P0_PSTOP - mov al, MEM_16384 - out dx, al - - mov esi, test_data - mov ebx, 8192 - mov ecx, 14 - call eth_pio_write - - mov ebx, 8192 - mov ecx, 14 - mov edi, test_buffer - call eth_pio_read - - mov esi, test_buffer - mov edi, test_data - mov ecx, 13 - cld - rep cmpsb - - je ep_set_vendor - - mov al, [eth_flags] - or al, FLAG_16BIT - mov [eth_flags], al - - mov al, MEM_32768 - mov [eth_memsize], al - - mov al, 64 - mov [eth_tx_start], al - - add al, D8390_TXBUF_SIZE - mov [eth_rx_start], al - - mov bx, [eth_nic_base] - - mov dx, bx - add dx, D8390_P0_DCR - mov al, D8390_DCR_WTS_FT1_LS - out dx, al - - mov dx, bx - add dx, D8390_P0_PSTART - mov al, MEM_16384 - out dx, al - - mov dx, bx - add dx, D8390_P0_PSTOP - mov al, MEM_32768 - out dx, al - - mov esi, test_data - mov ebx, 16384 - mov ecx, 14 - call eth_pio_write - - mov ebx, 16384 - mov ecx, 14 - mov edi, test_buffer - call eth_pio_read - - mov esi, test_buffer - mov edi, test_data - mov ecx, 13 - cld - rep cmpsb - -ep_set_vendor: - ; this bit is odd - probably left over from my hacking - mov ax, [eth_nic_base] - cmp ax, 0 - je rtl8029_exit - cmp ax, ISA_MAX_ADDR - jbe ep_001 - mov al, [eth_flags] - or al, FLAG_16BIT - mov [eth_flags], al - -ep_001: - mov al, VENDOR_NOVELL - mov [eth_vendor], al - - mov ebx, 0 - mov ecx, 16 - mov edi, romdata - call eth_pio_read - - - mov ecx, ETH_ALEN - mov esi, romdata - mov edi, node_addr - - mov bl, [eth_flags] - and bl, FLAG_16BIT - -ep_002: - mov al, [esi] - mov [edi], al - - inc edi - inc esi - cmp bl, FLAG_16BIT - jne ep_003 - - inc esi - -ep_003: - loop ep_002 - -ep_check_have_vendor: - mov al, [eth_vendor] - cmp al, VENDOR_NONE - je rtl8029_exit - - cmp al, VENDOR_3COM - je ep_reset_card - - mov eax, [eth_bmem] - mov [eth_rmem], eax - -ep_reset_card: - ; Reset the card - call rtl8029_reset - - ; Indicate that we have successfully reset the card - mov eax, [pci_data] - mov [eth_status], eax - -rtl8029_exit: - ret - - - -;*************************************************************************** -; Function -; rtl8029_poll -; -; Description -; Polls the ethernet card for a received packet -; Received data, if any, ends up in Ether_buffer -; -;*************************************************************************** -rtl8029_poll: - mov eax, Ether_buffer - mov [eth_rx_data_ptr], eax - - mov bx, [eth_nic_base] - - mov dx, bx - add dx, D8390_P0_RSR - in al, dx - - and al, D8390_RSTAT_PRX - cmp al, D8390_RSTAT_PRX - jne nsp_exit - - mov dx, bx - add dx, D8390_P0_BOUND - in al, dx - inc al - - cmp al, [eth_memsize] - jb nsp_001 - - mov al, [eth_rx_start] - -nsp_001: - mov ch, al - - mov dx, bx - add dx, D8390_P0_COMMAND - mov al, D8390_COMMAND_PS1 - out dx, al - - mov dx, bx - add dx, D8390_P1_CURR - in al, dx ; get current page - mov cl, al - - mov dx, bx - add dx, D8390_P0_COMMAND - mov al, D8390_COMMAND_PS0 - out dx, al - - cmp cl, [eth_memsize] - jb nsp_002 - - mov cl, [eth_rx_start] - -nsp_002: - cmp cl, ch - je nsp_exit - - xor ax, ax - mov ah, ch - - mov [pktoff], ax - - mov al, [eth_flags] - and al, FLAG_PIO - cmp al, FLAG_PIO - jne nsp_003 - - movzx ebx, word [pktoff] - mov edi, pkthdr - mov ecx, 4 - call eth_pio_read - jmp nsp_004 - -nsp_003: - mov edi, [eth_rmem] - movzx eax, word [pktoff] - add edi, eax - mov eax, [edi] - mov [pkthdr], eax - -nsp_004: - mov ax, [pktoff] - add ax, 4 - mov [pktoff], ax - - mov ax, [pkthdr + 2] - sub ax, 4 - - mov [eth_tmp_len], ax - - cmp ax, ETH_ZLEN - jb nsp_exit - - cmp ax, ETH_FRAME_LEN - ja nsp_exit - - mov al, [pkthdr] - and al, D8390_RSTAT_PRX - cmp al, D8390_RSTAT_PRX - jne nsp_exit - - ; Right, we can now get the data - - mov ax, [eth_tmp_len] - mov [eth_rx_data_len], ax - - xor ebx, ebx - mov bh, [eth_memsize] - sub bx, [pktoff] - - cmp [eth_tmp_len], bx - jbe nsp_005 - - mov al, [eth_flags] - and al, FLAG_PIO - cmp al, FLAG_PIO - jne nsp_006 - - push ebx - mov ecx, ebx - xor ebx, ebx - mov bx, [pktoff] - mov edi, [eth_rx_data_ptr] - call eth_pio_read - pop ebx - jmp nsp_007 - -nsp_006: - ; Not implemented, as we are using PIO mode on this card - -nsp_007: - xor ax, ax - mov ah, [eth_rx_start] - mov [pktoff], ax - - mov eax, [eth_rx_data_ptr] - add eax, ebx - mov [eth_rx_data_ptr], eax - - mov ax, [eth_tmp_len] - sub ax, bx - mov [eth_tmp_len], ax - -nsp_005: - mov al, [eth_flags] - and al, FLAG_PIO - cmp al, FLAG_PIO - jne nsp_008 - - xor ebx, ebx - mov bx, [pktoff] - xor ecx, ecx - mov cx, [eth_tmp_len] - mov edi, [eth_rx_data_ptr] - call eth_pio_read - jmp nsp_009 - -nsp_008: - ; Not implemented, as we are using PIO mode on this card - -nsp_009: - mov al, [pkthdr+1] - cmp al, [eth_rx_start] - jne nsp_010 - - mov al, [eth_memsize] - -nsp_010: - mov dx, [eth_nic_base] - add dx, D8390_P0_BOUND - dec al - out dx, al - -nsp_exit: - ret - - - -;*************************************************************************** -; Function -; rtl8029_transmit -; -; Description -; Transmits a packet of data via the ethernet card -; Pointer to 48 bit destination address in edi -; Type of packet in bx -; size of packet in ecx -; pointer to packet data in esi -; -;*************************************************************************** -rtl8029_transmit: - mov [eth_type], bx - - pusha - - mov esi, edi - xor bx, bx - mov bh, [eth_tx_start] - mov ecx, ETH_ALEN - call eth_pio_write - - mov esi, node_addr - xor bx, bx - mov bh, [eth_tx_start] - add bx, ETH_ALEN - mov ecx, ETH_ALEN - call eth_pio_write - - mov esi, eth_type - xor bx, bx - mov bh, [eth_tx_start] - add bx, ETH_ALEN - add bx, ETH_ALEN - mov ecx, 2 - call eth_pio_write - - popa - - xor bx, bx - mov bh, [eth_tx_start] - add bx, ETH_HLEN - push ecx - call eth_pio_write - pop ecx - - add ecx, ETH_HLEN - cmp ecx, ETH_ZLEN - jae nst_001 - - mov ecx, ETH_ZLEN - -nst_001: - push ecx - - mov bx, [eth_nic_base] - - mov dx, bx - add dx, D8390_P0_COMMAND - mov al, D8390_COMMAND_PS0_RD2_STA - out dx, al - - mov dx, bx - add dx, D8390_P0_TPSR - mov al, [eth_tx_start] - out dx, al - - pop ecx - - mov dx, bx - add dx, D8390_P0_TBCR0 - mov al, cl - out dx, al - - mov dx, bx - add dx, D8390_P0_TBCR1 - mov al, ch - out dx, al - - mov dx, bx - add dx, D8390_P0_COMMAND - mov al, D8390_COMMAND_PS0_TXP_RD2_STA - out dx, al - - ret diff --git a/kernel/trunk/network/eth_drv/drivers/rtl8139.inc b/kernel/trunk/network/eth_drv/drivers/rtl8139.inc deleted file mode 100644 index 2be59f5f8c..0000000000 --- a/kernel/trunk/network/eth_drv/drivers/rtl8139.inc +++ /dev/null @@ -1,624 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; RTL8139.INC ;; -;; ;; -;; Ethernet driver for Menuet OS ;; -;; ;; -;; Version 0.2 11 August 2003 ;; -;; ;; -;; Driver for chips of RealTek 8139 family ;; -;; References: ;; -;; www.realtek.com.hw - data sheets ;; -;; rtl8139.c - linux driver ;; -;; 8139too.c - linux driver ;; -;; ethernet driver template by Mike Hibbett ;; -;; ;; -;; The copyright statement is ;; -;; ;; -;; GNU GENERAL PUBLIC LICENSE ;; -;; Version 2, June 1991 ;; -;; ;; -;; Copyright 2003 Endre Kozma, ;; -;; endre.kozma@axelero.hu ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;; 10.01.2007 Bugfix for l8139_transmit from Paolo Franchetti ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - - ETH_ALEN equ 6 - ETH_HLEN equ (2 * ETH_ALEN + 2) - ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for - ; mininmum 64bytes frame length - - PCI_REG_COMMAND equ 0x04 ; command register - PCI_BIT_PIO equ 0 ; bit0: io space control - PCI_BIT_MMIO equ 1 ; bit1: memory space control - PCI_BIT_MASTER equ 2 ; bit2: device acts as a PCI master - - RTL8139_REG_MAR0 equ 0x08 ; multicast filter register 0 - RTL8139_REG_MAR4 equ 0x0c ; multicast filter register 4 - RTL8139_REG_TSD0 equ 0x10 ; transmit status of descriptor - RTL8139_REG_TSAD0 equ 0x20 ; transmit start address of descriptor - RTL8139_REG_RBSTART equ 0x30 ; RxBuffer start address - RTL8139_REG_COMMAND equ 0x37 ; command register - RTL8139_REG_CAPR equ 0x38 ; current address of packet read - RTL8139_REG_IMR equ 0x3c ; interrupt mask register - RTL8139_REG_ISR equ 0x3e ; interrupt status register - RTL8139_REG_TXCONFIG equ 0x40 ; transmit configuration register - RTL8139_REG_TXCONFIG_0 equ 0x40 ; transmit configuration register 0 - RTL8139_REG_TXCONFIG_1 equ 0x41 ; transmit configuration register 1 - RTL8139_REG_TXCONFIG_2 equ 0x42 ; transmit configuration register 2 - RTL8139_REG_TXCONFIG_3 equ 0x43 ; transmit configuration register 3 - RTL8139_REG_RXCONFIG equ 0x44 ; receive configuration register 0 - RTL8139_REG_RXCONFIG_0 equ 0x44 ; receive configuration register 0 - RTL8139_REG_RXCONFIG_1 equ 0x45 ; receive configuration register 1 - RTL8139_REG_RXCONFIG_2 equ 0x46 ; receive configuration register 2 - RTL8139_REG_RXCONFIG_3 equ 0x47 ; receive configuration register 3 - RTL8139_REG_MPC equ 0x4c ; missed packet counter - RTL8139_REG_9346CR equ 0x50 ; serial eeprom 93C46 command register - RTL8139_REG_CONFIG1 equ 0x52 ; configuration register 1 - RTL8139_REG_CONFIG4 equ 0x5a ; configuration register 4 - RTL8139_REG_HLTCLK equ 0x5b ; undocumented halt clock register - RTL8139_REG_BMCR equ 0x62 ; basic mode control register - RTL8139_REG_ANAR equ 0x66 ; auto negotiation advertisement register - -; 5.1 packet header - RTL8139_BIT_RUNT equ 4 ; total packet length < 64 bytes - RTL8139_BIT_LONG equ 3 ; total packet length > 4k - RTL8139_BIT_CRC equ 2 ; crc error occured - RTL8139_BIT_FAE equ 1 ; frame alignment error occured - RTL8139_BIT_ROK equ 0 ; received packet is ok -; 5.4 command register - RTL8139_BIT_RST equ 4 ; reset bit - RTL8139_BIT_RE equ 3 ; receiver enabled - RTL8139_BIT_TE equ 2 ; transmitter enabled - RTL8139_BIT_BUFE equ 0 ; rx buffer is empty, no packet stored -; 5.6 interrupt status register - RTL8139_BIT_ISR_TOK equ 2 ; transmit ok - RTL8139_BIT_ISR_RER equ 1 ; receive error interrupt - RTL8139_BIT_ISR_ROK equ 0 ; receive ok -; 5.7 transmit configyration register - RTL8139_BIT_TX_MXDMA equ 8 ; Max DMA burst size per Tx DMA burst - RTL8139_BIT_TXRR equ 4 ; Tx Retry count 16+(TXRR*16) -; 5.8 receive configuration register - RTL8139_BIT_RXFTH equ 13 ; Rx fifo threshold - RTL8139_BIT_RBLEN equ 11 ; Ring buffer length indicator - RTL8139_BIT_RX_MXDMA equ 8 ; Max DMA burst size per Rx DMA burst - RTL8139_BIT_NOWRAP equ 7 ; transfered data wrapping - RTL8139_BIT_9356SEL equ 6 ; eeprom selector 9346/9356 - RTL8139_BIT_AER equ 5 ; accept error packets - RTL8139_BIT_AR equ 4 ; accept runt packets - RTL8139_BIT_AB equ 3 ; accept broadcast packets - RTL8139_BIT_AM equ 2 ; accept multicast packets - RTL8139_BIT_APM equ 1 ; accept physical match packets - RTL8139_BIT_AAP equ 0 ; accept all packets -; 5.9 93C46/93C56 command register - RTL8139_BIT_93C46_EEM1 equ 7 ; RTL8139 eeprom operating mode1 - RTL8139_BIT_93C46_EEM0 equ 6 ; RTL8139 eeprom operating mode0 - RTL8139_BIT_93C46_EECS equ 3 ; chip select - RTL8139_BIT_93C46_EESK equ 2 ; serial data clock - RTL8139_BIT_93C46_EEDI equ 1 ; serial data input - RTL8139_BIT_93C46_EEDO equ 0 ; serial data output -; 5.11 configuration register 1 - RTL8139_BIT_LWACT equ 4 ; see RTL8139_REG_CONFIG1 - RTL8139_BIT_SLEEP equ 1 ; sleep bit at older chips - RTL8139_BIT_PWRDWN equ 0 ; power down bit at older chips - RTL8139_BIT_PMEn equ 0 ; power management enabled -; 5.14 configuration register 4 - RTL8139_BIT_LWPTN equ 2 ; see RTL8139_REG_CONFIG4 -; 6.2 transmit status register - RTL8139_BIT_ERTXTH equ 16 ; early TX threshold - RTL8139_BIT_TOK equ 15 ; transmit ok - RTL8139_BIT_OWN equ 13 ; tx DMA operation is completed -; 6.18 basic mode control register - RTL8139_BIT_ANE equ 12 ; auto negotiation enable -; 6.20 auto negotiation advertisement register - RTL8139_BIT_TXFD equ 8 ; 100base-T full duplex - RTL8139_BIT_TX equ 7 ; 100base-T - RTL8139_BIT_10FD equ 6 ; 10base-T full duplex - RTL8139_BIT_10 equ 5 ; 10base-T - RTL8139_BIT_SELECTOR equ 0 ; binary encoded selector CSMA/CD=00001 -; RX/TX buffer size - RTL8139_RBLEN equ 0 ; 0==8K 1==16k 2==32k 3==64k - RTL8139_RX_BUFFER_SIZE equ (8192 shl RTL8139_RBLEN) - MAX_ETH_FRAME_SIZE equ 1516 ; exactly 1514 wthout CRC - RTL8139_NUM_TX_DESC equ 4 - RTL8139_TX_BUFFER_SIZE equ (MAX_ETH_FRAME_SIZE * RTL8139_NUM_TX_DESC) - RTL8139_TXRR equ 8 ; total retries = 16+(TXRR*16) - RTL8139_TX_MXDMA equ 6 ; 0==16 1==32 2==64 3==128 - ; 4==256 5==512 6==1024 7==2048 - RTL8139_ERTXTH equ 8 ; in unit of 32 bytes e.g:(8*32)=256 - RTL8139_RX_MXDMA equ 7 ; 0==16 1==32 2==64 3==128 - ; 4==256 5==512 6==1024 7==unlimited - RTL8139_RXFTH equ 7 ; 0==16 1==32 2==64 3==128 - ; 4==256 5==512 6==1024 7==no threshold - RTL8139_RX_CONFIG equ ((RTL8139_RBLEN shl RTL8139_BIT_RBLEN) \ - or (RTL8139_RX_MXDMA shl RTL8139_BIT_RX_MXDMA) \ - or (1 shl RTL8139_BIT_NOWRAP) \ - or (RTL8139_RXFTH shl RTL8139_BIT_RXFTH) \ - or (1 shl RTL8139_BIT_AB) or (1 shl RTL8139_BIT_APM) \ - or (1 shl RTL8139_BIT_AER) or (1 shl RTL8139_BIT_AR) \ - or (1 shl RTL8139_BIT_AM)) - RTL8139_TX_TIMEOUT equ 30 ; 300 milliseconds timeout - - EE_93C46_REG_ETH_ID equ 7 ; MAC offset - EE_93C46_READ_CMD equ (6 shl 6) ; 110b + 6bit address - EE_93C56_READ_CMD equ (6 shl 8) ; 110b + 8bit address - EE_93C46_CMD_LENGTH equ 9 ; start bit + cmd + 6bit address - EE_93C56_CMD_LENGTH equ 11 ; start bit + cmd + 8bit ddress - - VER_RTL8139 equ 1100000b - VER_RTL8139A equ 1110000b -; VER_RTL8139AG equ 1110100b - VER_RTL8139B equ 1111000b - VER_RTL8130 equ VER_RTL8139B - VER_RTL8139C equ 1110100b - VER_RTL8100 equ 1111010b - VER_RTL8100B equ 1110101b - VER_RTL8139D equ VER_RTL8100B - VER_RTL8139CP equ 1110110b - VER_RTL8101 equ 1110111b - - IDX_RTL8139 equ 0 - IDX_RTL8139A equ 1 - IDX_RTL8139B equ 2 - IDX_RTL8139C equ 3 - IDX_RTL8100 equ 4 - IDX_RTL8139D equ 5 - IDX_RTL8139D equ 6 - IDX_RTL8101 equ 7 - - -; These two must be 4 byte aligned ( which they are ) -rtl8139_rx_buff equ eth_data_start -rtl8139_tx_buff equ rtl8139_rx_buff + (RTL8139_RX_BUFFER_SIZE + MAX_ETH_FRAME_SIZE) - -uglobal - align 4 -rtl8139_rx_buff_offset: - dd 0 -curr_tx_desc dd 0 -endg - -iglobal -hw_ver_array: - db VER_RTL8139, VER_RTL8139A, VER_RTL8139B, VER_RTL8139C - db VER_RTL8100, VER_RTL8139D, VER_RTL8139CP, VER_RTL8101 -HW_VER_ARRAY_SIZE = $-hw_ver_array -endg - -uglobal -hw_ver_id: - db 0 -endg - -;*************************************************************************** -; Function -; rtl8139_probe -; Description -; Searches for an ethernet card, enables it and clears the rx buffer -; If a card was found, it enables the ethernet -> TCPIP link -; Destroyed registers -; eax, ebx, ecx, edx -; -;*************************************************************************** -rtl8139_probe: -; enable the device - mov al, 2 - mov ah, [pci_bus] - mov bh, [pci_dev] - mov bl, PCI_REG_COMMAND - call pci_read_reg - mov cx, ax - or cl, (1 shl PCI_BIT_MASTER) or (1 shl PCI_BIT_PIO) - and cl, not (1 shl PCI_BIT_MMIO) - mov al, 2 - mov ah, [pci_bus] - mov bh, [pci_dev] - mov bl, PCI_REG_COMMAND - call pci_write_reg -; get chip version - mov edx, [io_addr] - add edx, RTL8139_REG_TXCONFIG_2 - in ax, dx - shr ah, 2 - shr ax, 6 - and al, 01111111b - mov ecx, HW_VER_ARRAY_SIZE-1 -.chip_ver_loop: - cmp al, [hw_ver_array+ecx] - je .chip_ver_found - dec ecx - jns .chip_ver_loop - xor cl, cl ; default RTL8139 -.chip_ver_found: - mov [hw_ver_id], cl -; wake up the chip - mov edx, [io_addr] - add edx, RTL8139_REG_HLTCLK - mov al, 'R' ; run the clock - out dx, al -; unlock config and BMCR registers - add edx, RTL8139_REG_9346CR - RTL8139_REG_HLTCLK - mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EEM0) - out dx, al -; enable power management - add edx, RTL8139_REG_CONFIG1 - RTL8139_REG_9346CR - in al, dx - cmp byte [hw_ver_id], IDX_RTL8139B - jl .old_chip -; set LWAKE pin to active high (default value). -; it is for Wake-On-LAN functionality of some motherboards. -; this signal is used to inform the motherboard to execute a wake-up process. -; only at newer chips. - or al, (1 shl RTL8139_BIT_PMEn) - and al, not (1 shl RTL8139_BIT_LWACT) - out dx, al - add edx, RTL8139_REG_CONFIG4 - RTL8139_REG_CONFIG1 - in al, dx - and al, not (1 shl RTL8139_BIT_LWPTN) - out dx, al - jmp .finish_wake_up -.old_chip: -; wake up older chips - and al, not ((1 shl RTL8139_BIT_SLEEP) or (1 shl RTL8139_BIT_PWRDWN)) - out dx, al -.finish_wake_up: -; lock config and BMCR registers - xor al, al - mov edx, [io_addr] - add edx, RTL8139_REG_9346CR - out dx, al -;*************************************************************************** -; Function -; rt8139_reset -; Description -; Place the chip (ie, the ethernet card) into a virgin state -; Destroyed registers -; eax, ebx, ecx, edx -; -;*************************************************************************** -rtl8139_reset: - mov edx, [io_addr] - add edx, RTL8139_REG_COMMAND - mov al, 1 shl RTL8139_BIT_RST - out dx, al - mov cx, 1000 ; wait no longer for the reset -.wait_for_reset: - in al, dx - test al, 1 shl RTL8139_BIT_RST - jz .reset_completed ; RST remains 1 during reset - dec cx - jns .wait_for_reset -.reset_completed: -; get MAC (hardware address) - mov ecx, 2 -.mac_read_loop: - lea eax, [EE_93C46_REG_ETH_ID+ecx] - push ecx - call rtl8139_read_eeprom - pop ecx - mov [node_addr+ecx*2], ax - dec ecx - jns .mac_read_loop -; unlock config and BMCR registers - mov edx, [io_addr] - add edx, RTL8139_REG_9346CR - mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EEM0) - out dx, al -; initialize multicast registers (no filtering) - mov eax, 0xffffffff - add edx, RTL8139_REG_MAR0 - RTL8139_REG_9346CR - out dx, eax - add edx, RTL8139_REG_MAR4 - RTL8139_REG_MAR0 - out dx, eax -; enable Rx/Tx - mov al, (1 shl RTL8139_BIT_RE) or (1 shl RTL8139_BIT_TE) - add edx, RTL8139_REG_COMMAND - RTL8139_REG_MAR4 - out dx, al -; 32k Rxbuffer, unlimited dma burst, no wrapping, no rx threshold -; accept broadcast packets, accept physical match packets - mov eax, RTL8139_RX_CONFIG - add edx, RTL8139_REG_RXCONFIG - RTL8139_REG_COMMAND - out dx, eax -; 1024 bytes DMA burst, total retries = 16 + 8 * 16 = 144 - mov eax, (RTL8139_TX_MXDMA shl RTL8139_BIT_TX_MXDMA) \ - or (RTL8139_TXRR shl RTL8139_BIT_TXRR) - add edx, RTL8139_REG_TXCONFIG - RTL8139_REG_RXCONFIG - out dx, eax -; enable auto negotiation - add edx, RTL8139_REG_BMCR - RTL8139_REG_TXCONFIG - in ax, dx - or ax, (1 shl RTL8139_BIT_ANE) - out dx, ax -; set auto negotiation advertisement - add edx, RTL8139_REG_ANAR - RTL8139_REG_BMCR - in ax, dx - or ax, (1 shl RTL8139_BIT_SELECTOR) or (1 shl RTL8139_BIT_10) \ - or (1 shl RTL8139_BIT_10FD) or (1 shl RTL8139_BIT_TX) \ - or (1 shl RTL8139_BIT_TXFD) - out dx, ax -; lock config and BMCR registers - xor eax, eax - add edx, RTL8139_REG_9346CR - RTL8139_REG_ANAR - out dx, al -; init RX/TX pointers - mov [rtl8139_rx_buff_offset], eax - mov [curr_tx_desc], eax -; clear missing packet counter - add edx, RTL8139_REG_MPC - RTL8139_REG_9346CR - out dx, eax -; disable all interrupts - add edx, RTL8139_REG_IMR - RTL8139_REG_MPC - out dx, ax -; set RxBuffer address, init RX buffer offset, init TX ring - mov eax, rtl8139_rx_buff ; simba - sub eax, OS_BASE - add edx, RTL8139_REG_RBSTART - RTL8139_REG_IMR - out dx, eax -; Indicate that we have successfully reset the card - mov eax, [pci_data] - mov [eth_status], eax - ret - -;*************************************************************************** -; Function -; rtl8139_read_eeprom -; Description -; reads eeprom type 93c46 and 93c56 -; Parameters -; al - word to be read (6bit in case of 93c46 and 8bit otherwise) -; Return value -; ax - word read in -; Destroyed register(s) -; eax, cx, ebx, edx -; -;*************************************************************************** -rtl8139_read_eeprom: - movzx ebx, al - mov edx, [io_addr] - add edx, RTL8139_REG_RXCONFIG - in al, dx - test al, (1 shl RTL8139_BIT_9356SEL) - jz .type_93c46 -; and bl, 01111111b ; don't care first bit - or bx, EE_93C56_READ_CMD ; it contains start bit - mov cx, EE_93C56_CMD_LENGTH-1 ; cmd_loop counter - jmp .read_eeprom -.type_93c46: - and bl, 00111111b - or bx, EE_93C46_READ_CMD ; it contains start bit - mov cx, EE_93C46_CMD_LENGTH-1 ; cmd_loop counter -.read_eeprom: - add edx, RTL8139_REG_9346CR - RTL8139_REG_RXCONFIG_0 -; mov al, (1 shl RTL8139_BIT_93C46_EEM1) -; out dx, al - mov al, (1 shl RTL8139_BIT_93C46_EEM1) \ - or (1 shl RTL8139_BIT_93C46_EECS) ; wake up the eeprom - out dx, al -.cmd_loop: - mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EECS) - bt bx, cx - jnc .zero_bit - or al, (1 shl RTL8139_BIT_93C46_EEDI) -.zero_bit: - out dx, al -; push eax -; in eax, dx ; eeprom delay -; pop eax - or al, (1 shl RTL8139_BIT_93C46_EESK) - out dx, al -; in eax, dx ; eeprom delay - dec cx - jns .cmd_loop -; in eax, dx ; eeprom delay - mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EECS) - out dx, al - mov cl, 0xf -.read_loop: - shl ebx, 1 - mov al, (1 shl RTL8139_BIT_93C46_EEM1) \ - or (1 shl RTL8139_BIT_93C46_EECS) \ - or (1 shl RTL8139_BIT_93C46_EESK) - out dx, al -; in eax, dx ; eeprom delay - in al, dx - and al, (1 shl RTL8139_BIT_93C46_EEDO) - jz .dont_set - inc ebx -.dont_set: - mov al, (1 shl RTL8139_BIT_93C46_EEM1) \ - or (1 shl RTL8139_BIT_93C46_EECS) - out dx, al -; in eax, dx ; eeprom delay - dec cl - jns .read_loop - xor al, al - out dx, al - mov ax, bx - ret - -;*************************************************************************** -; Function -; rtl8139_transmit -; Description -; Transmits a packet of data via the ethernet card -; Pointer to 48 bit destination address in edi -; Type of packet in bx -; Size of packet in ecx -; Pointer to packet data in esi -; Destroyed registers -; eax, edx, esi, edi -; ToDo -; for waiting of timeout the rtl8139 internal timer -; should be used -; -;*************************************************************************** -rtl8139_transmit: - cmp ecx, MAX_ETH_FRAME_SIZE - jg .finish ; packet is too long - push ecx -; check descriptor - mov ecx, [curr_tx_desc] - mov edx, [io_addr] - lea edx, [edx+ecx*4+RTL8139_REG_TSD0] - push edx ebx - in ax, dx - test ax, 0x1fff ; or no size given - jz .send_packet - and ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN) - cmp ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN) - jz .send_packet -; wait for timeout - mov ebx, RTL8139_TX_TIMEOUT - mov eax, 0x5 ; delay x/100 secs - int 0x40 - in ax, dx - and ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN) - cmp ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN) - jz .send_packet -; chip hung, reset it - call rtl8139_reset -; reset the card -.send_packet: -; calculate tx_buffer address - pop ebx - push esi - mov eax, MAX_ETH_FRAME_SIZE - mul dword [curr_tx_desc] - mov esi, edi - lea edi, [rtl8139_tx_buff+eax] - mov eax, edi - cld -; copy destination address - movsd - movsw -; copy source address - mov esi, node_addr - movsd - movsw -; copy packet type - mov [edi], bx - add edi, 2 -; copy the packet data - pop esi edx ecx - push ecx - shr ecx, 2 - rep movsd - pop ecx - push ecx - and ecx, 3 - rep movsb -; set address - sub eax, OS_BASE - add edx, RTL8139_REG_TSAD0 - RTL8139_REG_TSD0 - out dx, eax -; set size and early threshold - pop eax ; pick up the size - add eax, ETH_HLEN - cmp eax, ETH_ZLEN - jnc .no_pad - mov eax, ETH_ZLEN -.no_pad: - or eax, (RTL8139_ERTXTH shl RTL8139_BIT_ERTXTH) - add edx, RTL8139_REG_TSD0 - RTL8139_REG_TSAD0 - out dx, eax -; get next descriptor 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, ... - inc dword [curr_tx_desc] - and dword [curr_tx_desc], 3 -.finish: - ret - -;*************************************************************************** -; Function -; rtl8139_poll -; -; Description -; Polls the ethernet card for a received packet -; Received data, if any, ends up in Ether_buffer -; Destroyed register(s) -; eax, edx, ecx -; -;*************************************************************************** -rtl8139_poll: - mov word [eth_rx_data_len], 0 - mov edx, [io_addr] - add edx, RTL8139_REG_COMMAND - in al, dx - test al, (1 shl RTL8139_BIT_BUFE) - jnz .finish -; new packet received copy it from rx_buffer into Ether_buffer - mov eax, rtl8139_rx_buff - add eax, [rtl8139_rx_buff_offset] -; check if packet is ok - test byte [eax], (1 shl RTL8139_BIT_ROK) - jz .reset_rx -; packet is ok copy it into the Ether_buffer - movzx ecx, word [eax+2] ; packet length - sub ecx, 4 ; don't copy CRC - mov word [eth_rx_data_len], cx - push ecx - shr ecx, 2 ; first copy dword-wise - lea esi, [eax+4] ; don't copy the packet header - mov edi, Ether_buffer - cld - rep movsd ; copy the dwords - pop ecx - and ecx, 3 - rep movsb ; copy the rest bytes -; update rtl8139_rx_buff_offset - movzx eax, word [eax+2] ; packet length - add eax, [rtl8139_rx_buff_offset] - add eax, 4+3 ; packet header is 4 bytes long + dword alignment - and eax, not 3 ; dword alignment - cmp eax, RTL8139_RX_BUFFER_SIZE - jl .no_wrap - sub eax, RTL8139_RX_BUFFER_SIZE -.no_wrap: - mov [rtl8139_rx_buff_offset], eax -; update CAPR register - sub eax, 0x10 ; value 0x10 is a constant for CAPR - add edx, RTL8139_REG_CAPR - RTL8139_REG_COMMAND - out dx, ax -.finish: -; clear active interrupt sources - mov edx, [io_addr] - add edx, RTL8139_REG_ISR - in ax, dx - out dx, ax - ret -.reset_rx: - in al, dx ; read command register - push eax - and al, not (1 shl RTL8139_BIT_RE) - out dx, al - pop eax - out dx, al - add edx, RTL8139_REG_RXCONFIG - RTL8139_REG_COMMAND - mov ax, RTL8139_RX_CONFIG - out dx, ax - ret - -rtl8139_cable: - pusha - mov edx, [io_addr] - add edx, 0x58 - in al, dx - test al, 1 SHL 2 - jnz .notconnected - popa - xor al, al - inc al - ret - .notconnected: - popa - xor al, al - ret diff --git a/kernel/trunk/network/eth_drv/drivers/rtl8169.inc b/kernel/trunk/network/eth_drv/drivers/rtl8169.inc deleted file mode 100644 index 2d3671c2f4..0000000000 --- a/kernel/trunk/network/eth_drv/drivers/rtl8169.inc +++ /dev/null @@ -1,1239 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; RTL8169.INC ;; -;; ;; -;; Ethernet driver for Menuet OS ;; -;; ;; -;; Version 0.1 11 February 2007 ;; -;; ;; -;; Driver for chips of RealTek 8169 family ;; -;; References: ;; -;; r8169.c - linux driver (etherboot project) ;; -;; ethernet driver template by Mike Hibbett ;; -;; ;; -;; The copyright statement is ;; -;; ;; -;; GNU GENERAL PUBLIC LICENSE ;; -;; Version 2, June 1991 ;; -;; ;; -;; Copyright 2007 mike.dld, ;; -;; mike.dld@gmail.com ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - - ETH_ALEN equ 6 - ETH_HLEN equ (2 * ETH_ALEN + 2) - ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for - ; mininmum 64bytes frame length - - RTL8169_REG_MAC0 equ 0x0 ; Ethernet hardware address - RTL8169_REG_MAR0 equ 0x8 ; Multicast filter - RTL8169_REG_TxDescStartAddr equ 0x20 - RTL8169_REG_TxHDescStartAddr equ 0x28 - RTL8169_REG_FLASH equ 0x30 - RTL8169_REG_ERSR equ 0x36 - RTL8169_REG_ChipCmd equ 0x37 - RTL8169_REG_TxPoll equ 0x38 - RTL8169_REG_IntrMask equ 0x3C - RTL8169_REG_IntrStatus equ 0x3E - RTL8169_REG_TxConfig equ 0x40 - RTL8169_REG_RxConfig equ 0x44 - RTL8169_REG_RxMissed equ 0x4C - RTL8169_REG_Cfg9346 equ 0x50 - RTL8169_REG_Config0 equ 0x51 - RTL8169_REG_Config1 equ 0x52 - RTL8169_REG_Config2 equ 0x53 - RTL8169_REG_Config3 equ 0x54 - RTL8169_REG_Config4 equ 0x55 - RTL8169_REG_Config5 equ 0x56 - RTL8169_REG_MultiIntr equ 0x5C - RTL8169_REG_PHYAR equ 0x60 - RTL8169_REG_TBICSR equ 0x64 - RTL8169_REG_TBI_ANAR equ 0x68 - RTL8169_REG_TBI_LPAR equ 0x6A - RTL8169_REG_PHYstatus equ 0x6C - RTL8169_REG_RxMaxSize equ 0xDA - RTL8169_REG_CPlusCmd equ 0xE0 - RTL8169_REG_RxDescStartAddr equ 0xE4 - RTL8169_REG_ETThReg equ 0xEC - RTL8169_REG_FuncEvent equ 0xF0 - RTL8169_REG_FuncEventMask equ 0xF4 - RTL8169_REG_FuncPresetState equ 0xF8 - RTL8169_REG_FuncForceEvent equ 0xFC - - ; InterruptStatusBits - RTL8169_ISB_SYSErr equ 0x8000 - RTL8169_ISB_PCSTimeout equ 0x4000 - RTL8169_ISB_SWInt equ 0x0100 - RTL8169_ISB_TxDescUnavail equ 0x80 - RTL8169_ISB_RxFIFOOver equ 0x40 - RTL8169_ISB_LinkChg equ 0x20 - RTL8169_ISB_RxOverflow equ 0x10 - RTL8169_ISB_TxErr equ 0x08 - RTL8169_ISB_TxOK equ 0x04 - RTL8169_ISB_RxErr equ 0x02 - RTL8169_ISB_RxOK equ 0x01 - - ; RxStatusDesc - RTL8169_SD_RxRES equ 0x00200000 - RTL8169_SD_RxCRC equ 0x00080000 - RTL8169_SD_RxRUNT equ 0x00100000 - RTL8169_SD_RxRWT equ 0x00400000 - - ; ChipCmdBits - RTL8169_CMD_Reset equ 0x10 - RTL8169_CMD_RxEnb equ 0x08 - RTL8169_CMD_TxEnb equ 0x04 - RTL8169_CMD_RxBufEmpty equ 0x01 - - ; Cfg9346Bits - RTL8169_CFG_9346_Lock equ 0x00 - RTL8169_CFG_9346_Unlock equ 0xC0 - - ; rx_mode_bits - RTL8169_RXM_AcceptErr equ 0x20 - RTL8169_RXM_AcceptRunt equ 0x10 - RTL8169_RXM_AcceptBroadcast equ 0x08 - RTL8169_RXM_AcceptMulticast equ 0x04 - RTL8169_RXM_AcceptMyPhys equ 0x02 - RTL8169_RXM_AcceptAllPhys equ 0x01 - - ; RxConfigBits - RTL8169_RXC_FIFOShift equ 13 - RTL8169_RXC_DMAShift equ 8 - - ; TxConfigBits - RTL8169_TXC_InterFrameGapShift equ 24 - RTL8169_TXC_DMAShift equ 8 ; DMA burst value (0-7) is shift this many bits - - ; rtl8169_PHYstatus - RTL8169_PHYS_TBI_Enable equ 0x80 - RTL8169_PHYS_TxFlowCtrl equ 0x40 - RTL8169_PHYS_RxFlowCtrl equ 0x20 - RTL8169_PHYS_1000bpsF equ 0x10 - RTL8169_PHYS_100bps equ 0x08 - RTL8169_PHYS_10bps equ 0x04 - RTL8169_PHYS_LinkStatus equ 0x02 - RTL8169_PHYS_FullDup equ 0x01 - - ; GIGABIT_PHY_registers - RTL8169_PHY_CTRL_REG equ 0 - RTL8169_PHY_STAT_REG equ 1 - RTL8169_PHY_AUTO_NEGO_REG equ 4 - RTL8169_PHY_1000_CTRL_REG equ 9 - - ; GIGABIT_PHY_REG_BIT - RTL8169_PHY_Restart_Auto_Nego equ 0x0200 - RTL8169_PHY_Enable_Auto_Nego equ 0x1000 - - ; PHY_STAT_REG = 1; - RTL8169_PHY_Auto_Neco_Comp equ 0x0020 - - ; PHY_AUTO_NEGO_REG = 4; - RTL8169_PHY_Cap_10_Half equ 0x0020 - RTL8169_PHY_Cap_10_Full equ 0x0040 - RTL8169_PHY_Cap_100_Half equ 0x0080 - RTL8169_PHY_Cap_100_Full equ 0x0100 - - ; PHY_1000_CTRL_REG = 9; - RTL8169_PHY_Cap_1000_Full equ 0x0200 - RTL8169_PHY_Cap_1000_Half equ 0x0100 - - RTL8169_PHY_Cap_PAUSE equ 0x0400 - RTL8169_PHY_Cap_ASYM_PAUSE equ 0x0800 - - RTL8169_PHY_Cap_Null equ 0x0 - - ; _MediaType - RTL8169_MT_10_Half equ 0x01 - RTL8169_MT_10_Full equ 0x02 - RTL8169_MT_100_Half equ 0x04 - RTL8169_MT_100_Full equ 0x08 - RTL8169_MT_1000_Full equ 0x10 - - ; _TBICSRBit - RTL8169_TBI_LinkOK equ 0x02000000 - - ; _DescStatusBit - RTL8169_DSB_OWNbit equ 0x80000000 - RTL8169_DSB_EORbit equ 0x40000000 - RTL8169_DSB_FSbit equ 0x20000000 - RTL8169_DSB_LSbit equ 0x10000000 - -; MAC address length -MAC_ADDR_LEN equ 6 - -; max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4) -MAX_ETH_FRAME_SIZE equ 1536 - -TX_FIFO_THRESH equ 256 ; In bytes - -RX_FIFO_THRESH equ 7 ; 7 means NO threshold, Rx buffer level before first PCI xfer -RX_DMA_BURST equ 7 ; Maximum PCI burst, '6' is 1024 -TX_DMA_BURST equ 7 ; Maximum PCI burst, '6' is 1024 -ETTh equ 0x3F ; 0x3F means NO threshold - -EarlyTxThld equ 0x3F ; 0x3F means NO early transmit -RxPacketMaxSize equ 0x0800 ; Maximum size supported is 16K-1 -InterFrameGap equ 0x03 ; 3 means InterFrameGap = the shortest one - -NUM_TX_DESC equ 1 ; Number of Tx descriptor registers -NUM_RX_DESC equ 4 ; Number of Rx descriptor registers -RX_BUF_SIZE equ 1536 ; Rx Buffer size - -HZ equ 1000 - -RTL_MIN_IO_SIZE equ 0x80 -TX_TIMEOUT equ (6*HZ) - -RTL8169_TIMER_EXPIRE_TIME equ 100 - -ETH_HDR_LEN equ 14 -DEFAULT_MTU equ 1500 -DEFAULT_RX_BUF_LEN equ 1536 - - -;#ifdef RTL8169_JUMBO_FRAME_SUPPORT -;#define MAX_JUMBO_FRAME_MTU ( 10000 ) -;#define MAX_RX_SKBDATA_SIZE ( MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN ) -;#else -MAX_RX_SKBDATA_SIZE equ 1600 -;#endif //end #ifdef RTL8169_JUMBO_FRAME_SUPPORT - -;#ifdef RTL8169_USE_IO -;!!!#define RTL_W8(reg, val8) outb ((val8), ioaddr + (reg)) -macro RTL_W8 reg,val8 { - if ~reg eq dx - mov dx, word[rtl8169_tpc.mmio_addr] - add dx, reg - end if - if ~val8 eq al - mov al, val8 - end if - out dx, al -} -;!!!#define RTL_W16(reg, val16) outw ((val16), ioaddr + (reg)) -macro RTL_W16 reg,val16 { - if ~reg eq dx - mov dx, word[rtl8169_tpc.mmio_addr] - add dx, reg - end if - if ~val16 eq ax - mov ax, val16 - end if - out dx, ax -} -;!!!#define RTL_W32(reg, val32) outl ((val32), ioaddr + (reg)) -macro RTL_W32 reg,val32 { - if ~reg eq dx - mov dx, word[rtl8169_tpc.mmio_addr] - add dx, reg - end if - if ~val32 eq eax - mov eax, val32 - end if - out dx, eax -} -;!!!#define RTL_R8(reg) inb (ioaddr + (reg)) -macro RTL_R8 reg { - if ~reg eq dx - mov dx, word[rtl8169_tpc.mmio_addr] - add dx, reg - end if - in al, dx -} -;!!!#define RTL_R16(reg) inw (ioaddr + (reg)) -macro RTL_R16 reg { - if ~reg eq dx - mov dx, word[rtl8169_tpc.mmio_addr] - add dx, reg - end if - in ax, dx -} -;!!!#define RTL_R32(reg) ((unsigned long) inl (ioaddr + (reg))) -macro RTL_R32 reg { - if ~reg eq dx - mov dx, word[rtl8169_tpc.mmio_addr] - add dx, reg - end if - in eax, dx -} -;#else -; write/read MMIO register -;#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) -;#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) -;#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) -;#define RTL_R8(reg) readb (ioaddr + (reg)) -;#define RTL_R16(reg) readw (ioaddr + (reg)) -;#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) -;#endif - -MCFG_METHOD_01 equ 0x01 -MCFG_METHOD_02 equ 0x02 -MCFG_METHOD_03 equ 0x03 -MCFG_METHOD_04 equ 0x04 -MCFG_METHOD_05 equ 0x05 -MCFG_METHOD_11 equ 0x0b -MCFG_METHOD_12 equ 0x0c -MCFG_METHOD_13 equ 0x0d -MCFG_METHOD_14 equ 0x0e -MCFG_METHOD_15 equ 0x0f - -PCFG_METHOD_1 equ 0x01 ; PHY Reg 0x03 bit0-3 == 0x0000 -PCFG_METHOD_2 equ 0x02 ; PHY Reg 0x03 bit0-3 == 0x0001 -PCFG_METHOD_3 equ 0x03 ; PHY Reg 0x03 bit0-3 == 0x0002 - -PCI_COMMAND_IO equ 0x1 ; Enable response in I/O space -PCI_COMMAND_MEM equ 0x2 ; Enable response in mem space -PCI_COMMAND_MASTER equ 0x4 ; Enable bus mastering -PCI_LATENCY_TIMER equ 0x0d ; 8 bits -PCI_COMMAND_SPECIAL equ 0x8 ; Enable response to special cycles -PCI_COMMAND_INVALIDATE equ 0x10 ; Use memory write and invalidate -PCI_COMMAND_VGA_PALETTE equ 0x20 ; Enable palette snooping -PCI_COMMAND_PARITY equ 0x40 ; Enable parity checking -PCI_COMMAND_WAIT equ 0x80 ; Enable address/data stepping -PCI_COMMAND_SERR equ 0x100 ; Enable SERR -PCI_COMMAND_FAST_BACK equ 0x200 ; Enable back-to-back writes - -struc rtl8169_TxDesc { - .status dd ? - .vlan_tag dd ? - .buf_addr dd ? - .buf_Haddr dd ? -} -virtual at 0 - rtl8169_TxDesc rtl8169_TxDesc - sizeof.rtl8169_TxDesc = $ - rtl8169_TxDesc -end virtual - -struc rtl8169_RxDesc { - .status dd ? - .vlan_tag dd ? - .buf_addr dd ? - .buf_Haddr dd ? -} -virtual at 0 - rtl8169_RxDesc rtl8169_RxDesc - sizeof.rtl8169_RxDesc = $ - rtl8169_RxDesc -end virtual - -virtual at eth_data_start - -; Define the TX Descriptor -align 256 -rtl8169_tx_ring rb NUM_TX_DESC * sizeof.rtl8169_TxDesc - -; Create a static buffer of size RX_BUF_SZ for each -; TX Descriptor. All descriptors point to a -; part of this buffer -align 256 -rtl8169_txb rb NUM_TX_DESC * RX_BUF_SIZE - -; Define the RX Descriptor -align 256 -rtl8169_rx_ring rb NUM_RX_DESC * sizeof.rtl8169_RxDesc - -; Create a static buffer of size RX_BUF_SZ for each -; RX Descriptor All descriptors point to a -; part of this buffer -align 256 -rtl8169_rxb rb NUM_RX_DESC * RX_BUF_SIZE - -rtl8169_tpc: - .mmio_addr dd ? ; memory map physical address - .chipset dd ? - .pcfg dd ? - .mcfg dd ? - .cur_rx dd ? ; Index into the Rx descriptor buffer of next Rx pkt - .cur_tx dd ? ; Index into the Tx descriptor buffer of next Rx pkt - .TxDescArrays dd ? ; Index of Tx Descriptor buffer - .RxDescArrays dd ? ; Index of Rx Descriptor buffer - .TxDescArray dd ? ; Index of 256-alignment Tx Descriptor buffer - .RxDescArray dd ? ; Index of 256-alignment Rx Descriptor buffer - .RxBufferRing rd NUM_RX_DESC ; Index of Rx Buffer array - .Tx_skbuff rd NUM_TX_DESC - -end virtual - -rtl8169_intr_mask = RTL8169_ISB_LinkChg or RTL8169_ISB_RxOverflow or RTL8169_ISB_RxFIFOOver or RTL8169_ISB_TxErr or RTL8169_ISB_TxOK or RTL8169_ISB_RxErr or RTL8169_ISB_RxOK -rtl8169_rx_config = (RX_FIFO_THRESH shl RTL8169_RXC_FIFOShift) or (RX_DMA_BURST shl RTL8169_RXC_DMAShift) or 0x0000000E - -iglobal - -;static struct { -; const char *name; -; u8 mcfg; /* depend on RTL8169 docs */ -; u32 RxConfigMask; /* should clear the bits supported by this chip */ -;} -rtl_chip_info dd \ - MCFG_METHOD_01, 0xff7e1880, \ ; RTL8169 - MCFG_METHOD_02, 0xff7e1880, \ ; RTL8169s/8110s - MCFG_METHOD_03, 0xff7e1880, \ ; RTL8169s/8110s - MCFG_METHOD_04, 0xff7e1880, \ ; RTL8169sb/8110sb - MCFG_METHOD_05, 0xff7e1880, \ ; RTL8169sc/8110sc - MCFG_METHOD_11, 0xff7e1880, \ ; RTL8168b/8111b // PCI-E - MCFG_METHOD_12, 0xff7e1880, \ ; RTL8168b/8111b // PCI-E - MCFG_METHOD_13, 0xff7e1880, \ ; RTL8101e // PCI-E 8139 - MCFG_METHOD_14, 0xff7e1880, \ ; RTL8100e // PCI-E 8139 - MCFG_METHOD_15, 0xff7e1880 ; RTL8100e // PCI-E 8139 - -mac_info dd \ - 0x38800000, MCFG_METHOD_15, \ - 0x38000000, MCFG_METHOD_12, \ - 0x34000000, MCFG_METHOD_13, \ - 0x30800000, MCFG_METHOD_14, \ - 0x30000000, MCFG_METHOD_11, \ - 0x18000000, MCFG_METHOD_05, \ - 0x10000000, MCFG_METHOD_04, \ - 0x04000000, MCFG_METHOD_03, \ - 0x00800000, MCFG_METHOD_02, \ - 0x00000000, MCFG_METHOD_01 ; catch-all - -endg - -PCI_COMMAND_IO equ 0x1 ; Enable response in I/O space -PCI_COMMAND_MEM equ 0x2 ; Enable response in mem space -PCI_COMMAND_MASTER equ 0x4 ; Enable bus mastering -PCI_LATENCY_TIMER equ 0x0d ; 8 bits -PCI_COMMAND_SPECIAL equ 0x8 ; Enable response to special cycles -PCI_COMMAND_INVALIDATE equ 0x10 ; Use memory write and invalidate -PCI_COMMAND_VGA_PALETTE equ 0x20 ; Enable palette snooping -PCI_COMMAND_PARITY equ 0x40 ; Enable parity checking -PCI_COMMAND_WAIT equ 0x80 ; Enable address/data stepping -PCI_COMMAND_SERR equ 0x100 ; Enable SERR -PCI_COMMAND_FAST_BACK equ 0x200 ; Enable back-to-back writes - -PCI_VENDOR_ID equ 0x00 ; 16 bits -PCI_DEVICE_ID equ 0x02 ; 16 bits -PCI_COMMAND equ 0x04 ; 16 bits - -PCI_BASE_ADDRESS_0 equ 0x10 ; 32 bits -PCI_BASE_ADDRESS_1 equ 0x14 ; 32 bits -PCI_BASE_ADDRESS_2 equ 0x18 ; 32 bits -PCI_BASE_ADDRESS_3 equ 0x1c ; 32 bits -PCI_BASE_ADDRESS_4 equ 0x20 ; 32 bits -PCI_BASE_ADDRESS_5 equ 0x24 ; 32 bits - -PCI_BASE_ADDRESS_MEM_TYPE_MASK equ 0x06 -PCI_BASE_ADDRESS_MEM_TYPE_32 equ 0x00 ; 32 bit address -PCI_BASE_ADDRESS_MEM_TYPE_1M equ 0x02 ; Below 1M [obsolete] -PCI_BASE_ADDRESS_MEM_TYPE_64 equ 0x04 ; 64 bit address - -PCI_BASE_ADDRESS_IO_MASK equ (not 0x03) -PCI_BASE_ADDRESS_MEM_MASK equ (not 0x0f) -PCI_BASE_ADDRESS_SPACE_IO equ 0x01 -PCI_ROM_ADDRESS equ 0x30 ; 32 bits - -proc CONFIG_CMD,where:byte - movzx eax, byte[pci_bus] - shl eax, 8 - mov al, [pci_dev] - shl eax, 8 - mov al, [where] - and al, not 3 - or eax, 0x80000000 - ret -endp - -proc pci_read_config_byte,where:dword - push edx - stdcall CONFIG_CMD, [where] - mov dx, 0xCF8 - out dx, eax - mov edx, [where] - and edx, 3 - add edx, 0xCFC - in al, dx - pop edx - ret -endp - -proc pci_read_config_word,where:dword - push edx - stdcall CONFIG_CMD, [where] - mov dx, 0xCF8 - out dx, eax - mov edx, [where] - and edx, 2 - add edx, 0xCFC - in ax, dx - pop edx - ret -endp - -proc pci_read_config_dword,where:dword - push edx - stdcall CONFIG_CMD, [where] - mov edx, 0xCF8 - out dx, eax - mov edx, 0xCFC - in eax, dx - pop edx - ret -endp - -proc pci_write_config_byte,where:dword,value:byte - push edx - stdcall CONFIG_CMD, [where] - mov dx, 0xCF8 - out dx, eax - mov edx, [where] - and edx, 3 - add edx, 0xCFC - mov al, [value] - out dx, al - pop edx - ret -endp - -proc pci_write_config_word,where:dword,value:word - push edx - stdcall CONFIG_CMD, [where] - mov dx, 0xCF8 - out dx, eax - mov edx, [where] - and edx, 2 - add edx, 0xCFC - mov ax, [value] - out dx, ax - pop edx - ret -endp - -proc pci_write_config_dword,where:dword,value:dword - push edx - stdcall CONFIG_CMD, [where] - mov edx, 0xCF8 - out dx, eax - mov edx, 0xCFC - mov eax, [value] - out dx, eax - pop edx - ret -endp - -; Set device to be a busmaster in case BIOS neglected to do so. -; Also adjust PCI latency timer to a reasonable value, 32. -proc adjust_pci_device - -; DEBUGF 1,"K : adjust_pci_device\n" - - stdcall pci_read_config_word, PCI_COMMAND - mov bx, ax - or bx, PCI_COMMAND_MASTER or PCI_COMMAND_IO - cmp ax, bx - je @f -; DEBUGF 1,"K : adjust_pci_device: The PCI BIOS has not enabled this device!\nK : Updating PCI command %x->%x. pci_bus %x pci_device_fn %x\n",ax,bx,[pci_bus]:2,[pci_dev]:2 - stdcall pci_write_config_word, PCI_COMMAND, ebx - @@: - stdcall pci_read_config_byte, PCI_LATENCY_TIMER - cmp al, 32 - jae @f -; DEBUGF 1,"K : adjust_pci_device: PCI latency timer (CFLT) is unreasonably low at %d.\nK : Setting to 32 clocks.\n",al - stdcall pci_write_config_byte, PCI_LATENCY_TIMER, 32 - @@: - ret -endp - -; Find the start of a pci resource -proc pci_bar_start,index:dword - stdcall pci_read_config_dword, [index] - test eax, PCI_BASE_ADDRESS_SPACE_IO - jz @f - and eax, PCI_BASE_ADDRESS_IO_MASK - jmp .exit - @@: - push eax - and eax, PCI_BASE_ADDRESS_MEM_TYPE_MASK - cmp eax, PCI_BASE_ADDRESS_MEM_TYPE_64 - jne .not64 - mov eax, [index] - add eax, 4 - stdcall pci_read_config_dword, eax - or eax, eax - jz .not64 -; DEBUGF 1,"K : pci_bar_start: Unhandled 64bit BAR\n" - add esp, 4 - or eax, -1 - ret - .not64: - pop eax - and eax, PCI_BASE_ADDRESS_MEM_MASK - .exit: - ret -endp - -proc rtl8169_init_board - -; DEBUGF 1,"K : rtl8169_init_board\n" - - call adjust_pci_device - - stdcall pci_bar_start, PCI_BASE_ADDRESS_0 - mov [rtl8169_tpc.mmio_addr], eax - ; Soft reset the chip - RTL_W8 RTL8169_REG_ChipCmd,RTL8169_CMD_Reset - - ; Check that the chip has finished the reset - mov ecx, 1000 - @@: - RTL_R8 RTL8169_REG_ChipCmd - test al, RTL8169_CMD_Reset - jz @f - stdcall udelay, 10 - loop @b - @@: - ; identify config method - RTL_R32 RTL8169_REG_TxConfig - and eax, 0x7c800000 -; DEBUGF 1,"K : rtl8169_init_board: TxConfig & 0x7c800000 = 0x%x\n",eax - mov esi, mac_info-8 - @@: - add esi, 8 - mov ecx, eax - and ecx, [esi] - cmp ecx, [esi] - jne @b - mov eax, [esi+4] - mov [rtl8169_tpc.mcfg], eax - - mov [rtl8169_tpc.pcfg], PCFG_METHOD_3 - stdcall RTL8169_READ_GMII_REG, 3 - and al, 0x0f - or al, al - jnz @f - mov [rtl8169_tpc.pcfg], PCFG_METHOD_1 - jmp .pconf - @@: - dec al - jnz .pconf - mov [rtl8169_tpc.pcfg], PCFG_METHOD_2 - .pconf: - - ; identify chip attached to board - mov ecx, 10 - mov eax, [rtl8169_tpc.mcfg] - @@: - dec ecx - js @f - cmp eax, [rtl_chip_info+ecx*8] - jne @b - mov [rtl8169_tpc.chipset], ecx - jmp .match - @@: - ; if unknown chip, assume array element #0, original RTL-8169 in this case -; DEBUGF 1,"K : rtl8169_init_board: PCI device: unknown chip version, assuming RTL-8169\n" - RTL_R32 RTL8169_REG_TxConfig -; DEBUGF 1,"K : rtl8169_init_board: PCI device: TxConfig = 0x%x\n",eax - - mov [rtl8169_tpc.chipset], 0 - - xor eax, eax - inc eax - ret - - .match: - xor eax, eax - ret -endp - -proc rtl8169_hw_PHY_config - -; DEBUGF 1,"K : rtl8169_hw_PHY_config: priv.mcfg=%d, priv.pcfg=%d\n",[rtl8169_tpc.mcfg],[rtl8169_tpc.pcfg] - -; DBG_PRINT("priv->mcfg=%d, priv->pcfg=%d\n", tpc->mcfg, tpc->pcfg); - - cmp [rtl8169_tpc.mcfg], MCFG_METHOD_04 - jne .not_4 -; stdcall RTL8169_WRITE_GMII_REG,0x1F,0x0001 -; stdcall RTL8169_WRITE_GMII_REG,0x1b,0x841e -; stdcall RTL8169_WRITE_GMII_REG,0x0e,0x7bfb -; stdcall RTL8169_WRITE_GMII_REG,0x09,0x273a - stdcall RTL8169_WRITE_GMII_REG, 0x1F, 0x0002 - stdcall RTL8169_WRITE_GMII_REG, 0x01, 0x90D0 - stdcall RTL8169_WRITE_GMII_REG, 0x1F, 0x0000 - jmp .exit - .not_4: - cmp [rtl8169_tpc.mcfg], MCFG_METHOD_02 - je @f - cmp [rtl8169_tpc.mcfg], MCFG_METHOD_03 - jne .not_2_or_3 - @@: - stdcall RTL8169_WRITE_GMII_REG, 0x1F, 0x0001 - stdcall RTL8169_WRITE_GMII_REG, 0x15, 0x1000 - stdcall RTL8169_WRITE_GMII_REG, 0x18, 0x65C7 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x0000 - stdcall RTL8169_WRITE_GMII_REG, 0x03, 0x00A1 - stdcall RTL8169_WRITE_GMII_REG, 0x02, 0x0008 - stdcall RTL8169_WRITE_GMII_REG, 0x01, 0x1020 - stdcall RTL8169_WRITE_GMII_REG, 0x00, 0x1000 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x0800 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x0000 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x7000 - stdcall RTL8169_WRITE_GMII_REG, 0x03, 0xFF41 - stdcall RTL8169_WRITE_GMII_REG, 0x02, 0xDE60 - stdcall RTL8169_WRITE_GMII_REG, 0x01, 0x0140 - stdcall RTL8169_WRITE_GMII_REG, 0x00, 0x0077 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x7800 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x7000 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xA000 - stdcall RTL8169_WRITE_GMII_REG, 0x03, 0xDF01 - stdcall RTL8169_WRITE_GMII_REG, 0x02, 0xDF20 - stdcall RTL8169_WRITE_GMII_REG, 0x01, 0xFF95 - stdcall RTL8169_WRITE_GMII_REG, 0x00, 0xFA00 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xA800 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xA000 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xB000 - stdcall RTL8169_WRITE_GMII_REG, 0x03, 0xFF41 - stdcall RTL8169_WRITE_GMII_REG, 0x02, 0xDE20 - stdcall RTL8169_WRITE_GMII_REG, 0x01, 0x0140 - stdcall RTL8169_WRITE_GMII_REG, 0x00, 0x00BB - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xB800 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xB000 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xF000 - stdcall RTL8169_WRITE_GMII_REG, 0x03, 0xDF01 - stdcall RTL8169_WRITE_GMII_REG, 0x02, 0xDF20 - stdcall RTL8169_WRITE_GMII_REG, 0x01, 0xFF95 - stdcall RTL8169_WRITE_GMII_REG, 0x00, 0xBF00 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xF800 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xF000 - stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x0000 - stdcall RTL8169_WRITE_GMII_REG, 0x1F, 0x0000 - stdcall RTL8169_WRITE_GMII_REG, 0x0B, 0x0000 - jmp .exit - .not_2_or_3: -; DBG_PRINT("tpc->mcfg=%d. Discard hw PHY config.\n", tpc->mcfg); -; DEBUGF 1,"K : tpc.mcfg=%d, discard hw PHY config\n",[rtl8169_tpc.mcfg] - .exit: - ret -endp - -;proc pci_write_config_byte -; ret -;endp - -proc RTL8169_WRITE_GMII_REG,RegAddr:byte,value:dword - -;;; DEBUGF 1,"K : RTL8169_WRITE_GMII_REG: 0x%x 0x%x\n",[RegAddr]:2,[value] - - movzx eax, [RegAddr] - shl eax, 16 - or eax, [value] - or eax, 0x80000000 - RTL_W32 RTL8169_REG_PHYAR,eax - stdcall udelay, 1 ;;;1000 - - mov ecx, 2000 - ; Check if the RTL8169 has completed writing to the specified MII register - @@: - RTL_R32 RTL8169_REG_PHYAR - test eax, 0x80000000 - jz .exit - stdcall udelay, 1 ;;;100 - loop @b - .exit: - ret -endp - -proc RTL8169_READ_GMII_REG,RegAddr:byte - -;;; DEBUGF 1,"K : RTL8169_READ_GMII_REG: 0x%x\n",[RegAddr]:2 - - push ecx - movzx eax, [RegAddr] - shl eax, 16 -; or eax,0x0 - RTL_W32 RTL8169_REG_PHYAR,eax - stdcall udelay, 1 ;;;1000 - - mov ecx, 2000 - ; Check if the RTL8169 has completed retrieving data from the specified MII register - @@: - RTL_R32 RTL8169_REG_PHYAR - test eax, 0x80000000 - jnz .exit - stdcall udelay, 1 ;;;100 - loop @b - - or eax, -1 - pop ecx - ret - .exit: - RTL_R32 RTL8169_REG_PHYAR - and eax, 0xFFFF - pop ecx - ret -endp - -proc rtl8169_set_rx_mode - -; DEBUGF 1,"K : rtl8169_set_rx_mode\n" - - ; IFF_ALLMULTI - ; Too many to filter perfectly -- accept all multicasts - RTL_R32 RTL8169_REG_RxConfig - mov ecx, [rtl8169_tpc.chipset] - and eax, [rtl_chip_info + ecx * 8 + 4]; RxConfigMask - or eax, rtl8169_rx_config or (RTL8169_RXM_AcceptBroadcast or RTL8169_RXM_AcceptMulticast or RTL8169_RXM_AcceptMyPhys) - RTL_W32 RTL8169_REG_RxConfig,eax - - ; Multicast hash filter - RTL_W32 RTL8169_REG_MAR0 + 0,0xffffffff - RTL_W32 RTL8169_REG_MAR0 + 4,0xffffffff - ret -endp - -proc rtl8169_init_ring - -; DEBUGF 1,"K : rtl8169_init_ring\n" - - xor eax, eax - mov [rtl8169_tpc.cur_rx], eax - mov [rtl8169_tpc.cur_tx], eax - - mov edi, [rtl8169_tpc.TxDescArray] - mov ecx, (NUM_TX_DESC * sizeof.rtl8169_TxDesc) / 4 - cld - rep stosd - mov edi, [rtl8169_tpc.RxDescArray] - mov ecx, (NUM_RX_DESC * sizeof.rtl8169_RxDesc) / 4 - rep stosd - - mov edi, rtl8169_tpc.Tx_skbuff - mov eax, rtl8169_txb - mov ecx, NUM_TX_DESC - @@: - stosd - inc eax ; add eax,RX_BUF_SIZE ??? - loop @b - -;!!! for (i = 0; i < NUM_RX_DESC; i++) { -;!!! if (i == (NUM_RX_DESC - 1)) -;!!! tpc->RxDescArray[i].status = (OWNbit | EORbit) | RX_BUF_SIZE; -;!!! else -;!!! tpc->RxDescArray[i].status = OWNbit | RX_BUF_SIZE; -;!!! tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE]; -;!!! tpc->RxDescArray[i].buf_addr = virt_to_bus(tpc->RxBufferRing[i]); -;!!! } - mov esi, rtl8169_tpc.RxBufferRing - mov edi, [rtl8169_tpc.RxDescArray] - mov eax, rtl8169_rxb - mov ecx, NUM_RX_DESC - @@: - mov [esi], eax - mov [edi+rtl8169_RxDesc.buf_addr], eax - sub [edi+rtl8169_RxDesc.buf_addr], OS_BASE ; shurf 28.09.2008 - mov [edi+rtl8169_RxDesc.status], RTL8169_DSB_OWNbit or RX_BUF_SIZE - add esi, 4 - add edi, sizeof.rtl8169_RxDesc - add eax, RX_BUF_SIZE - loop @b - - or [edi - sizeof.rtl8169_RxDesc + rtl8169_RxDesc.status], RTL8169_DSB_EORbit - - ret -endp - -proc rtl8169_hw_start - -; DEBUGF 1,"K : rtl8169_hw_start\n" - - ; Soft reset the chip - RTL_W8 RTL8169_REG_ChipCmd,RTL8169_CMD_Reset - ; Check that the chip has finished the reset - mov ecx, 1000 - @@: - RTL_R8 RTL8169_REG_ChipCmd - and al, RTL8169_CMD_Reset - jz @f - stdcall udelay, 10 - loop @b - @@: - RTL_W8 RTL8169_REG_Cfg9346,RTL8169_CFG_9346_Unlock - RTL_W8 RTL8169_REG_ChipCmd,RTL8169_CMD_TxEnb or RTL8169_CMD_RxEnb - RTL_W8 RTL8169_REG_ETThReg,ETTh - ; For gigabit rtl8169 - RTL_W16 RTL8169_REG_RxMaxSize,RxPacketMaxSize - ; Set Rx Config register - RTL_R32 RTL8169_REG_RxConfig - mov ecx, [rtl8169_tpc.chipset] - and eax, [rtl_chip_info + ecx * 8 + 4]; RxConfigMask - or eax, rtl8169_rx_config - RTL_W32 RTL8169_REG_RxConfig,eax - ; Set DMA burst size and Interframe Gap Time - RTL_W32 RTL8169_REG_TxConfig,(TX_DMA_BURST shl RTL8169_TXC_DMAShift) or (InterFrameGap shl RTL8169_TXC_InterFrameGapShift) - RTL_R16 RTL8169_REG_CPlusCmd - RTL_W16 RTL8169_REG_CPlusCmd,ax - - RTL_R16 RTL8169_REG_CPlusCmd - or ax, 1 shl 3 - cmp [rtl8169_tpc.mcfg], MCFG_METHOD_02 - jne @f - cmp [rtl8169_tpc.mcfg], MCFG_METHOD_03 - jne @f - or ax, 1 shl 14 -; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n" - jmp .set - @@:;DEBUGF 1,"K : Set MAC Reg C+CR Offset 0xE0: bit-3\n" - .set: - RTL_W16 RTL8169_REG_CPlusCmd,ax - -; RTL_W16 0xE2,0x1517 -; RTL_W16 0xE2,0x152a -; RTL_W16 0xE2,0x282a - RTL_W16 0xE2,0x0000 - - MOV [rtl8169_tpc.cur_rx],0 - push eax ; shurf 28.09.2008 - mov eax, [rtl8169_tpc.TxDescArray] ; shurf 28.09.2008 - sub eax, OS_BASE ; shurf 28.09.2008 - RTL_W32 RTL8169_REG_TxDescStartAddr,eax ;[rtl8169_tpc.TxDescArray] ; shurf 28.09.2008 - mov eax, [rtl8169_tpc.RxDescArray] ; shurf 28.09.2008 - sub eax, OS_BASE ; shurf 28.09.2008 - RTL_W32 RTL8169_REG_RxDescStartAddr,eax ;[rtl8169_tpc.RxDescArray] ; shurf 28.09.2008 - pop eax ; shurf 28.09.2008 - RTL_W8 RTL8169_REG_Cfg9346,RTL8169_CFG_9346_Lock - stdcall udelay, 10 - RTL_W32 RTL8169_REG_RxMissed,0 - call rtl8169_set_rx_mode - ; no early-rx interrupts - RTL_R16 RTL8169_REG_MultiIntr - and ax, 0xF000 - RTL_W16 RTL8169_REG_MultiIntr,ax - RTL_W16 RTL8169_REG_IntrMask,0 ; rtl8169_intr_mask - ret -endp - -proc udelay,msec:dword - push esi - mov esi, [msec] - call delay_ms - pop esi - ret -endp - -;*************************************************************************** -; Function -; rtl8169_probe -; Description -; Searches for an ethernet card, enables it and clears the rx buffer -; If a card was found, it enables the ethernet -> TCPIP link -; Destroyed registers -; eax, ebx, ecx, edx -; -;*************************************************************************** -proc rtl8169_probe - -; DEBUGF 1,"K : rtl8169_probe: 0x%x : 0x%x 0x%x\n",[io_addr]:8,[pci_bus]:2,[pci_dev]:2 - - call rtl8169_init_board - - mov ecx, MAC_ADDR_LEN - mov edx, [rtl8169_tpc.mmio_addr] - add edx, RTL8169_REG_MAC0 - xor ebx, ebx - ; Get MAC address. FIXME: read EEPROM - @@: - RTL_R8 dx - mov [node_addr+ebx], al - inc edx - inc ebx - loop @b - -; DEBUGF 1,"K : rtl8169_probe: MAC = %x-%x-%x-%x-%x-%x\n",[node_addr+0]:2,[node_addr+1]:2,[node_addr+2]:2,[node_addr+3]:2,[node_addr+4]:2,[node_addr+5]:2 - - ; Config PHY - stdcall rtl8169_hw_PHY_config -; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0x82h = 0x01h\n" - RTL_W8 0x82,0x01 - cmp [rtl8169_tpc.mcfg], MCFG_METHOD_03 - jae @f -; DEBUGF 1,"K : Set PCI Latency=0x40\n" -; stdcall pci_write_config_byte,PCI_LATENCY_TIMER,0x40 - @@: - cmp [rtl8169_tpc.mcfg], MCFG_METHOD_02 - jne @f -; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0x82h = 0x01h\n" - RTL_W8 0x82,0x01 -; DEBUGF 1,"K : Set PHY Reg 0x0bh = 0x00h\n" - stdcall RTL8169_WRITE_GMII_REG, 0x0b, 0x0000 ; w 0x0b 15 0 0 - @@: - ; if TBI is not enabled - RTL_R8 RTL8169_REG_PHYstatus - test al, RTL8169_PHYS_TBI_Enable - jz .tbi_dis - stdcall RTL8169_READ_GMII_REG, RTL8169_PHY_AUTO_NEGO_REG - ; enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged - and eax, 0x0C1F - or eax, RTL8169_PHY_Cap_10_Half or RTL8169_PHY_Cap_10_Full or RTL8169_PHY_Cap_100_Half or RTL8169_PHY_Cap_100_Full - stdcall RTL8169_WRITE_GMII_REG, RTL8169_PHY_AUTO_NEGO_REG, eax - ; enable 1000 Full Mode - stdcall RTL8169_WRITE_GMII_REG, RTL8169_PHY_1000_CTRL_REG, RTL8169_PHY_Cap_1000_Full or RTL8169_PHY_Cap_1000_Half; rtl8168 - ; Enable auto-negotiation and restart auto-nigotiation - stdcall RTL8169_WRITE_GMII_REG, RTL8169_PHY_CTRL_REG, RTL8169_PHY_Enable_Auto_Nego or RTL8169_PHY_Restart_Auto_Nego - stdcall udelay, 100 - mov ecx, 10000 - ; wait for auto-negotiation process - @@: - dec ecx - jz @f - stdcall RTL8169_READ_GMII_REG, RTL8169_PHY_STAT_REG - stdcall udelay, 100 - test eax, RTL8169_PHY_Auto_Neco_Comp - jz @b - RTL_R8 RTL8169_REG_PHYstatus - jmp @f - .tbi_dis: - stdcall udelay, 100 - @@: - call rtl8169_reset - ret -endp - -;*************************************************************************** -; Function -; rt8169_reset -; Description -; Place the chip (ie, the ethernet card) into a virgin state -; Destroyed registers -; eax, ebx, ecx, edx -; -;*************************************************************************** -proc rtl8169_reset - -; DEBUGF 1,"K : rtl8169_reset: 0x%x : 0x%x 0x%x\n",[io_addr]:8,[pci_bus]:2,[pci_dev]:2 - - mov [rtl8169_tpc.TxDescArrays], rtl8169_tx_ring - ; Tx Desscriptor needs 256 bytes alignment - mov [rtl8169_tpc.TxDescArray], rtl8169_tx_ring - - mov [rtl8169_tpc.RxDescArrays], rtl8169_rx_ring - ; Rx Desscriptor needs 256 bytes alignment - mov [rtl8169_tpc.RxDescArray], rtl8169_rx_ring - - call rtl8169_init_ring - call rtl8169_hw_start - ; Construct a perfect filter frame with the mac address as first match - ; and broadcast for all others - mov edi, rtl8169_txb - or al, -1 - mov ecx, 192 - cld - rep stosb - - mov esi, node_addr - mov edi, rtl8169_txb - movsd - movsw - - mov eax, [pci_data] - mov [eth_status], eax - ret -endp - -;*************************************************************************** -; Function -; rtl8169_transmit -; Description -; Transmits a packet of data via the ethernet card -; d - edi - Pointer to 48 bit destination address -; t - bx - Type of packet -; s - ecx - size of packet -; p - esi - pointer to packet data -; Destroyed registers -; eax, edx, esi, edi -; -;*************************************************************************** -proc rtl8169_transmit - -; DEBUGF 1,"K : rtl8169_transmit\n" ;: 0x%x : 0x%x 0x%x 0x%x 0x%x\n",[io_addr]:8,edi,bx,ecx,esi - - push ecx edx esi - mov eax, MAX_ETH_FRAME_SIZE - mul [rtl8169_tpc.cur_tx] - mov esi, edi - ; point to the current txb incase multiple tx_rings are used - mov edi, [rtl8169_tpc.Tx_skbuff + eax * 4] - mov eax, edi - cld -; copy destination address - movsd - movsw -; copy source address - mov esi, node_addr - movsd - movsw -; copy packet type - mov [edi], bx - add edi, 2 -; copy the packet data - pop esi edx ecx - push ecx - shr ecx, 2 - rep movsd - pop ecx - push ecx - and ecx, 3 - rep movsb - -;!!! s += ETH_HLEN; -;!!! s &= 0x0FFF; -;!!! while (s < ETH_ZLEN) -;!!! ptxb[s++] = '\0'; - mov edi, eax - pop ecx - push eax - add ecx, ETH_HLEN - and ecx, 0x0FFF - xor al, al - add edi, ecx - @@: - cmp ecx, ETH_ZLEN - jae @f - stosb - inc ecx - jmp @b - @@: - pop eax - - mov ebx, eax - mov eax, sizeof.rtl8169_TxDesc - mul [rtl8169_tpc.cur_tx] - add eax, [rtl8169_tpc.TxDescArray] - xchg eax, ebx - mov [ebx + rtl8169_TxDesc.buf_addr], eax - sub [ebx + rtl8169_TxDesc.buf_addr], OS_BASE ; shurf 28.09.2008 - - mov eax, ecx - cmp eax, ETH_ZLEN - jae @f - mov eax, ETH_ZLEN - @@: - or eax, RTL8169_DSB_OWNbit or RTL8169_DSB_FSbit or RTL8169_DSB_LSbit - cmp [rtl8169_tpc.cur_tx], NUM_TX_DESC - 1 - jne @f - or eax, RTL8169_DSB_EORbit - @@: - mov [ebx + rtl8169_TxDesc.status], eax - - RTL_W8 RTL8169_REG_TxPoll,0x40 ; set polling bit - - inc [rtl8169_tpc.cur_tx] - and [rtl8169_tpc.cur_tx], NUM_TX_DESC - 1 - -;!!! to = currticks() + TX_TIMEOUT; -;!!! while ((tpc->TxDescArray[entry].status & OWNbit) && (currticks() < to)); /* wait */ - mov ecx, TX_TIMEOUT / 10 - @@: - test [ebx + rtl8169_TxDesc.status], RTL8169_DSB_OWNbit - jnz @f - stdcall udelay, 10 - loop @b -; DEBUGF 1,"K : rtl8169_transmit: TX Time Out\n" - @@: - - ret -endp - -;*************************************************************************** -; Function -; rtl8169_poll -; -; Description -; Polls the ethernet card for a received packet -; Received data, if any, ends up in Ether_buffer -; Destroyed register(s) -; eax, edx, ecx -; -;*************************************************************************** -proc rtl8169_poll - -; DEBUGF 1,"K : rtl8169_poll\n" ;: 0x%x : none\n",[io_addr]:8 - - mov word[eth_rx_data_len], 0 - - mov eax, sizeof.rtl8169_RxDesc - mul [rtl8169_tpc.cur_rx] - add eax, [rtl8169_tpc.RxDescArray] - mov ebx, eax - -; DEBUGF 1,"K : rtl8169_RxDesc.status = 0x%x\n",[ebx + rtl8169_RxDesc.status] - - test [ebx + rtl8169_RxDesc.status], RTL8169_DSB_OWNbit; 0x80000600 - jnz .exit - -; DEBUGF 1,"K : rtl8169_tpc.cur_rx = %u\n",[rtl8169_tpc.cur_rx] - - ; h/w no longer present (hotplug?) or major error, bail - RTL_R16 RTL8169_REG_IntrStatus - -; DEBUGF 1,"K : IntrStatus = 0x%x\n",ax - - cmp ax, 0xFFFF - je .exit - - push eax - and ax, not (RTL8169_ISB_RxFIFOOver or RTL8169_ISB_RxOverflow or RTL8169_ISB_RxOK) - RTL_W16 RTL8169_REG_IntrStatus,ax - - mov eax, [ebx + rtl8169_RxDesc.status] - -; DEBUGF 1,"K : RxDesc.status = 0x%x\n",eax - - test eax, RTL8169_SD_RxRES - jnz .else - and eax, 0x00001FFF -; jz .exit.pop - add eax, -4 - mov [eth_rx_data_len], ax - -; DEBUGF 1,"K : rtl8169_poll: data length = %u\n",ax - - push eax - mov ecx, eax - shr ecx, 2 - mov eax, [rtl8169_tpc.cur_rx] - mov edx, [rtl8169_tpc.RxBufferRing + eax * 4] - mov esi, edx - mov edi, Ether_buffer - cld - rep movsd - pop ecx - and ecx, 3 - rep movsb - - mov eax, RTL8169_DSB_OWNbit or RX_BUF_SIZE - cmp [rtl8169_tpc.cur_rx], NUM_RX_DESC - 1 - jne @f - or eax, RTL8169_DSB_EORbit - @@: - mov [ebx + rtl8169_RxDesc.status], eax - - mov [ebx + rtl8169_RxDesc.buf_addr], edx - sub [ebx + rtl8169_RxDesc.buf_addr], OS_BASE ; shurf 28.09.2008 - jmp @f - .else: -; DEBUGF 1,"K : rtl8169_poll: Rx Error\n" - ; FIXME: shouldn't I reset the status on an error - @@: - inc [rtl8169_tpc.cur_rx] - and [rtl8169_tpc.cur_rx], NUM_RX_DESC - 1 - .exit.pop: - pop eax - and ax, RTL8169_ISB_RxFIFOOver or RTL8169_ISB_RxOverflow or RTL8169_ISB_RxOK - RTL_W16 RTL8169_REG_IntrStatus,ax - .exit: - ret -endp - -proc rtl8169_cable - ret -endp diff --git a/kernel/trunk/network/eth_drv/drivers/sis900.inc b/kernel/trunk/network/eth_drv/drivers/sis900.inc deleted file mode 100644 index 1a9f87b072..0000000000 --- a/kernel/trunk/network/eth_drv/drivers/sis900.inc +++ /dev/null @@ -1,1166 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; SIS900.INC ;; -;; ;; -;; Ethernet driver for Menuet OS ;; -;; ;; -;; Version 0.4 26 April 2004 ;; -;; ;; -;; This driver is based on the SIS900 driver from ;; -;; the etherboot 5.0.6 project. The copyright statement is ;; -;; ;; -;; GNU GENERAL PUBLIC LICENSE ;; -;; Version 2, June 1991 ;; -;; ;; -;; remaining parts Copyright 2004 Jason Delozier, ;; -;; cordata51@hotmail.com ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;; Updates: ;; -;; Revision Look up table and SIS635 Mac Address by Jarek Pelczar ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -;******************************************************************** -; Interface -; SIS900_reset -; SIS900_probe -; SIS900_poll -; SIS900_transmit -; -;******************************************************************** -;******************************************************************** -; Comments: -; Known to work with the following SIS900 ethernet cards: -; - Device ID: 0x0900 Vendor ID: 0x1039 Revision: 0x91 -; - Device ID: 0x0900 Vendor ID: 0x1039 Revision: 0x90 -; -; If your card is not listed, try it and let me know if it -; functions properly and it will be aded to the list. If not -; we may be able to add support for it. -; -; How To Use: -; Add the following lines to Ethernet.inc in their appropriate locations -; -; include "Sis900.INC" -; dd 0x09001039, SIS900_probe, SIS900_reset, SIS900_poll, -; SIS900_transmit -; dd 0x70161039, SIS900_probe, SIS900_reset, SIS900_poll, -; SIS900_transmit ;untested -; -; ToDo: -; - Enable MII interface for reading speed -; and duplex settings. -; -; - Update Poll routine to support packet fragmentation. -; -; - Add additional support for other sis900 based cards -; -;******************************************************************** - -; comment the next line out if you don't want debug info printed -; on the debug board. This option adds a lot of bytes to the driver -; so it's worth to comment it out. -; SIS900_DEBUG equ 1 - - -;* buffers and descriptors -cur_rx db 0 -NUM_RX_DESC equ 4 ;* Number of RX descriptors * -NUM_TX_DESC equ 1 ;* Number of TX descriptors * -RX_BUFF_SZ equ 1520 ;* Buffer size for each Rx buffer * -TX_BUFF_SZ equ 1516 ;* Buffer size for each Tx buffer * - -uglobal -align 4 -txd: - times (3 * NUM_TX_DESC) dd 0 -rxd: - times (3 * NUM_RX_DESC) dd 0 -endg - -txb equ eth_data_start -rxb equ txb + (NUM_TX_DESC * TX_BUFF_SZ) -SIS900_ETH_ALEN equ 6 ;* Size of Ethernet address * -SIS900_ETH_HLEN equ 14 ;* Size of ethernet header * -SIS900_ETH_ZLEN equ 60 ;* Minimum packet length * -SIS900_DSIZE equ 0x00000fff -SIS900_CRC_SIZE equ 4 -SIS900_RFADDR_shift equ 16 -;SIS900 Symbolic offsets to registers. - SIS900_cr equ 0x0 ; Command Register - SIS900_cfg equ 0x4 ; Configuration Register - SIS900_mear equ 0x8 ; EEPROM Access Register - SIS900_ptscr equ 0xc ; PCI Test Control Register - SIS900_isr equ 0x10 ; Interrupt Status Register - SIS900_imr equ 0x14 ; Interrupt Mask Register - SIS900_ier equ 0x18 ; Interrupt Enable Register - SIS900_epar equ 0x18 ; Enhanced PHY Access Register - SIS900_txdp equ 0x20 ; Transmit Descriptor Pointer Register - SIS900_txcfg equ 0x24 ; Transmit Configuration Register - SIS900_rxdp equ 0x30 ; Receive Descriptor Pointer Register - SIS900_rxcfg equ 0x34 ; Receive Configuration Register - SIS900_flctrl equ 0x38 ; Flow Control Register - SIS900_rxlen equ 0x3c ; Receive Packet Length Register - SIS900_rfcr equ 0x48 ; Receive Filter Control Register - SIS900_rfdr equ 0x4C ; Receive Filter Data Register - SIS900_pmctrl equ 0xB0 ; Power Management Control Register - SIS900_pmer equ 0xB4 ; Power Management Wake-up Event Register -;SIS900 Command Register Bits - SIS900_RELOAD equ 0x00000400 - SIS900_ACCESSMODE equ 0x00000200 - SIS900_RESET equ 0x00000100 - SIS900_SWI equ 0x00000080 - SIS900_RxRESET equ 0x00000020 - SIS900_TxRESET equ 0x00000010 - SIS900_RxDIS equ 0x00000008 - SIS900_RxENA equ 0x00000004 - SIS900_TxDIS equ 0x00000002 - SIS900_TxENA equ 0x00000001 -;SIS900 Configuration Register Bits - SIS900_DESCRFMT equ 0x00000100 ; 7016 specific - SIS900_REQALG equ 0x00000080 - SIS900_SB equ 0x00000040 - SIS900_POW equ 0x00000020 - SIS900_EXD equ 0x00000010 - SIS900_PESEL equ 0x00000008 - SIS900_LPM equ 0x00000004 - SIS900_BEM equ 0x00000001 - SIS900_RND_CNT equ 0x00000400 - SIS900_FAIR_BACKOFF equ 0x00000200 - SIS900_EDB_MASTER_EN equ 0x00002000 -;SIS900 Eeprom Access Reigster Bits - SIS900_MDC equ 0x00000040 - SIS900_MDDIR equ 0x00000020 - SIS900_MDIO equ 0x00000010 ; 7016 specific - SIS900_EECS equ 0x00000008 - SIS900_EECLK equ 0x00000004 - SIS900_EEDO equ 0x00000002 - SIS900_EEDI equ 0x00000001 -;SIS900 TX Configuration Register Bits - SIS900_ATP equ 0x10000000 ;Automatic Transmit Padding - SIS900_MLB equ 0x20000000 ;Mac Loopback Enable - SIS900_HBI equ 0x40000000 ;HeartBeat Ignore (Req for full-dup) - SIS900_CSI equ 0x80000000 ;CarrierSenseIgnore (Req for full-du -;SIS900 RX Configuration Register Bits - SIS900_AJAB equ 0x08000000 ; - SIS900_ATX equ 0x10000000 ;Accept Transmit Packets - SIS900_ARP equ 0x40000000 ;accept runt packets (<64bytes) - SIS900_AEP equ 0x80000000 ;accept error packets -;SIS900 Interrupt Reigster Bits - SIS900_WKEVT equ 0x10000000 - SIS900_TxPAUSEEND equ 0x08000000 - SIS900_TxPAUSE equ 0x04000000 - SIS900_TxRCMP equ 0x02000000 - SIS900_RxRCMP equ 0x01000000 - SIS900_DPERR equ 0x00800000 - SIS900_SSERR equ 0x00400000 - SIS900_RMABT equ 0x00200000 - SIS900_RTABT equ 0x00100000 - SIS900_RxSOVR equ 0x00010000 - SIS900_HIBERR equ 0x00008000 - SIS900_SWINT equ 0x00001000 - SIS900_MIBINT equ 0x00000800 - SIS900_TxURN equ 0x00000400 - SIS900_TxIDLE equ 0x00000200 - SIS900_TxERR equ 0x00000100 - SIS900_TxDESC equ 0x00000080 - SIS900_TxOK equ 0x00000040 - SIS900_RxORN equ 0x00000020 - SIS900_RxIDLE equ 0x00000010 - SIS900_RxEARLY equ 0x00000008 - SIS900_RxERR equ 0x00000004 - SIS900_RxDESC equ 0x00000002 - SIS900_RxOK equ 0x00000001 -;SIS900 Interrupt Enable Reigster Bits - SIS900_IE equ 0x00000001 -;SIS900 Revision ID - SIS900B_900_REV equ 0x03 - SIS630A_900_REV equ 0x80 - SIS630E_900_REV equ 0x81 - SIS630S_900_REV equ 0x82 - SIS630EA1_900_REV equ 0x83 - SIS630ET_900_REV equ 0x84 - SIS635A_900_REV equ 0x90 - SIS900_960_REV equ 0x91 -;SIS900 Receive Filter Control Register Bits - SIS900_RFEN equ 0x80000000 - SIS900_RFAAB equ 0x40000000 - SIS900_RFAAM equ 0x20000000 - SIS900_RFAAP equ 0x10000000 - SIS900_RFPromiscuous equ 0x70000000 -;SIS900 Reveive Filter Data Mask - SIS900_RFDAT equ 0x0000FFFF -;SIS900 Eeprom Address - SIS900_EEPROMSignature equ 0x00 - SIS900_EEPROMVendorID equ 0x02 - SIS900_EEPROMDeviceID equ 0x03 - SIS900_EEPROMMACAddr equ 0x08 - SIS900_EEPROMChecksum equ 0x0b -;The EEPROM commands include the alway-set leading bit. -;SIS900 Eeprom Command - SIS900_EEread equ 0x0180 - SIS900_EEwrite equ 0x0140 - SIS900_EEerase equ 0x01C0 - SIS900_EEwriteEnable equ 0x0130 - SIS900_EEwriteDisable equ 0x0100 - SIS900_EEeraseAll equ 0x0120 - SIS900_EEwriteAll equ 0x0110 - SIS900_EEaddrMask equ 0x013F - SIS900_EEcmdShift equ 16 -;For SiS962 or SiS963, request the eeprom software access - SIS900_EEREQ equ 0x00000400 - SIS900_EEDONE equ 0x00000200 - SIS900_EEGNT equ 0x00000100 -;General Varibles - SIS900_pci_revision: - db 0 - SIS900_Status dd 0x03000000 -sis900_specific_table: -; dd SIS630A_900_REV,Get_Mac_SIS630A_900_REV,0 -; dd SIS630E_900_REV,Get_Mac_SIS630E_900_REV,0 - dd SIS630S_900_REV,Get_Mac_SIS635_900_REV,0 - dd SIS630EA1_900_REV,Get_Mac_SIS635_900_REV,0 - dd SIS630ET_900_REV,Get_Mac_SIS635_900_REV,0;SIS630ET_900_REV_SpecialFN - dd SIS635A_900_REV,Get_Mac_SIS635_900_REV,0 - dd SIS900_960_REV,SIS960_get_mac_addr,0 - dd SIS900B_900_REV,SIS900_get_mac_addr,0 - dd 0,0,0,0 ; end of list -sis900_get_mac_func: - dd 0 -sis900_special_func: - dd 0 -sis900_table_entries: - db 8 - -;*************************************************************************** -; Function -; SIS900_probe -; Description -; Searches for an ethernet card, enables it and clears the rx buffer -; If a card was found, it enables the ethernet -> TCPIP link -;not done - still need to probe mii transcievers -;*************************************************************************** -if defined SIS900_DEBUG -SIS900_Debug_Str_Unsupported db 'Sorry your card is unsupported ',13,10,0 -end if -SIS900_probe: -;******Wake Up Chip******* - mov al, 4 - mov bh, [pci_dev] - mov ecx, 0 - mov ah, [pci_bus] - mov bl, 0x40 - call pci_write_reg -;*******Set some PCI Settings********* - call SIS900_adjust_pci_device -;*****Get Card Revision****** - mov al, 1 ;one byte to read - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, 0x08 ;Revision Register - call pci_read_reg - mov [SIS900_pci_revision], al;save the revision for later use -;****** Look up through the sis900_specific_table - mov esi, sis900_specific_table -.probe_loop: - cmp dword [esi], 0 ; Check if we reached end of the list - je .probe_loop_failed - cmp al, [esi] ; Check if revision is OK - je .probe_loop_ok - add esi, 12 ; Advance to next entry - jmp .probe_loop -.probe_loop_failed: - jmp SIS900_Probe_Unsupported -;*********Find Get Mac Function********* -.probe_loop_ok: - mov eax, [esi+4] ; Get pointer to "get MAC" function - mov [sis900_get_mac_func], eax - mov eax, [esi+8] ; Get pointer to special initialization fn - mov [sis900_special_func], eax -;******** Get MAC ******** - call dword [sis900_get_mac_func] -;******** Call special initialization fn if requested ******** - cmp dword [sis900_special_func], 0 - je .no_special_init - call dword [sis900_special_func] -.no_special_init: -;******** Set table entries ******** - mov al, [SIS900_pci_revision] - cmp al, SIS635A_900_REV - jae .ent16 - cmp al, SIS900B_900_REV - je .ent16 - jmp .ent8 -.ent16: - mov byte [sis900_table_entries], 16 -.ent8: -;*******Probe for mii transceiver******* -;TODO!!********************* -;*******Initialize Device******* - call sis900_init - ret - -SIS900_Probe_Unsupported: -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Str_Unsupported - call sys_msg_board_str -end if - ret -;*************************************************************************** -; Function: sis900_init -; -; Description: resets the ethernet controller chip and various -; data structures required for sending and receiving packets. -; -; Arguments: -; -; returns: none -;not done -;*************************************************************************** -sis900_init: - call SIS900_reset ;Done - call SIS900_init_rxfilter;Done - call SIS900_init_txd;Done - call SIS900_init_rxd ;Done - call SIS900_set_rx_mode;done - call SIS900_set_tx_mode - ;call SIS900_check_mode - ret - -;*************************************************************************** -; Function -; SIS900_reset -; Description -; disables interrupts and soft resets the controller chip -; -;done+ -;*************************************************************************** -if defined SIS900_DEBUG - SIS900_Debug_Reset_Failed db 'Reset Failed ',0 -end if -SIS900_reset: - ;******Disable Interrupts and reset Receive Filter******* - mov ebp, [io_addr] ; base address - xor eax, eax ; 0 to initialize - lea edx, [ebp+SIS900_ier] - out dx, eax ; Write 0 to location - lea edx, [ebp+SIS900_imr] - out dx, eax ; Write 0 to location - lea edx, [ebp+SIS900_rfcr] - out dx, eax ; Write 0 to location - ;*******Reset Card*********************************************** - lea edx, [ebp+SIS900_cr] - in eax, dx ; Get current Command Register - or eax, SIS900_RESET ; set flags - or eax, SIS900_RxRESET ; - or eax, SIS900_TxRESET ; - out dx, eax ; Write new Command Register - ;*******Wait Loop************************************************ - lea edx, [ebp+SIS900_isr] - mov ecx, [SIS900_Status]; Status we would like to see from card - mov ebx, 2001 ; only loop 1000 times -SIS900_Wait: - dec ebx ; 1 less loop - jz SIS900_DoneWait_e ; 1000 times yet? - in eax, dx ; move interrup status to eax - and eax, ecx - xor ecx, eax - jz SIS900_DoneWait - jmp SIS900_Wait -SIS900_DoneWait_e: -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Reset_Failed - call sys_msg_board_str -end if -SIS900_DoneWait: - ;*******Set Configuration Register depending on Card Revision******** - lea edx, [ebp+SIS900_cfg] - mov eax, SIS900_PESEL ; Configuration Register Bit - mov bl, [SIS900_pci_revision]; card revision - mov cl, SIS635A_900_REV ; Check card revision - cmp bl, cl - je SIS900_RevMatch - mov cl, SIS900B_900_REV ; Check card revision - cmp bl, cl - je SIS900_RevMatch - out dx, eax ; no revision match - jmp SIS900_Reset_Complete -SIS900_RevMatch: ; Revision match - or eax, SIS900_RND_CNT ; Configuration Register Bit - out dx, eax -SIS900_Reset_Complete: - mov eax, [pci_data] - mov [eth_status], eax - ret - -;*************************************************************************** -; Function: sis_init_rxfilter -; -; Description: sets receive filter address to our MAC address -; -; Arguments: -; -; returns: -;done+ -;*************************************************************************** -SIS900_init_rxfilter: - ;****Get Receive Filter Control Register ******** - mov ebp, [io_addr] ; base address - lea edx, [ebp+SIS900_rfcr] - in eax, dx ; get register - push eax - ;****disable packet filtering before setting filter******* - mov eax, SIS900_RFEN;move receive filter enable flag - not eax ;1s complement - pop ebx ;and with our saved register - and eax, ebx ;disable receiver - push ebx ;save filter for another use - out dx, eax ;set receive disabled - ;********load MAC addr to filter data register********* - xor ecx, ecx -SIS900_RXINT_Mac_Write: - ;high word of eax tells card which mac byte to write - mov eax, ecx - lea edx, [ebp+SIS900_rfcr] - shl eax, 16 ; - out dx, eax ; - lea edx, [ebp+SIS900_rfdr] - mov ax, word [node_addr+ecx*2]; Get Mac ID word - out dx, ax ; Send Mac ID - inc cl ; send next word - cmp cl, 3 ; more to send? - jne SIS900_RXINT_Mac_Write - ;********enable packet filitering ***** - pop eax ;old register value - lea edx, [ebp+SIS900_rfcr] - or eax, SIS900_RFEN;enable filtering - out dx, eax ;set register - ret - -;*************************************************************************** -;* -;* Function: sis_init_txd -;* -;* Description: initializes the Tx descriptor -;* -;* Arguments: -;* -;* returns: -;*done -;*************************************************************************** -SIS900_init_txd: - ;********** initialize TX descriptor ************** - mov [txd], dword 0 ;put link to next descriptor in link field - mov [txd+4], dword 0;clear status field - mov [txd+8], dword txb - OS_BASE;save address to buffer ptr field - ;*************** load Transmit Descriptor Register *************** - mov dx, [io_addr] ; base address - add dx, SIS900_txdp ; TX Descriptor Pointer - mov eax, txd - OS_BASE ; First Descriptor - out dx, eax ; move the pointer - ret - -;*************************************************************************** -;* Function: sis_init_rxd -;* -;* Description: initializes the Rx descriptor ring -;* -;* Arguments: -;* -;* Returns: -;*done -;*************************************************************************** -SIS900_init_rxd: - xor ecx, ecx - mov [cur_rx], cl ;Set cuurent rx discriptor to 0 - ;******** init RX descriptors ******** -SIS900_init_rxd_Loop: - mov eax, ecx ;current descriptor - imul eax, 12 ; - mov ebx, ecx ;determine next link descriptor - inc ebx ; - cmp ebx, NUM_RX_DESC ; - jne SIS900_init_rxd_Loop_0 ; - xor ebx, ebx ; -SIS900_init_rxd_Loop_0: ; - imul ebx, 12 ; - add ebx, rxd - OS_BASE ; - mov [rxd+eax], ebx ;save link to next descriptor - mov [rxd+eax+4], dword RX_BUFF_SZ ;status bits init to buf size - mov ebx, ecx ;find where the buf is located - imul ebx, RX_BUFF_SZ ; - add ebx, rxb - OS_BASE ; - mov [rxd+eax+8], ebx ;save buffer pointer - inc ecx ;next descriptor - cmp ecx, NUM_RX_DESC ; - jne SIS900_init_rxd_Loop ; - ;********* load Receive Descriptor Register with address of first - ; descriptor********* - mov dx, [io_addr] - add dx, SIS900_rxdp - mov eax, rxd - OS_BASE - out dx, eax - ret - -;*************************************************************************** -;* Function: sis900_set_tx_mode -;* -;* Description: -;* sets the transmit mode to allow for full duplex -;* -;* -;* Arguments: -;* -;* Returns: -;* -;* Comments: -;* If you are having problems transmitting packet try changing the -;* Max DMA Burst, Possible settings are as follows: -;* 0x00000000 = 512 bytes -;* 0x00100000 = 4 bytes -;* 0x00200000 = 8 bytes -;* 0x00300000 = 16 bytes -;* 0x00400000 = 32 bytes -;* 0x00500000 = 64 bytes -;* 0x00600000 = 128 bytes -;* 0x00700000 = 256 bytes -;*************************************************************************** -SIS900_set_tx_mode: - mov ebp, [io_addr] - lea edx, [ebp+SIS900_cr] - in eax, dx ; Get current Command Register - or eax, SIS900_TxENA;Enable Receive - out dx, eax - lea edx, [ebp+SIS900_txcfg]; Transmit config Register offset - mov eax, SIS900_ATP ;allow automatic padding - or eax, SIS900_HBI ;allow heartbeat ignore - or eax, SIS900_CSI ;allow carrier sense ignore - or eax, 0x00600000 ;Max DMA Burst - or eax, 0x00000100 ;TX Fill Threshold - or eax, 0x00000020 ;TX Drain Threshold - out dx, eax - ret - -;*************************************************************************** -;* Function: sis900_set_rx_mode -;* -;* Description: -;* sets the receive mode to accept all broadcast packets and packets -;* with our MAC address, and reject all multicast packets. Also allows -;* full-duplex -;* -;* Arguments: -;* -;* Returns: -;* -;* Comments: -;* If you are having problems receiving packet try changing the -;* Max DMA Burst, Possible settings are as follows: -;* 0x00000000 = 512 bytes -;* 0x00100000 = 4 bytes -;* 0x00200000 = 8 bytes -;* 0x00300000 = 16 bytes -;* 0x00400000 = 32 bytes -;* 0x00500000 = 64 bytes -;* 0x00600000 = 128 bytes -;* 0x00700000 = 256 bytes -;*************************************************************************** -SIS900_mc_filter: - times 16 dw 0 -SIS900_set_rx_mode: - mov ebp, [io_addr] - ;**************update Multicast Hash Table in Receive Filter - mov ebx, 0xffff - xor cl, cl -SIS900_set_rx_mode_Loop: - mov eax, ecx - shl eax, 1 - mov [SIS900_mc_filter+eax], bx - lea edx, [ebp+SIS900_rfcr] ; Receive Filter Control Reg offset - mov eax, 4 ;determine table entry - add al, cl - shl eax, 16 - out dx, eax ;tell card which entry to modify - lea edx, [ebp+SIS900_rfdr] ; Receive Filter Control Reg offset - mov eax, ebx ;entry value - out dx, ax ;write value to table in card - inc cl ;next entry - cmp cl, [sis900_table_entries]; - jl SIS900_set_rx_mode_Loop - ;*******Set Receive Filter Control Register************* - lea edx, [ebp+SIS900_rfcr] ; Receive Filter Control Register offset - mov eax, SIS900_RFAAB ;accecpt all broadcast packets - or eax, SIS900_RFAAM ;accept all multicast packets - or eax, SIS900_RFAAP ;Accept all packets - or eax, SIS900_RFEN ;enable receiver filter - out dx, eax - ;******Enable Receiver************ - lea edx, [ebp+SIS900_cr]; Command Register offset - in eax, dx ; Get current Command Register - or eax, SIS900_RxENA;Enable Receive - out dx, eax - ;*********Set - lea edx, [ebp+SIS900_rxcfg] ; Receive Config Register offset - mov eax, SIS900_ATX ;Accept Transmit Packets - ; (Req for full-duplex and PMD Loopback) - or eax, 0x00600000 ;Max DMA Burst - or eax, 0x00000002 ;RX Drain Threshold, 8X8 bytes or 64bytes - out dx, eax ; - ret - -;*************************************************************************** -; * SIS960_get_mac_addr: - Get MAC address for SiS962 or SiS963 model -; * @pci_dev: the sis900 pci device -; * @net_dev: the net device to get address for -; * -; * SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM -; * is shared by -; * LAN and 1394. When access EEPROM, send EEREQ signal to hardware first -; * and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access -; * by LAN, otherwise is not. After MAC address is read from EEPROM, send -; * EEDONE signal to refuse EEPROM access by LAN. -; * The EEPROM map of SiS962 or SiS963 is different to SiS900. -; * The signature field in SiS962 or SiS963 spec is meaningless. -; * MAC address is read into @net_dev->dev_addr. -; *done -;* -;* Return 0 is EAX = failure -;*Done+ -;*************************************************************************** -if defined SIS900_DEBUG -SIS900_Debug_Str_GetMac_Start db 'Attempting to get SIS900 Mac ID: ',13,10,0 -SIS900_Debug_Str_GetMac_Failed db 'Access to EEprom Failed',13,10,0 -SIS900_Debug_Str_GetMac_Address db 'Your Mac ID is: ',0 -SIS900_Debug_Str_GetMac_Address2 db 'Your SIS96x Mac ID is: ',0 -end if -SIS960_get_mac_addr: - mov ebp, [io_addr] - ;**********Send Request for eeprom access********************* - lea edx, [ebp+SIS900_mear] ; Eeprom access register - mov eax, SIS900_EEREQ ; Request access to eeprom - out dx, eax ; Send request - xor ebx, ebx ; - ;******Loop 4000 times and if access not granted error out***** -SIS96X_Get_Mac_Wait: - in eax, dx ;get eeprom status - and eax, SIS900_EEGNT ;see if eeprom access granted flag is set - jnz SIS900_Got_EEP_Access ;if it is, go access the eeprom - inc ebx ;else keep waiting - cmp ebx, 4000 ;have we tried 4000 times yet? - jl SIS96X_Get_Mac_Wait ;if not ask again - xor eax, eax ;return zero in eax indicating failure - ;*******Debug ********************** -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Str_GetMac_Failed - call sys_msg_board_str -end if - jmp SIS960_get_mac_addr_done - ;**********EEprom access granted, read MAC from card************* -SIS900_Got_EEP_Access: - ; zero based so 3-16 bit reads will take place - mov ecx, 2 -SIS96x_mac_read_loop: - mov eax, SIS900_EEPROMMACAddr;Base Mac Address - add eax, ecx ;Current Mac Byte Offset - push ecx - call sis900_read_eeprom ;try to read 16 bits - pop ecx - mov [node_addr+ecx*2], ax ;save 16 bits to the MAC ID varible - dec ecx ;one less word to read - jns SIS96x_mac_read_loop ;if more read more - mov eax, 1 ;return non-zero indicating success - ;*******Debug Print MAC ID to debug window********************** -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Str_GetMac_Address2 - call sys_msg_board_str - mov edx, node_addr - call Create_Mac_String -end if - ;**********Tell EEPROM We are Done Accessing It********************* -SIS960_get_mac_addr_done: - lea edx, [ebp+SIS900_mear] ; Eeprom access register - mov eax, SIS900_EEDONE ;tell eeprom we are done - out dx, eax - ret -;*************************************************************************** -;* sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model -;* @pci_dev: the sis900 pci device -;* @net_dev: the net device to get address for -;* -;* Older SiS900 and friends, use EEPROM to store MAC address. -;* MAC address is read from read_eeprom() into @net_dev->dev_addr. -;* done/untested -;*************************************************************************** -SIS900_get_mac_addr: - ;*******Debug ********************** -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Str_GetMac_Start - call sys_msg_board_str -end if - ;******** check to see if we have sane EEPROM ******* - mov eax, SIS900_EEPROMSignature;Base Eeprom Signature - call sis900_read_eeprom ;try to read 16 bits - cmp ax, 0xffff - je SIS900_Bad_Eeprom - cmp ax, 0 - je SIS900_Bad_Eeprom - ;**************Read MacID************** - ; zero based so 3-16 bit reads will take place - mov ecx, 2 -SIS900_mac_read_loop: - mov eax, SIS900_EEPROMMACAddr;Base Mac Address - add eax, ecx ;Current Mac Byte Offset - push ecx - call sis900_read_eeprom ;try to read 16 bits - pop ecx - mov [node_addr+ecx*2], ax ;save 16 bits to the MAC ID storage - dec ecx ;one less word to read - jns SIS900_mac_read_loop ;if more read more - mov eax, 1 ;return non-zero indicating success - ;*******Debug Print MAC ID to debug window********************** -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Str_GetMac_Address - call sys_msg_board_str - mov edx, node_addr - call Create_Mac_String -end if - ret - -SIS900_Bad_Eeprom: - xor eax, eax - ;*******Debug ********************** -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Str_GetMac_Failed - call sys_msg_board_str -end if - ret -;*************************************************************************** -;* Get_Mac_SIS635_900_REV: - Get MAC address for model 635 -;* -;* -;*************************************************************************** -Get_Mac_SIS635_900_REV: -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Str_GetMac_Start - call sys_msg_board_str -end if - mov ebp, [io_addr] - lea edx, [ebp+SIS900_rfcr] - in eax, dx - mov edi, eax; EDI=rfcrSave - lea edx, [ebp+SIS900_cr] - or eax, SIS900_RELOAD - out dx, eax - xor eax, eax - out dx, eax - ; Disable packet filtering before setting filter - lea edx, [ebp+SIS900_rfcr] - mov eax, edi - and edi, not SIS900_RFEN - out dx, eax - ; Load MAC to filter data register - xor ecx, ecx - mov esi, node_addr -.get_mac_loop: - lea edx, [ebp+SIS900_rfcr] - mov eax, ecx - shl eax, SIS900_RFADDR_shift - out dx, eax - lea edx, [ebp+SIS900_rfdr] - in eax, dx - mov [esi], ax - add esi, 2 - inc ecx - cmp ecx, 3 - jne .get_mac_loop - ; Enable packet filtering - ;lea edx,[ebp+SIS900_rfcr] - ;mov eax,edi - ;or eax,SIS900_RFEN - ;out dx, eax - ;*******Debug Print MAC ID to debug window********************** -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Str_GetMac_Address - call sys_msg_board_str - mov edx, node_addr - call Create_Mac_String -end if - ret -;*************************************************************************** -;* Function: sis900_read_eeprom -;* -;* Description: reads and returns a given location from EEPROM -;* -;* Arguments: eax - location: requested EEPROM location -;* -;* Returns: eax : contents of requested EEPROM location -;* -; Read Serial EEPROM through EEPROM Access Register, Note that location is -; in word (16 bits) unit */ -;done+ -;*************************************************************************** -sis900_read_eeprom: - push esi - push edx - push ecx - push ebx - mov ebp, [io_addr] - mov ebx, eax ;location of Mac byte to read - or ebx, SIS900_EEread ; - lea edx, [ebp+SIS900_mear]; Eeprom access register - xor eax, eax ; start send - out dx, eax - call SIS900_Eeprom_Delay_1 - mov eax, SIS900_EECLK - out dx, eax - call SIS900_Eeprom_Delay_1 - ;************ Shift the read command (9) bits out. ********* - mov cl, 8 ; -sis900_read_eeprom_Send: - mov eax, 1 - shl eax, cl - and eax, ebx - jz SIS900_Read_Eeprom_8 - mov eax, 9 - jmp SIS900_Read_Eeprom_9 -SIS900_Read_Eeprom_8: - mov eax, 8 -SIS900_Read_Eeprom_9: - out dx, eax - call SIS900_Eeprom_Delay_1 - or eax, SIS900_EECLK - out dx, eax - call SIS900_Eeprom_Delay_1 - cmp cl, 0 - je sis900_read_eeprom_Send_Done - dec cl - jmp sis900_read_eeprom_Send - ;********************* -sis900_read_eeprom_Send_Done: - mov eax, SIS900_EECS ; - out dx, eax - call SIS900_Eeprom_Delay_1 - ;********** Read 16-bits of data in *************** - mov cx, 16 ;16 bits to read -sis900_read_eeprom_Send2: - mov eax, SIS900_EECS - out dx, eax - call SIS900_Eeprom_Delay_1 - or eax, SIS900_EECLK - out dx, eax - call SIS900_Eeprom_Delay_1 - in eax, dx - shl ebx, 1 - and eax, SIS900_EEDO - jz SIS900_Read_Eeprom_0 - or ebx, 1 -SIS900_Read_Eeprom_0: - dec cx - jnz sis900_read_eeprom_Send2 - ;************** Terminate the EEPROM access. ************** - xor eax, eax - out dx, eax - call SIS900_Eeprom_Delay_1 - mov eax, SIS900_EECLK - out dx, eax - mov eax, ebx - and eax, 0x0000ffff ;return only 16 bits - pop ebx - pop ecx - pop edx - pop esi - ret -;*************************************************************************** -; Function -; SIS900_Eeprom_Delay_1 -; Description -; -; -; -; -;*************************************************************************** -SIS900_Eeprom_Delay_1: - push eax - in eax, dx - pop eax - ret - -;*************************************************************************** -; Function -; SIS900_poll -; Description -; polls card to see if there is a packet waiting -; -; Currently only supports one descriptor per packet, if packet is fragmented -; between multiple descriptors you will lose part of the packet -;*************************************************************************** -if defined SIS900_DEBUG -SIS900_Debug_Pull_Packet_good db 'Good Packet Waiting: ',13,10,0 -SIS900_Debug_Pull_Bad_Packet_Status db 'Bad Packet Waiting: Status',13,10,0 -SIS900_Debug_Pull_Bad_Packet_Size db 'Bad Packet Waiting: Size',13,10,0 -end if -SIS900_poll: - ;**************Get Status ************** - xor eax, eax ;get RX_Status - mov [eth_rx_data_len], ax - mov al, [cur_rx] ;find current discriptor - imul eax, 12 ; - mov ecx, [rxd+eax+4] ; get receive status - ;**************Check Status ************** - mov ebx, ecx ;move status - ;Check RX_Status to see if packet is waiting - and ebx, 0x80000000 - jnz SIS900_poll_IS_packet - ret - ;**********There is a packet waiting check it for errors************** -SIS900_poll_IS_packet: - mov ebx, ecx ;move status - and ebx, 0x67C0000 ;see if there are any errors - jnz SIS900_Poll_Error_Status - ;**************Check size of packet************* - and ecx, SIS900_DSIZE ;get packet size minus CRC - cmp cx, SIS900_CRC_SIZE - ;make sure packet contains data - jle SIS900_Poll_Error_Size - ;*******Copy Good Packet to receive buffer****** - sub cx, SIS900_CRC_SIZE ;dont want crc - mov word [eth_rx_data_len], cx ;save size of packet - ;**********Continue copying packet**************** - push ecx - ; first copy dword-wise, divide size by 4 - shr ecx, 2 - mov esi, [rxd+eax+8] ; set source - add esi, OS_BASE ; get linear address - mov edi, Ether_buffer ; set destination - cld ; clear direction - rep movsd ; copy the dwords - pop ecx - and ecx, 3 ; - rep movsb - ;********Debug, tell user we have a good packet************* -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Pull_Packet_good - call sys_msg_board_str -end if - jmp SIS900_Poll_Cnt ; - ;*************Error occured let user know through debug window*********** -SIS900_Poll_Error_Status: -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Pull_Bad_Packet_Status - call sys_msg_board_str -end if - jmp SIS900_Poll_Cnt -SIS900_Poll_Error_Size: -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Pull_Bad_Packet_Size - call sys_msg_board_str -end if - ;*************Increment to next available descriptor************** -SIS900_Poll_Cnt: - ;Reset status, allow ethernet card access to descriptor - mov ecx, RX_BUFF_SZ - mov [rxd+eax+4], ecx ; - inc [cur_rx] ;get next descriptor - and [cur_rx], 3 ;only 4 descriptors 0-3 - ;******Enable Receiver************ - mov ebp, [io_addr] ; Base Address - lea edx, [ebp+SIS900_cr]; Command Register offset - in eax, dx ; Get current Command Register - or eax, SIS900_RxENA;Enable Receive - out dx, eax - ret -;*************************************************************************** -; Function -; SIS900_transmit -; Description -; Transmits a packet of data via the ethernet card -; Pointer to 48 bit destination address in edi -; Type of packet in bx -; size of packet in ecx -; pointer to packet data in esi -; -; only one transmit descriptor is used -; -;*************************************************************************** -if defined SIS900_DEBUG -SIS900_Debug_Transmit_Packet db 'Transmitting Packet: ',13,10,0 -SIS900_Debug_Transmit_Packet_Err db 'Transmitting Packet Error: ',13,10,0 -end if -str1 db 'Transmitting packet:',13,10,0 -str2 db ' ',0 -SIS900_transmit: - mov ebp, [io_addr] ; Base Address - ;******** Stop the transmitter ******** - lea edx, [ebp+SIS900_cr]; Command Register offset - in eax, dx ; Get current Command Register - or eax, SIS900_TxDIS; Disable Transmitter - out dx, eax - ;*******load Transmit Descriptor Register ******* - lea edx, [ebp+SIS900_txdp] - mov eax, txd - OS_BASE - out dx, eax - ;******* copy packet to descriptor******* - push esi - mov esi, edi ;copy destination addess - mov edi, txb - cld - movsd - movsw - mov esi, node_addr;copy my mac address - movsd - movsw - mov [edi], bx ;copy packet type - add edi, 2 - pop esi ;restore pointer to source of packet - push ecx ;save packet size - shr ecx, 2 ;divide by 4, size in bytes send in dwords - rep movsd ;copy data to decriptor - pop ecx ;restore packet size - push ecx ;save packet size - and ecx, 3 ;last three bytes if not a multiple of 4 - rep movsb - ;**************set length tag************** - pop ecx ;restore packet size - add ecx, SIS900_ETH_HLEN;add header to length - and ecx, SIS900_DSIZE; - ;**************pad to minimum packet size **************not needed - ;cmp ecx, SIS900_ETH_ZLEN - ;jge SIS900_transmit_Size_Ok - ;push ecx - ;mov ebx, SIS900_ETH_ZLEN - ;sub ebx, ecx - ;mov ecx, ebx - ;rep movsb - ;pop ecx -SIS900_transmit_Size_Ok: - mov [txd+4], dword 0x80000000 ;card owns descriptor - or [txd+4], ecx ;set size of packet -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Transmit_Packet - call sys_msg_board_str -end if - ;***************restart the transmitter ******** - lea edx, [ebp+SIS900_cr] - in eax, dx ; Get current Command Register - or eax, SIS900_TxENA; Enable Transmitter - out dx, eax - ;****make sure packet transmitted successfully**** -; mov esi,10 -; call delay_ms - mov eax, [txd+4] - and eax, 0x6200000 - jz SIS900_transmit_OK - ;**************Tell user there was an error through debug window -if defined SIS900_DEBUG - mov esi, SIS900_Debug_Transmit_Packet_Err - call sys_msg_board_str -end if -SIS900_transmit_OK: - ;******** Disable interrupts by clearing the interrupt mask. ******** - lea edx, [ebp+SIS900_imr] ; Interupt Mask Register - xor eax, eax - out dx, eax - ret - -;*************************************************************************** -;* Function: Create_Mac_String -;* -;* Description: Converts the 48 bit value to a string for display -;* -;* String Format: XX:XX:XX:XX:XX:XX -;* -;* Arguments: node_addr is location of 48 bit MAC ID -;* -;* Returns: Prints string to general debug window -;* -;* -;done -;*************************************************************************** -if defined SIS900_DEBUG - -SIS900_Char_String db '0','1','2','3','4','5','6','7','8','9' - db 'A','B','C','D','E','F' -Mac_str_build: - times 20 db 0 -Create_Mac_String: - pusha - xor ecx, ecx -Create_Mac_String_loop: - mov al, byte [edx+ecx];[node_addr+ecx] - push eax - shr eax, 4 - and eax, 0x0f - mov bl, byte [SIS900_Char_String+eax] - mov [Mac_str_build+ecx*3], bl - pop eax - and eax, 0x0f - mov bl, byte [SIS900_Char_String+eax] - mov [Mac_str_build+1+ecx*3], bl - cmp ecx, 5 - je Create_Mac_String_done - mov bl, ':' - mov [Mac_str_build+2+ecx*3], bl - inc ecx - jmp Create_Mac_String_loop -Create_Mac_String_done: ;Insert CR and Zero Terminate - mov [Mac_str_build+2+ecx*3], byte 13 - mov [Mac_str_build+3+ecx*3], byte 10 - mov [Mac_str_build+4+ecx*3], byte 0 - mov esi, Mac_str_build - call sys_msg_board_str ;Print String to message board - popa - ret -end if -;*************************************************************************** -;* Set device to be a busmaster in case BIOS neglected to do so. -;* Also adjust PCI latency timer to a reasonable value, 64. -;*************************************************************************** -SIS900_adjust_pci_device: - ;*******Get current setting************************ - mov al, 2 ;read a word - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, 0x04 ;from command Register - call pci_read_reg - ;******see if its already set as bus master******** - mov bx, ax - and bx, 5 - cmp bx, 5 - je SIS900_adjust_pci_device_Latency - ;******Make card a bus master******* - mov cx, ax ;value to write - mov bh, [pci_dev] - mov al, 2 ;write a word - or cx, 5 - mov ah, [pci_bus] - mov bl, 0x04 ;to command register - call pci_write_reg - ;******Check latency setting*********** -SIS900_adjust_pci_device_Latency: - ;*******Get current latency setting************************ - mov al, 1 ;read a byte - mov bh, [pci_dev] - mov ah, [pci_bus] - mov bl, 0x0D ;from Lantency Timer Register - call pci_read_reg - ;******see if its aat least 64 clocks******** - cmp ax, 64 - jge SIS900_adjust_pci_device_Done - ;******Set latency to 32 clocks******* - mov cx, 64 ;value to write - mov bh, [pci_dev] - mov al, 1 ;write a byte - mov ah, [pci_bus] - mov bl, 0x0D ;to Lantency Timer Register - call pci_write_reg - ;******Check latency setting*********** -SIS900_adjust_pci_device_Done: - ret diff --git a/kernel/trunk/network/eth_drv/ethernet.inc b/kernel/trunk/network/eth_drv/ethernet.inc deleted file mode 100644 index 4834ce1912..0000000000 --- a/kernel/trunk/network/eth_drv/ethernet.inc +++ /dev/null @@ -1,525 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; ETHERNET.INC ;; -;; ;; -;; Ethernet network layer for Menuet OS ;; -;; ;; -;; This file contains the following: ;; -;; PCI bus scanning for valid devices ;; -;; Table of supported ethernet drivers ;; -;; Code to identify and activate a supported driver ;; -;; ARP handler ;; -;; Driver interface to the IP layer ;; -;; Gateway support ;; -;; ;; -;; Individual driver files are included here ;; -;; ;; -;; The PCI bus scanning code was ported from the etherboot ;; -;; 5.0.6 project. The copyright statement for that code is ;; -;; ;; -;; GNU GENERAL PUBLIC LICENSE ;; -;; Version 2, June 1991 ;; -;; ;; -;; remaining parts Copyright 2002 Mike Hibbett ;; -;; mikeh@oceanfree.net ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -;******************************************************************** -; Interface -; ethernet_driver called by stack_handler in stack.inc -; eth_probe called by app_stack_handler in stack.inc -; -;******************************************************************** - -ETHER_IP equ 0x0008 ; Reversed from 0800 for intel -ETHER_ARP equ 0x0608 ; Reversed from 0806 for intel -ETHER_RARP equ 0x3580 - -struc ETH_FRAME -{ .DstMAC dp ? ;destination MAC-address [6 bytes] - .SrcMAC dp ? ;source MAC-address [6 bytes] - .Type dw ? ;type of the upper-layer protocol [2 bytes] - .Data db ? ;data [46-1500 bytes] - } - -virtual at Ether_buffer - ETH_FRAME ETH_FRAME -end virtual - - -; Some useful information on data structures - -; Ethernet Packet - ARP Request example -; -; 0 1 2 3 -; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -; -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Dest H/W Address | -; | ( 14 byte header ) | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | | Source H/W Address | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Protocol - ARP 08 06 | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | H/W Type 00 01 | Protocol Type 08 00 | -; | ( ARP Request packet ) | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | HLen 0x06 | PLen 0x04 | OpCode 00 01 | -; | ( 0001 for request, 0002 for reply ) | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Source Hardware Address ( MAC Address ) | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | | Source IP Address | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | | Destination Hardware Address | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Destination IP Address | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -; Include individual drivers source files at this point. -; If you create a new driver, include it below. - -include "drivers/rtl8029.inc" -include "drivers/i8255x.inc" -include "drivers/rtl8139.inc" -include "drivers/3c59x.inc" -include "drivers/sis900.inc" -include "drivers/pcnet32.inc" -include "drivers/rtl8169.inc" -include "drivers/forcedeth.inc" -include "drivers/r6040.inc" - -; PCICards -; ======== -; PCI vendor and hardware types for hardware supported by the above drivers -; If you add a driver, ensure you update this datastructure, otherwise the -; card will not be probed. -; Each driver is defined by 4 double words. These are -; PCIVendorDevice probeFunction ResetFunction PollFunction transmitFunction -; The last entry must be kept at all zeros, to indicate the end of the list -; As a PCI driver may support more than one hardware implementation, there may -; be several lines which refer to the same functions. -; The first driver found on the PCI bus will be the one used. - -PCICARDS_ENTRY_SIZE equ 24 ; Size of each PCICARDS entry - -iglobal -PCICards: -dd 0x12098086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 -dd 0x10298086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 -dd 0x12298086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 -dd 0x10308086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 -dd 0x24498086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 -dd 0x10688086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 - -dd 0x802910ec, rtl8029_probe, rtl8029_reset, rtl8029_poll, rtl8029_transmit, 0 - -dd 0x813910ec, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x813810ec, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x12111113, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x13601500, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x13604033, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x13001186, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x13401186, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0xab0613d1, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0xa1171259, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0xa11e1259, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0xab0614ea, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0xab0714ea, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x123411db, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x91301432, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x101202ac, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x0106018a, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x1211126c, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x81391743, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable -dd 0x8139021b, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable - -dd 0x816810ec, rtl8169_probe, rtl8169_reset, rtl8169_poll, rtl8169_transmit, 0 -dd 0x816910ec, rtl8169_probe, rtl8169_reset, rtl8169_poll, rtl8169_transmit, 0 -dd 0x011616ec, rtl8169_probe, rtl8169_reset, rtl8169_poll, rtl8169_transmit, 0 -dd 0x43001186, rtl8169_probe, rtl8169_reset, rtl8169_poll, rtl8169_transmit, 0 -dd 0x816710ec, rtl8169_probe, rtl8169_reset, rtl8169_poll, rtl8169_transmit, 0 - -dd 0x590010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x592010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x597010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x595010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x595110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x595210b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x900010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x900110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x900410b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x900510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x900610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x900A10b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x905010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x905110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x905510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x905810b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x905A10b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x920010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x980010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x980510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x764610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x505510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x605510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x605610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x5b5710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x505710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x515710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x525710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x656010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x656210b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x656410b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 -dd 0x450010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 - -dd 0x09001039, SIS900_probe, SIS900_reset, SIS900_poll, SIS900_transmit, 0 -dd 0x70161039, SIS900_probe, SIS900_reset, SIS900_poll, SIS900_transmit, 0 - -dd 0x20001022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit, 0 -dd 0x26251022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit, 0 -dd 0x20011022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit, 0 - -dd 0x006610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; nVidia Corporation nForce2 Ethernet Controller -dd 0x01c310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x00D610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x008610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x008c10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x00e610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x00df10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x005610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x005710de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x003710de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x003810de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x026810de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x026910de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x037210de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x037310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x03e510de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x03e610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x03ee10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x03ef10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x045010de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x045110de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x045210de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x045310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x054c10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x054d10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x054e10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x054f10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x07dc10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x07dd10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x07de10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x07df10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x076010de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; MCP77 Ethernet Controller -dd 0x076110de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x076210de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x076310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x0ab010de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x0ab110de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x0ab210de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x0ab310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested -dd 0x0d7d10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested - -dd 0x604017F3, r6040_probe, r6040_reset, r6040_poll, r6040_transmit, 0 - -rb PCICARDS_ENTRY_SIZE ; end of list marker, do not remove -endg - -uglobal -;Net-stack's interface's settings - node_addr: - db 0,0,0,0,0,0 - gateway_ip: - dd 0 - dns_ip: - dd 0 - - eth_rx_data_len: - dw 0 - eth_status: - dd 0 - io_addr: - dd 0 - hdrtype: - db 0 - vendor_device: - dd 0 - pci_data: - dd 0 - pci_dev: - dd 0 - pci_bus: - dd 0 - - ; These will hold pointers to the selected driver functions - drvr_probe: - dd 0 - drvr_reset: - dd 0 - drvr_poll: - dd 0 - drvr_transmit: - dd 0 - drvr_cable: - dd 0 - -endg - -iglobal - broadcast_add: - db 0xff,0xff,0xff,0xff,0xff,0xff - subnet_mask: - dd 0x00ffffff ; 255.255.255.0 -endg - -include "arp.inc" ;arp-protocol functions -include "pci.inc" ;PCI bus access functions - - -;*************************************************************************** -; Function -; eth_tx -; -; Description -; Looks at the NET1OUT_QUEUE for data to send. -; Stores that destination IP in a location used by the tx routine -; Looks up the MAC address in the ARP table; stores that where -; the tx routine can get it -; Get the length of the data. Store that where the tx routine wants it -; Call tx -; Places buffer on empty queue when the tx routine finished -; -;*************************************************************************** -proc eth_tx stdcall uses ebx esi edi -local MACAddress dp ? ;allocate 6 bytes in the stack - - ; Look for a buffer to tx - mov eax, NET1OUT_QUEUE - call dequeue - cmp ax, NO_BUFFER - je .exit ; Exit if no buffer available - - push eax;save buffer number - - ; convert buffer pointer eax to the absolute address - imul eax, IPBUFFSIZE - add eax, IPbuffs - - ; Extract the destination IP - ; find the destination IP in the ARP table, get MAC - ; store this MAC in 'MACAddress' - mov ebx, eax ; Save buffer address - mov edx, [ebx + 16] ; get destination address - - ; If the destination address is 255.255.255.255, - ; set the MACAddress to all ones ( broadcast ) - cld - mov esi, broadcast_add - lea edi, [MACAddress] - movsd - movsw - cmp edx, 0xffffffff - je .send ; If it is broadcast, just send - - lea eax, [MACAddress];cause this is local variable - stdcall arp_table_manager, ARP_TABLE_IP_TO_MAC, edx, eax;opcode,IP,MAC_ptr - Get the MAC address. - - cmp eax, ARP_VALID_MAPPING - je .send - - ; No valid entry. Has the request been sent, but timed out? - cmp eax, ARP_RESPONSE_TIMEOUT - je .freebuf - - .wait_response: ;we wait arp-response - ; Re-queue the packet, and exit - pop ebx - mov eax, NET1OUT_QUEUE - call queue ; Get the buffer back - jmp .exit - - .send: ;if ARP_VALID_MAPPING then send the packet - lea edi, [MACAddress] ; Pointer to 48 bit destination address - movzx ecx, word[ebx+2] ; Size of IP packet to send - xchg ch, cl ; because mirror byte-order - mov esi, ebx ; Pointer to packet data - mov bx, ETHER_IP ; Type of packet - push ebp - call dword [drvr_transmit]; Call the drivers transmit function - pop ebp - - ; OK, we have sent a packet, so increment the count - inc dword [ip_tx_count] - - ; And finally, return the buffer to the free queue - .freebuf: - pop eax - call freeBuff - - .exit: - ret -endp - -;*************************************************************************** -; Function -; ether_IP_handler -; -; Description -; Called when an IP ethernet packet is received on the ethernet -; Header + Data is in Ether_buffer[] -; We just need to get a buffer from the 'free' queue, and -; store the packet in it, then insert the packet number into the -; IPRX queue. -; If no queue entry is available, the packet is silently discarded -; All registers may be destroyed -; -;*************************************************************************** -;uglobal -; ether_IP_handler_cnt dd ? -;endg -ether_IP_handler: - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je eiph00x - - ; convert buffer pointer eax to the absolute address - push eax - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs - - mov edi, eax - - ; get a pointer to the start of the DATA - mov esi, ETH_FRAME.Data - - ; Now store it all away - mov ecx, IPBUFFSIZE / 4 ; Copy all of the available - ; data across - worse case - cld - rep movsd - -; inc [ether_IP_handler_cnt] -; DEBUGF 1, "K : ether_IP_handler (%u)\n", [ether_IP_handler_cnt] - - ; And finally, place the buffer in the IPRX queue - pop ebx - mov eax, IPIN_QUEUE - call queue - -eiph00x: - ret - -;*************************************************************************** -; Function -; eth_probe -; Description -; Searches for an ethernet card. If found, the card is enabled and -; the ethernet -> IP link established -; -; This function scans the PCI bus looking for a supported device. -; ISA bus is currently not supported. -; -; eax is 0 if no hardware found -;*************************************************************************** -eth_probe: - ; Find a card on the PCI bus, and get it's address - call scan_bus ; Find the ethernet cards PIC address - xor eax, eax - cmp [io_addr], eax - je ep_00x ; Return 0 in eax if no cards found - - call dword [drvr_probe] ; Call the drivers probe function - - mov eax, [io_addr] ; return a non zero value - -ep_00x: - ret - -;*************************************************************************** -; Function -; ethernet_driver -; -; Description -; The ethernet RX and TX handler -; This is a kernel function, called by stack_handler -; -;*************************************************************************** -ethernet_driver: - ; Do nothing if the driver is inactive - cmp [ethernet_active], byte 0 - je eth_exit - - call eth_rx - call eth_tx - -eth_exit: - ret - -;*************************************************************************** -; Function -; eth_rx -; -; Description -; Polls the ethernet card for received data. Extracts if present -; Depending on the Protocol within the packet: -; ARP : Pass to ARP_handler. This may result in an ARP reply -; being tx'ed -; IP : Store in an IP buffer -; -;*************************************************************************** -eth_rx: - xor ax, ax - mov [eth_rx_data_len], ax - call dword [drvr_poll] ; Call the drivers poll function - - mov ax, [eth_rx_data_len] - cmp ax, 0 - je .exit - - - ; Check the protocol. Call appropriate handler - - mov ax, [ETH_FRAME.Type]; The address of the protocol word - - cmp ax, ETHER_IP - je .is_ip ; It's IP - - cmp ax, ETHER_ARP - je .is_arp ; It is ARP - -; DEBUGF 1,"K : eth_rx - dumped (%u)\n", ax - inc [dumped_rx_count] - jmp .exit ; If not IP or ARP, ignore - - .is_ip: -; DEBUGF 1,"K : eth_rx - IP packet\n" - inc dword [ip_rx_count] - call ether_IP_handler - jmp .exit - - .is_arp: -; DEBUGF 1,"K : eth_rx - ARP packet\n" - ; At this point, the packet is still in the Ether_buffer - call arp_handler - - .exit: - ret diff --git a/kernel/trunk/network/eth_drv/pci.inc b/kernel/trunk/network/eth_drv/pci.inc deleted file mode 100644 index 56fa23286b..0000000000 --- a/kernel/trunk/network/eth_drv/pci.inc +++ /dev/null @@ -1,351 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -;*************************************************************************** -; -; PCI CODE FOLLOWS -; -; the following functions provide access to the PCI interface. -; These functions are used by scan_bus, and also some ethernet drivers -; -;*************************************************************************** - -; PCI Bus defines -PCI_HEADER_TYPE equ 0x0e ;8 bit -PCI_BASE_ADDRESS_0 equ 0x10 ;32 bit -PCI_BASE_ADDRESS_5 equ 0x24 ;32 bits -PCI_BASE_ADDRESS_SPACE_IO equ 0x01 -PCI_VENDOR_ID equ 0x00 ;16 bit -PCI_BASE_ADDRESS_IO_MASK equ 0xFFFFFFFC - -;*************************************************************************** -; Function -; config_cmd -; -; Description -; creates a command dword for use with the PCI bus -; bus # in ebx -; devfn in ecx -; where in edx -; -; command dword returned in eax -; Only eax destroyed -;*************************************************************************** -config_cmd: - push ecx - mov eax, ebx - shl eax, 16 - or eax, 0x80000000 - shl ecx, 8 - or eax, ecx - pop ecx - or eax, edx - and eax, 0xFFFFFFFC - ret - -;*************************************************************************** -; Function -; pcibios_read_config_byte -; -; Description -; reads a byte from the PCI config space -; bus # in ebx -; devfn in ecx -; where in edx ( ls 16 bits significant ) -; -; byte returned in al ( rest of eax zero ) -; Only eax/edx destroyed -;*************************************************************************** -pcibios_read_config_byte: - call config_cmd - push dx - mov dx, 0xCF8 - out dx, eax - pop dx - - xor eax, eax - and dx, 0x03 - add dx, 0xCFC -; and dx, 0xFFC - in al, dx - ret - -;*************************************************************************** -; Function -; pcibios_read_config_word -; -; Description -; reads a word from the PCI config space -; bus # in ebx -; devfn in ecx -; where in edx ( ls 16 bits significant ) -; -; word returned in ax ( rest of eax zero ) -; Only eax/edx destroyed -;*************************************************************************** -pcibios_read_config_word: - call config_cmd - push dx - mov dx, 0xCF8 - out dx, eax - pop dx - - xor eax, eax - and dx, 0x02 - add dx, 0xCFC -; and dx, 0xFFC - in ax, dx - ret - -;*************************************************************************** -; Function -; pcibios_read_config_dword -; -; Description -; reads a dword from the PCI config space -; bus # in ebx -; devfn in ecx -; where in edx ( ls 16 bits significant ) -; -; dword returned in eax -; Only eax/edx destroyed -;*************************************************************************** -pcibios_read_config_dword: - push edx - call config_cmd - push dx - mov dx, 0xCF8 - out dx, eax - pop dx - xor eax, eax - mov dx, 0xCFC - in eax, dx - pop edx - ret - -;*************************************************************************** -; Function -; pcibios_write_config_byte -; -; Description -; write a byte in al to the PCI config space -; bus # in ebx -; devfn in ecx -; where in edx ( ls 16 bits significant ) -; -; Only eax/edx destroyed -;*************************************************************************** -pcibios_write_config_byte: - push ax - call config_cmd - push dx - mov dx, 0xCF8 - out dx, eax - pop dx - pop ax - - and dx, 0x03 - add dx, 0xCFC - out dx, al - ret - -;*************************************************************************** -; Function -; pcibios_write_config_word -; -; Description -; write a word in ax to the PCI config space -; bus # in ebx -; devfn in ecx -; where in edx ( ls 16 bits significant ) -; -; Only eax/edx destroyed -;*************************************************************************** -pcibios_write_config_word: - push ax - call config_cmd - push dx - mov dx, 0xCF8 - out dx, eax - pop dx - pop ax - - and dx, 0x02 - add dx, 0xCFC - out dx, ax - ret - -;*************************************************************************** -; Function -; delay_us -; -; Description -; delays for 30 to 60 us -; -; I would prefer this routine to be able to delay for -; a selectable number of microseconds, but this works for now. -; -; If you know a better way to do 2us delay, pleae tell me! -;*************************************************************************** -delay_us: - push eax - push ecx - - mov ecx, 2 - - in al, 0x61 - and al, 0x10 - mov ah, al - cld - -dcnt1: - in al, 0x61 - and al, 0x10 - cmp al, ah - jz dcnt1 - - mov ah, al - loop dcnt1 - - pop ecx - pop eax - - ret - -;*************************************************************************** -; Function -; scan_bus -; -; Description -; Scans the PCI bus for a supported device -; If a supported device is found, the drvr_ variables are initialised -; to that drivers functions ( as defined in the PCICards table) -; -; io_addr holds card I/O space. 32 bit, but only LS 16 bits valid -; pci_data holds the PCI vendor + device code -; pci_dev holds PCI bus dev # -; pci_bus holds PCI bus # -; -; io_addr will be zero if no card found -; -;*************************************************************************** -scan_bus: - xor eax, eax - mov [hdrtype], al - mov [pci_data], eax - - xor ebx, ebx ; ebx = bus# 0 .. 255 - -sb_bus_loop: - xor ecx, ecx ; ecx = devfn# 0 .. 254 ( not 255? ) - -sb_devf_loop: - mov eax, ecx - and eax, 0x07 - - cmp eax, 0 - jne sb_001 - - mov edx, PCI_HEADER_TYPE - call pcibios_read_config_byte - mov [hdrtype], al - jmp sb_002 - -sb_001: - mov al, [hdrtype] - and al, 0x80 - cmp al, 0x80 - jne sb_inc_devf - -sb_002: - mov edx, PCI_VENDOR_ID - call pcibios_read_config_dword - mov [vendor_device], eax - cmp eax, 0xffffffff - je sb_empty - cmp eax, 0 - jne sb_check_vendor - -sb_empty: - mov [hdrtype], byte 0 - jmp sb_inc_devf - -sb_check_vendor: - ; iterate though PCICards until end or match found - mov esi, PCICards - -sb_check: - cmp [esi], dword 0 - je sb_inc_devf ; Quit if at last entry - cmp eax, [esi] - je sb_got_card - add esi, PCICARDS_ENTRY_SIZE - jmp sb_check - -sb_got_card: - ; indicate that we have found the card - mov [pci_data], eax - mov [pci_dev], ecx - mov [pci_bus], ebx - - ; Define the driver functions - push eax - mov eax, [esi+4] - mov [drvr_probe], eax - mov eax, [esi+8] - mov [drvr_reset], eax - mov eax, [esi+12] - mov [drvr_poll], eax - mov eax, [esi+16] - mov [drvr_transmit], eax - mov eax, [esi+20] - mov [drvr_cable], eax - pop eax - - mov edx, PCI_BASE_ADDRESS_0 - -sb_reg_check: - call pcibios_read_config_dword - mov [io_addr], eax - and eax, PCI_BASE_ADDRESS_IO_MASK - cmp eax, 0 - je sb_inc_reg - mov eax, [io_addr] - and eax, PCI_BASE_ADDRESS_SPACE_IO - cmp eax, 0 - je sb_inc_reg - - mov eax, [io_addr] - and eax, PCI_BASE_ADDRESS_IO_MASK - mov [io_addr], eax - -sb_exit1: - ret - -sb_inc_reg: - add edx, 4 - cmp edx, PCI_BASE_ADDRESS_5 - jbe sb_reg_check - -sb_inc_devf: - inc ecx - cmp ecx, 255 - jb sb_devf_loop - inc ebx - cmp ebx, 256 - jb sb_bus_loop - - ; We get here if we didn't find our card - ; set io_addr to 0 as an indication - xor eax, eax - mov [io_addr], eax - -sb_exit2: - ret diff --git a/kernel/trunk/network/ethernet.inc b/kernel/trunk/network/ethernet.inc new file mode 100644 index 0000000000..f34a29ab41 --- /dev/null +++ b/kernel/trunk/network/ethernet.inc @@ -0,0 +1,233 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ETHERNET.INC ;; +;; ;; +;; Ethernet network layer for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 3346 $ + +ETH_FRAME_MINIMUM = 60 + +struct ETH_header + + DstMAC dp ? ; destination MAC-address + SrcMAC dp ? ; source MAC-address + Type dw ? ; type of the upper-layer protocol + +ends + +struct ETH_DEVICE NET_DEVICE + + mac dp ? + +ends + +align 4 +iglobal + + ETH_BROADCAST dp 0xffffffffffff +endg + +;----------------------------------------------------------------- +; +; ETH_input +; +; This function is called by ethernet drivers, +; It pushes the received ethernet packets onto the eth_in_queue +; +; IN: [esp] = Pointer to buffer +; [esp+4] = size of buffer +; ebx = pointer to eth_device +; OUT: / +; +;----------------------------------------------------------------- +align 4 +ETH_input: + mov eax, [esp] + mov ecx, [esp+4] + + DEBUGF 1,"ETH_input: size=%u\n", ecx + cmp ecx, ETH_FRAME_MINIMUM + jb .dump + sub ecx, sizeof.ETH_header + + lea edx, [eax + sizeof.ETH_header] + mov ax, [eax + ETH_header.Type] + + cmp ax, ETHER_IPv4 + je IPv4_input + + cmp ax, ETHER_ARP + je ARP_input + + cmp ax, ETHER_IPv6 + je IPv6_input + + cmp ax, ETHER_PPP_DISCOVERY + je PPPoE_discovery_input + + cmp ax, ETHER_PPP_SESSION + je PPPoE_session_input + + DEBUGF 2,"ETH_input: Unknown packet type=%x\n", ax + + .dump: + DEBUGF 2,"ETH_input: dumping\n" + call kernel_free + add esp, 4 + ret + +;----------------------------------------------------------------- +; +; ETH_output +; +; IN: eax = pointer to source mac +; ebx = device ptr +; ecx = packet size +; edx = pointer to destination mac +; di = protocol +; +; OUT: edi = 0 on error, pointer to buffer otherwise +; eax = buffer start +; ebx = to device structure +; ecx = unchanged (packet size of embedded data) +; edx = size of complete buffer +; +;----------------------------------------------------------------- +align 4 +ETH_output: + + DEBUGF 1,"ETH_output: size=%u device=%x\n", ecx, ebx + + cmp ecx, [ebx + NET_DEVICE.mtu] + ja .exit + + push ecx + push di eax edx + + add ecx, sizeof.ETH_header + stdcall kernel_alloc, ecx + test eax, eax + jz .out_of_ram + mov edi, eax + + pop esi + movsd + movsw + pop esi + movsd + movsw + pop ax + stosw + + lea eax, [edi - sizeof.ETH_header] ; Set eax to buffer start + pop ecx + lea edx, [ecx + sizeof.ETH_header] ; Set edx to complete buffer size + + cmp edx, ETH_FRAME_MINIMUM + jbe .adjust_size + .done: + DEBUGF 1,"ETH_output: ptr=%x size=%u\n", eax, edx + ret + + .adjust_size: + mov edx, ETH_FRAME_MINIMUM + test edx, edx ; clear zero flag + jmp .done + + .out_of_ram: + DEBUGF 2,"ETH_output: Out of ram!\n" + add esp, 4+4+2+4 + sub edi, edi + ret + + .exit: + DEBUGF 2,"ETH_output: Packet too large!\n" + sub edi, edi + ret + + + +;----------------------------------------------------------------- +; +; ETH_API +; +; This function is called by system function 75 +; +; IN: subfunction number in bl +; device number in bh +; ecx, edx, .. depends on subfunction +; +; OUT: +; +;----------------------------------------------------------------- +align 4 +ETH_api: + + cmp bh, MAX_NET_DEVICES + ja .error + movzx eax, bh + mov eax, dword [NET_DRV_LIST + 4*eax] + cmp [eax + NET_DEVICE.type], NET_TYPE_ETH + jne .error + + and ebx, 0xff + cmp ebx, .number + ja .error + jmp dword [.table + 4*ebx] + + .table: + dd .packets_tx ; 0 + dd .packets_rx ; 1 + dd .bytes_tx ; 2 + dd .bytes_rx ; 3 + dd .read_mac ; 4 + dd .state ; 5 + .number = ($ - .table) / 4 - 1 + + .error: + or eax, -1 + ret + + .packets_tx: + mov eax, [eax + NET_DEVICE.packets_tx] + + ret + + .packets_rx: + mov eax, [eax + NET_DEVICE.packets_rx] + ret + + .bytes_tx: + mov ebx, dword [eax + NET_DEVICE.bytes_tx + 4] + mov eax, dword [eax + NET_DEVICE.bytes_tx] + mov [esp+20+4], ebx ; TODO: fix this ugly code + ret + + .bytes_rx: + mov ebx, dword [eax + NET_DEVICE.bytes_rx + 4] + mov eax, dword [eax + NET_DEVICE.bytes_rx] + mov [esp+20+4], ebx ; TODO: fix this ugly code + ret + + + .read_mac: + movzx ebx, word [eax + ETH_DEVICE.mac] + mov eax, dword [eax + ETH_DEVICE.mac + 2] + mov [esp+20+4], ebx ; TODO: fix this ugly code + ret + + .state: + mov eax, [eax + NET_DEVICE.state] + ret + diff --git a/kernel/trunk/network/icmp.inc b/kernel/trunk/network/icmp.inc index 47a82b1e34..9ef776eae8 100644 --- a/kernel/trunk/network/icmp.inc +++ b/kernel/trunk/network/icmp.inc @@ -1,193 +1,431 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; ICMP.INC ;; -;; ;; -;; Internet Control Message Protocol ( RFC 792 ) ;; -;; ;; -;; Last revision: 11.11.2006 ;; -;; ;; -;; This file contains the following: ;; -;; icmp_rx - processes ICMP-packets received by the IP layer ;; -;; ;; -;; Changes history: ;; -;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net ;; -;; 11.11.2006 - [Johnny_B] and [smb] ;; -;; ;; -;; Current status: ;; -;; This implemetation of ICMP proto supports message of ECHO type. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ICMP.INC ;; +;; ;; +;; Part of the tcp/ip network stack for KolibriOS ;; +;; ;; +;; Based on the work of [Johnny_B] and [smb] ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -struc ICMP_PACKET -{ .Type db ? ;+00 - .Code db ? ;+01 - .Checksum dw ? ;+02 - .Identifier dw ? ;+04 - .SequenceNumber dw ? ;+06 - .Data db ? ;+08 +$Revision: 2924 $ + +; ICMP types & codes + +ICMP_ECHOREPLY = 0 ; echo reply message + +ICMP_UNREACH = 3 +ICMP_UNREACH_NET = 0 ; bad net +ICMP_UNREACH_HOST = 1 ; bad host +ICMP_UNREACH_PROTOCOL = 2 ; bad protocol +ICMP_UNREACH_PORT = 3 ; bad port +ICMP_UNREACH_NEEDFRAG = 4 ; IP_DF caused drop +ICMP_UNREACH_SRCFAIL = 5 ; src route failed +ICMP_UNREACH_NET_UNKNOWN = 6 ; unknown net +ICMP_UNREACH_HOST_UNKNOWN = 7 ; unknown host +ICMP_UNREACH_ISOLATED = 8 ; src host isolated +ICMP_UNREACH_NET_PROHIB = 9 ; prohibited access +ICMP_UNREACH_HOST_PROHIB = 10 ; ditto +ICMP_UNREACH_TOSNET = 11 ; bad tos for net +ICMP_UNREACH_TOSHOST = 12 ; bad tos for host +ICMP_UNREACH_FILTER_PROHIB = 13 ; admin prohib +ICMP_UNREACH_HOST_PRECEDENCE = 14 ; host prec vio. +ICMP_UNREACH_PRECEDENCE_CUTOFF = 15 ; prec cutoff + +ICMP_SOURCEQUENCH = 4 ; Packet lost, slow down + +ICMP_REDIRECT = 5 ; shorter route, codes: +ICMP_REDIRECT_NET = 0 ; for network +ICMP_REDIRECT_HOST = 1 ; for host +ICMP_REDIRECT_TOSNET = 2 ; for tos and net +ICMP_REDIRECT_TOSHOST = 3 ; for tos and host + +ICMP_ALTHOSTADDR = 6 ; alternate host address +ICMP_ECHO = 8 ; echo service +ICMP_ROUTERADVERT = 9 ; router advertisement +ICMP_ROUTERADVERT_NORMAL = 0 ; normal advertisement +ICMP_ROUTERADVERT_NOROUTE_COMMON= 16 ; selective routing + +ICMP_ROUTERSOLICIT = 10 ; router solicitation +ICMP_TIMXCEED = 11 ; time exceeded, code: +ICMP_TIMXCEED_INTRANS = 0 ; ttl==0 in transit +ICMP_TIMXCEED_REASS = 1 ; ttl==0 in reass + +ICMP_PARAMPROB = 12 ; ip header bad +ICMP_PARAMPROB_ERRATPTR = 0 ; error at param ptr +ICMP_PARAMPROB_OPTABSENT = 1 ; req. opt. absent +ICMP_PARAMPROB_LENGTH = 2 ; bad length + +ICMP_TSTAMP = 13 ; timestamp request +ICMP_TSTAMPREPLY = 14 ; timestamp reply +ICMP_IREQ = 15 ; information request +ICMP_IREQREPLY = 16 ; information reply +ICMP_MASKREQ = 17 ; address mask request +ICMP_MASKREPLY = 18 ; address mask reply +ICMP_TRACEROUTE = 30 ; traceroute +ICMP_DATACONVERR = 31 ; data conversion error +ICMP_MOBILE_REDIRECT = 32 ; mobile host redirect +ICMP_IPV6_WHEREAREYOU = 33 ; IPv6 where-are-you +ICMP_IPV6_IAMHERE = 34 ; IPv6 i-am-here +ICMP_MOBILE_REGREQUEST = 35 ; mobile registration req +ICMP_MOBILE_REGREPLY = 36 ; mobile registreation reply +ICMP_SKIP = 39 ; SKIP + +ICMP_PHOTURIS = 40 ; Photuris +ICMP_PHOTURIS_UNKNOWN_INDEX = 1 ; unknown sec index +ICMP_PHOTURIS_AUTH_FAILED = 2 ; auth failed +ICMP_PHOTURIS_DECRYPT_FAILED = 3 ; decrypt failed + + + +struct ICMP_header + + Type db ? + Code db ? + Checksum dw ? + Identifier dw ? + SequenceNumber dw ? + +ends + + +align 4 +uglobal + ICMP_PACKETS_TX rd MAX_NET_DEVICES + ICMP_PACKETS_RX rd MAX_NET_DEVICES +endg + + + +;----------------------------------------------------------------- +; +; ICMP_init +; +;----------------------------------------------------------------- + +macro ICMP_init { + + xor eax, eax + mov edi, ICMP_PACKETS_TX + mov ecx, 2*MAX_NET_DEVICES + rep stosd + } -virtual at 0 - ICMP_PACKET ICMP_PACKET -end virtual - -; Example: -; ECHO message format +;----------------------------------------------------------------- ; +; ICMP_input: ; -; 0 1 2 3 -; 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Type | Code | Checksum | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Identifier | Sequence Number | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Data ... -; +-+-+-+-+- +; This procedure will send reply's to ICMP echo's +; and insert packets into sockets when needed ; - +; IN: Pointer to buffer in [esp] +; size of buffer in [esp+4] +; ebx = pointer to device struct +; ecx = ICMP Packet size +; esi = ptr to ICMP Packet data +; edi = ptr to ipv4 source and dest address ; -; ICMP types & codes, RFC 792 and FreeBSD's ICMP sources +; OUT: / ; +;----------------------------------------------------------------- +align 4 +ICMP_input: -ICMP_ECHOREPLY equ 0 ; echo reply message + DEBUGF 1,"ICMP_input:\n" -ICMP_UNREACH equ 3 - ICMP_UNREACH_NET equ 0 ; bad net - ICMP_UNREACH_HOST equ 1 ; bad host - ICMP_UNREACH_PROTOCOL equ 2 ; bad protocol - ICMP_UNREACH_PORT equ 3 ; bad port - ICMP_UNREACH_NEEDFRAG equ 4 ; IP_DF caused drop - ICMP_UNREACH_SRCFAIL equ 5 ; src route failed - ICMP_UNREACH_NET_UNKNOWN equ 6 ; unknown net - ICMP_UNREACH_HOST_UNKNOWN equ 7 ; unknown host - ICMP_UNREACH_ISOLATED equ 8 ; src host isolated - ICMP_UNREACH_NET_PROHIB equ 9 ; prohibited access - ICMP_UNREACH_HOST_PROHIB equ 10 ; ditto - ICMP_UNREACH_TOSNET equ 11 ; bad tos for net - ICMP_UNREACH_TOSHOST equ 12 ; bad tos for host - ICMP_UNREACH_FILTER_PROHIB equ 13 ; admin prohib - ICMP_UNREACH_HOST_PRECEDENCE equ 14 ; host prec vio. - ICMP_UNREACH_PRECEDENCE_CUTOFF equ 15 ; prec cutoff +; First, check the checksum (altough some implementations ignore it) -ICMP_SOURCEQUENCH equ 4 ; packet lost, slow down + push esi ecx + push [esi + ICMP_header.Checksum] + mov [esi + ICMP_header.Checksum], 0 + xor edx, edx + call checksum_1 + call checksum_2 + pop si + cmp dx, si + pop ecx edx + jne .checksum_mismatch -ICMP_REDIRECT equ 5 ; shorter route, codes: - ICMP_REDIRECT_NET equ 0 ; for network - ICMP_REDIRECT_HOST equ 1 ; for host - ICMP_REDIRECT_TOSNET equ 2 ; for tos and net - ICMP_REDIRECT_TOSHOST equ 3 ; for tos and host + cmp [edx + ICMP_header.Type], ICMP_ECHO ; Is this an echo request? + jne .check_sockets -ICMP_ALTHOSTADDR equ 6 ; alternate host address -ICMP_ECHO equ 8 ; echo service -ICMP_ROUTERADVERT equ 9 ; router advertisement - ICMP_ROUTERADVERT_NORMAL equ 0 ; normal advertisement - ICMP_ROUTERADVERT_NOROUTE_COMMON equ 16 ; selective routing +; We well re-use the packet so we can create the response as fast as possible +; Notice: this only works on pure ethernet -ICMP_ROUTERSOLICIT equ 10 ; router solicitation -ICMP_TIMXCEED equ 11 ; time exceeded, code: - ICMP_TIMXCEED_INTRANS equ 0 ; ttl==0 in transit - ICMP_TIMXCEED_REASS equ 1 ; ttl==0 in reass + DEBUGF 1,"got echo request\n" + mov [edx + ICMP_header.Type], ICMP_ECHOREPLY ; Change Packet type to reply -ICMP_PARAMPROB equ 12 ; ip header bad - ICMP_PARAMPROB_ERRATPTR equ 0 ; error at param ptr - ICMP_PARAMPROB_OPTABSENT equ 1 ; req. opt. absent - ICMP_PARAMPROB_LENGTH equ 2 ; bad length + mov esi, [esp] ; Start of buffer -ICMP_TSTAMP equ 13 ; timestamp request -ICMP_TSTAMPREPLY equ 14 ; timestamp reply -ICMP_IREQ equ 15 ; information request -ICMP_IREQREPLY equ 16 ; information reply -ICMP_MASKREQ equ 17 ; address mask request -ICMP_MASKREPLY equ 18 ; address mask reply -ICMP_TRACEROUTE equ 30 ; traceroute -ICMP_DATACONVERR equ 31 ; data conversion error -ICMP_MOBILE_REDIRECT equ 32 ; mobile host redirect -ICMP_IPV6_WHEREAREYOU equ 33 ; IPv6 where-are-you - ICMP_IPV6_IAMHERE equ 34 ; IPv6 i-am-here -ICMP_MOBILE_REGREQUEST equ 35 ; mobile registration req -ICMP_MOBILE_REGREPLY equ 36 ; mobile registreation reply -ICMP_SKIP equ 39 ; SKIP + cmp dword[edi + 4], 1 shl 24 + 127 + je .loopback -ICMP_PHOTURIS equ 40 ; Photuris - ICMP_PHOTURIS_UNKNOWN_INDEX equ 1 ; unknown sec index - ICMP_PHOTURIS_AUTH_FAILED equ 2 ; auth failed - ICMP_PHOTURIS_DECRYPT_FAILED equ 3 ; decrypt failed +; Update stats (and validate device ptr) + call NET_ptr_to_num + cmp edi,-1 + je .dump + inc [ICMP_PACKETS_RX + 4*edi] + inc [ICMP_PACKETS_TX + 4*edi] +; exchange dest and source address in IP header +; exchange dest and source MAC in ETH header + push dword [esi + ETH_header.DstMAC] + push dword [esi + ETH_header.SrcMAC] + pop dword [esi + ETH_header.DstMAC] + pop dword [esi + ETH_header.SrcMAC] + push word [esi + ETH_header.DstMAC + 4] + push word [esi + ETH_header.SrcMAC + 4] + pop word [esi + ETH_header.DstMAC + 4] + pop word [esi + ETH_header.SrcMAC + 4] + add esi, sizeof.ETH_header-2 -;*************************************************************************** -; Function -; icmp_rx [by Johnny_B] -; -; Description -; ICMP protocol handler -; This is a kernel function, called by ip_rx -; -; IN: -; buffer_number - # of IP-buffer. This buffer must be reused or marked as empty afterwards -; IPPacketBase - IP_PACKET base address -; IPHeaderLength - Header length of IP_PACKET -; -; OUT: -; EAX=not defined -; -; All used registers will be saved -; -;*************************************************************************** -proc icmp_rx stdcall uses ebx esi edi,\ - buffer_number:DWORD,IPPacketBase:DWORD,IPHeaderLength:DWORD + .loopback: + add esi, 2 + push [esi + IPv4_header.SourceAddress] + push [esi + IPv4_header.DestinationAddress] + pop [esi + IPv4_header.SourceAddress] + pop [esi + IPv4_header.DestinationAddress] - mov esi, [IPPacketBase];esi=IP_PACKET base address - mov edi, esi - add edi, [IPHeaderLength];edi=ICMP_PACKET base address +; Recalculate ip header checksum + movzx ecx, [esi + IPv4_header.VersionAndIHL] ; Calculate IP Header length by using IHL field + and ecx, 0x0f + shl cx, 2 + mov edi, ecx ; IP header length + mov eax, edx ; ICMP packet start addr - cmp byte[edi + ICMP_PACKET.Type], ICMP_ECHO; Is this an echo request? discard if not - jz .icmp_echo + push esi ; Calculate the IP checksum + xor edx, edx ; + call checksum_1 ; + call checksum_2 ; + pop esi ; + mov [esi + IPv4_header.HeaderChecksum], dx ; - mov eax, [buffer_number] - call freeBuff - jmp .exit +; Recalculate ICMP CheckSum + movzx ecx, [esi + IPv4_header.TotalLength] ; Find length of IP Packet + xchg ch, cl ; + sub ecx, edi ; IP packet length - IP header length = ICMP packet length - .icmp_echo: + mov esi, eax ; Calculate ICMP checksum + xor edx, edx ; + call checksum_1 ; + call checksum_2 ; + mov [eax + ICMP_header.Checksum], dx ; - ; swap the source and destination addresses - mov ecx, [esi + IP_PACKET.DestinationAddress] - mov ebx, [esi + IP_PACKET.SourceAddress] - mov [esi + IP_PACKET.DestinationAddress], ebx - mov [esi + IP_PACKET.SourceAddress], ecx - - ; recalculate the IP header checksum - mov eax, [IPHeaderLength] - stdcall checksum_jb, esi, eax;buf_ptr,buf_size - - mov byte[esi + IP_PACKET.HeaderChecksum], ah - mov byte[esi + IP_PACKET.HeaderChecksum + 1], al ; ?? correct byte order? - - mov byte[edi + ICMP_PACKET.Type], ICMP_ECHOREPLY; change the request to a response - mov word[edi + ICMP_PACKET.Checksum], 0; clear ICMP checksum prior to re-calc - - ; Calculate the length of the ICMP data ( IP payload) - xor eax, eax - mov ah, byte[esi + IP_PACKET.TotalLength] - mov al, byte[esi + IP_PACKET.TotalLength + 1] - sub ax, word[IPHeaderLength];ax=ICMP-packet length - - stdcall checksum_jb, edi, eax;buf_ptr,buf_size - - mov byte[edi + ICMP_PACKET.Checksum], ah - mov byte[edi + ICMP_PACKET.Checksum + 1], al - - ; Queue packet for transmission - mov ebx, [buffer_number] - mov eax, NET1OUT_QUEUE - call queue - - .exit: +; Transmit the packet (notice that packet ptr and packet size have been on stack since start of the procedure!) + call [ebx + NET_DEVICE.transmit] + ret + + + + + .check_sockets: + ; Look for an open ICMP socket + + mov esi, [edi] ; ipv4 source address + mov eax, net_sockets + .try_more: +; mov , [edx + ICMP_header.Identifier] + .next_socket: + mov eax, [eax + SOCKET.NextPtr] + or eax, eax + jz .dump + + cmp [eax + SOCKET.Domain], AF_INET4 + jne .next_socket + + cmp [eax + SOCKET.Protocol], IP_PROTO_ICMP + jne .next_socket + + cmp [eax + IP_SOCKET.RemoteIP], esi + jne .next_socket + +; cmp [eax + ICMP_SOCKET.Identifier], +; jne .next_socket + +; call IPv4_dest_to_dev +; cmp edi,-1 +; je .dump +; inc [ICMP_PACKETS_RX+edi] + + DEBUGF 1,"socket=%x\n", eax + + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + popa + + mov esi, edx + jmp SOCKET_input + + + .checksum_mismatch: + DEBUGF 1,"checksum mismatch\n" + + .dump: + DEBUGF 1,"ICMP_input: dumping\n" + + call kernel_free + add esp, 4 ; pop (balance stack) + + ret + + +;----------------------------------------------------------------- +; +; ICMP_output +; +; IN: eax = dest ip +; ebx = source ip +; ecx = data length +; dh = type +; dl = code +; esi = data offset +; edi = identifier shl 16 + sequence number +; +;----------------------------------------------------------------- +align 4 +ICMP_output: + + DEBUGF 1,"Creating ICMP Packet\n" + + push esi edi dx + + mov edx, [eax + IP_SOCKET.LocalIP] + mov eax, [eax + IP_SOCKET.RemoteIP] + add ecx, sizeof.ICMP_header + mov di, IP_PROTO_ICMP SHL 8 + 128 ; TTL + call IPv4_output + jz .exit + + DEBUGF 1,"full icmp packet size: %u\n", edx + + pop word [edi + ICMP_header.Type] ; Write both type and code bytes at once + pop dword [edi + ICMP_header.Identifier] ; identifier and sequence number + mov [edi + ICMP_header.Checksum], 0 + + push ebx ecx edx + mov esi, edi + xor edx, edx + call checksum_1 + call checksum_2 + mov [edi + ICMP_header.Checksum], dx + pop edx ecx ebx esi + + sub ecx, sizeof.ICMP_header + add edi, sizeof.ICMP_header + push cx + shr cx, 2 + rep movsd + pop cx + and cx, 3 + rep movsb + + sub edi, edx ;;; TODO: find a better way to remember start of packet + push edx edi + DEBUGF 1,"Sending ICMP Packet\n" + call [ebx + NET_DEVICE.transmit] + ret + .exit: + DEBUGF 1,"Creating ICMP Packet failed\n" + add esp, 2*4 + 2 + ret + + + + +;----------------------------------------------------------------- +; +; ICMP_output +; +; IN: eax = socket ptr +; ecx = data length +; esi = data offset +; +;----------------------------------------------------------------- +align 4 +ICMP_output_raw: + + DEBUGF 1,"Creating ICMP Packet for socket %x, data ptr=%x\n", eax, edx + + push edx + + mov di, IP_PROTO_ICMP SHL 8 + 128 ; TTL + mov edx, [eax + IP_SOCKET.LocalIP] + mov eax, [eax + IP_SOCKET.RemoteIP] + call IPv4_output + jz .exit + + pop esi + push edx + push eax + + push edi ecx + DEBUGF 1,"copying %u bytes from %x to %x\n", ecx, esi, edi + rep movsb + pop ecx edi + + mov [edi + ICMP_header.Checksum], 0 + + mov esi, edi + xor edx, edx + call checksum_1 + call checksum_2 + mov [edi + ICMP_header.Checksum], dx + + DEBUGF 1,"Sending ICMP Packet\n" + call [ebx + NET_DEVICE.transmit] + ret + .exit: + DEBUGF 1,"Creating ICMP Packet failed\n" + add esp, 4 + ret + + + + +;----------------------------------------------------------------- +; +; ICMP_API +; +; This function is called by system function 75 +; +; IN: subfunction number in bl +; device number in bh +; ecx, edx, .. depends on subfunction +; +; OUT: +; +;----------------------------------------------------------------- +align 4 +ICMP_api: + + movzx eax, bh + shl eax, 2 + + test bl, bl + jz .packets_tx ; 0 + dec bl + jz .packets_rx ; 1 + + .error: + mov eax, -1 + ret + + .packets_tx: + mov eax, [ICMP_PACKETS_TX + eax] + ret + + .packets_rx: + mov eax, [ICMP_PACKETS_RX + eax] ret -endp diff --git a/kernel/trunk/network/ip.inc b/kernel/trunk/network/ip.inc deleted file mode 100644 index cf6e40d17c..0000000000 --- a/kernel/trunk/network/ip.inc +++ /dev/null @@ -1,248 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; ;; -;; IP.INC ;; -;; ;; -;; IP Processes for Menuet OS TCP/IP stack ;; -;; ;; -;; Version 0.3 29 August 2002 ;; -;; ;; -;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -; IP underlying protocols numbers -PROTOCOL_ICMP equ 1 -PROTOCOL_TCP equ 6 -PROTOCOL_UDP equ 17 - -struc IP_PACKET -{ .VersionAndIHL db ? ;+00 - Version[0-3 bits] and IHL(header length)[4-7 bits] - .TypeOfService db ? ;+01 - .TotalLength dw ? ;+02 - .Identification dw ? ;+04 - .FlagsAndFragmentOffset dw ? ;+06 - Flags[0-2] and FragmentOffset[3-15] - .TimeToLive db ? ;+08 - .Protocol db ? ;+09 - .HeaderChecksum dw ? ;+10 - .SourceAddress dd ? ;+12 - .DestinationAddress dd ? ;+16 - .DataOrOptional dd ? ;+20 -} - -virtual at 0 - IP_PACKET IP_PACKET -end virtual - - -;******************************************************************* -; Interface -; -; ip_rx processes all packets received by the network layer -; It calls the appropriate protocol handler -; -; -; -;******************************************************************* - - -; -; IP Packet after reception - Normal IP packet format -; -; 0 1 2 3 -; 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 -; -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;0 |Version| IHL |Type of Service| Total Length | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;4 | Identification |Flags| Fragment Offset | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;8 | Time to Live | Protocol | Header Checksum | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;12 | Source Address | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;16 | Destination Address | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;20 | Data | -; +-+-+-.......... -+ -; -; -; [smb] attention! according to RFC 791 IP packet may have 'options' sections, -; so we can't simply think, that data have offset 20. We must calculate offset from -; IHL field -; -macro GET_IHL reg, header_addr -{ - movzx reg, byte [header_addr] - - ; we need 4-7 bits, so.... - and reg, 0x0000000F - - ; IHL keeps number of octets, so we need to << 2 'reg' - shl reg, 2 -} - - -include "tcp.inc" -include "udp.inc" -include "icmp.inc" - -;*************************************************************************** -; Function -; ip_rx -; -; Description -; This is a kernel function, called by stack_handler -; Processes all IP-packets received by the network layer -; It calls the appropriate protocol handler -; -;*************************************************************************** -proc ip_rx stdcall -local buffer_number dd ? - - ; Look for a buffer to tx - mov eax, IPIN_QUEUE - call dequeue - cmp ax, NO_BUFFER - je .exit ; Exit if no buffer available - - mov [buffer_number], eax;save buffer number - - ; convert buffer pointer eax to the absolute address - imul eax, IPBUFFSIZE - add eax, IPbuffs - - mov ebx, eax; ebx=pointer to IP_PACKET - -; DEBUGF 1, "K : ip_rx - proto: %u\n", [ebx + IP_PACKET.Protocol]:1 - - ; Validate the IP checksum - mov dx, word[ebx + IP_PACKET.HeaderChecksum] - xchg dh, dl ; Get the checksum in intel format - - mov [ebx + IP_PACKET.HeaderChecksum], 0; clear checksum field - need to when - ; recalculating checksum - ; this needs two data pointers and two size #. - ; 2nd pointer can be of length 0 - - GET_IHL ecx, ebx + IP_PACKET.VersionAndIHL ;get packet length in ecx - stdcall checksum_jb, ebx, ecx;buf_ptr, buf_size - cmp dx, ax - -; DEBUGF 1, "K : ip_rx - checksums: %x - %x\n", dx, ax - - jnz .dump.1;if CHECKSUM isn't valid then dump packet - mov edx, ebx; EDX (IP-BUFFER POINTER) WILL BE USED FOR *_rx HANDLERS BELOW!!! - -; DEBUGF 1, "K : ip_rx - dest: %x - %x\n", [ebx + IP_PACKET.DestinationAddress], [stack_ip] - - ; Validate the IP address, if it isn't broadcast - mov eax, [stack_ip] - cmp dword[ebx + IP_PACKET.DestinationAddress], eax - je @f - - ; If the IP address is 255.255.255.255, accept it - ; - it is a broadcast packet, which we need for dhcp - - mov eax, [ebx + IP_PACKET.DestinationAddress] - cmp eax, 0xffffffff - je @f - mov ecx, [stack_ip] - and eax, [subnet_mask] - and ecx, [subnet_mask] - cmp eax, ecx - jne .dump.2 - mov eax, [ebx + IP_PACKET.DestinationAddress] - or eax, [subnet_mask] - cmp eax, 0xffffffff - jne .dump.2 - - @@: - mov al, [ebx + IP_PACKET.VersionAndIHL] - and al, 0x0f;get IHL(header length) - cmp al, 0x05;if IHL!= 5*4(20 bytes) -; DEBUGF 1, "K : ip_rx - ihl: %x - 05\n", al - jnz .dump.3 ;then dump it - -; DEBUGF 1, "K : ip_rx - ttl: %x - 00\n", [ebx + IP_PACKET.TimeToLive]:2 - - cmp [ebx + IP_PACKET.TimeToLive], 0 - je .dump.4 ;if TTL==0 then dump it - - mov ax, [ebx + IP_PACKET.FlagsAndFragmentOffset] - and ax, 0xFFBF;get flags -; DEBUGF 1, "K : ip_rx - flags: %x - 0000\n", ax - cmp ax, 0 ;if some flags was set then we dump this packet - jnz .dump.5 ;the flags should be used for fragmented packets - - ; Check the protocol, and call the appropriate handler - ; Each handler will re-use or free the queue buffer as appropriate - - mov al, [ebx + IP_PACKET.Protocol] - - cmp al , PROTOCOL_TCP - jne .not_tcp -; DEBUGF 1,"K : ip_rx - TCP packet\n" - mov eax, dword[buffer_number] - call tcp_rx - jmp .exit - - .not_tcp: - cmp al, PROTOCOL_UDP - jne .not_udp -; DEBUGF 1,"K : ip_rx - UDP packet\n" - mov eax, dword[buffer_number] - call udp_rx - jmp .exit - - .not_udp: - cmp al, PROTOCOL_ICMP - jne .dump.6 ;protocol ain't supported - -; DEBUGF 1,"K : ip_rx - ICMP packet\n" - ;GET_IHL ecx, ebx + IP_PACKET.VersionAndIHL ;get packet length in ecx - mov eax, dword[buffer_number] - stdcall icmp_rx, eax, ebx, ecx;buffer_number,IPPacketBase,IPHeaderLength - jmp .exit - - - .dump.1: -; DEBUGF 1, "K : ip_rx - dumped (checksum: 0x%x-0x%x)\n", dx, ax - jmp .dump.x - - .dump.2: -; DEBUGF 1, "K : ip_rx - dumped (ip: %u.%u.%u.%u)\n", [ebx + IP_PACKET.DestinationAddress + 0]:1, [ebx + IP_PACKET.DestinationAddress + 1]:1, [ebx + IP_PACKET.DestinationAddress + 2]:1, [ebx + IP_PACKET.DestinationAddress + 3]:1 - jmp .dump.x - - .dump.3: -; DEBUGF 1, "K : ip_rx - dumped (ihl: %u)\n", al - jmp .dump.x - - .dump.4: -; DEBUGF 1, "K : ip_rx - dumped (ttl: %u)\n", [ebx + IP_PACKET.TimeToLive] - jmp .dump.x - - .dump.5: -; DEBUGF 1, "K : ip_rx - dumped (flags: 0x%x)\n", ax - jmp .dump.x - - .dump.6: -; DEBUGF 1, "K : ip_rx - dumped (proto: %u)\n", [ebx + IP_PACKET.Protocol]:1 - - .dump.x: - inc dword[dumped_rx_count] - mov eax, [buffer_number] - call freeBuff - - .exit: - ret -endp - diff --git a/kernel/trunk/network/loopback.inc b/kernel/trunk/network/loopback.inc new file mode 100644 index 0000000000..e8f9eb42cf --- /dev/null +++ b/kernel/trunk/network/loopback.inc @@ -0,0 +1,126 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; loopback.inc ;; +;; ;; +;; LoopBack device for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 2891 $ + +iglobal + +LOOPBACK_DEVICE: + .type dd NET_TYPE_LOOPBACK + .mtu dd 4096 + .name dd .namestr + + .unload dd .dummy_fn + .reset dd .dummy_fn + .transmit dd LOOP_input + + .bytes_tx dq 0 + .bytes_rx dq 0 + .packets_tx dd 0 + .packets_rx dd 0 + + .namestr db 'loopback', 0 + + .dummy_fn: + ret + +endg + +;----------------------------------------------------------------- +; +; LOOP_input +; +; IN: [esp+4] = Pointer to buffer +; [esp+8] = size of buffer +; +; OUT: / +; +;----------------------------------------------------------------- +align 4 +LOOP_input: + pop ebx + pop eax + pop ecx + + push ebx + push ecx + push eax + + DEBUGF 1,"LOOP_input: size=%u\n", ecx + lea edx, [eax + 2] + mov ax, word[eax] + mov ebx, LOOPBACK_DEVICE + + cmp ax, ETHER_IPv4 + je IPv4_input + + DEBUGF 2,"LOOP_input: Unknown packet type=%x\n", ax + + .dump: + DEBUGF 2,"LOOP_input: dumping\n" + call kernel_free + add esp, 4 + ret + +;----------------------------------------------------------------- +; +; LOOP_output +; +; IN: +; ecx = packet size +; di = protocol +; +; OUT: edi = 0 on error, pointer to buffer otherwise +; eax = buffer start +; ebx = to device structure +; ecx = unchanged (packet size of embedded data) +; edx = size of complete buffer +; +;----------------------------------------------------------------- +align 4 +LOOP_output: + + DEBUGF 1,"LOOP_output\n" + + push ecx + push di + + add ecx, 2 + cmp ecx, [LOOPBACK_DEVICE.mtu] + ja .out_of_ram + stdcall kernel_alloc, ecx + test eax, eax + jz .out_of_ram + mov edi, eax + pop ax + stosw + + lea eax, [edi - 2] ; Set eax to buffer start + pop ecx + lea edx, [ecx + 2] ; Set edx to complete buffer size + mov ebx, LOOPBACK_DEVICE + + .done: + DEBUGF 2,"LOOP_output: ptr=%x size=%u\n", eax, edx + ret + + .out_of_ram: + DEBUGF 2,"LOOP_output: failed\n" + add esp, 2+4 + sub edi, edi + ret + + diff --git a/kernel/trunk/network/queue.inc b/kernel/trunk/network/queue.inc index ad9700610e..eae232df99 100644 --- a/kernel/trunk/network/queue.inc +++ b/kernel/trunk/network/queue.inc @@ -1,229 +1,100 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; +;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; +;; queue.inc ;; ;; ;; -;; QUEUE.INC ;; +;; Written by hidnplayr@kolibrios.org ;; ;; ;; -;; Buffer queue management for Menuet OS TCP/IP Stack ;; -;; ;; -;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; -;; ;; -;; See file COPYING for details ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -$Revision$ +$Revision: 2305 $ - -;******************************************************************* -; Interface +; The Queues implemented by these macros form a ring-buffer. +; The data to these queue's always looks like this: ; -; queueInit Configures the queues to empty -; dequeue Removes a buffer pointer from a queue -; queue Inserts a buffer pointer into a queue -; freeBuff Adds the buffer pointer to the list of free buffers -; queueSize Returns the number of entries in a queue -; -; The various defines for queue names can be found in stack.inc -; -;******************************************************************* +; At top, you have the queue struct, wich has the size (number of currently queued packets, read and write pointers. +; This struct is followed by a number of slots wich you can read and write to using the macros. +; How these slots look like is up to you to chose, normally they should have at least a pointer to where the real data is. +; (you can see some examples below) -;*************************************************************************** -; Function -; freeBuff -; -; Description -; Adds a buffer number to the beginning of the free list. -; buffer number in eax ( ms word zeroed ) -; all other registers preserved -; This always works, so no error returned -;*************************************************************************** -;uglobal -; freeBuff_cnt dd ? -;endg -freeBuff: -; inc [freeBuff_cnt] -; DEBUGF 1, "K : freeBuff (%u)\n", [freeBuff_cnt] - push ebx - push ecx - mov ebx, queues + EMPTY_QUEUE * 2 - cli ; Ensure that another process does not interfer - mov cx, [ebx] - mov [ebx], ax - mov [queueList + eax * 2], cx - sti - pop ecx - pop ebx +struct queue - ret + size dd ? ; number of queued packets in this queue + w_ptr dd ? ; current writing pointer in queue + r_ptr dd ? ; current reading pointer +ends -;*************************************************************************** -; Function -; queueSize -; -; Description -; Counts the number of entries in a queue -; queue number in ebx ( ms word zeroed ) -; Queue size returned in eax -; This always works, so no error returned -;*************************************************************************** -queueSize: - xor eax, eax - shl ebx, 1 - add ebx, queues - movzx ecx, word [ebx] - cmp cx, NO_BUFFER - je qs_exit +; The following macros share these inputs: -qs_001: - inc eax - shl ecx, 1 - add ecx, queueList - movzx ecx, word [ecx] - cmp cx, NO_BUFFER - je qs_exit - jmp qs_001 +; ptr = pointer to where the queue data is located +; size = number of slots/entrys in the queue +; entry_size = size of one slot, in bytes +; failaddr = the address where macro will jump to when there is no data in the queue -qs_exit: - ret +; additionally, add_to_queue requires you to set esi to the data wich you want to queue +; get_from_queue on the other hand will return a pointer in esi, to the entry you're interessed in +; PS: macros WILL destroy ecx and edi +macro add_to_queue ptr, size, entry_size, failaddr { -;*************************************************************************** -; Function -; queue -; -; Description -; Adds a buffer number to the *end* of a queue -; This is quite quick because these queues will be short -; queue number in eax ( ms word zeroed ) -; buffer number in ebx ( ms word zeroed ) -; all other registers preserved -; This always works, so no error returned -;*************************************************************************** -;uglobal -; queue_cnt dd ? -;endg -queue: -; inc [queue_cnt] -; DEBUGF 1, "K : queue (%u)\n", [queue_cnt] - push ebx - shl ebx, 1 - add ebx, queueList ; eax now holds address of queue entry - mov [ebx], word NO_BUFFER; This buffer will be the last + cmp [ptr + queue.size], size ; Check if queue isnt full + jae failaddr - cli - shl eax, 1 - add eax, queues ; eax now holds address of queue - movzx ebx, word [eax] + inc [ptr + queue.size] ; if not full, queue one more - cmp bx, NO_BUFFER - jne qu_001 + mov edi, [ptr + queue.w_ptr] ; Current write pointer (FIFO!) + mov ecx, entry_size/4 ; Write the queue entry + rep movsd ; - pop ebx - ; The list is empty, so add this to the head - mov [eax], bx - jmp qu_exit + lea ecx, [size*entry_size+ptr+sizeof.queue] + cmp edi, ecx ; entry size + jb .no_wrap -qu_001: - ; Find the last entry - shl ebx, 1 - add ebx, queueList - mov eax, ebx - movzx ebx, word [ebx] - cmp bx, NO_BUFFER - jne qu_001 + sub edi, size*entry_size - mov ebx, eax - pop eax - mov [ebx], ax + .no_wrap: + mov [ptr + queue.w_ptr], edi -qu_exit: - sti - ret +} -;*************************************************************************** -; Function -; dequeue -; -; Description -; removes a buffer number from the head of a queue -; This is fast, as it unlinks the first entry in the list -; queue number in eax ( ms word zeroed ) -; buffer number returned in eax ( ms word zeroed ) -; all other registers preserved -; -;*************************************************************************** -;uglobal -; dequeue_cnt dd ? -;endg -dequeue: - push ebx - shl eax, 1 - add eax, queues ; eax now holds address of queue - mov ebx, eax - cli - movzx eax, word [eax] - cmp ax, NO_BUFFER - je dq_exit -; inc [dequeue_cnt] -; DEBUGF 1, "K : dequeue (%u)\n", [dequeue_cnt] - push eax - shl eax, 1 - add eax, queueList ; eax now holds address of queue entry - mov ax, [eax] - mov [ebx], ax - pop eax +macro get_from_queue ptr, size, entry_size, failaddr { -dq_exit: - sti - pop ebx - ret + cmp [ptr + queue.size], 0 ; any packets queued? + je failaddr + dec [ptr + queue.size] ; if so, dequeue one -;*************************************************************************** -; Function -; queueInit -; -; Description -; Initialises the queues to empty, and creates the free queue -; list. -; -;*************************************************************************** -queueInit: - mov esi, queues - mov ecx, NUMQUEUES - mov ax, NO_BUFFER + mov esi, [ptr + queue.r_ptr] + push esi -qi001: - mov [esi], ax - inc esi - inc esi - loop qi001 + add esi, entry_size - mov esi, queues + ( 2 * EMPTY_QUEUE ) + lea ecx, [size*entry_size+ptr+sizeof.queue] + cmp esi, ecx ; entry size + jb .no_wrap - ; Initialise empty queue list + sub esi, size*entry_size - xor ax, ax - mov [esi], ax + .no_wrap: + mov dword [ptr + queue.r_ptr], esi - mov ecx, NUMQUEUEENTRIES - 1 - mov esi, queueList + pop esi -qi002: - inc ax - mov [esi], ax - inc esi - inc esi - loop qi002 +} - mov ax, NO_BUFFER - mov [esi], ax +macro init_queue ptr { - ret + mov [ptr + queue.size] , 0 + lea edi, [ptr + sizeof.queue] + mov [ptr + queue.w_ptr], edi + mov [ptr + queue.r_ptr], edi +} \ No newline at end of file diff --git a/kernel/trunk/network/socket.inc b/kernel/trunk/network/socket.inc index c67bb865c6..454999da3c 100644 --- a/kernel/trunk/network/socket.inc +++ b/kernel/trunk/network/socket.inc @@ -1,1129 +1,2284 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; SOCKET.INC ;; -;; ;; -;; Sockets constants, structures and functions ;; -;; ;; -;; This file contains the following: ;; -;; is_localport_unused ;; -;; get_free_socket ;; -;; socket_open ;; -;; socket_open_tcp ;; -;; socket_close ;; -;; socket_close_tcp ;; -;; socket_poll ;; -;; socket_status ;; -;; socket_read ;; -;; socket_write ;; -;; socket_write_tcp ;; -;; ;; -;; ;; -;; Changes history: ;; -;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net ;; -;; 11.11.2006 - [Johnny_B] and [smb] ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Part of the TCP/IP network stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org, ;; +;; and Clevermouse. ;; +;; ;; +;; Based on code by mike.dld ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 3514 $ -$Revision$ -; socket data structure struct SOCKET - PrevPtr dd ? ; pointer to previous socket in list - NextPtr dd ? ; pointer to next socket in list - Number dd ? ; socket number (unique within single process) - PID dd ? ; application process id - LocalIP dd ? ; local IP address - LocalPort dw ? ; local port - RemoteIP dd ? ; remote IP address - RemotePort dw ? ; remote port - OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state) - OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state) - rxDataCount dd ? ; rx data count - TCBState dd ? ; TCB state - TCBTimer dd ? ; TCB timer (seconds) - ISS dd ? ; initial send sequence - IRS dd ? ; initial receive sequence - SND_UNA dd ? ; sequence number of unack'ed sent packets - SND_NXT dd ? ; bext send sequence number to use - SND_WND dd ? ; send window - RCV_NXT dd ? ; next receive sequence number to use - RCV_WND dd ? ; receive window - SEG_LEN dd ? ; segment length - SEG_WND dd ? ; segment window - wndsizeTimer dd ? ; window size timer - mutex MUTEX ; lock mutex - rxData dd ? ; receive data buffer here + + NextPtr dd ? ; pointer to next socket in list + PrevPtr dd ? ; pointer to previous socket in list + Number dd ? ; socket number + + mutex MUTEX + + PID dd ? ; process ID + TID dd ? ; thread ID + Domain dd ? ; INET/LOCAL/.. + Type dd ? ; RAW/STREAM/DGRAP + Protocol dd ? ; ICMP/IPv4/ARP/TCP/UDP + errorcode dd ? + device dd ? ; driver pointer, socket pointer if it's an LOCAL socket + + options dd ? + state dd ? + backlog dw ? ; how many incoming connections that can be queued + + snd_proc dd ? + rcv_proc dd ? + ends -; TCP opening modes -SOCKET_PASSIVE = 0 -SOCKET_ACTIVE = 1 +struct IP_SOCKET SOCKET -; socket types -SOCK_STREAM = 1 -SOCK_DGRAM = 2 + LocalIP rd 4 ; network byte order + RemoteIP rd 4 ; network byte order + +ends + +struct TCP_SOCKET IP_SOCKET + + LocalPort dw ? ; network byte order + RemotePort dw ? ; network byte order + + t_state dd ? ; TCB state + t_rxtshift db ? + rb 3 ; align + t_rxtcur dd ? + t_dupacks dd ? + t_maxseg dd ? + t_force dd ? + t_flags dd ? + +;--------------- +; RFC783 page 21 + +; send sequence + SND_UNA dd ? ; sequence number of unack'ed sent Packets + SND_NXT dd ? ; next send sequence number to use + SND_UP dd ? ; urgent pointer + SND_WL1 dd ? ; window minus one + SND_WL2 dd ? ; + ISS dd ? ; initial send sequence number + SND_WND dd ? ; send window + +; receive sequence + RCV_WND dd ? ; receive window + RCV_NXT dd ? ; next receive sequence number to use + RCV_UP dd ? ; urgent pointer + IRS dd ? ; initial receive sequence number + +;--------------------- +; Additional variables + +; receive variables + RCV_ADV dd ? + +; retransmit variables + SND_MAX dd ? + +; congestion control + SND_CWND dd ? + SND_SSTHRESH dd ? + +;---------------------- +; Transmit timing stuff + t_idle dd ? + t_rtt dd ? + t_rtseq dd ? + t_srtt dd ? + t_rttvar dd ? + t_rttmin dd ? + max_sndwnd dd ? + +;----------------- +; Out-of-band data + t_oobflags dd ? + t_iobc dd ? + t_softerror dd ? + + +;--------- +; RFC 1323 ; the order of next 4 elements may not change + + SND_SCALE db ? + RCV_SCALE db ? + requested_s_scale db ? + request_r_scale db ? + + ts_recent dd ? ; a copy of the most-recent valid timestamp from the other end + ts_recent_age dd ? + last_ack_sent dd ? + + +;------- +; Timers + timer_retransmission dd ? ; rexmt + timer_persist dd ? + timer_keepalive dd ? ; keepalive/syn timeout + timer_timed_wait dd ? ; also used as 2msl timer + +; extra + + ts_ecr dd ? ; timestamp echo reply + ts_val dd ? + + seg_next dd ? ; re-assembly queue + + temp_bits db ? + rb 3 ; align + +ends + +struct UDP_SOCKET IP_SOCKET + + LocalPort dw ? ; network byte order + RemotePort dw ? ; network byte order + firstpacket db ? + +ends + + +struct ICMP_SOCKET IP_SOCKET + + Identifier dw ? + +ends + + +struct RING_BUFFER + + mutex MUTEX + start_ptr dd ? ; Pointer to start of buffer + end_ptr dd ? ; pointer to end of buffer + read_ptr dd ? ; Read pointer + write_ptr dd ? ; Write pointer + size dd ? ; Number of bytes buffered + +ends + +struct STREAM_SOCKET TCP_SOCKET + + rcv RING_BUFFER + snd RING_BUFFER + +ends + +struct socket_queue_entry + + data_ptr dd ? + buf_ptr dd ? + data_size dd ? + +ends + + +SOCKETBUFFSIZE = 4096 ; in bytes + +SOCKET_QUEUE_SIZE = 10 ; maximum number of incoming packets queued for 1 socket +; the incoming packet queue for sockets is placed in the socket struct itself, at this location from start +SOCKET_QUEUE_LOCATION = (SOCKETBUFFSIZE - SOCKET_QUEUE_SIZE*sizeof.socket_queue_entry - sizeof.queue) -; pointer to bitmap of free ports (1=free, 0=used) uglobal -align 4 -network_free_ports dd ? + net_sockets rd 4 + last_socket_num dd ? + last_UDP_port dw ? ; These values give the number of the last used ephemeral port + last_TCP_port dw ? ; endg -iglobal -align 4 -network_free_hint dd 1024/8 -endg -;; Allocate memory for socket data and put new socket into the list -; Newly created socket is initialized with calling PID and number and -; put into beginning of list (which is a fastest way). +;----------------------------------------------------------------- ; -; @return socket structure address in EAX -;; -proc net_socket_alloc stdcall uses ebx ecx edx edi - stdcall kernel_alloc, SOCKETBUFFSIZE - DEBUGF 1, "K : net_socket_alloc (0x%x)\n", eax - ; check if we can allocate needed amount of memory - or eax, eax - jz .exit +; SOCKET_init +; +;----------------------------------------------------------------- +macro SOCKET_init { - ; zero-initialize allocated memory - push eax - mov edi, eax - mov ecx, SOCKETBUFFSIZE / 4 - cld xor eax, eax - rep stosd + mov edi, net_sockets + mov ecx, 5 + rep stosd + + @@: + pseudo_random eax + cmp ax, MIN_EPHEMERAL_PORT + jb @r + cmp ax, MAX_EPHEMERAL_PORT + ja @r + xchg al, ah + mov [last_UDP_port], ax + + @@: + pseudo_random eax + cmp ax, MIN_EPHEMERAL_PORT + jb @r + cmp ax, MAX_EPHEMERAL_PORT + ja @r + xchg al, ah + mov [last_TCP_port], ax + +} + +;----------------------------------------------------------------- +; +; Socket API (function 74) +; +;----------------------------------------------------------------- +align 4 +sys_socket: + + cmp ebx, 255 + jz SOCKET_debug + + cmp ebx, .number + ja s_error + jmp dword [.table + 4*ebx] + + .table: + dd SOCKET_open ; 0 + dd SOCKET_close ; 1 + dd SOCKET_bind ; 2 + dd SOCKET_listen ; 3 + dd SOCKET_connect ; 4 + dd SOCKET_accept ; 5 + dd SOCKET_send ; 6 + dd SOCKET_receive ; 7 + dd SOCKET_set_opt ; 8 + dd SOCKET_get_opt ; 9 + dd SOCKET_pair ; 10 + .number = ($ - .table) / 4 - 1 + +s_error: + DEBUGF 2,"SOCKET: error\n" + mov dword [esp+32], -1 + + ret + +;----------------------------------------------------------------- +; +; SOCKET_open +; +; IN: domain in ecx +; type in edx +; protocol in esi +; OUT: eax is socket num, -1 on error +; +;----------------------------------------------------------------- +align 4 +SOCKET_open: + + DEBUGF 2,"SOCKET_open: domain=%u type=%u protocol=%x ", ecx, edx, esi + + push ecx edx esi + call SOCKET_alloc + pop esi edx ecx + jz s_error + + mov [esp+32], edi ; return socketnumber + DEBUGF 2,"socknum=%u\n", edi + +; push edx +; and edx, SO_NONBLOCK + or [eax + SOCKET.options], SO_NONBLOCK ;edx +; pop edx +; and edx, not SO_NONBLOCK + + mov [eax + SOCKET.Domain], ecx + mov [eax + SOCKET.Type], edx + mov [eax + SOCKET.Protocol], esi + + cmp ecx, AF_INET4 + jne .no_inet4 + + cmp edx, SOCK_DGRAM + je .udp + + cmp edx, SOCK_STREAM + je .tcp + + cmp edx, SOCK_RAW + je .raw + + .no_inet4: + cmp ecx, AF_PPP + jne .no_ppp + + cmp esi, PPP_PROTO_ETHERNET + je .pppoe + + .no_ppp: + DEBUGF 2,"Unknown socket family/protocol\n" + ret + +align 4 + .raw: + test esi, esi ; IP_PROTO_IP + jz .ip + + cmp esi, IP_PROTO_ICMP + je .icmp + + cmp esi, IP_PROTO_UDP + je .udp + + cmp esi, IP_PROTO_TCP + je .tcp + + ret + +align 4 + .udp: + mov [eax + SOCKET.Protocol], IP_PROTO_UDP + mov [eax + SOCKET.snd_proc], SOCKET_send_udp + mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram + ret + +align 4 + .tcp: + mov [eax + SOCKET.Protocol], IP_PROTO_TCP + mov [eax + SOCKET.snd_proc], SOCKET_send_tcp + mov [eax + SOCKET.rcv_proc], SOCKET_receive_stream + + TCP_init_socket eax + ret + + +align 4 + .ip: + mov [eax + SOCKET.snd_proc], SOCKET_send_ip + mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram + ret + + +align 4 + .icmp: + mov [eax + SOCKET.snd_proc], SOCKET_send_icmp + mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram + ret + +align 4 + .pppoe: + push eax + init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue pop eax + mov [eax + SOCKET.snd_proc], SOCKET_send_pppoe + mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram + ret + + +;----------------------------------------------------------------- +; +; SOCKET_bind +; +; IN: socket number in ecx +; pointer to sockaddr struct in edx +; length of that struct in esi +; OUT: 0 on success +; +;----------------------------------------------------------------- +align 4 +SOCKET_bind: + + DEBUGF 2,"SOCKET_bind: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi + + call SOCKET_num_to_ptr + jz s_error + + cmp esi, 2 + jb s_error + + cmp word [edx], AF_INET4 + je .af_inet4 + + cmp word [edx], AF_LOCAL + je .af_local + + jmp s_error + + .af_local: + ; TODO: write code here + + mov dword [esp+32], 0 + ret + + .af_inet4: + + cmp esi, 6 + jb s_error + + cmp [eax + SOCKET.Protocol], IP_PROTO_UDP + je .udp + + cmp [eax + SOCKET.Protocol], IP_PROTO_TCP + je .tcp + + jmp s_error + + .tcp: + .udp: + + mov ebx, [edx + 4] ; First, fill in the IP + test ebx, ebx ; If IP is 0, use default + jnz @f + mov ebx, [NET_DEFAULT] + mov ebx, [IP_LIST + 4*ebx] + @@: + mov [eax + IP_SOCKET.LocalIP], ebx + + mov bx, [edx + 2] ; Now fill in the local port if it's still available + call SOCKET_check_port + jz s_error ; ZF is set by socket_check_port, on error + + DEBUGF 1,"SOCKET_bind: local ip=%u.%u.%u.%u\n",\ + [eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\ + [eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1 + + mov dword [esp+32], 0 + ret + + + + +;----------------------------------------------------------------- +; +; SOCKET_connect +; +; IN: socket number in ecx +; pointer to sockaddr struct in edx +; length of that struct in esi +; OUT: 0 on success +; +;----------------------------------------------------------------- +align 4 +SOCKET_connect: + + DEBUGF 2,"SOCKET_connect: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi + + call SOCKET_num_to_ptr + jz s_error + + cmp esi, 8 + jb s_error + + cmp word [edx], AF_INET4 + je .af_inet4 + + jmp s_error + + .af_inet4: + cmp [eax + IP_SOCKET.LocalIP], 0 + jne @f + push [IP_LIST] ; FIXME + pop [eax + IP_SOCKET.LocalIP] + @@: + + cmp [eax + SOCKET.Protocol], IP_PROTO_UDP + je .udp + + cmp [eax + SOCKET.Protocol], IP_PROTO_TCP + je .tcp + + cmp [eax + SOCKET.Protocol], IP_PROTO_IP + je .ip + + cmp [eax + SOCKET.Protocol], IP_PROTO_ICMP + je .ip + + jmp s_error + +align 4 + .udp: + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + popa + + pushw [edx + 2] + pop [eax + UDP_SOCKET.RemotePort] + + pushd [edx + 4] + pop [eax + IP_SOCKET.RemoteIP] + + cmp [eax + UDP_SOCKET.LocalPort], 0 + jne @f + call SOCKET_find_port + @@: + + mov [eax + UDP_SOCKET.firstpacket], 0 + + push eax + init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue + pop eax + + lea ecx, [eax + SOCKET.mutex] + call mutex_unlock + + mov dword [esp+32], 0 + ret + +align 4 + .tcp: + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + popa + + pushw [edx + 2] + pop [eax + TCP_SOCKET.RemotePort] + + pushd [edx + 4] + pop [eax + IP_SOCKET.RemoteIP] + + cmp [eax + TCP_SOCKET.LocalPort], 0 + jne @f + call SOCKET_find_port + @@: + + mov [eax + TCP_SOCKET.timer_persist], 0 + mov [eax + TCP_SOCKET.t_state], TCPS_SYN_SENT + + push [TCP_sequence_num] + add [TCP_sequence_num], 6400 + pop [eax + TCP_SOCKET.ISS] + mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init + + + TCP_sendseqinit eax + +; mov [ebx + TCP_SOCKET.timer_retransmission], ;; todo: create macro to set retransmission timer + mov ebx, eax - lea ecx, [eax+SOCKET.mutex] - call mutex_init + + lea eax, [ebx + STREAM_SOCKET.snd] + call SOCKET_ring_create + + lea eax, [ebx + STREAM_SOCKET.rcv] + call SOCKET_ring_create + + pusha + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + popa + mov eax, ebx + call TCP_output - ; add socket to the list by changing pointers - mov ebx, net_sockets - push [ebx + SOCKET.NextPtr] - mov [ebx + SOCKET.NextPtr], eax - mov [eax + SOCKET.PrevPtr], ebx - pop ebx - mov [eax + SOCKET.NextPtr], ebx - or ebx, ebx +;;; TODO: wait for successfull connection if blocking socket + + mov dword [esp+32], 0 + ret + +align 4 + .ip: + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + popa + + pushd [edx + 4] + pop [eax + IP_SOCKET.RemoteIP] + + push eax + init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue + pop eax + + lea ecx, [eax + SOCKET.mutex] + call mutex_unlock + + mov dword [esp+32], 0 + ret + + +;----------------------------------------------------------------- +; +; SOCKET_listen +; +; IN: socket number in ecx +; backlog in edx +; OUT: eax is socket num, -1 on error +; +;----------------------------------------------------------------- +align 4 +SOCKET_listen: + + DEBUGF 2,"SOCKET_listen: socknum=%u backlog=%u\n", ecx, edx + + call SOCKET_num_to_ptr + jz s_error + + cmp [eax + SOCKET.Domain], AF_INET4 + jne s_error + + cmp [eax + SOCKET.Protocol], IP_PROTO_TCP + jne s_error + + cmp [eax + TCP_SOCKET.LocalPort], 0 + je s_error + + cmp [eax + IP_SOCKET.LocalIP], 0 + jne @f + push [IP_LIST] + pop [eax + IP_SOCKET.LocalIP] + @@: + + cmp edx, MAX_backlog + jbe @f + mov edx, MAX_backlog + @@: + + mov [eax + SOCKET.backlog], dx + or [eax + SOCKET.options], SO_ACCEPTCON + mov [eax + TCP_SOCKET.t_state], TCPS_LISTEN + mov [eax + TCP_SOCKET.timer_keepalive], 0 ; disable keepalive timer + + push eax + init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up sockets queue + pop eax + + mov dword [esp+32], 0 + + ret + + +;----------------------------------------------------------------- +; +; SOCKET_accept +; +; IN: socket number in ecx +; addr in edx +; addrlen in esi +; OUT: eax is socket num, -1 on error +; +;----------------------------------------------------------------- +align 4 +SOCKET_accept: + + DEBUGF 2,"SOCKET_accept: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi + + call SOCKET_num_to_ptr + jz s_error + + test [eax + SOCKET.options], SO_ACCEPTCON + jz s_error + + cmp [eax + SOCKET.Domain], AF_INET4 + jne s_error + + cmp [eax + SOCKET.Protocol], IP_PROTO_TCP + jne s_error + + .loop: + get_from_queue (eax + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .block + +; Ok, we got a socket ptr + mov eax, [esi] + +; Change thread ID to that of the current thread + mov ebx, [TASK_BASE] + mov ebx, [ebx + TASKDATA.pid] + mov [eax + SOCKET.TID], ebx + +; Convert it to a socket number + call SOCKET_ptr_to_num + jz s_error +; and return it to caller + mov [esp+32], eax + ret + + .block: + test [eax + SOCKET.options], SO_NONBLOCK + jnz s_error + + call SOCKET_block + jmp .loop + +;----------------------------------------------------------------- +; +; SOCKET_close +; +; IN: socket number in ecx +; OUT: eax is socket num, -1 on error +; +;----------------------------------------------------------------- +align 4 +SOCKET_close: + + DEBUGF 2,"SOCKET_close: socknum=%u\n", ecx + + call SOCKET_num_to_ptr + jz s_error + + mov dword [esp+32], 0 ; The socket exists, so we will succeed in closing it. + + .socket: + or [eax + SOCKET.options], SO_NONBLOCK ; Mark the socket as non blocking, we dont want it to block any longer! + + test [eax + SOCKET.state], SS_BLOCKED ; Is the socket still in blocked state? jz @f - mov [ebx + SOCKET.PrevPtr], eax + call SOCKET_notify.unblock ; Unblock it. + @@: - @@: ; set socket owner PID to the one of calling process + cmp [eax + SOCKET.Domain], AF_INET4 + jne .free + + cmp [eax + SOCKET.Protocol], IP_PROTO_TCP + je .tcp + + .free: + call SOCKET_free + ret + + .tcp: + cmp [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED ; state must be LISTEN, SYN_SENT or CLOSED + jb .free + + call TCP_usrclosed + call TCP_output ;;;; Fixme: is this nescessary?? + + ret + + +;----------------------------------------------------------------- +; +; SOCKET_receive +; +; IN: socket number in ecx +; addr to buffer in edx +; length of buffer in esi +; flags in edi +; OUT: eax is number of bytes copied, -1 on error +; +;----------------------------------------------------------------- +align 4 +SOCKET_receive: + + DEBUGF 2,"SOCKET_receive: socknum=%u bufaddr=%x buflength=%u flags=%x\n", ecx, edx, esi, edi + + call SOCKET_num_to_ptr + jz s_error + + jmp [eax + SOCKET.rcv_proc] + + +align 4 +SOCKET_receive_dgram: + + DEBUGF 1,"SOCKET_receive: DGRAM\n" + + mov ebx, esi + mov edi, edx ; addr to buffer + + .loop: + get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .block ; destroys esi and ecx + + mov ecx, [esi + socket_queue_entry.data_size] + DEBUGF 1,"SOCKET_receive: %u bytes data\n", ecx + + cmp ecx, ebx + ja .too_small + + push [esi + socket_queue_entry.buf_ptr] ; save the buffer addr so we can clear it later + mov esi, [esi + socket_queue_entry.data_ptr] + DEBUGF 1,"SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi + mov [esp+32+4], ecx ; return number of bytes copied + +; copy the data + shr ecx, 1 + jnc .nb + movsb + .nb: + shr ecx, 1 + jnc .nw + movsw + .nw: + test ecx, ecx + jz .nd + rep movsd + .nd: + + call kernel_free ; remove the packet + ret + + .too_small: + + DEBUGF 2,"SOCKET_receive: Buffer too small\n" + jmp s_error + + .block: + test [eax + SOCKET.options], SO_NONBLOCK + jnz s_error + + call SOCKET_block + jmp .loop + + +align 4 +SOCKET_receive_local: + + ; does this socket have a PID yet? + cmp [eax + SOCKET.PID], 0 + jne @f + + ; Change PID to that of current process mov ebx, [TASK_BASE] mov ebx, [ebx + TASKDATA.pid] mov [eax + SOCKET.PID], ebx + mov [eax + SOCKET.TID], ebx ; currently TID = PID in kolibrios :( + @@: - ; find first free socket number and use it - ;mov edx, ebx - mov ebx, net_sockets - xor ecx, ecx - .next_socket_number: - inc ecx - .next_socket: - mov ebx, [ebx + SOCKET.NextPtr] - or ebx, ebx - jz .last_socket_number - cmp [ebx + SOCKET.Number], ecx - jne .next_socket - ;cmp [ebx + SOCKET.PID], edx - ;jne .next_socket - mov ebx, net_sockets - jmp .next_socket_number + mov [eax + SOCKET.rcv_proc], SOCKET_receive_stream - .last_socket_number: - mov [eax + SOCKET.Number], ecx +align 4 +SOCKET_receive_stream: - .exit: - ret -endp - -;; Free socket data memory and pop socket off the list -; -; @param sockAddr is a socket structure address -;; -proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD - mov eax, [sockAddr] - DEBUGF 1, "K : net_socket_free (0x%x)\n", eax - ; check if we got something similar to socket structure address - or eax, eax - jz .error - - ; make sure sockAddr is one of the socket addresses in the list - mov ebx, net_sockets - ;mov ecx, [TASK_BASE] - ;mov ecx, [ecx + TASKDATA.pid] - .next_socket: - mov ebx, [ebx + SOCKET.NextPtr] - or ebx, ebx - jz .error - cmp ebx, eax - jne .next_socket - ;cmp [ebx + SOCKET.PID], ecx - ;jne .next_socket - - ; okay, we found the correct one - ; mark local port as unused - movzx ebx, [eax + SOCKET.LocalPort] - push eax - mov eax, [network_free_ports] - xchg bl, bh - lock bts [eax], ebx - pop eax - ; remove it from the list first, changing pointers - mov ebx, [eax + SOCKET.NextPtr] - mov eax, [eax + SOCKET.PrevPtr] - mov [eax + SOCKET.NextPtr], ebx - or ebx, ebx - jz @f - mov [ebx + SOCKET.PrevPtr], eax - - @@: ; and finally free the memory structure used - stdcall kernel_free, [sockAddr] - ret - - .error: - DEBUGF 1, "K : failed\n" - ret -endp - -;; Get socket structure address by its number -; Scan through sockets list to find the socket with specified number. -; This proc uses SOCKET.PID indirectly to check if socket is owned by -; calling process. -; -; @param sockNum is a socket number -; @return socket structure address or 0 (not found) in EAX -;; -proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD - mov eax, [sockNum] - ; check if we got something similar to socket number - or eax, eax - jz .error - - ; scan through sockets list - mov ebx, net_sockets - ;mov ecx, [TASK_BASE] - ;mov ecx, [ecx + TASKDATA.pid] - .next_socket: - mov ebx, [ebx + SOCKET.NextPtr] - or ebx, ebx - jz .error - cmp [ebx + SOCKET.Number], eax - jne .next_socket - ;cmp [ebx + SOCKET.PID], ecx - ;jne .next_socket - - ; okay, we found the correct one - mov eax, ebx - ret - - .error: - xor eax, eax - ret -endp - -;; Get socket number by its structure address -; Scan through sockets list to find the socket with specified address. -; This proc uses SOCKET.PID indirectly to check if socket is owned by -; calling process. -; -; @param sockAddr is a socket structure address -; @return socket number (SOCKET.Number) or 0 (not found) in EAX -;; -proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD - mov eax, [sockAddr] - ; check if we got something similar to socket structure address - or eax, eax - jz .error - - ; scan through sockets list - mov ebx, net_sockets - ;mov ecx, [TASK_BASE] - ;mov ecx, [ecx + TASKDATA.pid] - .next_socket: - mov ebx, [ebx + SOCKET.NextPtr] - or ebx, ebx - jz .error - cmp ebx, eax - jne .next_socket - ;cmp [ebx + SOCKET.PID], ecx - ;jne .next_socket - - ; okay, we found the correct one - mov eax, [ebx + SOCKET.Number] - ret - - .error: - xor eax, eax - ret -endp - -;; [53.9] Check if local port is used by any socket in the system. -; Scan through sockets list, checking SOCKET.LocalPort. -; Useful when you want a to generate a unique local port number. -; This proc doesn't guarantee that after calling it and trying to use -; the port reported being free in calls to socket_open/socket_open_tcp it'll -; still be free or otherwise it'll still be used if reported being in use. -; -; @param BX is a port number -; @return 1 (port is free) or 0 (port is in use) in EAX -;; -proc is_localport_unused stdcall - movzx ebx, bx - mov eax, [network_free_ports] - bt [eax], ebx - setc al - movzx eax, al - ret -endp - -;====================================== -set_local_port: -;-------------------------------------- -;? Set local port in socket structure. -;-------------------------------------- -;> eax -> struct SOCKET -;> bx = local port, or 0 if the kernel must select it itself -;-------------------------------------- -;< CF set on error / cleared on success -;< [eax+SOCKET.LocalPort] filled on success -;====================================== -; 0. Prepare: save registers, make eax point to ports table, expand port to ebx. - push eax ecx - mov eax, [network_free_ports] - movzx ebx, bx -; 1. Test, whether the kernel should choose port itself. If no, proceed to 5. - test ebx, ebx - jnz .given -; 2. Yes, it should. Set ecx = limit of table, eax = start value - lea ecx, [eax+0x10000/8] - add eax, [network_free_hint] -; 3. First scan loop: from free hint to end of table. -.scan1: -; 3a. For each dword, find bit set to 1 - bsf ebx, [eax] - jz .next1 -; 3b. If such bit has been found, atomically test again and clear it. - lock btr [eax], ebx -; 3c. If the bit was still set (usual case), we have found and reserved one port. -; Proceed to 6. - jc .found -; 3d. Otherwise, someone has reserved it between bsf and btr, so retry search. - jmp .scan1 -.next1: -; 3e. All bits are cleared, so advance to next dword. - add eax, 4 -; 3f. Check limit and continue loop. - cmp eax, ecx - jb .scan1 -; 4. Second scan loop: from port 1024 (start of non-system ports) to free hint. - mov eax, [network_free_ports] - mov ecx, eax - add ecx, [network_free_hint] - add eax, 1024/8 -; 4a. Test whether there is something to scan. - cmp eax, ecx - jae .fail -; 4b. Enter the loop, the process is same as for 3. -.scan2: - bsf ebx, [eax] - jz .next2 - lock btr [eax], ebx - jc .found - jmp .scan2 -.next2: - add eax, 4 - cmp eax, ecx - jb .scan2 -; 4c. None found. Fail. -.fail: - pop ecx eax - stc - ret -; 5. No, the kernel should reserve selected port. -.given: -; 5a. Atomically test old value and clear bit. - lock btr [eax], ebx -; 5b. If the bit was set, reservation is successful. Proceed to 8. - jc .set -; 5c. Otherwise, fail. - jmp .fail -.found: -; 6. We have found the bit set to 1, convert the position to port number. - sub eax, [network_free_ports] - lea ebx, [ebx+eax*8] -; 7. Update free hint. - add eax, 4 - cmp eax, 65536/8 - jb @f - mov eax, 1024/8 -@@: - mov [network_free_hint], eax -.set: -; 8. Restore eax, set SOCKET.LocalPort and return. - pop ecx eax - xchg bl, bh ; Intel -> network byte order - mov [eax + SOCKET.LocalPort], bx - clc - ret - -;; [53.0] Open DGRAM socket (connectionless, unreliable) -; -; @param BX is local port number -; @param CX is remote port number -; @param EDX is remote IP address -; @return socket number or -1 (error) in EAX -;; -proc socket_open stdcall - call net_socket_alloc - or eax, eax - jz .error - - DEBUGF 1, "K : socket_open (0x%x)\n", eax - - push eax - - call set_local_port - jc .error.free - xchg ch, cl - mov [eax + SOCKET.RemotePort], cx - mov ebx, [stack_ip] - mov [eax + SOCKET.LocalIP], ebx - mov [eax + SOCKET.RemoteIP], edx - - ;pop eax ; Get the socket number back, so we can return it - stdcall net_socket_addr_to_num - ret - - .error.free: - stdcall net_socket_free;, eax - - .error: - DEBUGF 1, "K : socket_open (fail)\n" - or eax, -1 - ret -endp - -;; [53.5] Open STREAM socket (connection-based, sequenced, reliable, two-way) -; -; @param BX is local port number -; @param CX is remote port number -; @param EDX is remote IP address -; @param ESI is open mode (SOCKET_ACTIVE, SOCKET_PASSIVE) -; @return socket number or -1 (error) in EAX -;; -proc socket_open_tcp stdcall -local sockAddr dd ? - - cmp esi, SOCKET_PASSIVE - jne .skip_port_check - - push ebx - mov eax, ebx - xchg al, ah - mov ebx, net_sockets - - .next_socket: - mov ebx, [ebx + SOCKET.NextPtr] - or ebx, ebx - jz .last_socket - cmp [ebx + SOCKET.TCBState], TCB_LISTEN - jne .next_socket - cmp [ebx + SOCKET.LocalPort], ax - jne .next_socket - - xchg al, ah - DEBUGF 1, "K : error: port %u is listened by 0x%x\n", ax, ebx - pop ebx - jmp .error - - .last_socket: - pop ebx - - .skip_port_check: - call net_socket_alloc - or eax, eax - jz .error - - DEBUGF 1, "K : socket_open_tcp (0x%x)\n", eax - - mov [sockAddr], eax - - ; TODO - check this works! - ;mov [eax + SOCKET.wndsizeTimer], 0 ; Reset the window timer. - - call set_local_port - jc .error.free - xchg ch, cl - mov [eax + SOCKET.RemotePort], cx - mov [eax + SOCKET.OrigRemotePort], cx - mov ebx, [stack_ip] - mov [eax + SOCKET.LocalIP], ebx - mov [eax + SOCKET.RemoteIP], edx - mov [eax + SOCKET.OrigRemoteIP], edx - - mov ebx, TCB_LISTEN - cmp esi, SOCKET_PASSIVE - je @f - mov ebx, TCB_SYN_SENT - @@: - mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB - - cmp ebx, TCB_LISTEN - je .exit - - ; Now, if we are in active mode, then we have to send a SYN to the specified remote port - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je .exit - - push eax - - mov bl, TH_SYN - xor ecx, ecx - stdcall build_tcp_packet, [sockAddr] - - mov eax, NET1OUT_QUEUE - mov edx, [stack_ip] - mov ecx, [sockAddr] - cmp edx, [ecx + SOCKET.RemoteIP] - jne .not_local - mov eax, IPIN_QUEUE - - .not_local: - ; Send it. - pop ebx - call queue - - mov esi, [sockAddr] - - ; increment SND.NXT in socket - add esi, SOCKET.SND_NXT - call inc_inet_esi - - .exit: - ; Get the socket number back, so we can return it - stdcall net_socket_addr_to_num, [sockAddr] - ret - - .error.free: - stdcall net_socket_free, eax - - .error: - DEBUGF 1, "K : socket_open_tcp (fail)\n" - or eax, -1 - ret -endp - -;; [53.1] Close DGRAM socket -; -; @param EBX is socket number -; @return 0 (closed successfully) or -1 (error) in EAX -;; -proc socket_close stdcall - DEBUGF 1, "K : socket_close (0x%x)\n", ebx - stdcall net_socket_num_to_addr, ebx - or eax, eax - jz .error - - stdcall net_socket_free, eax - - xor eax, eax - ret - - .error: - DEBUGF 1, "K : socket_close (fail)\n" - or eax, -1 - ret -endp - -;; [53.8] Close STREAM socket -; Closing TCP sockets takes time, so when you get successful return code -; from this function doesn't always mean that socket is actually closed. -; -; @param EBX is socket number -; @return 0 (closed successfully) or -1 (error) in EAX -;; -proc socket_close_tcp stdcall -local sockAddr dd ? - - DEBUGF 1, "K : socket_close_tcp (0x%x)\n", ebx - ; first, remove any resend entries - pusha - - mov esi, resendQ - mov ecx, 0 - - .next_resendq: - cmp ecx, NUMRESENDENTRIES - je .last_resendq ; None left - cmp [esi + 4], ebx - je @f ; found one - inc ecx - add esi, 8 - jmp .next_resendq - - @@: - mov dword[esi + 4], 0 - inc ecx - add esi, 8 - jmp .next_resendq - - .last_resendq: - popa - - stdcall net_socket_num_to_addr, ebx - or eax, eax - jz .error - - mov ebx, eax - mov [sockAddr], eax - - cmp [ebx + SOCKET.TCBState], TCB_LISTEN - je .destroy_tcb - cmp [ebx + SOCKET.TCBState], TCB_SYN_SENT - je .destroy_tcb - cmp [ebx + SOCKET.TCBState], TCB_CLOSED - je .destroy_tcb - - ; Now construct the response, and queue for sending by IP - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je .error - - push eax - - mov bl, TH_FIN+TH_ACK - xor ecx, ecx - xor esi, esi - stdcall build_tcp_packet, [sockAddr] - - mov ebx, [sockAddr] - ; increament SND.NXT in socket - lea esi, [ebx + SOCKET.SND_NXT] - call inc_inet_esi - - ; Get the socket state - mov eax, [ebx + SOCKET.TCBState] - cmp eax, TCB_SYN_RECEIVED - je .fin_wait_1 - cmp eax, TCB_ESTABLISHED - je .fin_wait_1 - - ; assume CLOSE WAIT - ; Send a fin, then enter last-ack state - mov [ebx + SOCKET.TCBState], TCB_LAST_ACK - jmp .send - - .fin_wait_1: - ; Send a fin, then enter finwait2 state - mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_1 - - .send: - mov eax, NET1OUT_QUEUE - mov edx, [stack_ip] - mov ecx, [sockAddr] - cmp edx, [ecx + SOCKET.RemoteIP] - jne .not_local - mov eax, IPIN_QUEUE - - .not_local: - ; Send it. - pop ebx - call queue - jmp .exit - - .destroy_tcb: - - ; Clear the socket variables - stdcall net_socket_free, ebx - - .exit: - xor eax, eax - ret - - .error: - DEBUGF 1, "K : socket_close_tcp (fail)\n" - or eax, -1 - ret -endp - -;; [53.2] Poll socket -; -; @param EBX is socket number -; @return count or bytes in rx buffer or 0 (error) in EAX -;; -proc socket_poll stdcall -; DEBUGF 1, "socket_poll(0x%x)\n", ebx - stdcall net_socket_num_to_addr, ebx - or eax, eax - jz .error - - mov eax, [eax + SOCKET.rxDataCount] - ret - - .error: - xor eax, eax - ret -endp - -;; [53.6] Get socket TCB state -; -; @param EBX is socket number -; @return socket TCB state or 0 (error) in EAX -;; -proc socket_status stdcall -;; DEBUGF 1, "socket_status(0x%x)\n", ebx - stdcall net_socket_num_to_addr, ebx - or eax, eax - jz .error - - mov eax, [eax + SOCKET.TCBState] - ret - - .error: - xor eax, eax - ret -endp - -;; [53.3] Get one byte from rx buffer -; This function can return 0 in two cases: if there's one byte read and -; non left, and if an error occured. Behavior should be changed and function -; shouldn't be used for now. Consider using [53.11] instead. -; -; @param EBX is socket number -; @return number of bytes left in rx buffer or 0 (error) in EAX -; @return byte read in BL -;; -proc socket_read stdcall -; DEBUGF 1, "socket_read(0x%x)\n", ebx - stdcall net_socket_num_to_addr, ebx - or eax, eax - jz .error - - mov ebx, eax - lea ecx, [eax + SOCKET.mutex] - call mutex_lock - - mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes - test eax, eax - jz .error_release - - dec eax - mov esi, ebx ; esi is address of socket - mov [ebx + SOCKET.rxDataCount], eax ; store new count - movzx eax, byte[ebx + SOCKET.rxData] ; get the byte - - mov ecx, SOCKETBUFFSIZE - SOCKET.rxData - 1 - lea edi, [esi + SOCKET.rxData] - lea esi, [edi + 1] - cld - push ecx - shr ecx, 2 - rep movsd - pop ecx - and ecx, 3 - rep movsb - - lea ecx, [ebx + SOCKET.mutex] - mov ebx, eax - call mutex_unlock - mov eax, ebx - ret - - .error_release: - lea ecx, [ebx + SOCKET.mutex] - call mutex_unlock - .error: - xor ebx, ebx - xor eax, eax - ret -endp - -;; [53.11] Get specified number of bytes from rx buffer -; Number of bytes in rx buffer can be less than requested size. In this case, -; only available number of bytes is read. -; This function can return 0 in two cases: if there's no data to read, and if -; an error occured. Behavior should be changed. -; -; @param EBX is socket number -; @param ECX is pointer to application buffer -; @param EDX is application buffer size (number of bytes to read) -; @return number of bytes read or 0 (error) in EAX -;; -proc socket_read_packet stdcall -; DEBUGF 1, "socket_read_packet(0x%x)\n", ebx - stdcall net_socket_num_to_addr, ebx ; get real socket address - or eax, eax - jz .error - - mov ebx, eax - - push ecx edx - lea ecx, [eax + SOCKET.mutex] - call mutex_lock - pop edx ecx - - mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes - test eax, eax ; if count of bytes is zero.. - jz .exit ; exit function (eax will be zero) - - test edx, edx ; if buffer size is zero, copy all data - jz .copy_all_bytes - cmp edx, eax ; if buffer size is larger then the bytes of data, copy all data - jge .copy_all_bytes - - sub eax, edx ; store new count (data bytes in buffer - bytes we're about to copy) - mov [ebx + SOCKET.rxDataCount], eax ; - push eax - mov eax, edx ; number of bytes we want to copy must be in eax - call .start_copy ; copy to the application - - mov esi, ebx ; now we're going to copy the remaining bytes to the beginning - add esi, SOCKET.rxData ; we dont need to copy the header - mov edi, esi ; edi is where we're going to copy to - add esi, edx ; esi is from where we copy - pop ecx ; count of bytes we have left - push ecx ; push it again so we can re-use it later - shr ecx, 2 ; divide eax by 4 - cld - rep movsd ; copy all full dwords - pop ecx - and ecx, 3 - rep movsb ; copy remaining bytes - - .exit: - lea ecx, [ebx + SOCKET.mutex] - mov ebx, eax - call mutex_unlock - mov eax, ebx - ret ; at last, exit - - .error: - xor eax, eax - ret - - .copy_all_bytes: - xor esi, esi - mov [ebx + SOCKET.rxDataCount], esi ; store new count (zero) - call .start_copy - lea ecx, [ebx + SOCKET.mutex] - mov ebx, eax - call mutex_unlock - mov eax, ebx - ret - - .start_copy: - mov edi, ecx - mov esi, ebx - add esi, SOCKET.rxData ; we dont need to copy the header - mov ecx, eax ; eax is count of bytes - push ecx - shr ecx, 2 ; divide eax by 4 - cld ; copy all full dwords - rep movsd - pop ecx - and ecx, 3 - rep movsb ; copy the rest bytes - retn ; exit, or go back to shift remaining bytes if any -endp - -;; [53.4] Send data through DGRAM socket -; -; @param EBX is socket number -; @param ECX is application data size (number of bytes to send) -; @param EDX is pointer to application data buffer -; @return 0 (sent successfully) or -1 (error) in EAX -;; -proc socket_write stdcall -; DEBUGF 1, "socket_write(0x%x)\n", ebx - stdcall net_socket_num_to_addr, ebx ; get real socket address - or eax, eax - jz .error - - mov ebx, eax - - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je .error - - ; Save the queue entry number - push eax - - ; save the pointers to the data buffer & size - push edx - push ecx - - ; convert buffer pointer eax to the absolute address - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs - - mov edx, eax - - ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr - - ; Fill in the IP header (some data is in the socket descriptor) - mov eax, [ebx + SOCKET.LocalIP] - mov [edx + IP_PACKET.SourceAddress], eax - mov eax, [ebx + SOCKET.RemoteIP] - mov [edx + IP_PACKET.DestinationAddress], eax - - mov [edx + IP_PACKET.VersionAndIHL], 0x45 - mov [edx + IP_PACKET.TypeOfService], 0 - - pop eax ; Get the UDP data length - push eax - - add eax, 20 + 8 ; add IP header and UDP header lengths - xchg al, ah - mov [edx + IP_PACKET.TotalLength], ax - xor eax, eax - mov [edx + IP_PACKET.Identification], ax - mov [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040 - mov [edx + IP_PACKET.TimeToLive], 0x20 - mov [edx + IP_PACKET.Protocol], PROTOCOL_UDP - - ; Checksum left unfilled - mov [edx + IP_PACKET.HeaderChecksum], ax - - ; Fill in the UDP header (some data is in the socket descriptor) - mov ax, [ebx + SOCKET.LocalPort] - mov [edx + 20 + UDP_PACKET.SourcePort], ax - - mov ax, [ebx + SOCKET.RemotePort] - mov [edx + 20 + UDP_PACKET.DestinationPort], ax - - pop eax - push eax - - add eax, 8 - xchg al, ah - mov [edx + 20 + UDP_PACKET.Length], ax - - ; Checksum left unfilled - xor eax, eax - mov [edx + 20 + UDP_PACKET.Checksum], ax - - pop ecx ; count of bytes to send - mov ebx, ecx ; need the length later - pop eax ; get callers ptr to data to send - - ; Get the address of the callers data - mov edi, [TASK_BASE] - add edi, TASKDATA.mem_start - add eax, [edi] - mov esi, eax + DEBUGF 1,"SOCKET_receive: STREAM\n" + mov ebx, edi + mov ecx, esi mov edi, edx - add edi, 28 - cld - rep movsb ; copy the data across + xor edx, edx - ; we have edx as IPbuffer ptr. - ; Fill in the UDP checksum - ; First, fill in pseudoheader - mov eax, [edx + IP_PACKET.SourceAddress] - mov [pseudoHeader], eax - mov eax, [edx + IP_PACKET.DestinationAddress] - mov [pseudoHeader + 4], eax - mov word[pseudoHeader + 8], PROTOCOL_UDP shl 8 + 0 ; 0 + protocol - add ebx, 8 - mov eax, ebx - xchg al, ah - mov [pseudoHeader + 10], ax + test ebx, MSG_DONTWAIT + jnz .dontwait + .loop: + cmp [eax + STREAM_SOCKET.rcv + RING_BUFFER.size], 0 + je .block + .dontwait: + test ebx, MSG_PEEK + jnz .peek - mov eax, pseudoHeader - mov [checkAdd1], eax - mov [checkSize1], word 12 - mov eax, edx - add eax, 20 - mov [checkAdd2], eax - mov eax, ebx - mov [checkSize2], ax ; was eax!! mjh 8/7/02 + add eax, STREAM_SOCKET.rcv + call SOCKET_ring_read + call SOCKET_ring_free - call checksum - - ; store it in the UDP checksum ( in the correct order! ) - mov ax, [checkResult] - - ; If the UDP checksum computes to 0, we must make it 0xffff - ; (0 is reserved for 'not used') - test ax, ax - jnz @f - mov ax, 0xffff - - @@: - xchg al, ah - mov [edx + 20 + UDP_PACKET.Checksum], ax - - ; Fill in the IP header checksum - GET_IHL ecx,edx ; get IP-Header length - stdcall checksum_jb, edx, ecx; buf_ptr, buf_size - xchg al, ah - mov [edx + IP_PACKET.HeaderChecksum], ax - - ; Check destination IP address. - ; If it is the local host IP, route it back to IP_RX - - pop ebx - - mov eax, NET1OUT_QUEUE - mov ecx, [edx + SOCKET.RemoteIP] - mov edx, [stack_ip] - cmp edx, ecx - jne .not_local - mov eax, IPIN_QUEUE - - .not_local: - ; Send it. - call queue - - xor eax, eax + mov [esp+32], ecx ; return number of bytes copied ret - .error: - or eax, -1 + .peek: + mov ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size] + mov [esp+32], ecx ; return number of bytes available ret -endp -;; [53.7] Send data through STREAM socket + .block: + test [eax + SOCKET.options], SO_NONBLOCK + jnz .return0 + + call SOCKET_block + jmp .loop + + .return0: + xor ecx, ecx + mov [esp+32], ecx + ret + + +;----------------------------------------------------------------- ; -; @param EBX is socket number -; @param ECX is application data size (number of bytes to send) -; @param EDX is pointer to application data buffer -; @return 0 (sent successfully) or -1 (error) in EAX -;; -proc socket_write_tcp stdcall -local sockAddr dd ? +; SOCKET_send +; +; +; IN: socket number in ecx +; pointer to data in edx +; datalength in esi +; flags in edi +; OUT: -1 on error +; +;----------------------------------------------------------------- +align 4 +SOCKET_send: -; DEBUGF 1, "socket_write_tcp(0x%x)\n", ebx - stdcall net_socket_num_to_addr, ebx - or eax, eax - jz .error + DEBUGF 2,"SOCKET_send: socknum=%u data ptr=%x length=%u flags=%x\n", ecx, edx, esi, edi - mov ebx, eax - mov [sockAddr], ebx + call SOCKET_num_to_ptr + jz s_error - ; If the sockets window timer is nonzero, do not queue packet - cmp [ebx + SOCKET.wndsizeTimer], 0 - jne .error - - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je .error - - push eax - - ; Get the address of the callers data - mov edi, [TASK_BASE] - add edi, TASKDATA.mem_start - add edx, [edi] + mov ecx, esi mov esi, edx - pop eax + jmp [eax + SOCKET.snd_proc] + + +align 4 +SOCKET_send_udp: + + DEBUGF 1,"SOCKET_send: UDP\n" + + mov [esp+32], ecx + call UDP_output + cmp eax, -1 + je s_error + ret + + +align 4 +SOCKET_send_tcp: + + DEBUGF 1,"SOCKET_send: TCP\n" + push eax - - push ecx - mov bl, TH_ACK - stdcall build_tcp_packet, [sockAddr] - pop ecx - - ; Check destination IP address. - ; If it is the local host IP, route it back to IP_RX - - pop ebx - push ecx - - mov eax, NET1OUT_QUEUE - mov edx, [stack_ip] - mov ecx, [sockAddr] - cmp edx, [ecx + SOCKET.RemoteIP] - jne .not_local - mov eax, IPIN_QUEUE - - .not_local: - pop ecx - push ebx ; save ipbuffer number - - call queue - - mov esi, [sockAddr] - - ; increament SND.NXT in socket - ; Amount to increment by is in ecx - add esi, SOCKET.SND_NXT - call add_inet_esi - - pop ebx - - ; Copy the IP buffer to a resend queue - ; If there isn't one, dont worry about it for now - mov esi, resendQ - mov ecx, 0 - - .next_resendq: - cmp ecx, NUMRESENDENTRIES - je .exit ; None found - cmp dword[esi + 4], 0 - je @f ; found one - inc ecx - add esi, 8 - jmp .next_resendq - - @@: - push ebx - - ; OK, we have a buffer descriptor ptr in esi. - ; resend entry # in ecx - ; Populate it - ; socket # - ; retries count - ; retry time - ; fill IP buffer associated with this descriptor - - stdcall net_socket_addr_to_num, [sockAddr] - mov [esi + 4], eax - mov byte[esi + 1], TCP_RETRIES - mov word[esi + 2], TCP_TIMEOUT - - inc ecx - ; Now get buffer location, and copy buffer across. argh! more copying,, - mov edi, resendBuffer - IPBUFFSIZE - - @@: - add edi, IPBUFFSIZE - loop @b - - ; we have dest buffer location in edi + add eax, STREAM_SOCKET.snd + call SOCKET_ring_write pop eax - ; convert source buffer pointer eax to the absolute address - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs - mov esi, eax - ; do copy - mov ecx, IPBUFFSIZE - cld - rep movsb + mov [esp+32], ecx + + call TCP_output + ret + + +align 4 +SOCKET_send_ip: + + DEBUGF 1,"SOCKET_send: IPv4\n" + + mov [esp+32], ecx + call IPv4_output_raw + cmp eax, -1 + je s_error + ret + + +align 4 +SOCKET_send_icmp: + + DEBUGF 1,"SOCKET_send: ICMP\n" + + mov [esp+32], ecx + call ICMP_output_raw + cmp eax, -1 + je s_error + ret + + +align 4 +SOCKET_send_pppoe: + + DEBUGF 1,"SOCKET_send: PPPoE\n" + + mov [esp+32], ecx + mov ebx, [eax + SOCKET.device] + + call PPPoE_discovery_output + cmp eax, -1 + je s_error + ret + + + +align 4 +SOCKET_send_local: + + ; does this socket have a PID yet? + cmp [eax + SOCKET.PID], 0 + jne @f + + ; Change PID to that of current process + mov ebx, [TASK_BASE] + mov ebx, [ebx + TASKDATA.pid] + mov [eax + SOCKET.PID], ebx + mov [eax + SOCKET.TID], ebx ; currently TID = PID in kolibrios :( + @@: + mov [eax + SOCKET.snd_proc], SOCKET_send_local_ + +align 4 +SOCKET_send_local_: + + DEBUGF 1,"SOCKET_send: LOCAL\n" + + ; get the other side's socket and check if it still exists + mov eax, [eax + SOCKET.device] + call SOCKET_check + jz s_error + + ; allright, shove in the data! + push eax + add eax, STREAM_SOCKET.rcv + call SOCKET_ring_write + pop eax + + ; return the number of written bytes (or errorcode) to application + mov [esp+32], ecx + + ; and notify the other end + call SOCKET_notify + + ret + + +;----------------------------------------------------------------- +; +; SOCKET_get_options +; +; IN: ecx = socket number +; edx = pointer to the options: +; dd level, optname, optval, optlen +; OUT: -1 on error +; +; At moment, uses only pseudo-optname -2 for get last_ack_number for TCP. +; TODO: find best way to notify that send()'ed data were acknowledged +; Also pseudo-optname -3 is valid and returns socket state, one of TCPS_*. +; +;----------------------------------------------------------------- +align 4 +SOCKET_get_opt: + + DEBUGF 2,"SOCKET_get_opt\n" + + call SOCKET_num_to_ptr + jz s_error + + cmp dword [edx], IP_PROTO_TCP + jne s_error + cmp dword [edx+4], -2 + je @f + cmp dword [edx+4], -3 + jne s_error +@@: +; mov eax, [edx+12] +; test eax, eax +; jz .fail +; cmp dword [eax], 4 +; mov dword [eax], 4 +; jb .fail +; stdcall net_socket_num_to_addr, ecx +; test eax, eax +; jz .fail +; ; todo: check that eax is really TCP socket +; mov ecx, [eax + TCP_SOCKET.last_ack_number] +; cmp dword [edx+4], -2 +; jz @f +; mov ecx, [eax + TCP_SOCKET.state] +@@: + mov eax, [edx+8] + test eax, eax + jz @f + mov [eax], ecx +@@: + mov dword [esp+32], 0 + ret + + + +;----------------------------------------------------------------- +; +; SOCKET_set_options +; +; IN: ecx = socket number +; edx = pointer to the options: +; dd level, optname, optlen, optval +; OUT: -1 on error +; +;----------------------------------------------------------------- +align 4 +SOCKET_set_opt: + + DEBUGF 2,"SOCKET_set_opt\n" + + call SOCKET_num_to_ptr + jz s_error + + cmp dword [edx], SOL_SOCKET + jne s_error + + cmp dword [edx+4], SO_BINDTODEVICE + je .bind + + cmp dword [edx+4], SO_BLOCK + je .block + + jmp s_error + + .bind: + cmp dword [edx+8], 0 + je .unbind + + movzx edx, byte [edx + 9] + cmp edx, MAX_NET_DEVICES + ja s_error + + mov edx, [NET_DRV_LIST + 4*edx] + test edx, edx + jz s_error + mov [eax + SOCKET.device], edx + + DEBUGF 1,"SOCKET_set_opt: Bound socket %x to device %x\n",eax, edx + + mov dword [esp+32], 0 ; success! + ret + + .unbind: + mov [eax + SOCKET.device], 0 + + mov dword [esp+32], 0 ; success! + ret + + .block: + cmp dword [edx+8], 0 + je .unblock + + and [eax + SOCKET.options], not SO_NONBLOCK + + mov dword [esp+32], 0 ; success! + ret + + .unblock: + or [eax + SOCKET.options], SO_NONBLOCK + + mov dword [esp+32], 0 ; success! + ret + + + +;----------------------------------------------------------------- +; +; SOCKET_pair +; +; Allocates a pair of linked LOCAL domain sockets +; +; IN: / +; OUT: eax is socket1 num, -1 on error +; ebx is socket2 num +; +;----------------------------------------------------------------- +align 4 +SOCKET_pair: + + DEBUGF 2,"SOCKET_pair\n" + + call SOCKET_alloc + jz s_error + mov [esp+32], edi ; application's eax + + mov [eax + SOCKET.Domain], AF_LOCAL + mov [eax + SOCKET.Type], SOCK_STREAM + mov [eax + SOCKET.Protocol], 0 ;;; CHECKME + mov [eax + SOCKET.snd_proc], SOCKET_send_local + mov [eax + SOCKET.rcv_proc], SOCKET_receive_local + mov [eax + SOCKET.PID], 0 + mov ebx, eax + + call SOCKET_alloc + jz .error + mov [esp+24], edi ; application's ebx + + mov [eax + SOCKET.Domain], AF_LOCAL + mov [eax + SOCKET.Type], SOCK_STREAM + mov [eax + SOCKET.Protocol], 0 ;;; CHECKME + mov [eax + SOCKET.snd_proc], SOCKET_send_local + mov [eax + SOCKET.rcv_proc], SOCKET_receive_local + mov [eax + SOCKET.PID], 0 + + ; Link the two sockets to eachother + mov [eax + SOCKET.device], ebx + mov [ebx + SOCKET.device], eax + + lea eax, [eax + STREAM_SOCKET.rcv] + call SOCKET_ring_create + + lea eax, [ebx + STREAM_SOCKET.rcv] + call SOCKET_ring_create + pop eax - .exit: - xor eax, eax ret .error: - or eax, -1 + mov eax, ebx + call SOCKET_free + jmp s_error + + + +;----------------------------------------------------------------- +; +; SOCKET_debug +; +; Copies socket variables to application buffer +; +; IN: ecx = socket number +; edx = pointer to buffer +; +; OUT: -1 on error +;----------------------------------------------------------------- +align 4 +SOCKET_debug: + + DEBUGF 1,"SOCKET_debug\n" + + mov edi, edx + + test ecx, ecx + jz .returnall + + call SOCKET_num_to_ptr + jz s_error + + mov esi, eax + mov ecx, SOCKETBUFFSIZE/4 + rep movsd + + mov dword [esp+32], 0 ret -endp + + .returnall: + mov ebx, net_sockets + .next_socket: + mov ebx, [ebx + SOCKET.NextPtr] + test ebx, ebx + jz .done + mov eax, [ebx + SOCKET.Number] + stosd + jmp .next_socket + .done: + xor eax, eax + stosd + + mov dword [esp+32], 0 + ret + + +;----------------------------------------------------------------- +; +; SOCKET_find_port +; +; Fills in the local port number for TCP and UDP sockets +; This procedure always works because the number of sockets is +; limited to a smaller number then the number of possible ports +; +; IN: eax = socket pointer +; OUT: / +; +;----------------------------------------------------------------- +align 4 +SOCKET_find_port: + + DEBUGF 2,"SOCKET_find_port\n" + + push ebx esi ecx + + cmp [eax + SOCKET.Protocol], IP_PROTO_UDP + je .udp + + cmp [eax + SOCKET.Protocol], IP_PROTO_TCP + je .tcp + + pop ecx esi ebx + ret + + .udp: + mov bx, [last_UDP_port] + call .findit + mov [last_UDP_port], bx + + pop ecx esi ebx + ret + + .tcp: + mov bx, [last_TCP_port] + call .findit + mov [last_TCP_port], bx + + pop ecx esi ebx + ret + + + .restart: + mov bx, MIN_EPHEMERAL_PORT_N + .findit: + cmp bx, MAX_EPHEMERAL_PORT_N + je .restart + + add bh, 1 + adc bl, 0 + + call SOCKET_check_port + jz .findit + ret + + + +;----------------------------------------------------------------- +; +; SOCKET_check_port (to be used with AF_INET only!) +; +; Checks if a local port number is unused +; If the proposed port number is unused, it is filled in in the socket structure +; +; IN: eax = socket ptr (to find out if its a TCP/UDP socket) +; bx = proposed socket number (network byte order) +; +; OUT: ZF = set on error +; +;----------------------------------------------------------------- +align 4 +SOCKET_check_port: + + DEBUGF 2,"SOCKET_check_port: " + + mov ecx, [eax + SOCKET.Protocol] + mov edx, [eax + IP_SOCKET.LocalIP] + mov esi, net_sockets + + .next_socket: + mov esi, [esi + SOCKET.NextPtr] + or esi, esi + jz .port_ok + + cmp [esi + SOCKET.Protocol], ecx + jne .next_socket + + cmp [esi + IP_SOCKET.LocalIP], edx + jne .next_socket + + cmp [esi + UDP_SOCKET.LocalPort], bx + jne .next_socket + + DEBUGF 2,"local port %x already in use\n", bx ; FIXME: find a way to print big endian values with debugf + ret + + .port_ok: + DEBUGF 2,"local port %x is free\n", bx ; FIXME: find a way to print big endian values with debugf + mov [eax + UDP_SOCKET.LocalPort], bx + or bx, bx ; clear the zero-flag + ret + + + +;----------------------------------------------------------------- +; +; SOCKET_input +; +; Updates a (stateless) socket with received data +; +; Note: the mutex should already be set ! +; +; IN: eax = socket ptr +; ecx = data size +; esi = ptr to data +; [esp] = ptr to buf +; [esp + 4] = buf size +; +; OUT: / +; +;----------------------------------------------------------------- +align 4 +SOCKET_input: + + DEBUGF 2,"SOCKET_input: socket=%x, data=%x size=%u\n", eax, esi, ecx + + mov [esp+4], ecx + push esi + mov esi, esp + + add_to_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, SOCKET_input.full + + DEBUGF 1,"SOCKET_input: success\n" + add esp, sizeof.socket_queue_entry + + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_unlock + popa + + jmp SOCKET_notify + + .full: + DEBUGF 2,"SOCKET_input: socket %x is full!\n", eax + + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_unlock + popa + + call kernel_free + add esp, 8 + + ret + + +;-------------------------- +; +; eax = ptr to ring struct (just a buffer of the right size) +; +align 4 +SOCKET_ring_create: + + push esi + mov esi, eax + + push edx + stdcall create_ring_buffer, SOCKET_MAXDATA, PG_SW + pop edx + + DEBUGF 1,"SOCKET_ring_created: %x\n", eax + + pusha + lea ecx, [esi + RING_BUFFER.mutex] + call mutex_init + popa + + mov [esi + RING_BUFFER.start_ptr], eax + mov [esi + RING_BUFFER.write_ptr], eax + mov [esi + RING_BUFFER.read_ptr], eax + mov [esi + RING_BUFFER.size], 0 + add eax, SOCKET_MAXDATA + mov [esi + RING_BUFFER.end_ptr], eax + mov eax, esi + pop esi + + ret + +;----------------------------------------------------------------- +; +; SOCKET_ring_write +; +; Adds data to a stream socket, and updates write pointer and size +; +; IN: eax = ptr to ring struct +; ecx = data size +; esi = ptr to data +; +; OUT: ecx = number of bytes stored +; +;----------------------------------------------------------------- +align 4 +SOCKET_ring_write: + + DEBUGF 1,"SOCKET_ring_write: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx + +; lock mutex + pusha + lea ecx, [eax + RING_BUFFER.mutex] + call mutex_lock ; TODO: check what registers this function actually destroys + popa + +; calculate available size + mov edi, SOCKET_MAXDATA + sub edi, [eax + RING_BUFFER.size] ; available buffer size in edi + cmp ecx, edi + jbe .copy + mov ecx, edi + .copy: + mov edi, [eax + RING_BUFFER.write_ptr] + DEBUGF 2,"SOCKET_ring_write: %u bytes from %x to %x\n", ecx, esi, edi + +; update write ptr + push edi + add edi, ecx + cmp edi, [eax + RING_BUFFER.end_ptr] + jb @f + sub edi, SOCKET_MAXDATA ; WRAP + @@: + mov [eax + RING_BUFFER.write_ptr], edi + pop edi + +; update size + add [eax + RING_BUFFER.size], ecx + +; copy the data + push ecx + shr ecx, 1 + jnc .nb + movsb + .nb: + shr ecx, 1 + jnc .nw + movsw + .nw: + test ecx, ecx + jz .nd + rep movsd + .nd: + pop ecx + +; unlock mutex + push eax ecx + lea ecx, [eax + RING_BUFFER.mutex] + call mutex_unlock ; TODO: check what registers this function actually destroys + pop ecx eax + + ret + +;----------------------------------------------------------------- +; +; SOCKET_ring_read +; +; IN: eax = ring struct ptr +; ecx = bytes to read +; edx = offset +; edi = ptr to buffer start +; +; OUT: eax = unchanged +; ecx = number of bytes read (0 on error) +; edx = destroyed +; esi = destroyed +; edi = ptr to buffer end +; +;----------------------------------------------------------------- +align 4 +SOCKET_ring_read: + + DEBUGF 1,"SOCKET_ring_read: ringbuff=%x ptr=%x size=%u offset=%x\n", eax, edi, ecx, edx + + pusha + lea ecx, [eax + RING_BUFFER.mutex] + call mutex_lock ; TODO: check what registers this function actually destroys + popa + + mov esi, [eax + RING_BUFFER.read_ptr] + add esi, edx ; esi = start_ptr + offset + + neg edx + add edx, [eax + RING_BUFFER.size] ; edx = snd.size - offset + jle .no_data_at_all + + pusha + lea ecx, [eax + RING_BUFFER.mutex] + call mutex_unlock ; TODO: check what registers this function actually destroys + popa + + cmp ecx, edx + ja .less_data + + .copy: + DEBUGF 2,"SOCKET_ring_read: %u bytes from %x to %x\n", ecx, esi, edi + push ecx + shr ecx, 1 + jnc .nb + movsb + .nb: + shr ecx, 1 + jnc .nw + movsw + .nw: + test ecx, ecx + jz .nd + rep movsd + .nd: + pop ecx + ret + + .no_data_at_all: + pusha + lea ecx, [eax + RING_BUFFER.mutex] + call mutex_unlock ; TODO: check what registers this function actually destroys + popa + + DEBUGF 1,"SOCKET_ring_read: no data at all!\n" + xor ecx, ecx + ret + + .less_data: + mov ecx, edx + jmp .copy + + +;----------------------------------------------------------------- +; +; SOCKET_ring_free +; +; Free's some bytes from the ringbuffer +; +; IN: eax = ptr to ring struct +; ecx = data size +; +; OUT: ecx = number of bytes free-ed +; +;----------------------------------------------------------------- +align 4 +SOCKET_ring_free: + + DEBUGF 1,"SOCKET_ring_free: %u bytes from ring %x\n", ecx, eax + + push eax ecx + lea ecx, [eax + RING_BUFFER.mutex] + call mutex_lock ; TODO: check what registers this function actually destroys + pop ecx eax + + sub [eax + RING_BUFFER.size], ecx + jb .error + add [eax + RING_BUFFER.read_ptr], ecx + + mov edx, [eax + RING_BUFFER.end_ptr] + cmp [eax + RING_BUFFER.read_ptr], edx + jb @f + sub [eax + RING_BUFFER.read_ptr], SOCKET_MAXDATA + @@: + + push eax ecx + lea ecx, [eax + RING_BUFFER.mutex] ; TODO: check what registers this function actually destroys + call mutex_unlock + pop ecx eax + + ret + + .error: ; we could free all available bytes, but that would be stupid, i guess.. + DEBUGF 1,"SOCKET_ring_free: buffer=%x error!\n", eax + add [eax + RING_BUFFER.size], ecx + + push eax + lea ecx, [eax + RING_BUFFER.mutex] + call mutex_unlock ; TODO: check what registers this function actually destroys + pop eax + + xor ecx, ecx + ret + + +;----------------------------------------------------------------- +; +; SOCKET_block +; +; Suspends the thread attached to a socket +; +; IN: eax = socket ptr +; OUT: / +; +;----------------------------------------------------------------- +align 4 +SOCKET_block: + + DEBUGF 1,"SOCKET_block: %x\n", eax + + pushf + cli + + ; Set the 'socket is blocked' flag + or [eax + SOCKET.state], SS_BLOCKED + + ; Suspend the thread + push edx + mov edx, [TASK_BASE] + mov [edx + TASKDATA.state], 1 ; Suspended + + ; Remember the thread ID so we can wake it up again + mov edx, [edx + TASKDATA.pid] + DEBUGF 1,"SOCKET_block: suspending thread: %u\n", edx + mov [eax + SOCKET.TID], edx + pop edx + + call change_task + popf + + DEBUGF 1,"SOCKET_block: continueing\n" + + ret + + +;----------------------------------------------------------------- +; +; SOCKET_notify +; +; notify's the owner of a socket that something happened +; +; IN: eax = socket ptr +; OUT: / +; +;----------------------------------------------------------------- +align 4 +SOCKET_notify: + + DEBUGF 1,"SOCKET_notify: %x\n", eax + + call SOCKET_check + jz .error + + test [eax + SOCKET.state], SS_BLOCKED + jnz .unblock + + test [eax + SOCKET.options], SO_NONBLOCK + jz .error + + push eax ecx esi + +; socket exists and is of non blocking type. +; We'll try to flag an event to the thread + + mov eax, [eax + SOCKET.TID] + test eax, eax + jz .done + mov ecx, 1 + mov esi, TASK_DATA + TASKDATA.pid + + .next_pid: + cmp [esi], eax + je .found_pid + inc ecx + add esi, 0x20 + cmp ecx, [TASK_COUNT] + jbe .next_pid +; PID not found, TODO: close socket! + jmp .done + + .found_pid: + shl ecx, 8 + or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK + + DEBUGF 1,"SOCKET_notify: Raised a network event!\n" + + jmp .done + + .unblock: + push eax ecx esi + ; Clear the 'socket is blocked' flag + and [eax + SOCKET.state], not SS_BLOCKED + + ; Find the thread's TASK_DATA + mov eax, [eax + SOCKET.TID] + test eax, eax + jz .error + xor ecx, ecx + inc ecx + mov esi, TASK_DATA + .next: + cmp [esi + TASKDATA.pid], eax + je .found + inc ecx + add esi, 0x20 + cmp ecx, [TASK_COUNT] + jbe .next + jmp .error + .found: + + ; Run the thread + mov [esi + TASKDATA.state], 0 ; Running + DEBUGF 1,"SOCKET_notify: Unblocked socket!\n" + + .done: + pop esi ecx eax + + .error: + ret + + +;-------------------------------------------------------------------- +; +; SOCKET_alloc +; +; Allocate memory for socket data and put new socket into the list +; Newly created socket is initialized with calling PID and number and +; put into beginning of list (which is a fastest way). +; +; IN: / +; OUT: eax = 0 on error, socket ptr otherwise +; edi = socket number +; ZF = cleared on error +; +;-------------------------------------------------------------------- +align 4 +SOCKET_alloc: + + push ebx + + stdcall kernel_alloc, SOCKETBUFFSIZE + DEBUGF 1, "SOCKET_alloc: ptr=%x\n", eax + or eax, eax + jz .exit + +; zero-initialize allocated memory + push eax + mov edi, eax + mov ecx, SOCKETBUFFSIZE / 4 + xor eax, eax + rep stosd + pop eax + +; set send-and receive procedures to return -1 + mov [eax + SOCKET.snd_proc], s_error + mov [eax + SOCKET.rcv_proc], s_error + +; find first free socket number and use it + mov edi, [last_socket_num] + .next_socket_number: + inc edi + jz .next_socket_number ; avoid socket nr 0 + cmp edi, -1 + je .next_socket_number ; avoid socket nr -1 + mov ebx, net_sockets + .next_socket: + mov ebx, [ebx + SOCKET.NextPtr] + test ebx, ebx + jz .last_socket + + cmp [ebx + SOCKET.Number], edi + jne .next_socket + jmp .next_socket_number + + .last_socket: + mov [last_socket_num], edi + mov [eax + SOCKET.Number], edi + DEBUGF 1, "SOCKET_alloc: number=%u\n", edi + +; Fill in PID + mov ebx, [TASK_BASE] + mov ebx, [ebx + TASKDATA.pid] + mov [eax + SOCKET.PID], ebx + mov [eax + SOCKET.TID], ebx ; currently TID = PID in kolibrios :( + +; init mutex + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_init + popa + +; add socket to the list by re-arranging some pointers + mov ebx, [net_sockets + SOCKET.NextPtr] + + mov [eax + SOCKET.PrevPtr], net_sockets + mov [eax + SOCKET.NextPtr], ebx + + test ebx, ebx + jz @f + + pusha + lea ecx, [ebx + SOCKET.mutex] + call mutex_lock + popa + + mov [ebx + SOCKET.PrevPtr], eax + + pusha + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + popa + @@: + + mov [net_sockets + SOCKET.NextPtr], eax + or eax, eax ; used to clear zero flag + .exit: + pop ebx + + ret + + +;---------------------------------------------------- +; +; SOCKET_free +; +; Free socket data memory and remove socket from the list +; +; IN: eax = socket ptr +; OUT: / +; +;---------------------------------------------------- +align 4 +SOCKET_free: + + DEBUGF 1, "SOCKET_free: %x\n", eax + + call SOCKET_check + jz .error + + push ebx + + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + popa + + cmp [eax + SOCKET.Domain], AF_INET4 + jnz .no_tcp + + cmp [eax + SOCKET.Protocol], IP_PROTO_TCP + jnz .no_tcp + + mov ebx, eax + stdcall kernel_free, [ebx + STREAM_SOCKET.rcv.start_ptr] + stdcall kernel_free, [ebx + STREAM_SOCKET.snd.start_ptr] + mov eax, ebx + .no_tcp: + + push eax ; this will be passed to kernel_free + mov ebx, [eax + SOCKET.NextPtr] + mov eax, [eax + SOCKET.PrevPtr] + + DEBUGF 1, "SOCKET_free: linking socket %x to socket %x\n", eax, ebx + + test eax, eax + jz @f + mov [eax + SOCKET.NextPtr], ebx + @@: + + test ebx, ebx + jz @f + mov [ebx + SOCKET.PrevPtr], eax + @@: + + call kernel_free + pop ebx + + DEBUGF 1, "SOCKET_free: success!\n" + + .error: + ret + +;------------------------------------ +; +; SOCKET_fork +; +; Create a child socket +; +; IN: socket nr in ebx +; OUT: child socket nr in eax +; +;----------------------------------- +align 4 +SOCKET_fork: + + DEBUGF 1,"SOCKET_fork: %x\n", ebx + +; Exit if backlog queue is full + mov eax, [ebx + SOCKET_QUEUE_LOCATION + queue.size] + cmp ax, [ebx + SOCKET.backlog] + jae .fail + +; Allocate new socket + push ebx + call SOCKET_alloc + pop ebx + jz .fail + + push eax + mov esi, esp + add_to_queue (ebx + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .fail2 + pop eax + +; Copy structure from current socket to new +; We start at PID to preserve the socket num, and the 2 pointers at beginning of socket + lea esi, [ebx + SOCKET.PID] + lea edi, [eax + SOCKET.PID] + mov ecx, (SOCKET_QUEUE_LOCATION - SOCKET.PID + 3)/4 + rep movsd + + and [eax + SOCKET.options], not SO_ACCEPTCON + + ret + + .fail2: + add esp, 4+4+4 + .fail: + DEBUGF 1,"SOCKET_fork: failed\n" + xor eax, eax + ret + + +;--------------------------------------------------- +; +; SOCKET_num_to_ptr +; +; Get socket structure address by its number +; +; IN: ecx = socket number +; OUT: eax = 0 on error, socket ptr otherwise +; ZF = set on error +; +;--------------------------------------------------- +align 4 +SOCKET_num_to_ptr: + + DEBUGF 1,"SOCKET_num_to_ptr: num=%u ", ecx + + mov eax, net_sockets + + .next_socket: + mov eax, [eax + SOCKET.NextPtr] + or eax, eax + jz .error + cmp [eax + SOCKET.Number], ecx + jne .next_socket + + test eax, eax + + DEBUGF 1,"ptr=%x\n", eax + ret + + .error: + DEBUGF 1,"not found\n", eax + ret + + +;--------------------------------------------------- +; +; SOCKET_ptr_to_num +; +; Get socket number by its address +; +; IN: eax = socket ptr +; OUT: eax = 0 on error, socket num otherwise +; ZF = set on error +; +;--------------------------------------------------- +align 4 +SOCKET_ptr_to_num: + + DEBUGF 1,"SOCKET_ptr_to_num: ptr=%x ", eax + + call SOCKET_check + jz .error + + mov eax, [eax + SOCKET.Number] + + DEBUGF 1,"num=%u\n", eax + ret + + .error: + DEBUGF 1,"not found\n", eax + ret + + +;--------------------------------------------------- +; +; SOCKET_check +; +; checks if the given value is really a socket ptr +; +; IN: eax = socket ptr +; OUT: eax = 0 on error, unchanged otherwise +; ZF = set on error +; +;--------------------------------------------------- +align 4 +SOCKET_check: + + DEBUGF 1,"SOCKET_check: %x\n", eax + + push ebx + mov ebx, net_sockets + + .next_socket: + mov ebx, [ebx + SOCKET.NextPtr] + or ebx, ebx + jz .done + cmp ebx, eax + jnz .next_socket + + .done: + mov eax, ebx + test eax, eax + pop ebx + + ret + + + +;--------------------------------------------------- +; +; SOCKET_check_owner +; +; checks if the caller application owns the socket +; +; IN: eax = socket ptr +; OUT: ZF = true/false +; +;--------------------------------------------------- +align 4 +SOCKET_check_owner: + + DEBUGF 1,"SOCKET_check_owner: %x\n", eax + + push ebx + mov ebx, [TASK_BASE] + mov ebx, [ebx + TASKDATA.pid] + cmp [eax + SOCKET.PID], ebx + pop ebx + + ret + + + + +;------------------------------------------------------ +; +; SOCKET_process_end +; +; Kernel calls this function when a certain process ends +; This function will check if the process had any open sockets +; And update them accordingly +; +; IN: edx = pid +; OUT: / +; +;------------------------------------------------------ +align 4 +SOCKET_process_end: + + DEBUGF 1, "SOCKET_process_end: %x\n", edx + + push ebx + mov ebx, net_sockets + + .next_socket: + mov ebx, [ebx + SOCKET.NextPtr] + .next_socket_test: + test ebx, ebx + jz .done + + cmp [ebx + SOCKET.PID], edx + jne .next_socket + + DEBUGF 1, "SOCKET_process_end: killing socket %x\n", ebx + + mov [ebx + SOCKET.PID], 0 + mov eax, ebx + mov ebx, [ebx + SOCKET.NextPtr] + pusha + call SOCKET_close.socket + popa + jmp .next_socket_test + + .done: + pop ebx + + ret + + + + +;----------------------------------------------------------------- +; +; SOCKET_is_connecting +; +; IN: eax = socket ptr +; OUT: / +; +;----------------------------------------------------------------- + +align 4 +SOCKET_is_connecting: + + DEBUGF 1,"SOCKET_is_connecting: %x\n", eax + + and [eax + SOCKET.options], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING) + or [eax + SOCKET.options], SS_ISCONNECTING + + jmp SOCKET_notify + + + +;----------------------------------------------------------------- +; +; SOCKET_is_connected +; +; IN: eax = socket ptr +; OUT: / +; +;----------------------------------------------------------------- + +align 4 +SOCKET_is_connected: + + DEBUGF 1,"SOCKET_is_connected: %x\n", eax + + and [eax + SOCKET.options], not (SS_ISCONNECTING + SS_ISDISCONNECTING + SS_ISCONFIRMING) + or [eax + SOCKET.options], SS_ISCONNECTED + + jmp SOCKET_notify + + + + +;----------------------------------------------------------------- +; +; SOCKET_is_disconnecting +; +; IN: eax = socket ptr +; OUT: / +; +;----------------------------------------------------------------- + +align 4 +SOCKET_is_disconnecting: + + DEBUGF 1,"SOCKET_is_disconnecting: %x\n", eax + + and [eax + SOCKET.options], not (SS_ISCONNECTING) + or [eax + SOCKET.options], SS_ISDISCONNECTING + SS_CANTRCVMORE + SS_CANTSENDMORE + + jmp SOCKET_notify + + + +;----------------------------------------------------------------- +; +; SOCKET_is_disconnected +; +; IN: eax = socket ptr +; OUT: / +; +;----------------------------------------------------------------- + +align 4 +SOCKET_is_disconnected: + + DEBUGF 1,"SOCKET_is_disconnected: %x\n", eax + + and [eax + SOCKET.options], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING) + or [eax + SOCKET.options], SS_CANTRCVMORE + SS_CANTSENDMORE + + cmp [eax + SOCKET.Protocol], IP_PROTO_TCP + je .tcp + + cmp [eax + SOCKET.Protocol], IP_PROTO_UDP + je .udp + + jmp SOCKET_notify + + .tcp: + .udp: + mov [eax + UDP_SOCKET.LocalPort], 0 ; UDP and TCP structs store localport at the same offset + mov [eax + UDP_SOCKET.RemotePort], 0 + + jmp SOCKET_notify + + +;----------------------------------------------------------------- +; +; SOCKET_cant_recv_more +; +; IN: eax = socket ptr +; OUT: / +; +;----------------------------------------------------------------- + +align 4 +SOCKET_cant_recv_more: + + DEBUGF 1,"SOCKET_cant_recv_more: %x\n", eax + + or [eax + SOCKET.options], SS_CANTRCVMORE + + ret + + + +;----------------------------------------------------------------- +; +; SOCKET_cant_send_more +; +; IN: eax = socket ptr +; OUT: / +; +;----------------------------------------------------------------- + +align 4 +SOCKET_cant_send_more: + + DEBUGF 1,"SOCKET_cant_send_more: %x\n", eax + + or [eax + SOCKET.options], SS_CANTSENDMORE + + ret \ No newline at end of file diff --git a/kernel/trunk/network/stack.inc b/kernel/trunk/network/stack.inc index 779f9ffa94..a97f273f8e 100644 --- a/kernel/trunk/network/stack.inc +++ b/kernel/trunk/network/stack.inc @@ -1,918 +1,789 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; STACK.INC ;; -;; ;; -;; TCP/IP stack for Menuet OS ;; -;; ;; -;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;; Version 0.7 ;; -;; Added a timer per socket to allow delays when rx window ;; -;; gets below 1KB ;; -;; ;; -;;10.01.2007 Bugfix for checksum function from Paolo Franchetti ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; STACK.INC ;; +;; ;; +;; TCP/IP stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; Some parts of code are based on the work of: ;; +;; Mike Hibbett (menuetos network stack) ;; +;; Eugen Brasoveanu (solar os network stack and drivers) ;; +;; mike.dld (kolibrios socket code) ;; +;; ;; +;; TCP part is based on 4.4BSD ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -$Revision$ - - -;******************************************************************* -; Interface -; The interfaces defined in ETHERNET.INC plus: -; stack_init -; stack_handler -; app_stack_handler -; app_socket_handler -; checksum -; -;******************************************************************* +$Revision: 3523 $ uglobal -StackCounters: - dumped_rx_count dd 0 - arp_tx_count: - dd 0 - arp_rx_count: - dd 0 - ip_rx_count: - dd 0 - ip_tx_count: - dd 0 + net_10ms dd ? + net_tmr_count dw ? endg -; socket buffers -SOCKETBUFFSIZE equ 4096 ; state + config + buffer. -SOCKETHEADERSIZE equ SOCKET.rxData ; thus 4096 - SOCKETHEADERSIZE bytes data +MAX_NET_DEVICES = 16 +ARP_BLOCK = 1 ; true or false -;NUM_SOCKETS equ 16 ; Number of open sockets supported. Was 20 +MIN_EPHEMERAL_PORT = 49152 +MIN_EPHEMERAL_PORT_N = 0x00C0 ; same in Network byte order (FIXME) +MAX_EPHEMERAL_PORT = 61000 +MAX_EPHEMERAL_PORT_N = 0x48EE ; same in Network byte order (FIXME) -; IPBUFF status values -BUFF_EMPTY equ 0 -BUFF_RX_FULL equ 1 -BUFF_ALLOCATED equ 2 -BUFF_TX_FULL equ 3 +; Ethernet protocol numbers +ETHER_ARP = 0x0608 +ETHER_IPv4 = 0x0008 +ETHER_IPv6 = 0xDD86 +ETHER_PPP_DISCOVERY = 0x6388 +ETHER_PPP_SESSION = 0x6488 -NUM_IPBUFFERS equ 20 ; buffers allocated for TX/RX +; PPP protocol numbers +PPP_IPv4 = 0x2100 +PPP_IPV6 = 0x5780 -NUMQUEUES equ 4 +;Protocol family +AF_UNSPEC = 0 +AF_LOCAL = 1 +AF_INET4 = 2 +AF_INET6 = 10 +AF_PPP = 777 -EMPTY_QUEUE equ 0 -IPIN_QUEUE equ 1 -IPOUT_QUEUE equ 2 -NET1OUT_QUEUE equ 3 +; Internet protocol numbers +IP_PROTO_IP = 0 +IP_PROTO_ICMP = 1 +IP_PROTO_TCP = 6 +IP_PROTO_UDP = 17 -NO_BUFFER equ 0xFFFF -IPBUFFSIZE equ 1500 ; MTU of an ethernet packet -NUMQUEUEENTRIES equ NUM_IPBUFFERS -NUMRESENDENTRIES equ 18 ; Buffers for TCP resend packets +; PPP protocol number +PPP_PROTO_ETHERNET = 666 -; These are the 0x40 function codes for application access to the stack -STACK_DRIVER_STATUS equ 52 -SOCKET_INTERFACE equ 53 +; Socket types +SOCK_STREAM = 1 +SOCK_DGRAM = 2 +SOCK_RAW = 3 + +; Socket options +SO_ACCEPTCON = 1 shl 0 +SO_BROADCAST = 1 shl 1 +SO_DEBUG = 1 shl 2 +SO_DONTROUTE = 1 shl 3 +SO_KEEPALIVE = 1 shl 4 +SO_OOBINLINE = 1 shl 5 +SO_REUSEADDR = 1 shl 6 +SO_REUSEPORT = 1 shl 7 +SO_USELOOPBACK = 1 shl 8 +SO_BINDTODEVICE = 1 shl 9 + +SO_BLOCK = 1 shl 10 ; TO BE REMOVED +SO_NONBLOCK = 1 shl 31 + +; Socket flags for user calls +MSG_PEEK = 0x02 +MSG_DONTWAIT = 0x40 + +; Socket level +SOL_SOCKET = 0 -; 128KB allocated for the stack and network driver buffers and other -; data requirements -;stack_data_start equ 0x700000 -;eth_data_start equ 0x700000 -;stack_data equ 0x704000 -;stack_data_end equ 0x71ffff +; Socket States +SS_NOFDREF = 0x0001 ; no file table ref any more +SS_ISCONNECTED = 0x0002 ; socket connected to a peer +SS_ISCONNECTING = 0x0004 ; in process of connecting to peer +SS_ISDISCONNECTING = 0x0008 ; in process of disconnecting +SS_CANTSENDMORE = 0x0010 ; can't send more data to peer +SS_CANTRCVMORE = 0x0020 ; can't receive more data from peer +SS_RCVATMARK = 0x0040 ; at mark on input +SS_ISABORTING = 0x0080 ; aborting fd references - close() +SS_RESTARTSYS = 0x0100 ; restart blocked system calls +SS_ISDISCONNECTED = 0x0800 ; socket disconnected from peer -; 32 bit word -stack_config equ stack_data +SS_ASYNC = 0x0100 ; async i/o notify +SS_ISCONFIRMING = 0x0200 ; deciding to accept connection req +SS_MORETOCOME = 0x0400 -; 32 bit word - IP Address in network format -stack_ip equ stack_data + 4 - -; 1 byte. 0 == inactive, 1 = active -ethernet_active equ stack_data + 9 +SS_BLOCKED = 0x8000 -; TODO :: empty memory area +SOCKET_MAXDATA = 4096*32 ; must be 4096*(power of 2) where 'power of 2' is at least 8 -; Address of selected socket -;sktAddr equ stack_data + 32 -; Parameter to checksum routine - data ptr -checkAdd1 equ stack_data + 36 -; Parameter to checksum routine - 2nd data ptr -checkAdd2 equ stack_data + 40 -; Parameter to checksum routine - data size -checkSize1 equ stack_data + 44 -; Parameter to checksum routine - 2nd data size -checkSize2 equ stack_data + 46 -; result of checksum routine -checkResult equ stack_data + 48 +; Network driver types +NET_TYPE_LOOPBACK = 0 +NET_TYPE_ETH = 1 +NET_TYPE_SLIP = 2 -; holds the TCP/UDP pseudo header. SA|DA|0|prot|UDP len| -pseudoHeader equ stack_data + 50 +MAX_backlog = 20 ; maximum backlog for stream sockets -; receive and transmit IP buffer allocation -;sockets equ stack_data + 62 -Next_free2 equ stack_data + 62;Next_free2 equ sockets + (SOCKETBUFFSIZE * NUM_SOCKETS) -; 1560 byte buffer for rx / tx ethernet packets -Ether_buffer equ Next_free2 -Next_free3 equ Ether_buffer + 1518 -last_1sTick equ Next_free3 -IPbuffs equ Next_free3 + 1 -queues equ IPbuffs + ( NUM_IPBUFFERS * IPBUFFSIZE ) -queueList equ queues + (2 * NUMQUEUES) -last_1hsTick equ queueList + ( 2 * NUMQUEUEENTRIES ) +; Error Codes +ENOBUFS = 55 +ECONNREFUSED = 61 +ECONNRESET = 52 +ETIMEDOUT = 60 +ECONNABORTED = 53 -;resendQ equ queueList + ( 2 * NUMQUEUEENTRIES ) -;resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP -; equ resendBuffer + ( IPBUFFSIZE * NUMRESENDENTRIES ) +; Api protocol numbers +API_ETH = 0 +API_IPv4 = 1 +API_ICMP = 2 +API_UDP = 3 +API_TCP = 4 +API_ARP = 5 +API_PPPOE = 6 +API_IPv6 = 7 + +HWACC_TCP_IPv4 = 1 shl 0 + +struct NET_DEVICE + + type dd ? ; Type field + mtu dd ? ; Maximal Transmission Unit + name dd ? ; Ptr to 0 terminated string + + unload dd ? ; Ptrs to driver functions + reset dd ? ; + transmit dd ? ; + + bytes_tx dq ? ; Statistics, updated by the driver + bytes_rx dq ? ; + packets_tx dd ? ; + packets_rx dd ? ; + + state dd ? ; link state (0 = no link) + hwacc dd ? ; bitmask stating enabled HW accelerations (offload engines) + +ends +; Exactly as it says.. +macro pseudo_random reg { + add reg, [esp] + rol reg, 5 + xor reg, [timer_ticks] +; add reg, [CPU_FREQ] + imul reg, 214013 + xor reg, 0xdeadbeef + rol reg, 9 +} -;resendQ equ 0x770000 -;resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP ; XTODO: validate size -resendBuffer equ resendQ + ( 8 * NUMRESENDENTRIES ) ; for TCP +; Network to Hardware byte order (dword) +macro ntohd reg { + rol word reg, 8 + rol dword reg, 16 + rol word reg , 8 -uglobal -net_sockets rd 2 -endg +} + +; Network to Hardware byte order (word) +macro ntohw reg { + + rol word reg, 8 -; simple macro for memory set operation -macro _memset_dw adr,value,amount -{ - mov edi, adr - mov ecx, amount - if value = 0 - xor eax, eax - else - mov eax, value - end if - cld - rep stosd } -; Below, the main network layer source code is included -; include "queue.inc" -include "eth_drv/ethernet.inc" -include "ip.inc" + +include "loopback.inc" +include "ethernet.inc" + +include "PPPoE.inc" + +include "ARP.inc" +include "IPv4.inc" +include "IPv6.inc" + +include "icmp.inc" +include "udp.inc" +include "tcp.inc" + include "socket.inc" -;*************************************************************************** -; Function -; stack_init -; -; Description -; Clear all allocated memory to zero. This ensures that -; on startup, the stack is inactive, and consumes no resources -; This is a kernel function, called prior to the OS main loop -; in set_variables -; -;*************************************************************************** + +align 4 +uglobal + + NET_RUNNING dd ? + NET_DEFAULT dd ? + NET_DRV_LIST rd MAX_NET_DEVICES + +endg + + +;----------------------------------------------------------------- +; +; stack_init +; +; This function calls all network init procedures +; +; IN: / +; OUT: / +; +;----------------------------------------------------------------- +align 4 stack_init: - ; Init two address spaces with default values - _memset_dw stack_data_start, 0, 0x20000/4 - _memset_dw resendQ, 0, NUMRESENDENTRIES * 2 - mov [net_sockets], 0 - mov [net_sockets + 4], 0 +; Init the network drivers list + xor eax, eax + mov edi, NET_RUNNING + mov ecx, (MAX_NET_DEVICES + 2) + rep stosd - ; Queries initialization - call queueInit + PPPoE_init + + IPv4_init +; IPv6_init + ICMP_init + + ARP_init + UDP_init + TCP_init + + SOCKET_init + + mov [net_tmr_count], 0 - ; The following block sets up the 1s timer - mov al, 0x0 - out 0x70, al - in al, 0x71 - mov [last_1sTick], al ret + + ; Wakeup every tick. proc stack_handler_has_work? - mov eax, [timer_ticks] - cmp eax, [last_1hsTick] + + mov eax, [timer_ticks] + cmp eax, [net_10ms] + ret endp -;*************************************************************************** -; Function -; stack_handler +;----------------------------------------------------------------- ; -; Description -; The kernel loop routine for the stack -; This is a kernel function, called in the main loop +; stack_handler ; -;*************************************************************************** +; This function is called in kernel loop +; +; IN: / +; OUT: / +; +;----------------------------------------------------------------- align 4 stack_handler: - call ethernet_driver - call ip_rx + ; Test for 10ms tick + mov eax, [timer_ticks] + cmp eax, [net_10ms] + je .exit + mov [net_10ms], eax + cmp [NET_RUNNING], 0 + je .exit - ; Test for 10ms tick, call tcp timer - mov eax, [timer_ticks];[0xfdf0] - cmp eax, [last_1hsTick] - je sh_001 + test [net_10ms], 0x0f ; 160ms + jnz .exit - mov [last_1hsTick], eax - call tcp_tx_handler + TCP_timer_160ms -sh_001: + test [net_10ms], 0x3f ; 640ms + jnz .exit - ; Test for 1 second event, call 1s timer functions - mov al, 0x0;second - out 0x70, al - in al, 0x71 - cmp al, [last_1sTick] - je sh_exit + TCP_timer_640ms + ARP_decrease_entry_ttls + IPv4_decrease_fragment_ttls - mov [last_1sTick], al - - stdcall arp_table_manager, ARP_TABLE_TIMER, 0, 0 - call tcp_tcb_handler - -sh_exit: + .exit: ret -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Checksum [by Johnny_B] -;; IN: -;; buf_ptr=POINTER to buffer -;; buf_size=SIZE of buffer -;; OUT: -;; AX=16-bit checksum -;; Saves all used registers -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -proc checksum_jb stdcall uses ebx esi ecx,\ - buf_ptr:DWORD, buf_size:DWORD - xor eax, eax - xor ebx, ebx;accumulator - mov esi, dword[buf_ptr] - mov ecx, dword[buf_size] - shr ecx, 1; ecx=ecx/2 - jnc @f ; if CF==0 then size is even number - mov bh, byte[esi + ecx*2] - @@: - cld +align 4 +NET_link_changed: + + DEBUGF 1,"NET_link_changed device=0x%x status=0x%x\n", ebx, [ebx + NET_DEVICE.state] + +align 4 +NET_send_event: + + DEBUGF 1,"NET_send_event\n" + +; Send event to all applications + push edi ecx + mov edi, SLOT_BASE + mov ecx, [TASK_COUNT] .loop: - lodsw ;eax=word[esi],esi=esi+2 - xchg ah, al;cause must be a net byte-order - add ebx, eax + add edi, 256 + or [edi + APPDATA.event_mask], EVENT_NETWORK2 loop .loop + pop ecx edi + + ret + + + +;----------------------------------------------------------------- +; +; NET_add_device: +; +; This function is called by the network drivers, +; to register each running NIC to the kernel +; +; IN: Pointer to device structure in ebx +; OUT: Device num in eax, -1 on error +; +;----------------------------------------------------------------- +align 4 +NET_add_device: + + DEBUGF 1,"NET_Add_Device: %x\n", ebx ;;; TODO: use mutex to lock net device list + + cmp [NET_RUNNING], MAX_NET_DEVICES + jae .error + +;---------------------------------- +; Check if device is already listed + mov eax, ebx + mov ecx, MAX_NET_DEVICES ; We need to check whole list because a device may be removed without re-organizing list + mov edi, NET_DRV_LIST + + repne scasd ; See if device is already in the list + jz .error + +;---------------------------- +; Find empty slot in the list + xor eax, eax + mov ecx, MAX_NET_DEVICES + mov edi, NET_DRV_LIST + + repne scasd + jnz .error + + sub edi, 4 + +;----------------------------- +; Add device to the found slot + mov [edi], ebx ; add device to list + + mov eax, edi ; Calculate device number in eax + sub eax, NET_DRV_LIST + shr eax, 2 + + inc [NET_RUNNING] ; Indicate that one more network device is up and running + + cmp eax, 1 ; If it's the first network device, try to set it as default + jne @f + push eax + call NET_set_default + pop eax + @@: + + call NET_send_event + + DEBUGF 1,"Device number: %u\n", eax + ret + + .error: + or eax, -1 + DEBUGF 2,"Adding network device failed\n" + ret + + + +;----------------------------------------------------------------- +; +; NET_set_default +; +; API to set the default interface +; +; IN: Device num in eax +; OUT: Device num in eax, -1 on error +; +;----------------------------------------------------------------- +align 4 +NET_set_default: + + DEBUGF 1,"NET_set_default: device=%x\n", eax + + cmp eax, MAX_NET_DEVICES + jae .error + + cmp [NET_DRV_LIST+eax*4], 0 + je .error + + mov [NET_DEFAULT], eax + + DEBUGF 1,"NET_set_default: succes\n" + ret + + .error: + or eax, -1 + DEBUGF 1,"NET_set_default: failed\n" + ret + + +;----------------------------------------------------------------- +; +; NET_Remove_Device: +; +; This function is called by etwork drivers, +; to unregister network devices from the kernel +; +; IN: Pointer to device structure in ebx +; OUT: eax: -1 on error +; +;----------------------------------------------------------------- +align 4 +NET_remove_device: + + cmp [NET_RUNNING], 0 + je .error + + cmp [NET_DRV_LIST], ebx + jne @f + mov [NET_DRV_LIST], 0 + cmp [NET_RUNNING], 1 + je @f + ; there are still active devices, find one and make it default + xor eax, eax + mov ecx, MAX_NET_DEVICES + mov edi, NET_DRV_LIST + repe scasd + je @f + shr edi, 2 + dec edi + mov [NET_DEFAULT], edi + @@: + +;---------------------------- +; Find the driver in the list mov eax, ebx - shr eax, 16 - add ax, bx - not ax + mov ecx, MAX_NET_DEVICES + mov edi, NET_DRV_LIST+4 - ret -endp + repne scasd + jnz .error -;*************************************************************************** -; Function -; checksum -; -; Description -; checkAdd1,checkAdd2, checkSize1, checkSize2, checkResult -; Dont break anything; Most registers are used by the caller -; This code is derived from the 'C' source, cksum.c, in the book -; Internetworking with TCP/IP Volume II by D.E. Comer -; -;*************************************************************************** +;------------------------ +; Remove it from the list + xor eax, eax + mov dword [edi-4], eax -checksum: - pusha - mov eax, [checkAdd1] - xor edx, edx ; edx is the accumulative checksum - xor ebx, ebx - mov cx, [checkSize1] - shr cx, 1 - jz cs1_1 + call NET_send_event -cs1: - mov bh, [eax] - mov bl, [eax + 1] - - add eax, 2 - add edx, ebx - - loopw cs1 - -cs1_1: - and word [checkSize1], 0x01 - jz cs_test2 - - mov bh, [eax] - xor bl, bl - - add edx, ebx - -cs_test2: - mov cx, [checkSize2] - cmp cx, 0 - jz cs_exit ; Finished if no 2nd buffer - - mov eax, [checkAdd2] - - shr cx, 1 - jz cs2_1 - -cs2: - mov bh, [eax] - mov bl, [eax + 1] - - add eax, 2 - add edx, ebx - - loopw cs2 - -cs2_1: - and word [checkSize2], 0x01 - jz cs_exit - - mov bh, [eax] - xor bl, bl - - add edx, ebx - -cs_exit: - mov ebx, edx - - shr ebx, 16 - and edx, 0xffff - add edx, ebx - mov eax, edx - shr eax, 16 - add edx, eax - not dx - - mov [checkResult], dx - popa + dec [NET_RUNNING] ret - - - -;*************************************************************************** -; Function -; app_stack_handler -; -; Description -; This is an application service, called by int 0x40, function 52 -; It provides application access to the network interface layer -; -;*************************************************************************** -iglobal -align 4 -f52call: - dd app_stack_handler.00 - dd app_stack_handler.01 - dd app_stack_handler.02 - dd app_stack_handler.03 - dd app_stack_handler.fail ;04 - dd app_stack_handler.fail ;05 - dd stack_insert_packet ;app_stack_handler.06 - dd app_stack_handler.fail ;07 - dd stack_get_packet ;app_stack_handler.08 - dd app_stack_handler.09 - dd app_stack_handler.10 - dd app_stack_handler.11 - dd app_stack_handler.12 - dd app_stack_handler.13 - dd app_stack_handler.14 - dd app_stack_handler.15 -endg -app_stack_handler: -;in ebx,ecx -;out eax - cmp ebx, 15 - ja .fail ;if more than 15 then exit - - jmp dword [f52call+ebx*4] - - -.00: -; Read the configuration word - mov eax, [stack_config] - ret - -.01: -; read the IP address - mov eax, [stack_ip] - ret - -.02: -; write the configuration word - mov [stack_config], ecx - -; -; If ethernet now enabled, probe for the card, reset it and empty -; the packet buffer -; If all successfull, enable the card. -; If ethernet now disabled, set it as disabled. Should really -; empty the tcpip data area too. - -; ethernet interface is '3' in ls 7 bits - and cl, 0x7f - cmp cl, 3 - je ash_eth_enable -; Ethernet isn't enabled, so make sure that the card is disabled - mov [ethernet_active], byte 0 - ret - -.03: -; write the IP Address - mov [stack_ip], ecx - ret -;old functions was deleted -;.06: -; Insert an IP packet into the stacks received packet queue -; call stack_insert_packet -; ret - -; Test for any packets queued for transmission over the network - -;.08: -; call stack_get_packet -; Extract a packet queued for transmission by the network -; ret - -.09: -; read the gateway IP address - mov eax, [gateway_ip] - ret - -.10: -; read the subnet mask - mov eax, [subnet_mask] - ret -.11: -; write the gateway IP Address - mov [gateway_ip], ecx - ret - -.12: -; write the subnet mask - mov [subnet_mask], ecx - ret - -.13: -; read the dns - mov eax, [dns_ip] - ret - -.14: -; write the dns IP Address - mov [dns_ip], ecx - ret - -.15: -; -; in ecx we need 4 to read the last 2 bytes -; or we need 0 to read the first 4 bytes - cmp ecx, 4 - ja .param_error - -; read MAC, returned (in mirrored byte order) in eax - mov eax, [node_addr + ecx] - ret - -.param_error: - or eax, -1 ; params not accepted - ret - -.16: -; 0 -> arp_probe -; 1 -> arp_announce -; 2 -> arp_responce (not supported yet) - test ecx, ecx - je a_probe - - dec ebx - jz a_ann ; arp announce -.fail: + .error: or eax, -1 ret -; cmp ebx,2 -; jne a_resp ; arp response -; arp probe, sender IP must be set to 0.0.0.0, target IP is set to address being probed -; ecx: pointer to target MAC, MAC should set to 0 by application -; edx: target IP -a_probe: - push dword [stack_ip] - mov edx, [stack_ip] - and [stack_ip], dword 0 - mov esi, ecx ; pointer to target MAC address - call arp_request - - pop dword [stack_ip] - ret - -; arp announce, sender IP must be set to target IP -; ecx: pointer to target MAC -a_ann: - mov edx, [stack_ip] - mov esi, ecx ; pointer to target MAC address - call arp_request - ret - -.17: -; -; modified by [smb] - -; -; ARPTable manager interface - ;see "proc arp_table_manager" for more details - stdcall arp_table_manager, ecx, edx, esi;Opcode,Index,Extra - ret -; - -;;;;;;;;;;;;;;;;;;;;;;;;;;;; -ash_eth_enable: -; Probe for the card. This will reset it and enable the interface -; if found - call eth_probe - test eax, eax - jz ash_eth_done ; Abort if no hardware found - - mov [ethernet_active], byte 1 -ash_eth_done: - ret -;*************************************************************************** -; Function -; app_socket_handler +;----------------------------------------------------------------- ; -; Description -; This is an application service, called by int 0x40, function 53 -; It provides application access to stack socket services -; such as opening sockets +; NET_ptr_to_num ; -;*************************************************************************** -iglobal +; IN: ebx = ptr to device struct +; OUT: edi = -1 on error, device number otherwise +; +;----------------------------------------------------------------- align 4 -f53call: - dd socket_open ;00 - dd socket_close ;01 - dd socket_poll ;02 - dd socket_read ;03 - dd socket_write ;04 - dd socket_open_tcp ;05 - dd socket_status ;06 - dd socket_write_tcp ;07 - dd socket_close_tcp ;08 - dd is_localport_unused ;09 - dd app_socket_handler.10 - dd socket_read_packet ;11 -endg - -app_socket_handler: -;in ebx,ecx,edx,wsi -;out eax - cmp eax, 255 - je stack_internal_status - - cmp eax, 11 - ja .fail ;if more than 15 then exit - - jmp dword [f53call+eax*4] - -.10: - mov eax, dword[drvr_cable] - test eax, eax - jnz @f ; if function is not implented, return -1 - or al, -1 - ret -@@: - jmp dword[drvr_cable] - -.fail: - or eax, -1 - ret -uglobal - ARPTmp: - times 14 db 0 -endg - -;*************************************************************************** -; Function -; stack_internal_status -; -; Description -; Returns information about the internal status of the stack -; This is only useful for debugging -; It works with the ethernet driver -; sub function in ebx -; return requested data in eax -; -;*************************************************************************** -; This sub function allows access to debugging information on the stack -; ecx holds the request: -; 100 : return length of empty queue -; 101 : return length of IPOUT QUEUE -; 102 : return length of IPIN QUEUE -; 103 : return length of NET1OUT QUEUE -; 200 : return # of ARP entries -; 201 : return size of ARP table ( max # entries ) -; 202 : select ARP table entry # -; 203 : return IP of selected table entry -; 204 : return High 4 bytes of MAC address of selected table entry -; 205 : return low 2 bytes of MAC address of selected table entry -; 206 : return status word of selected table entry -; 207 : return Time to live of selected table entry - - -; 2 : return number of IP packets received -; 3 : return number of packets transmitted -; 4 : return number of received packets dumped -; 5 : return number of arp packets received -; 6 : return status of packet driver -; ( 0 == not active, FFFFFFFF = successful ) - - -stack_internal_status: - cmp ebx, 100 - jnz notsis100 - - ; 100 : return length of EMPTY QUEUE - mov ebx, EMPTY_QUEUE - call queueSize - ret - -notsis100: - cmp ebx, 101 - jnz notsis101 - - ; 101 : return length of IPOUT QUEUE - mov ebx, IPOUT_QUEUE - call queueSize - ret - -notsis101: - cmp ebx, 102 - jnz notsis102 - - ; 102 : return length of IPIN QUEUE - mov ebx, IPIN_QUEUE - call queueSize - ret - -notsis102: - cmp ebx, 103 - jnz notsis103 - - ; 103 : return length of NET1OUT QUEUE - mov ebx, NET1OUT_QUEUE - call queueSize - ret - -notsis103: - cmp ebx, 200 - jnz notsis200 - - ; 200 : return num entries in arp table - movzx eax, byte [NumARP] - ret - -notsis200: - cmp ebx, 201 - jnz notsis201 - - ; 201 : return arp table size - mov eax, 20; ARP_TABLE_SIZE - ret - -notsis201: - cmp ebx, 202 - jnz notsis202 - - ; 202 - read the requested table entry - ; into a temporary buffer - ; ecx holds the entry number - - mov eax, ecx - mov ecx, 14; ARP_ENTRY_SIZE - mul ecx - - mov ecx, [eax + ARPTable] - mov [ARPTmp], ecx - mov ecx, [eax + ARPTable+4] - mov [ARPTmp+4], ecx - mov ecx, [eax + ARPTable+8] - mov [ARPTmp+8], ecx - mov cx, [eax + ARPTable+12] - mov [ARPTmp+12], cx - ret - -notsis202: - cmp ebx, 203 - jnz notsis203 - - ; 203 - return IP address - mov eax, [ARPTmp] - ret - -notsis203: - cmp ebx, 204 - jnz notsis204 - - ; 204 - return MAC high dword - mov eax, [ARPTmp+4] - ret - -notsis204: - cmp ebx, 205 - jnz notsis205 - - ; 205 - return MAC ls word - movzx eax, word [ARPTmp+8] - ret - -notsis205: - cmp ebx, 206 - jnz notsis206 - - ; 206 - return status word - movzx eax, word [ARPTmp+10] - ret - -notsis206: - cmp ebx, 207 - jnz notsis207 - - ; 207 - return ttl word - movzx eax, word [ARPTmp+12] - ret - -notsis207: - cmp ebx, 2 - jnz notsis2 - - ; 2 : return number of IP packets received - mov eax, [ip_rx_count] - ret - -notsis2: - cmp ebx, 3 - jnz notsis3 - - ; 3 : return number of packets transmitted - mov eax, [ip_tx_count] - ret - -notsis3: - cmp ebx, 4 - jnz notsis4 - - ; 4 : return number of received packets dumped - mov eax, [dumped_rx_count] - ret - -notsis4: - cmp ebx, 5 - jnz notsis5 - - ; 5 : return number of arp packets received - mov eax, [arp_rx_count] - ret - -notsis5: - cmp ebx, 6 - jnz notsis6 - - ; 6 : return status of packet driver - ; ( 0 == not active, FFFFFFFF = successful ) - mov eax, [eth_status] - ret - -notsis6: - xor eax, eax - ret - - - -;*************************************************************************** -; Function -; stack_get_packet -; -; Description -; extracts an IP packet from the NET1 output queue -; and sends the data to the calling process -; pointer to data in edx -; returns number of bytes read in eax -; -;*************************************************************************** -stack_get_packet: - ; Look for a buffer to tx - mov eax, NET1OUT_QUEUE - call dequeue - cmp ax, NO_BUFFER - je sgp_non_exit ; Exit if no buffer available - - push eax ; Save buffer number for freeing at end - - push edx - ; convert buffer pointer eax to the absolute address - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs - pop edx - - push eax ; save address of IP data - ; Get the address of the callers data - mov edi, [TASK_BASE] - add edi, TASKDATA.mem_start - add edx, [edi] - mov edi, edx - pop eax - - mov ecx, 1500 ; should get the actual number of bytes to write - mov esi, eax - cld - rep movsb ; copy the data across - - ; And finally, return the buffer to the free queue - pop eax - call freeBuff - - mov eax, 1500 - ret - -sgp_non_exit: - xor eax, eax - ret - - - -;*************************************************************************** -; Function -; stack_insert_packet -; -; Description -; writes an IP packet into the stacks receive queue -; # of bytes to write in ecx -; pointer to data in edx -; returns 0 in eax ok, -1 == failed -; -;*************************************************************************** -stack_insert_packet: - - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je sip_err_exit - - push eax - - ; save the pointers to the data buffer & size - push edx +NET_ptr_to_num: push ecx - ; convert buffer pointer eax to the absolute address - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs + mov ecx, MAX_NET_DEVICES + mov edi, NET_DRV_LIST - mov edx, eax + .loop: + cmp ebx, [edi] + jz .found + add edi, 4 + dec ecx + jnz .loop - ; So, edx holds the IPbuffer ptr + ; repnz scasd could work too if eax is used instead of ebx! - pop ecx ; count of bytes to send - mov ebx, ecx ; need the length later - pop eax ; get callers ptr to data to send + or edi, -1 - ; Get the address of the callers data - mov edi, [TASK_BASE] - add edi, TASKDATA.mem_start - add eax, [edi] - mov esi, eax - - mov edi, edx - cld - rep movsb ; copy the data across - - pop ebx - - mov eax, IPIN_QUEUE - call queue - - inc dword [ip_rx_count] - - mov eax, 0 + pop ecx ret -sip_err_exit: - mov eax, 0xFFFFFFFF + .found: + sub edi, NET_DRV_LIST + shr edi, 2 + + pop ecx ret +;----------------------------------------------------------------- +; +; checksum_1 +; +; This is the first of two functions needed to calculate a checksum. +; +; IN: edx = start offset for semi-checksum +; esi = pointer to data +; ecx = data size +; OUT: edx = semi-checksum +; +; +; Code was optimized by diamond +; +;----------------------------------------------------------------- +align 4 +checksum_1: + + shr ecx, 1 + pushf + jz .no_2 + + shr ecx, 1 + pushf + jz .no_4 + + shr ecx, 1 + pushf + jz .no_8 + + .loop: + add dl, [esi+1] + adc dh, [esi+0] + + adc dl, [esi+3] + adc dh, [esi+2] + + adc dl, [esi+5] + adc dh, [esi+4] + + adc dl, [esi+7] + adc dh, [esi+6] + + adc edx, 0 + add esi, 8 + + dec ecx + jnz .loop + + adc edx, 0 + + .no_8: + popf + jnc .no_4 + + add dl, [esi+1] + adc dh, [esi+0] + + adc dl, [esi+3] + adc dh, [esi+2] + + adc edx, 0 + add esi, 4 + + .no_4: + popf + jnc .no_2 + + add dl, [esi+1] + adc dh, [esi+0] + + adc edx, 0 + inc esi + inc esi + + .no_2: + popf + jnc .end + + add dh, [esi+0] + adc edx, 0 + .end: + ret + +;----------------------------------------------------------------- +; +; checksum_2 +; +; This function calculates the final ip/tcp/udp checksum for you +; +; IN: edx = semi-checksum +; OUT: dx = checksum (in INET byte order) +; +;----------------------------------------------------------------- +align 4 +checksum_2: + + mov ecx, edx + shr ecx, 16 + and edx, 0xffff + add edx, ecx + + mov ecx, edx + shr ecx, 16 + add dx, cx + test dx, dx ; it seems that ZF is not set when CF is set :( + not dx + jnz .not_zero + dec dx + .not_zero: + xchg dl, dh + + DEBUGF 1,"Checksum: %x\n", dx + + ret + + + +;---------------------------------------------------------------- +; +; System function to work with network devices (75) +; +;---------------------------------------------------------------- +align 4 +sys_network: ; FIXME: make default device easily accessible + + cmp ebx, -1 + jne @f + + mov eax, [NET_RUNNING] + jmp .return + + @@: + cmp bh, MAX_NET_DEVICES ; Check if device number exists + jae .doesnt_exist + + mov esi, ebx + and esi, 0x0000ff00 + shr esi, 6 + + cmp dword [esi + NET_DRV_LIST], 0 ; check if driver is running + je .doesnt_exist + + mov eax, [esi + NET_DRV_LIST] + + and ebx, 0x000000ff + cmp ebx, .number + ja .doesnt_exist + jmp dword [.table + 4*ebx] + + .table: + dd .get_type ; 0 + dd .get_dev_name ; 1 + dd .reset ; 2 + dd .stop ; 3 + dd .get_ptr ; 4 + dd .get_drv_name ; 5 + dd .set_default ; 6 + .number = ($ - .table) / 4 - 1 + + .get_type: ; 0 = Get device type (ethernet/token ring/...) + + mov eax, [eax + NET_DEVICE.type] + jmp .return + + + .get_dev_name: ; 1 = Get device name + + mov esi, [eax + NET_DEVICE.name] + mov edi, ecx + + mov ecx, 64/4 ; max length + rep movsd + + xor eax, eax + jmp .return + + .reset: ; 2 = Reset the device + + call [eax + NET_DEVICE.reset] + jmp .return + + .stop: ; 3 = Stop driver for this device + + call [eax + NET_DEVICE.unload] + jmp .return + + + .get_ptr: ; 4 = Get driver pointer + + jmp .return + + + .get_drv_name: ; 5 = Get driver name + + xor eax, eax + jmp .return + + + .set_default: ; 6 = Set default device + + call NET_set_default + jmp .return + + .doesnt_exist: + mov eax, -1 + + .return: + mov [esp+32], eax + ret + + +;---------------------------------------------------------------- +; +; System function to work with protocols (76) +; +;---------------------------------------------------------------- +align 4 +sys_protocols: + cmp bh, MAX_NET_DEVICES ; Check if device number exists + jae .doesnt_exist + + mov esi, ebx + and esi, 0x0000ff00 + shr esi, 6 ; now we have the device num * 4 in esi + cmp [esi + NET_DRV_LIST], 0 ; check if driver is running + je .doesnt_exist + + push .return ; return address (we will be using jumps instead of calls) + + mov eax, ebx ; set ax to protocol number + shr eax, 16 ; + + cmp ax, API_ETH + je ETH_api + + cmp ax, API_IPv4 + je IPv4_api + + cmp ax, API_ICMP + je ICMP_api + + cmp ax, API_UDP + je UDP_api + + cmp ax, API_TCP + je TCP_api + + cmp ax, API_ARP + je ARP_api + + cmp ax, API_PPPOE + je PPPoE_api + + cmp ax, API_IPv6 + je IPv6_api + + add esp, 4 ; if we reached here, no function was called, so we need to balance stack + + .doesnt_exist: + mov eax, -1 + + .return: + mov [esp+28+4], eax ; return eax value to the program + ret diff --git a/kernel/trunk/network/tcp.inc b/kernel/trunk/network/tcp.inc index cbb66026be..d5f3dd5126 100644 --- a/kernel/trunk/network/tcp.inc +++ b/kernel/trunk/network/tcp.inc @@ -1,1176 +1,224 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; TCP.INC ;; -;; ;; -;; TCP Processes for Menuet OS TCP/IP stack ;; -;; ;; -;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; -;; ;; -;; See file COPYING for details ;; -;; v0.6 : Added reset handling in the established state ;; -;; Added a timer per socket to allow delays when ;; -;; rx window gets below 1KB ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Part of the TCP/IP network stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; Based on the code of 4.4BSD ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -$Revision$ +$Revision: 3406 $ +; Socket states +TCPS_CLOSED = 0 +TCPS_LISTEN = 1 +TCPS_SYN_SENT = 2 +TCPS_SYN_RECEIVED = 3 +TCPS_ESTABLISHED = 4 +TCPS_CLOSE_WAIT = 5 +TCPS_FIN_WAIT_1 = 6 +TCPS_CLOSING = 7 +TCPS_LAST_ACK = 8 +TCPS_FIN_WAIT_2 = 9 +TCPS_TIMED_WAIT = 10 -; TCP TCB states -TCB_LISTEN equ 1 -TCB_SYN_SENT equ 2 -TCB_SYN_RECEIVED equ 3 -TCB_ESTABLISHED equ 4 -TCB_FIN_WAIT_1 equ 5 -TCB_FIN_WAIT_2 equ 6 -TCB_CLOSE_WAIT equ 7 -TCB_CLOSING equ 8 -TCB_LAST_ACK equ 9 -TCB_TIMED_WAIT equ 10 -TCB_CLOSED equ 11 +; Socket Flags +TF_ACKNOW = 1 shl 0 ; ack peer immediately +TF_DELACK = 1 shl 1 ; ack, but try to delay it +TF_NODELAY = 1 shl 2 ; don't delay packets to coalesce +TF_NOOPT = 1 shl 3 ; don't use tcp options +TF_SENTFIN = 1 shl 4 ; have sent FIN +TF_REQ_SCALE = 1 shl 5 ; have/will request window scaling +TF_RCVD_SCALE = 1 shl 6 ; other side has requested scaling +TF_REQ_TSTMP = 1 shl 7 ; have/will request timestamps +TF_RCVD_TSTMP = 1 shl 8 ; a timestamp was received in SYN +TF_SACK_PERMIT = 1 shl 9 ; other side said I could SACK -TH_FIN = 0x01 -TH_SYN = 0x02 -TH_RST = 0x04 -TH_PUSH = 0x08 -TH_ACK = 0x10 -TH_URG = 0x20 +; Segment flags +TH_FIN = 1 shl 0 +TH_SYN = 1 shl 1 +TH_RST = 1 shl 2 +TH_PUSH = 1 shl 3 +TH_ACK = 1 shl 4 +TH_URG = 1 shl 5 -TWOMSL equ 10 ; # of secs to wait before closing socket +; Segment header options +TCP_OPT_EOL = 0 ; End of option list. +TCP_OPT_NOP = 1 ; No-Operation. +TCP_OPT_MAXSEG = 2 ; Maximum Segment Size. +TCP_OPT_WINDOW = 3 ; window scale +TCP_OPT_SACK_PERMIT = 4 ; Selective Acknowledgement +TCP_OPT_SACK = 5 +TCP_OPT_TIMESTAMP = 8 -TCP_RETRIES equ 5 ; Number of times to resend a packet -TCP_TIMEOUT equ 20 ; resend if not replied to in x hs +; Fundamental timer values +TCP_time_MSL = 47 ; max segment lifetime (30s) +TCP_time_re_min = 2 ; min retransmission (1,28s) +TCP_time_re_max = 100 ; max retransmission (64s) +TCP_time_pers_min = 8 ; min persist (5,12s) +TCP_time_pers_max = 94 ; max persist (60,16s) +TCP_time_keep_init = 118 ; connection establishment (75,52s) +TCP_time_keep_idle = 4608 ; idle time before 1st probe (2h) +TCP_time_keep_interval = 118 ; between probes when no response (75,52s) +TCP_time_rtt_default = 5 ; default Round Trip Time (3,2s) +TCP_time_srtt_default = 0 ; +TCP_time_max_idle = 8*TCP_time_keep_interval ; FIXME + +; timer constants +TCP_max_rxtshift = 12 ; max retransmissions waiting for ACK +TCP_max_keepcnt = 8 ; max keepalive probes -;******************************************************************* -; Interface ; -; tcp_tx_handler Handles the TCP transmit queue -; tcp_rx The protocol handler for received data -; buildTCPPacket fills in the packet headers and data -; tcpStateMachine Main state machine for received TCP packets -; tcp_tcb_handler 1s timer, to erase tcb's in TIME_WAIT state -; -;******************************************************************* +TCP_max_winshift = 14 +TCP_max_win = 65535 +TCP_re_xmit_thresh = 3 -; TCP Payload ( Data field in IP datagram ) -; -; 0 1 2 3 -; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;20 | Source Port | Destination Port | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;24 | Sequence Number | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;28 | Acknowledgment Number | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;32 | Data | |U|A|P|R|S|F| | -; | Offset| Reserved |R|C|S|S|Y|I| Window | -; | | |G|K|H|T|N|N| | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;36 | Checksum | Urgent Pointer | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;40 | Options | Padding | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | data +TCP_mss_default = 1480 ; default max segment size +; smoothed round trip time and estimated variance are stored as fixed point numbers, +; shifted by the value below. +; With these scales, srtt has 3 bits to the right of the binary point, and thus an "alpha" +; of .875. rttvar has 2 bits to the right and thus "alpha" of 0.75 +TCP_RTT_SHIFT = 3 +TCP_RTTVAR_SHIFT = 2 -struc TCP_PACKET -{ .SourcePort dw ? ;+00 - .DestinationPort dw ? ;+02 - .SequenceNumber dd ? ;+04 - .AckNumber dd ? ;+08 - .DataOffset db ? ;+12 - DataOffset[0-3 bits] and Reserved[4-7] - .Flags db ? ;+13 - Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN - .Window dw ? ;+14 - .Checksum dw ? ;+16 - .UrgentPointer dw ? ;+18 - .Options rb 3 ;+20 - .Padding db ? ;+23 - .Data db ? ;+24 -} +; bits used by tcp_input and tcp_output +TCP_BIT_NEEDOUTPUT = 1 shl 0 +TCP_BIT_TIMESTAMP = 1 shl 1 +TCP_BIT_DROPSOCKET = 1 shl 2 -virtual at 0 - TCP_PACKET TCP_PACKET -end virtual +TCP_BIT_SENDALOT = 1 shl 0 +TCP_PAWS_IDLE = 24*24*60*60*100 ; 24 days, in 1/100 seconds +TCP_QUEUE_SIZE = 50 -;*************************************************************************** -; Function -; tcp_tcb_handler -; -; Description -; Handles sockets in the timewait state, closing them -; when the TCB timer expires -; -;*************************************************************************** +struct TCP_header -proc tcp_tcb_handler stdcall uses ebx - ; scan through all the sockets, decrementing active timers + SourcePort dw ? + DestinationPort dw ? + SequenceNumber dd ? + AckNumber dd ? + DataOffset db ? ; DataOffset[0-3 bits] and Reserved[4-7] + Flags db ? ; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN + Window dw ? + Checksum dw ? + UrgentPointer dw ? - mov ebx, net_sockets +ends - cmp [ebx + SOCKET.NextPtr], 0 - je .exit - ;DEBUGF 1, "K : sockets:\n" +struct TCP_queue_entry - .next_socket: - mov ebx, [ebx + SOCKET.NextPtr] - or ebx, ebx - jz .exit + ip_ptr dd ? + segment_ptr dd ? + segment_size dd ? + device_ptr dd ? - ;DEBUGF 1, "K : %x-%x: %x-%x-%x-%u\n", [ebx + SOCKET.PID]:2, [ebx + SOCKET.Number]:2, [ebx + SOCKET.LocalPort]:4, [ebx + SOCKET.RemoteIP], [ebx + SOCKET.RemotePort]:4, [ebx + SOCKET.TCBState] + buffer_ptr dd ? + timestamp dd ? - cmp [ebx + SOCKET.TCBTimer], 0 - jne .decrement_tcb - cmp [ebx + SOCKET.wndsizeTimer], 0 - jne .decrement_wnd - jmp .next_socket +ends - .decrement_tcb: - ; decrement it, delete socket if TCB timer = 0 & socket in timewait state - dec [ebx + SOCKET.TCBTimer] - jnz .next_socket - - cmp [ebx + SOCKET.TCBState], TCB_TIMED_WAIT - jne .next_socket - - push [ebx + SOCKET.PrevPtr] - stdcall net_socket_free, ebx - pop ebx - jmp .next_socket - - .decrement_wnd: - ; TODO - prove it works! - dec [ebx + SOCKET.wndsizeTimer] - jmp .next_socket - - .exit: - ret -endp - - -;*************************************************************************** -; Function -; tcp_tx_handler -; -; Description -; Handles queued TCP data -; This is a kernel function, called by stack_handler -; -;*************************************************************************** - -proc tcp_tx_handler stdcall - ; decrement all resend buffers timers. If they - ; expire, queue them for sending, and restart the timer. - ; If the retries counter reach 0, delete the entry - - mov esi, resendQ - mov ecx, 0 - - .next_resendq: - cmp ecx, NUMRESENDENTRIES - je .exit ; None left - cmp dword[esi + 4], 0 - jne @f ; found one - inc ecx - add esi, 8 - jmp .next_resendq - - @@: ; we have one. decrement it's timer by 1 - dec word[esi + 2] - jz @f - inc ecx - add esi, 8 - jmp .next_resendq ; Timer not zero, so move on - - @@: - xor ebx, ebx - ; restart timer, and decrement retries - ; After the first resend, back of on next, by a factor of 5 - mov [esi + 2], word TCP_TIMEOUT * 5 - dec byte[esi + 1] - jnz @f - - ; retries now 0, so delete from queue - xchg [esi + 4], ebx - - @@: ; resend packet - pushad - - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - jne .tth004z - - ; TODO - try again in 10ms. - test ebx, ebx - jnz @f - mov [esi + 4], ebx - - @@: ; Mark it to expire in 10ms - 1 tick - mov byte[esi + 1], 1 - mov word[esi + 2], 1 - jmp .tth005 - - .tth004z: - ; we have a buffer # in ax - push eax ecx - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs - - ; we have the buffer address in eax - mov edi, eax - pop ecx - ; Now get buffer location, and copy buffer across. argh! more copying,, - imul esi, ecx, IPBUFFSIZE - add esi, resendBuffer - - ; we have resend buffer location in esi - mov ecx, IPBUFFSIZE - - ; copy data across - push edi - cld - rep movsb - pop edi - - ; queue packet - mov eax, NET1OUT_QUEUE - mov edx, [stack_ip] - cmp edx, [edi + IP_PACKET.DestinationAddress] - jne .not_local - mov eax, IPIN_QUEUE - - .not_local: - pop ebx - call queue - - .tth005: - popad - - inc ecx - add esi, 8 - jmp .next_resendq - - .exit: - ret -endp - - -;*************************************************************************** -; Function -; tcp_rx -; -; Description -; TCP protocol handler -; This is a kernel function, called by ip_rx -; IP buffer address given in edx -; IP buffer number in eax -; Free up (or re-use) IP buffer when finished -; -;*************************************************************************** - -proc tcp_rx stdcall uses ebx - ; The process is as follows. - ; Look for a socket with matching remote IP, remote port, local port - ; if not found, then - ; look for remote IP + local port match ( where sockets remote port = 0) - ; if not found, then - ; look for a socket where local socket port == IP packets remote port - ; where sockets remote port, remote IP = 0 - ; discard if not found - ; Call sockets tcbStateMachine, with pointer to packet. - ; the state machine will not delete the packet, so do that here. - - push eax - - ; Look for a socket where - ; IP Packet TCP Destination Port = local Port - ; IP Packet SA = Remote IP - ; IP Packet TCP Source Port = remote Port - - mov ebx, net_sockets - - .next_socket.1: - mov ebx, [ebx + SOCKET.NextPtr] - or ebx, ebx - jz .next_socket.1.exit - -; DEBUGF 1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 - - mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get the dest. port from the TCP hdr - cmp [ebx + SOCKET.LocalPort], ax ; get the dest. port from the TCP hdr - jne .next_socket.1 ; different - try next socket - -; DEBUGF 1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP] - - mov eax, [edx + IP_PACKET.SourceAddress] ; get the source IP Addr from the IP hdr - cmp [ebx + SOCKET.RemoteIP], eax ; compare with socket's remote IP - jne .next_socket.1 ; different - try next socket - -; DEBUGF 1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_PACKET.SourcePort]:4, [ebx + SOCKET.RemotePort]:4 - - mov ax, [edx + 20 + TCP_PACKET.SourcePort] ; get the source port from the TCP hdr - cmp [ebx + SOCKET.RemotePort], ax ; compare with socket's remote port - jne .next_socket.1 ; different - try next socket - - ; We have a complete match - use this socket - jmp .change_state - - .next_socket.1.exit: - - ; If we got here, there was no match - ; Look for a socket where - ; IP Packet TCP Destination Port = local Port - ; IP Packet SA = Remote IP - ; socket remote Port = 0 - - mov ebx, net_sockets - - .next_socket.2: - mov ebx, [ebx + SOCKET.NextPtr] - or ebx, ebx - jz .next_socket.2.exit - -; DEBUGF 1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 - - mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get the dest. port from the TCP hdr - cmp [ebx + SOCKET.LocalPort], ax ; compare with socket's local port - jne .next_socket.2 ; different - try next socket - -; DEBUGF 1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP] - - mov eax, [edx + IP_PACKET.SourceAddress] ; get the source IP Addr from the IP hdr - cmp [ebx + SOCKET.RemoteIP], eax ; compare with socket's remote IP - jne .next_socket.2 ; different - try next socket - -; DEBUGF 1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4 - - cmp [ebx + SOCKET.RemotePort], 0 ; only match a remote socket of 0 - jne .next_socket.2 ; different - try next socket - - ; We have a complete match - use this socket - jmp .change_state - - .next_socket.2.exit: - - ; If we got here, there was no match - ; Look for a socket where - ; IP Packet TCP Destination Port = local Port - ; socket Remote IP = 0 - ; socket remote Port = 0 - - mov ebx, net_sockets - - .next_socket.3: - mov ebx, [ebx + SOCKET.NextPtr] - or ebx, ebx - jz .next_socket.3.exit - -; DEBUGF 1, "K : tcp_rx - 3.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 - - mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get destination port from the TCP hdr - cmp [ebx + SOCKET.LocalPort], ax ; compare with socket's local port - jne .next_socket.3 ; different - try next socket - -; DEBUGF 1, "K : tcp_rx - 3.addr: 00000000 - %x\n", [ebx + SOCKET.RemoteIP] - - cmp [ebx + SOCKET.RemoteIP], 0 ; only match a socket remote IP of 0 - jne .next_socket.3 ; different - try next socket - -; DEBUGF 1, "K : tcp_rx - 3.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4 - - cmp [ebx + SOCKET.RemotePort], 0 ; only match a remote socket of 0 - jne .next_socket.3 ; different - try next socket - - ; We have a complete match - use this socket - jmp .change_state - - .next_socket.3.exit: - - ; If we got here, we need to reject the packet - - DEBUGF 1, "K : tcp_rx - dumped\n" - DEBUGF 1, "K : --------: %x-%x-%x (flags: %x)\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [edx + IP_PACKET.SourceAddress], [edx + 20 + TCP_PACKET.SourcePort]:4, [edx + 20 + TCP_PACKET.Flags]:2 - - inc [dumped_rx_count] - jmp .exit - - .change_state: - - ; We have a valid socket/TCB, so call the TCB State Machine for that skt. - ; socket is pointed to by ebx - ; IP packet is pointed to by edx - ; IP buffer number is on stack ( it will be popped at the end) - - stdcall tcpStateMachine, ebx - - .exit: - pop eax - call freeBuff - ret -endp - - -;*************************************************************************** -; Function -; buildTCPPacket -; -; Description -; builds an IP Packet with TCP data fully populated for transmission -; You may destroy any and all registers -; TCP control flags specified in bl -; This TCB is in [sktAddr] -; User data pointed to by esi -; Data length in ecx -; Transmit buffer number in eax -; -;*************************************************************************** - -proc build_tcp_packet stdcall, sockAddr:DWORD - push ecx ; Save data length - - ; convert buffer pointer eax to the absolute address - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs - - mov edx, eax - - mov [edx + 20 + TCP_PACKET.Flags], bl ; TCP flags - - mov ebx, [sockAddr] - - ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr - - ; Fill in the IP header ( some data is in the socket descriptor) - mov eax, [ebx + SOCKET.LocalIP] - mov [edx + IP_PACKET.SourceAddress], eax - mov eax, [ebx + SOCKET.RemoteIP] - mov [edx + IP_PACKET.DestinationAddress], eax - - mov [edx + IP_PACKET.VersionAndIHL], 0x45 - mov [edx + IP_PACKET.TypeOfService], 0 - - pop eax ; Get the TCP data length - push eax - - add eax, 20 + 20 ; add IP header and TCP header lengths - rol ax, 8 - mov [edx + IP_PACKET.TotalLength], ax - mov [edx + IP_PACKET.Identification], 0 - mov [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040 - mov [edx + IP_PACKET.TimeToLive], 0x20 - mov [edx + IP_PACKET.Protocol], PROTOCOL_TCP - - ; Checksum left unfilled - mov [edx + IP_PACKET.HeaderChecksum], 0 - - ; Fill in the TCP header (some data is in the socket descriptor) - mov ax, [ebx + SOCKET.LocalPort] - mov [edx + 20 + TCP_PACKET.SourcePort], ax ; Local Port - - mov ax, [ebx + SOCKET.RemotePort] - mov [edx + 20 + TCP_PACKET.DestinationPort], ax ; desitination Port - - ; Checksum left unfilled - mov [edx + 20 + TCP_PACKET.Checksum], 0 - - ; sequence number - mov eax, [ebx + SOCKET.SND_NXT] - mov [edx + 20 + TCP_PACKET.SequenceNumber], eax - - ; ack number - mov eax, [ebx + SOCKET.RCV_NXT] - mov [edx + 20 + TCP_PACKET.AckNumber], eax - - ; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size) - ; 768 bytes seems better - mov [edx + 20 + TCP_PACKET.Window], 0x0003 - - ; Urgent pointer (0) - mov [edx + 20 + TCP_PACKET.UrgentPointer], 0 - - ; data offset ( 0x50 ) - mov [edx + 20 + TCP_PACKET.DataOffset], 0x50 - - pop ecx ; count of bytes to send - mov ebx, ecx ; need the length later - - cmp ebx, 0 - jz @f - - mov edi, edx - add edi, 40 - cld - rep movsb ; copy the data across - - @@: ; we have edx as IPbuffer ptr. - ; Fill in the TCP checksum - ; First, fill in pseudoheader - mov eax, [edx + IP_PACKET.SourceAddress] - mov [pseudoHeader], eax - mov eax, [edx + IP_PACKET.DestinationAddress] - mov [pseudoHeader + 4], eax - mov word[pseudoHeader + 8], PROTOCOL_TCP shl 8 + 0 - add ebx, 20 - mov [pseudoHeader + 10], bh - mov [pseudoHeader + 11], bl - - mov eax, pseudoHeader - mov [checkAdd1], eax - mov word[checkSize1], 12 - mov eax, edx - add eax, 20 - mov [checkAdd2], eax - mov eax, ebx - mov [checkSize2], ax - - call checksum - - ; store it in the TCP checksum ( in the correct order! ) - mov ax, [checkResult] - rol ax, 8 - mov [edx + 20 + TCP_PACKET.Checksum], ax - - ; Fill in the IP header checksum - GET_IHL eax, edx ; get IP-Header length - stdcall checksum_jb, edx, eax ; buf_ptr, buf_size - rol ax, 8 - mov [edx + IP_PACKET.HeaderChecksum], ax - - ret -endp - - -; Increments the 32 bit value pointed to by esi in internet order -proc inc_inet_esi stdcall - push eax - mov eax, [esi] - bswap eax - inc eax - bswap eax - mov [esi], eax - pop eax - ret -endp - - -; Increments the 32 bit value pointed to by esi in internet order -; by the value in ecx -proc add_inet_esi stdcall - push eax - mov eax, [esi] - bswap eax - add eax, ecx - bswap eax - mov [esi], eax - pop eax - ret -endp - - -iglobal - TCBStateHandler dd \ - stateTCB_LISTEN, \ - stateTCB_SYN_SENT, \ - stateTCB_SYN_RECEIVED, \ - stateTCB_ESTABLISHED, \ - stateTCB_FIN_WAIT_1, \ - stateTCB_FIN_WAIT_2, \ - stateTCB_CLOSE_WAIT, \ - stateTCB_CLOSING, \ - stateTCB_LAST_ACK, \ - stateTCB_TIME_WAIT, \ - stateTCB_CLOSED +align 4 +uglobal + TCP_segments_tx rd MAX_NET_DEVICES + TCP_segments_rx rd MAX_NET_DEVICES + TCP_segments_missed rd MAX_NET_DEVICES + TCP_segments_dumped rd MAX_NET_DEVICES +; TCP_bytes_rx rq MAX_NET_DEVICES +; TCP_bytes_tx rq MAX_NET_DEVICES + TCP_sequence_num dd ? + TCP_queue rd TCP_QUEUE_SIZE*sizeof.TCP_queue_entry/4 + TCP_input_event dd ? endg -;*************************************************************************** -; Function -; tcpStateMachine +;----------------------------------------------------------------- ; -; Description -; TCP state machine -; This is a kernel function, called by tcp_rx +; TCP_init ; -; IP buffer address given in edx -; Socket/TCB address in ebx +; This function resets all TCP variables ; -; The IP buffer will be released by the caller -;*************************************************************************** +;----------------------------------------------------------------- +macro TCP_init { -proc tcpStateMachine stdcall, sockAddr:DWORD - ; as a packet has been received, update the TCB timer - mov [ebx + SOCKET.TCBTimer], TWOMSL + xor eax, eax + mov edi, TCP_segments_tx + mov ecx, (6*MAX_NET_DEVICES) + rep stosd - ; If the received packet has an ACK bit set, - ; remove any packets in the resend queue that this - ; received packet acknowledges - pushad - test [edx + 20 + TCP_PACKET.Flags], TH_ACK - jz .call_handler ; No ACK, so no data yet + pseudo_random eax + mov [TCP_sequence_num], eax - ; get skt number in eax - stdcall net_socket_addr_to_num, ebx + init_queue TCP_queue - ; The ack number is in [edx + 28], inet format - ; skt in eax + push 1 + pop ebx + mov ecx, TCP_process_input + call new_sys_threads - mov esi, resendQ - xor ecx, ecx +} - .next_resendq: - cmp ecx, NUMRESENDENTRIES - je .call_handler ; None left - cmp [esi + 4], eax - je @f ; found one - inc ecx - add esi, 8 - jmp .next_resendq - @@: ; Can we delete this buffer? +include 'tcp_timer.inc' +include 'tcp_subr.inc' +include 'tcp_usreq.inc' +include 'tcp_input.inc' +include 'tcp_output.inc' - ; If yes, goto @@. No, goto .next_resendq - ; Get packet data address - push ecx - ; Now get buffer location, and copy buffer across. argh! more copying,, - imul edi, ecx, IPBUFFSIZE - add edi, resendBuffer - - ; we have dest buffer location in edi. incoming packet in edx. - ; Get this packets sequence number - ; preserve al, ecx, esi, edx - mov ecx, [edi + 20 + TCP_PACKET.SequenceNumber] - bswap ecx - movzx ebx, word[edi + 2] - xchg bl, bh - sub ebx, 40 - add ecx, ebx ; ecx is now seq# of last byte +1, intel format - - ; get recievd ack #, in intel format - mov ebx, [edx + 20 + TCP_PACKET.AckNumber] - bswap ebx - - cmp ebx, ecx ; Finally. ecx = rx'ed ack. ebx = last byte in que - ; DANGER! need to handle case that we have just - ; passed the 2**32, and wrapped round! - pop ecx - jae @f ; if rx > old, delete old - - inc ecx - add esi, 8 - jmp .next_resendq - - @@: - mov dword[esi + 4], 0 - inc ecx - add esi, 8 - jmp .next_resendq - - .call_handler: - popad - - ; Call handler for given TCB state - - mov eax, [ebx + SOCKET.TCBState] - cmp eax, TCB_LISTEN - jb .exit - cmp eax, TCB_CLOSED - ja .exit - - stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr] - - .exit: - ret -endp - -;*************************************************************************** -; Function -; signal_network_event +;--------------------------------------------------------------------------- ; -; Description -; Signals about network event to socket owner -; This is a kernel function, called from TCP handler +; TCP_API ; -; Socket/TCB address in ebx -;*************************************************************************** -proc signal_network_event - push ecx esi eax - mov eax, [ebx + SOCKET.PID] - mov ecx, 1 - mov esi, TASK_DATA + TASKDATA.pid +; This function is called by system function 76 +; +; IN: subfunction number in bl +; device number in bh +; ecx, edx, .. depends on subfunction +; +; OUT: +; +;--------------------------------------------------------------------------- +align 4 +TCP_api: - .next_pid: - cmp [esi], eax - je .found_pid - inc ecx - add esi, 0x20 - cmp ecx, [TASK_COUNT] - jbe .next_pid + movzx eax, bh + shl eax, 2 - .found_pid: - shl ecx, 8 - or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event - pop eax esi ecx + test bl, bl + jz .packets_tx ; 0 + dec bl + jz .packets_rx ; 1 + dec bl + jz .packets_missed ; 2 + dec bl + jz .packets_dumped ; 3 + + .error: + mov eax, -1 ret -endp -proc stateTCB_LISTEN stdcall, sockAddr:DWORD - ; In this case, we are expecting a SYN packet - ; For now, if the packet is a SYN, process it, and send a response - ; If not, ignore it - - ; Look at control flags - test [edx + 20 + TCP_PACKET.Flags], TH_SYN - jz .exit - - ; We have a SYN. update the socket with this IP packets details, - ; And send a response - - mov eax, [edx + IP_PACKET.SourceAddress] - mov [ebx + SOCKET.RemoteIP], eax - mov ax, [edx + 20 + TCP_PACKET.SourcePort] - mov [ebx + SOCKET.RemotePort], ax - mov eax, [edx + 20 + TCP_PACKET.SequenceNumber] - mov [ebx + SOCKET.IRS], eax - mov [ebx + SOCKET.RCV_NXT], eax - lea esi, [ebx + SOCKET.RCV_NXT] - call inc_inet_esi ; RCV.NXT - mov eax, [ebx + SOCKET.ISS] - mov [ebx + SOCKET.SND_NXT], eax - - ; Now construct the response, and queue for sending by IP - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je .exit - - push ebx - push eax - mov bl, TH_SYN + TH_ACK - xor ecx, ecx - xor esi, esi - stdcall build_tcp_packet, [sockAddr] - - mov eax, NET1OUT_QUEUE - mov edx, [stack_ip] - mov ecx, [sockAddr] - cmp edx, [ecx + SOCKET.RemoteIP] - jne .not_local - mov eax, IPIN_QUEUE - - .not_local: - ; Send it. - pop ebx - call queue - - pop ebx - mov esi, [sockAddr] - mov [esi + SOCKET.TCBState], TCB_SYN_RECEIVED - call signal_network_event - - ; increment SND.NXT in socket - add esi, SOCKET.SND_NXT - call inc_inet_esi - - .exit: + .packets_tx: + mov eax, [TCP_segments_tx + eax] ret -endp - -proc stateTCB_SYN_SENT stdcall, sockAddr:DWORD - ; We are awaiting an ACK to our SYN, with a SYM - ; Look at control flags - expecting an ACK - - mov al, [edx + 20 + TCP_PACKET.Flags] - and al, TH_SYN + TH_ACK - cmp al, TH_SYN + TH_ACK - je .syn_ack - - test al, TH_SYN - jz .exit - - mov [ebx + SOCKET.TCBState], TCB_SYN_RECEIVED - push TH_SYN + TH_ACK - jmp .send - - .syn_ack: - mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED - push TH_ACK - - .send: - call signal_network_event - ; Store the recv.nxt field - mov eax, [edx + 20 + TCP_PACKET.SequenceNumber] - - ; Update our recv.nxt field - mov [ebx + SOCKET.RCV_NXT], eax - lea esi, [ebx + SOCKET.RCV_NXT] - call inc_inet_esi - - ; Send an ACK - ; Now construct the response, and queue for sending by IP - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - pop ebx - je .exit - - push eax - - xor ecx, ecx - xor esi, esi - stdcall build_tcp_packet, [sockAddr] - - mov eax, NET1OUT_QUEUE - mov edx, [stack_ip] - mov ecx, [sockAddr] - cmp edx, [ecx + SOCKET.RemoteIP] - jne .not_local - mov eax, IPIN_QUEUE - - .not_local: - ; Send it. - pop ebx - call queue - - .exit: + .packets_rx: + mov eax, [TCP_segments_rx + eax] ret -endp - -proc stateTCB_SYN_RECEIVED stdcall, sockAddr:DWORD - ; In this case, we are expecting an ACK packet - ; For now, if the packet is an ACK, process it, - ; If not, ignore it - - test [edx + 20 + TCP_PACKET.Flags], TH_RST - jz .check_ack - - push [ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP] - pop [ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort] - - mov [ebx + SOCKET.TCBState], TCB_LISTEN - jmp .signal - - .check_ack: - ; Look at control flags - expecting an ACK - test [edx + 20 + TCP_PACKET.Flags], TH_ACK - jz .exit - - mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED - .signal: - call signal_network_event - - .exit: + .packets_missed: + mov eax, [TCP_segments_missed + eax] ret -endp - -proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD - ; Here we are expecting data, or a request to close - ; OR both... - - ; Ignore all packets with sequnce number other than next expected - - ; recv.nxt is in dword [edx+24], in inet format - ; recv seq is in [sktAddr]+56, in inet format - ; just do a comparision - mov eax, [ebx + SOCKET.RCV_NXT] - cmp eax, [edx + 20 + TCP_PACKET.SequenceNumber] - jne .exit - - ; Did we receive a FIN or RST? - test [edx + 20 + TCP_PACKET.Flags], TH_FIN+TH_RST - jz .check_ack - - ; It was a fin or reset. - - ; Remove resend entries from the queue - I dont want to send any more data - pushad - - ; get skt # - stdcall net_socket_addr_to_num, ebx - - mov esi, resendQ - mov ecx, 0 - - .next_resendq: - cmp ecx, NUMRESENDENTRIES - je .last_resendq ; None left - cmp [esi + 4], eax - je @f ; found one - inc ecx - add esi, 8 - jmp .next_resendq - - @@: - mov dword[esi + 4], 0 - inc ecx - add esi, 8 - jmp .next_resendq - - .last_resendq: - popad - - @@: ; Send an ACK to that fin, and enter closewait state - - mov [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT - test [edx + 20 + TCP_PACKET.Flags], TH_RST - je @f - mov [ebx + SOCKET.TCBState], TCB_CLOSED - @@: - call signal_network_event - lea esi, [ebx + SOCKET.RCV_NXT] - mov eax, [esi] ; save original - call inc_inet_esi - ;; jmp ste_ack - NO, there may be data - - .check_ack: - ; Check that we received an ACK - test [edx + 20 + TCP_PACKET.Flags], TH_ACK - jz .exit - - ; TODO - done, I think! - ; First, look at the incoming window. If this is less than or equal to 1024, - ; Set the socket window timer to 1. This will stop an additional packets being queued. - ; ** I may need to tweak this value, since I do not know how many packets are already queued - mov cx, [edx + 20 + TCP_PACKET.Window] - xchg cl, ch - cmp cx, 1024 - ja @f - - mov [ebx + SOCKET.wndsizeTimer], 1 - - @@: ; OK, here is the deal - - - ; Read the data bytes, store in socket buffer - movzx ecx, [edx + IP_PACKET.TotalLength] - xchg cl, ch - sub ecx, 40 ; Discard 40 bytes of header - ja .data ; Read data, if any - - ; If we had received a fin, we need to ACK it. - cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT - je .ack - jmp .exit - - .data: - push ecx - push ecx edx - lea ecx, [ebx+SOCKET.mutex] - call mutex_lock - pop edx ecx - - push ebx - mov eax, [ebx + SOCKET.rxDataCount] - add eax, ecx - cmp eax, SOCKETBUFFSIZE - SOCKETHEADERSIZE - ja .overflow - - mov [ebx + SOCKET.rxDataCount], eax ; increment the count of bytes in buffer - - ; point to the location to store the data - lea edi, [ebx + eax + SOCKETHEADERSIZE] - sub edi, ecx - - add edx, 40 ; edx now points to the data - mov esi, edx - - cld - rep movsb ; copy the data across - - lea ecx, [ebx + SOCKET.mutex] - call mutex_unlock - - ; flag an event to the application - pop ebx - call signal_network_event - - pop ecx - - ; Update our recv.nxt field - lea esi, [ebx + SOCKET.RCV_NXT] - call add_inet_esi - - .ack: - ; Send an ACK - ; Now construct the response, and queue for sending by IP - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je .exit - - push eax - - mov bl, TH_ACK - xor ecx, ecx - xor esi, esi - stdcall build_tcp_packet, [sockAddr] - - mov eax, NET1OUT_QUEUE - - mov edx, [stack_ip] - mov ecx, [sockAddr] - cmp edx, [ecx + SOCKET.RemoteIP] - jne .not_local - mov eax, IPIN_QUEUE - - .not_local: - ; Send it. - pop ebx - call queue - - .exit: + .packets_dumped: + mov eax, [TCP_segments_dumped + eax] ret - .overflow: - ; no place in buffer - ; so simply restore stack and exit - lea ecx, [ebx + SOCKET.mutex] - call mutex_unlock - pop eax ecx - ret -endp - - -proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD - ; We can either receive an ACK of a fin, or a fin - mov al, [edx + 20 + TCP_PACKET.Flags] - and al, TH_FIN + TH_ACK - - cmp al, TH_ACK - jne @f - - ; It was an ACK - mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_2 - jmp .exit - - @@: - mov [ebx + SOCKET.TCBState], TCB_CLOSING - cmp al, TH_FIN - je @f - mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT - - @@: - lea esi, [ebx + SOCKET.RCV_NXT] - call inc_inet_esi - - ; Send an ACK - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je .exit - - push eax - - mov bl, TH_ACK - xor ecx, ecx - xor esi, esi - stdcall build_tcp_packet, [sockAddr] - - mov eax, NET1OUT_QUEUE - mov edx, [stack_ip] - mov ecx, [sockAddr] - cmp edx, [ecx + SOCKET.RemoteIP] - jne .not_local - mov eax, IPIN_QUEUE - - .not_local: - ; Send it. - pop ebx - call queue - - .exit: - ret -endp - - -proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD - test [edx + 20 + TCP_PACKET.Flags], TH_FIN - jz .exit - - ; Change state, as we have a fin - mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT - - lea esi, [ebx + SOCKET.RCV_NXT] - call inc_inet_esi - - ; Send an ACK - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je .exit - - push eax - - mov bl, TH_ACK - xor ecx, ecx - xor esi, esi - stdcall build_tcp_packet, [sockAddr] - - mov eax, NET1OUT_QUEUE - mov edx, [stack_ip] - mov ecx, [sockAddr] - cmp edx, [ecx + SOCKET.RemoteIP] - jne .not_local - mov eax, IPIN_QUEUE - - .not_local: - ; Send it. - pop ebx - call queue - - .exit: - ret -endp - - -proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD - ; Intentionally left empty - ; socket_close_tcp handles this - ret -endp - - -proc stateTCB_CLOSING stdcall, sockAddr:DWORD - ; We can either receive an ACK of a fin, or a fin - test [edx + 20 + TCP_PACKET.Flags], TH_ACK - jz .exit - - mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT - - .exit: - ret -endp - - -proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD - ; Look at control flags - expecting an ACK - test [edx + 20 + TCP_PACKET.Flags], TH_ACK - jz .exit - - ; delete the socket - stdcall net_socket_free, ebx - - .exit: - ret -endp - - -proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD - ret -endp - - -proc stateTCB_CLOSED stdcall, sockAddr:DWORD - ret -endp diff --git a/kernel/trunk/network/tcp_input.inc b/kernel/trunk/network/tcp_input.inc new file mode 100644 index 0000000000..07f2433f53 --- /dev/null +++ b/kernel/trunk/network/tcp_input.inc @@ -0,0 +1,1663 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Part of the TCP/IP network stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; Based on the code of 4.4BSD ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 3407 $ + +;----------------------------------------------------------------- +; +; TCP_input: +; +; Add a segment to the incoming TCP queue +; +; IN: [esp] = ptr to buffer +; [esp+4] = buffer size (dont care) +; ebx = ptr to device struct +; ecx = segment size +; esi = ptr to TCP segment +; edi = ptr to ipv4 source address, followed by ipv4 dest address +; +; OUT: / +; +;----------------------------------------------------------------- + +align 4 +TCP_input: + +; record the current time + mov eax, [timer_ticks] ; in 1/100 seconds + mov [esp + 4], eax + + push ebx ecx esi edi ; mind the order + mov esi, esp + + pushf + cli + add_to_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .fail + popf + + add esp, sizeof.TCP_queue_entry + + xor edx, edx + mov eax, [TCP_input_event] + mov ebx, [eax + EVENT.id] + xor esi, esi + call raise_event + + ret + + .fail: + popf + DEBUGF 2, "TCP incoming queue is full, discarding packet!\n" + + inc [TCP_segments_missed] ; FIXME: use correct interface + + add esp, sizeof.TCP_queue_entry - 8 + call kernel_free + add esp, 4 + + ret + + + + +align 4 +TCP_process_input: + + xor esi, esi + mov ecx, MANUAL_DESTROY + call create_event + mov [TCP_input_event], eax + + .wait: + mov eax, [TCP_input_event] + mov ebx, [eax + EVENT.id] + call wait_event + + .loop: + get_from_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .wait + + push [esi + TCP_queue_entry.timestamp] + push [esi + TCP_queue_entry.buffer_ptr] + + mov ebx, [esi + TCP_queue_entry.device_ptr] + mov ecx, [esi + TCP_queue_entry.segment_size] + mov edi, [esi + TCP_queue_entry.ip_ptr] ; ptr to ipv4 source address, followed by ipv4 destination address + mov esi, [esi + TCP_queue_entry.segment_ptr] ; change esi last + + DEBUGF 1,"TCP_input: size=%u time=%d\n", ecx, [timer_ticks] + + mov edx, esi + + cmp ebx, LOOPBACK_DEVICE + je .checksum_ok + +; re-calculate the checksum (if not already done by hw) +; test [ebx + NET_DEVICE.hwacc], HWACC_TCP_IPv4_IN +; jnz .checksum_ok + + push ecx esi + pushw [esi + TCP_header.Checksum] + mov [esi + TCP_header.Checksum], 0 + TCP_checksum (edi), (edi+4) + pop cx ; previous checksum + cmp cx, dx + pop edx ecx + jne .drop_no_socket + .checksum_ok: + +; Verify the data offset + and [edx + TCP_header.DataOffset], 0xf0 ; Calculate TCP segment header size (throwing away unused reserved bits in TCP header) + shr [edx + TCP_header.DataOffset], 2 + cmp [edx + TCP_header.DataOffset], sizeof.TCP_header ; Now see if it's at least the size of a standard TCP header + jb .drop_no_socket ; If not, drop the packet + + movzx eax, [edx + TCP_header.DataOffset] + sub ecx, eax ; substract TCP header size from total segment size + jb .drop_no_socket ; If total segment size is less then the advertised header size, drop packet + DEBUGF 1,"TCP_input: %u bytes of data\n", ecx + +;------------------------------------------- +; Convert Big-endian values to little endian + + ntohd [edx + TCP_header.SequenceNumber] + ntohd [edx + TCP_header.AckNumber] + + ntohw [edx + TCP_header.Window] + ntohw [edx + TCP_header.UrgentPointer] + +;------------------------ +; Find the socket pointer + +; IP Packet TCP Destination Port = local Port +; (IP Packet SenderAddress = Remote IP) OR (Remote IP = 0) +; (IP Packet TCP Source Port = remote Port) OR (remote Port = 0) + + .findpcb: + mov ebx, net_sockets + mov si, [edx + TCP_header.DestinationPort] + + .socket_loop: + mov ebx, [ebx + SOCKET.NextPtr] + or ebx, ebx + jz .respond_seg_reset + + cmp [ebx + SOCKET.Domain], AF_INET4 + jne .socket_loop + + cmp [ebx + SOCKET.Protocol], IP_PROTO_TCP + jne .socket_loop + + cmp [ebx + TCP_SOCKET.LocalPort], si + jne .socket_loop + + mov eax, [ebx + IP_SOCKET.RemoteIP] + cmp eax, [edi] ; Ipv4 source address + je @f + test eax, eax + jnz .socket_loop + @@: + + mov ax, [ebx + TCP_SOCKET.RemotePort] + cmp [edx + TCP_header.SourcePort], ax + je .found_socket + test ax, ax + jnz .socket_loop + .found_socket: ; ebx now contains the socketpointer + DEBUGF 1,"TCP_input: socket ptr=%x state=%u flags=%x\n", ebx, [ebx + TCP_SOCKET.t_state], [edx + TCP_header.Flags]:2 + +;------------- +; update stats + + inc [TCP_segments_rx] ; FIXME: correct interface? + +;---------------------------- +; Check if socket isnt closed + + cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSED + je .drop_no_socket + +;---------------- +; Lock the socket + + pusha + lea ecx, [ebx + SOCKET.mutex] + call mutex_lock + popa + + DEBUGF 1,"TCP_input: socket locked\n" + +;--------------------------- +; disable all temporary bits + + mov [ebx + TCP_SOCKET.temp_bits], 0 + +;--------------------------------------- +; unscale the window into a 32 bit value + + movzx eax, [edx + TCP_header.Window] + push ecx + mov cl, [ebx + TCP_SOCKET.SND_SCALE] + shl eax, cl + mov dword [edx + TCP_header.Window], eax ; word after window is checksum, we dont need checksum anymore + pop ecx + +;--------------------------------------- +; Are we accepting incoming connections? + + test [ebx + SOCKET.options], SO_ACCEPTCON + jz .no_accept + + DEBUGF 1,"TCP_input: Accepting new connection\n" + + pusha + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + popa + + push ecx edx esi edi ;;; + call SOCKET_fork + pop edi esi edx ecx + + test eax, eax + jz .drop_no_socket + + mov ebx, eax + + mov [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET ;;; FIXME: should we take over bits from previous socket? + + push dword [edi + 4] ; Ipv4 destination addres + pop [ebx + IP_SOCKET.LocalIP] + + push [edx + TCP_header.DestinationPort] + pop [ebx + TCP_SOCKET.LocalPort] + + mov [ebx + TCP_SOCKET.t_state], TCPS_LISTEN + .no_accept: + + +;------------------------------------- +; Reset idle timer and keepalive timer + + mov [ebx + TCP_SOCKET.t_idle], 0 + mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_idle + +;-------------------- +; Process TCP options + + push ecx + + movzx ecx, [edx + TCP_header.DataOffset] + cmp ecx, sizeof.TCP_header ; Does header contain any options? + je .no_options + + DEBUGF 1,"TCP_input: Segment has options\n" + +;;; FIXME: for LISTEN, options should be called after we determined route, we need it for MSS +;;; cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN ; no options when in listen state +;;; jz .not_uni_xfer ; also no header prediction + + add ecx, edx + lea esi, [edx + sizeof.TCP_header] + + .opt_loop: + cmp esi, ecx ; are we scanning outside of header? + jae .no_options + lodsb + cmp al, TCP_OPT_EOL ; end of option list? + je .no_options + cmp al, TCP_OPT_NOP + je .opt_loop + cmp al, TCP_OPT_MAXSEG + je .opt_maxseg + cmp al, TCP_OPT_WINDOW + je .opt_window + cmp al, TCP_OPT_SACK_PERMIT + je .opt_sack_permit +; cmp al, TCP_OPT_SACK +; je .opt_sack + cmp al, TCP_OPT_TIMESTAMP + je .opt_timestamp + DEBUGF 1,"TCP_input: unknown option:%u\n", al + jmp .no_options ; If we reach here, some unknown options were received, skip them all! + + .opt_maxseg: + lodsb + cmp al, 4 + jne .no_options ; error occured, ignore all options! + + test [edx + TCP_header.Flags], TH_SYN + jz @f + + lodsw + rol ax, 8 + DEBUGF 1,"TCP_input: Maxseg=%u\n", ax + call TCP_mss + @@: + jmp .opt_loop + + + .opt_window: + lodsb + cmp al, 3 + jne .no_options + + test [edx + TCP_header.Flags], TH_SYN + jz @f + + DEBUGF 1,"TCP_input: Got window scale option\n" + or [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE + + lodsb + mov [ebx + TCP_SOCKET.SND_SCALE], al + ;;;;; TODO + + @@: + jmp .opt_loop + + + .opt_sack_permit: + lodsb + cmp al, 2 + jne .no_options + + test [edx + TCP_header.Flags], TH_SYN + jz @f + + DEBUGF 1,"TCP_input: Selective Acknowledgement permitted\n" + or [ebx + TCP_SOCKET.t_flags], TF_SACK_PERMIT + + @@: + jmp .opt_loop + + + .opt_timestamp: + lodsb + cmp al, 10 ; length must be 10 + jne .no_options + + DEBUGF 1,"TCP_input: Got timestamp option\n" + + test [edx + TCP_header.Flags], TH_SYN + jz @f + or [ebx + TCP_SOCKET.t_flags], TF_RCVD_TSTMP + @@: + + lodsd + mov [ebx + TCP_SOCKET.ts_val], eax + lodsd ; timestamp echo reply + mov [ebx + TCP_SOCKET.ts_ecr], eax + or [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP + + ; Since we have a timestamp, lets do the paws test right away! + + test [edx + TCP_header.Flags], TH_RST + jnz .no_paws + + mov eax, [ebx + TCP_SOCKET.ts_recent] + test eax, eax + jz .no_paws + cmp eax, [ebx + TCP_SOCKET.ts_val] + jge .no_paws + + DEBUGF 1,"TCP_input: PAWS: detected an old segment\n" + + mov eax, [esp+4+4] ; tcp_now + sub eax, [ebx + TCP_SOCKET.ts_recent_age] + + pop ecx + cmp eax, TCP_PAWS_IDLE + jle .drop_after_ack ; TODO: update stats + push ecx + + mov [ebx + TCP_SOCKET.ts_recent], 0 ; timestamp was invalid, fix it. + .no_paws: + jmp .opt_loop + + .no_options: + + pop ecx + +;----------------------------------------------------------------------- +; Time to do some header prediction (Original Principle by Van Jacobson) + +; There are two common cases for an uni-directional data transfer. +; +; General rule: the packets has no control flags, is in-sequence, +; window width didnt change and we're not retransmitting. +; +; Second rules: +; - If the length is 0 and the ACK moved forward, we're the sender side of the transfer. +; In this case we'll free the ACK'ed data and notify higher levels that we have free space in buffer +; +; - If the length is not 0 and the ACK didn't move, we're the receiver side of the transfer. +; If the packets are in order (data queue is empty), add the data to the socket buffer and request a delayed ACK + + cmp [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED + jnz .not_uni_xfer + + test [edx + TCP_header.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG + jnz .not_uni_xfer + + test [edx + TCP_header.Flags], TH_ACK + jz .not_uni_xfer + + mov eax, [edx + TCP_header.SequenceNumber] + cmp eax, [ebx + TCP_SOCKET.RCV_NXT] + jne .not_uni_xfer + + mov eax, dword [edx + TCP_header.Window] + cmp eax, [ebx + TCP_SOCKET.SND_WND] + jne .not_uni_xfer + + mov eax, [ebx + TCP_SOCKET.SND_NXT] + cmp eax, [ebx + TCP_SOCKET.SND_MAX] + jne .not_uni_xfer + +;--------------------------------------- +; check if we are sender in the uni-xfer + +; If the following 4 conditions are all true, this segment is a pure ACK. +; +; - The segment contains no data. + test ecx, ecx + jnz .not_sender + +; - The congestion window is greater than or equal to the current send window. +; This test is true only if the window is fully open, that is, the connection is not in the middle of slow start or congestion avoidance. + mov eax, [ebx + TCP_SOCKET.SND_CWND] + cmp eax, [ebx + TCP_SOCKET.SND_WND] + jb .not_uni_xfer + +; - The acknowledgment field in the segment is less than or equal to the maximum sequence number sent. + mov eax, [edx + TCP_header.AckNumber] + cmp eax, [ebx + TCP_SOCKET.SND_MAX] + ja .not_uni_xfer + +; - The acknowledgment field in the segment is greater than the largest unacknowledged sequence number. + sub eax, [ebx + TCP_SOCKET.SND_UNA] + jbe .not_uni_xfer + + DEBUGF 1,"TCP_input: Header prediction: we are sender\n" + +;--------------------------------- +; Packet is a pure ACK, process it + +; Delete acknowledged bytes from send buffer + pusha + mov ecx, eax + lea eax, [ebx + STREAM_SOCKET.snd] + call SOCKET_ring_free + popa + +; Update RTT estimators + + test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP + jz .no_timestamp_rtt + mov eax, [esp + 4] ; timestamp when this segment was received + sub eax, [ebx + TCP_SOCKET.ts_ecr] + inc eax + call TCP_xmit_timer + jmp .rtt_done + + .no_timestamp_rtt: + cmp [ebx + TCP_SOCKET.t_rtt], 0 + je .rtt_done + mov eax, [edx + TCP_header.AckNumber] + cmp eax, [ebx + TCP_SOCKET.t_rtseq] + jbe .rtt_done + mov eax, [ebx + TCP_SOCKET.t_rtt] + call TCP_xmit_timer + + .rtt_done: + +; update window pointers + mov eax, [edx + TCP_header.AckNumber] + mov [ebx + TCP_SOCKET.SND_UNA], eax + +; Stop retransmit timer + mov [ebx + TCP_SOCKET.timer_retransmission], 0 + +; Unlock the socket + pusha + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + popa + +; Awaken waiting processes + mov eax, ebx + call SOCKET_notify + +; Generate more output + call TCP_output + + jmp .drop_no_socket + +;------------------------------------------------- +; maybe we are the receiver in the uni-xfer then.. + + .not_sender: +; - The amount of data in the segment is greater than 0 (data count is in ecx) + +; - The acknowledgment field equals the largest unacknowledged sequence number. This means no data is acknowledged by this segment. + mov eax, [edx + TCP_header.AckNumber] + cmp eax, [ebx + TCP_SOCKET.SND_UNA] + jne .not_uni_xfer + +; - The reassembly list of out-of-order segments for the connection is empty (seg_next equals tp). + +;;; TODO + +; jnz .not_uni_xfer + +; Complete processing of received data + + DEBUGF 1,"TCP_input: Header prediction: we are receiving %u bytes\n", ecx + + add [ebx + TCP_SOCKET.RCV_NXT], ecx ; Update sequence number with number of bytes we have copied + + movzx esi, [edx + TCP_header.DataOffset] + add esi, edx + lea eax, [ebx + STREAM_SOCKET.rcv] + call SOCKET_ring_write ; Add the data to the socket buffer + + mov eax, ebx + call SOCKET_notify + + or [ebx + TCP_SOCKET.t_flags], TF_DELACK ; Set delayed ack flag + + jmp .drop + +;-------------------------------------------------- +; Header prediction failed, do it the slow way + + .not_uni_xfer: + + DEBUGF 1,"TCP_input: Header prediction failed\n" + +; Calculate receive window size + + push edx + mov eax, SOCKETBUFFSIZE + sub eax, [ebx + STREAM_SOCKET.rcv.size] + mov edx, [ebx + TCP_SOCKET.RCV_ADV] + sub edx, [ebx + TCP_SOCKET.RCV_NXT] + cmp eax, edx + jg @f + mov eax, edx + @@: + DEBUGF 1,"Receive window size=%d\n", eax + mov [ebx + TCP_SOCKET.RCV_WND], eax + pop edx + +; If we are in listen or syn_sent state, go to that specific code right away + + cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN + je .LISTEN + + cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT + je .SYN_SENT + +;---------------------------- +; trim any data not in window + +; check for duplicate data at beginning of segment (635) + + mov eax, [ebx + TCP_SOCKET.RCV_NXT] + sub eax, [edx + TCP_header.SequenceNumber] + jle .no_duplicate + + DEBUGF 1,"TCP_input: %u bytes duplicate data!\n", eax + + test [edx + TCP_header.Flags], TH_SYN + jz .no_dup_syn + + DEBUGF 1,"TCP_input: got duplicate syn\n" + + and [edx + TCP_header.Flags], not (TH_SYN) + inc [edx + TCP_header.SequenceNumber] + + cmp [edx + TCP_header.UrgentPointer], 1 + jbe @f + dec [edx + TCP_header.UrgentPointer] + jmp .dup_syn + @@: + and [edx + TCP_header.Flags], not (TH_URG) + .dup_syn: + dec eax + .no_dup_syn: + +; Check for entire duplicate segment (646) + cmp eax, ecx ; eax holds number of bytes to drop, ecx is data size + jb .duplicate + jnz @f + test [edx + TCP_header.Flags], TH_FIN + jnz .duplicate + @@: + +; Any valid FIN must be to the left of the window. +; At this point the FIN must be out of sequence or a duplicate, drop it + and [edx + TCP_header.Flags], not TH_FIN + +; send an ACK and resynchronize and drop any data. +; But keep on processing for RST or ACK + DEBUGF 1, "616\n" + or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW + mov eax, ecx +;TODO: update stats + +;----------------------------------------------- +; Remove duplicate data and update urgent offset + + .duplicate: +;;; TODO: 677 + add [edx + TCP_header.SequenceNumber], eax + sub ecx, eax + + sub [edx + TCP_header.UrgentPointer], ax + jg @f + and [edx + TCP_header.Flags], not (TH_URG) + mov [edx + TCP_header.UrgentPointer], 0 + @@: + +;-------------------------------------------------- +; Handle data that arrives after process terminates (687) + + .no_duplicate: + cmp [ebx + SOCKET.PID], 0 + jne .not_terminated + cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT + jbe .not_terminated + test ecx, ecx + jz .not_terminated + + mov eax, ebx + call TCP_close +;;;TODO: update stats + jmp .respond_seg_reset + +;---------------------------------------- +; Remove data beyond right edge of window (700-736) + + .not_terminated: + mov eax, [edx + TCP_header.SequenceNumber] + add eax, ecx + sub eax, [ebx + TCP_SOCKET.RCV_NXT] + sub eax, [ebx + TCP_SOCKET.RCV_WND] ; eax now holds the number of bytes to drop + jle .no_excess_data + + DEBUGF 1,"%d bytes beyond right edge of window\n", eax + +;;; TODO: update stats + cmp eax, ecx + jl .dont_drop_all +; If a new connection request is received while in TIME_WAIT, drop the old connection and start over, +; if the sequence numbers are above the previous ones + + test [edx + TCP_header.Flags], TH_SYN + jz .no_new_request + cmp [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT + jne .no_new_request +; mov edx, [ebx + TCP_SOCKET.RCV_NXT] +; cmp edx, [edx + TCP_header.SequenceNumber] +; add edx, 64000 ; TCP_ISSINCR FIXME + mov eax, ebx + call TCP_close + jmp .findpcb ; FIXME: skip code for unscaling window, ... + .no_new_request: + +; If window is closed can only take segments at window edge, and have to drop data and PUSH from +; incoming segments. Continue processing, but remember to ACK. Otherwise drop segment and ACK + + cmp [ebx + TCP_SOCKET.RCV_WND], 0 + jne .drop_after_ack + mov eax, [edx + TCP_header.SequenceNumber] + cmp eax, [ebx + TCP_SOCKET.RCV_NXT] + jne .drop_after_ack + + DEBUGF 1, "690\n" + or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW +;;; TODO: update stats + jmp .no_excess_data + .dont_drop_all: +;;; TODO: update stats +;;; TODO: 733 + + sub ecx, eax + and [ebx + TCP_SOCKET.t_flags], not (TH_PUSH or TH_FIN) + .no_excess_data: + +;----------------- +; Record timestamp (737-746) + +; If last ACK falls within this segments sequence numbers, record its timestamp + test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP + jz .no_timestamp + mov eax, [ebx + TCP_SOCKET.last_ack_sent] + sub eax, [edx + TCP_header.SequenceNumber] + jb .no_timestamp + test [ebx + TCP_header.Flags], TH_SYN or TH_FIN ; syn and fin occupy one byte + jz @f + dec eax + @@: + sub eax, ecx + jae .no_timestamp + + DEBUGF 1,"Recording timestamp\n" + + mov eax, [esp + 4] ; tcp_now + mov [ebx + TCP_SOCKET.ts_recent_age], eax + mov eax, [ebx + TCP_SOCKET.ts_val] + mov [ebx + TCP_SOCKET.ts_recent], eax + .no_timestamp: + +;------------------ +; Process RST flags + + test [edx + TCP_header.Flags], TH_RST + jz .no_rst + + DEBUGF 1,"TCP_input: Got an RST flag\n" + + mov eax, [ebx + TCP_SOCKET.t_state] + shl eax, 2 + jmp dword [eax + .rst_sw_list] + + .rst_sw_list: + dd .no_rst ; TCPS_CLOSED + dd .no_rst ; TCPS_LISTEN + dd .no_rst ; TCPS_SYN_SENT + dd .econnrefused ; TCPS_SYN_RECEIVED + dd .econnreset ; TCPS_ESTABLISHED + dd .econnreset ; TCPS_CLOSE_WAIT + dd .econnreset ; TCPS_FIN_WAIT_1 + dd .rst_close ; TCPS_CLOSING + dd .rst_close ; TCPS_LAST_ACK + dd .econnreset ; TCPS_FIN_WAIT_2 + dd .rst_close ; TCPS_TIMED_WAIT + + .econnrefused: + DEBUGF 1,"TCP_input: Connection refused\n" + + mov [ebx + SOCKET.errorcode], ECONNREFUSED + jmp .close + + .econnreset: + DEBUGF 1,"TCP_input: Connection reset\n" + + mov [ebx + SOCKET.errorcode], ECONNRESET + + .close: + DEBUGF 1,"TCP_input: Closing connection\n" + + mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSED +;;; TODO: update stats (tcp drops) + mov eax, ebx + call TCP_close + jmp .drop_no_socket + + .rst_close: + DEBUGF 1,"TCP_input: Closing with reset\n" + + mov eax, ebx + call TCP_close + jmp .drop_no_socket + + .no_rst: + +;-------------------------------------- +; handle SYN-full and ACK-less segments + + test [edx + TCP_header.Flags], TH_SYN + jz .not_syn_full + + mov eax, ebx + mov ebx, ECONNRESET + call TCP_drop + jmp .drop_with_reset + .not_syn_full: + +;--------------- +; ACK processing + + test [edx + TCP_header.Flags], TH_ACK + jz .drop + + cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED + jb .ack_processed ; states: closed, listen, syn_sent + ja .no_syn_rcv ; established, fin_wait_1, fin_wait_2, close_wait, closing, last_ack, time_wait + + DEBUGF 1,"TCP_input: state=syn_received\n" + + mov eax, [edx + TCP_header.AckNumber] + cmp [ebx + TCP_SOCKET.SND_UNA], eax + ja .drop_with_reset + cmp eax, [ebx + TCP_SOCKET.SND_MAX] + ja .drop_with_reset + +;;; TODO: update stats + + mov eax, ebx + call SOCKET_is_connected + mov [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED + +; Do window scaling? + + test [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE + jz @f + test [ebx + TCP_SOCKET.t_flags], TF_REQ_SCALE + jz @f + + push word [ebx + TCP_SOCKET.requested_s_scale] ; Set send and receive scale factors to the received values + pop word [ebx + TCP_SOCKET.SND_SCALE] + @@: + +;;; TODO: call TCP_reassemble + + mov eax, [edx + TCP_header.SequenceNumber] + dec eax + mov [ebx + TCP_SOCKET.SND_WL1], eax + + .no_syn_rcv: + +;------------------------- +; check for duplicate ACKs + + mov eax, [edx + TCP_header.AckNumber] + cmp eax, [ebx + TCP_SOCKET.SND_UNA] + ja .not_dup_ack + + test ecx, ecx + jnz .reset_dupacks + + mov eax, dword [edx + TCP_header.Window] + cmp eax, [ebx + TCP_SOCKET.SND_WND] + jne .reset_dupacks + + DEBUGF 1,"TCP_input: Processing duplicate ACK\n" + +; If we have outstanding data, other than a window probe, this is a completely duplicate ACK +; (window info didnt change) The ACK is the biggest we've seen and we've seen exactly our rexmt threshold of them, +; assume a packet has been dropped and retransmit it. Kludge snd_nxt & the congestion window so we send only this one packet. + + cmp [ebx + TCP_SOCKET.timer_retransmission], 0 ;;;; FIXME + jg @f + + mov eax, [edx + TCP_header.AckNumber] + cmp eax, [ebx + TCP_SOCKET.SND_UNA] + je .dup_ack + + @@: + mov [ebx + TCP_SOCKET.t_dupacks], 0 + jmp .not_dup_ack + + .dup_ack: + inc [ebx + TCP_SOCKET.t_dupacks] + cmp [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh + jne .no_re_xmit + + push [ebx + TCP_SOCKET.SND_NXT] ; >>>> + + mov eax, [ebx + TCP_SOCKET.SND_WND] + cmp eax, [ebx + TCP_SOCKET.SND_CWND] + cmova eax, [ebx + TCP_SOCKET.SND_CWND] + shr eax, 1 + push edx + xor edx, edx + div [ebx + TCP_SOCKET.t_maxseg] + cmp eax, 2 + ja @f + xor eax, eax + mov al, 2 + @@: + mul [ebx + TCP_SOCKET.t_maxseg] + pop edx + mov [ebx + TCP_SOCKET.SND_SSTHRESH], eax + + mov [ebx + TCP_SOCKET.timer_retransmission], 0 ; turn off retransmission timer + mov [ebx + TCP_SOCKET.t_rtt], 0 + mov eax, [edx + TCP_header.AckNumber] + mov [ebx + TCP_SOCKET.SND_NXT], eax + mov eax, [ebx + TCP_SOCKET.t_maxseg] + mov [ebx + TCP_SOCKET.SND_CWND], eax + +; Unlock the socket + push ebx + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + +; retransmit missing segment + mov eax, [esp] + call TCP_output + +; Lock the socket again + mov ecx, [esp] + add ecx, SOCKET.mutex + call mutex_lock + pop ebx + +; Continue processing + xor edx, edx + mov eax, [ebx + TCP_SOCKET.t_maxseg] + mul [ebx + TCP_SOCKET.t_dupacks] + add eax, [ebx + TCP_SOCKET.SND_SSTHRESH] + mov [ebx + TCP_SOCKET.SND_CWND], eax + + pop eax ; <<<< + cmp eax, [ebx + TCP_SOCKET.SND_NXT] + jb @f + mov [ebx + TCP_SOCKET.SND_NXT], eax + @@: + + jmp .drop + + + .no_re_xmit: + jbe .not_dup_ack + + DEBUGF 1,"TCP_input: Increasing congestion window\n" + + mov eax, [ebx + TCP_SOCKET.t_maxseg] + add [ebx + TCP_SOCKET.SND_CWND], eax + +; Unlock the socket + push ebx + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + +; retransmit missing segment + mov eax, [esp] + call TCP_output + +; Lock the socket again + mov ecx, [esp] + add ecx, SOCKET.mutex + call mutex_lock + pop ebx + + jmp .drop + + + .not_dup_ack: + +;------------------------------------------------- +; If the congestion window was inflated to account +; for the other side's cached packets, retract it + + mov eax, [ebx + TCP_SOCKET.SND_SSTHRESH] + cmp eax, [ebx + TCP_SOCKET.SND_CWND] + ja @f + cmp [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh + jbe @f + mov [ebx + TCP_SOCKET.SND_CWND], eax + @@: + + mov [ebx + TCP_SOCKET.t_dupacks], 0 + + mov eax, [edx + TCP_header.AckNumber] + cmp eax, [ebx + TCP_SOCKET.SND_MAX] + jbe @f + + ;;; TODO: update stats + jmp .drop_after_ack + + @@: + + mov edi, [edx + TCP_header.AckNumber] + sub edi, [ebx + TCP_SOCKET.SND_UNA] ; now we got the number of acked bytes in edi + + ;;; TODO: update stats + + DEBUGF 1,"TCP_input: acceptable ACK for %u bytes\n", edi + +;------------------------------------------ +; RTT measurements and retransmission timer (912-926) + +; If we have a timestamp, update smoothed RTT + + test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP + jz .timestamp_not_present + mov eax, [esp+4] + sub eax, [ebx + TCP_SOCKET.ts_ecr] + inc eax + call TCP_xmit_timer + jmp .rtt_done_ + +; If no timestamp but transmit timer is running and timed sequence number was acked, +; update smoothed RTT. Since we now have an RTT measurement, cancel the timer backoff +; (Phil Karn's retransmit algo) +; Recompute the initial retransmit timer + + .timestamp_not_present: + mov eax, [edx + TCP_header.AckNumber] + cmp eax, [ebx + TCP_SOCKET.t_rtseq] + jbe .rtt_done_ + mov eax, [ebx + TCP_SOCKET.t_rtt] + test eax, eax + jz .rtt_done_ + call TCP_xmit_timer + + .rtt_done_: + +; If all outstanding data is acked, stop retransmit timer and remember to restart (more output or persist) +; If there is more data to be acked, restart retransmit timer, using current (possible backed-off) value. + + mov eax, [ebx + TCP_SOCKET.SND_MAX] + cmp eax, [edx + TCP_header.AckNumber] + jne .more_data + mov [ebx + TCP_SOCKET.timer_retransmission], 0 + or [ebx + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT + jmp .no_restart + .more_data: + cmp [ebx + TCP_SOCKET.timer_persist], 0 + jne .no_restart + + mov eax, [ebx + TCP_SOCKET.t_rxtcur] + mov [ebx + TCP_SOCKET.timer_retransmission], eax + + .no_restart: + + +;------------------------------------------- +; Open congestion window in response to ACKs + + mov esi, [ebx + TCP_SOCKET.SND_CWND] + mov eax, [ebx + TCP_SOCKET.t_maxseg] + + cmp esi, [ebx + TCP_SOCKET.SND_SSTHRESH] + jbe @f + push edx + push eax + mul eax + div esi + pop edx + shr edx, 3 + add eax, edx + pop edx + @@: + + add esi, eax + + push ecx + mov cl, [ebx + TCP_SOCKET.SND_SCALE] + mov eax, TCP_max_win + shl eax, cl + pop ecx + + cmp esi, eax + cmova esi, eax + mov [ebx + TCP_SOCKET.SND_CWND], esi + +;------------------------------------------ +; Remove acknowledged data from send buffer + + cmp edi, [ebx + STREAM_SOCKET.snd.size] + jbe .finiacked + + push ecx edx ebx + mov ecx, [ebx + STREAM_SOCKET.snd.size] + lea eax, [ebx + STREAM_SOCKET.snd] + sub [ebx + TCP_SOCKET.SND_WND], ecx + call SOCKET_ring_free + pop ebx edx ecx + + DEBUGF 1,"TCP_input: our FIN is acked\n" + stc + + jmp .wakeup + + .finiacked: + + push ecx edx ebx + mov ecx, edi + lea eax, [ebx + STREAM_SOCKET.snd] + call SOCKET_ring_free + pop ebx + sub [ebx + TCP_SOCKET.SND_WND], ecx + pop edx ecx + + DEBUGF 1,"TCP_input: our FIN is not acked\n" + clc + +;---------------------------------------- +; Wake up process waiting on send buffer + + .wakeup: + + pushf ; Keep the flags (Carry flag) + mov eax, ebx + call SOCKET_notify + +; Update TCPS + + mov eax, [edx + TCP_header.AckNumber] + mov [ebx + TCP_SOCKET.SND_UNA], eax + cmp eax, [ebx + TCP_SOCKET.SND_NXT] + jb @f + mov [ebx + TCP_SOCKET.SND_NXT], eax + @@: + + popf + +; General ACK handling complete +; Now do the state-specific ones +; Carry flag is set when our FIN is acked + + mov eax, [ebx + TCP_SOCKET.t_state] + jmp dword [eax*4 + .ACK_sw_list] + + .ACK_sw_list: + dd .ack_processed ; TCPS_CLOSED + dd .ack_processed ; TCPS_LISTEN + dd .ack_processed ; TCPS_SYN_SENT + dd .ack_processed ; TCPS_SYN_RECEIVED + dd .ack_processed ; TCPS_ESTABLISHED + dd .ack_processed ; TCPS_CLOSE_WAIT + dd .ack_fw1 ; TCPS_FIN_WAIT_1 + dd .ack_c ; TCPS_CLOSING + dd .ack_la ; TCPS_LAST_ACK + dd .ack_processed ; TCPS_FIN_WAIT_2 + dd .ack_tw ; TCPS_TIMED_WAIT + + + .ack_fw1: + jnc .ack_processed + + test [ebx + SOCKET.state], SS_CANTRCVMORE + jnz @f + mov eax, ebx + call SOCKET_is_disconnected + mov [ebx + TCP_SOCKET.timer_timed_wait], TCP_time_max_idle + @@: + mov [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2 + jmp .ack_processed + + .ack_c: + jnc .ack_processed + + mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT + mov eax, ebx + call TCP_cancel_timers + mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL + mov eax, ebx + call SOCKET_is_disconnected + jmp .ack_processed + + .ack_la: + jnc .ack_processed + + mov eax, ebx + call TCP_disconnect + jmp .drop + + .ack_tw: + mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL + jmp .drop_after_ack + + .reset_dupacks: ; We got a new ACK, reset duplicate ACK counter + mov [ebx + TCP_SOCKET.t_dupacks], 0 + jmp .ack_processed + +;------- +; LISTEN + +align 4 + .LISTEN: + + DEBUGF 1,"TCP_input: state=listen\n" + + test [edx + TCP_header.Flags], TH_RST + jnz .drop + + test [edx + TCP_header.Flags], TH_ACK + jnz .drop_with_reset + + test [edx + TCP_header.Flags], TH_SYN + jz .drop + +;;; TODO: check if it's a broadcast or multicast, and drop if so + + push dword [edi] ; Ipv4 source addres + pop [ebx + IP_SOCKET.RemoteIP] + + push [edx + TCP_header.SourcePort] + pop [ebx + TCP_SOCKET.RemotePort] + + push [edx + TCP_header.SequenceNumber] + pop [ebx + TCP_SOCKET.IRS] + + mov eax, [TCP_sequence_num] + add [TCP_sequence_num], 64000 / 2 + mov [ebx + TCP_SOCKET.ISS], eax + mov [ebx + TCP_SOCKET.SND_NXT], eax + + TCP_sendseqinit ebx + TCP_rcvseqinit ebx + + mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED + mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW + mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval ;;;; macro + + lea eax, [ebx + STREAM_SOCKET.snd] + call SOCKET_ring_create + + lea eax, [ebx + STREAM_SOCKET.rcv] + call SOCKET_ring_create + + and [ebx + TCP_SOCKET.temp_bits], not TCP_BIT_DROPSOCKET + +;;; call SOCKET_notify_owner + + jmp .trim_then_step6 + +;------------ +; Active Open + +align 4 + .SYN_SENT: + + DEBUGF 1,"TCP_input: state=syn_sent\n" + + test [edx + TCP_header.Flags], TH_ACK + jz @f + + mov eax, [edx + TCP_header.AckNumber] + cmp eax, [ebx + TCP_SOCKET.ISS] + jbe .drop_with_reset + + cmp eax, [ebx + TCP_SOCKET.SND_MAX] + ja .drop_with_reset + @@: + + test [edx + TCP_header.Flags], TH_RST + jz @f + + test [edx + TCP_header.Flags], TH_ACK + jz .drop + + mov eax, ebx + mov ebx, ECONNREFUSED + call TCP_drop + + jmp .drop + @@: + + test [edx + TCP_header.Flags], TH_SYN + jz .drop + +; at this point, segment seems to be valid + + test [edx + TCP_header.Flags], TH_ACK + jz .no_syn_ack + +; now, process received SYN in response to an active open + + mov eax, [edx + TCP_header.AckNumber] + mov [ebx + TCP_SOCKET.SND_UNA], eax + cmp eax, [ebx + TCP_SOCKET.SND_NXT] + jbe @f + mov [ebx + TCP_SOCKET.SND_NXT], eax + @@: + + .no_syn_ack: + mov [ebx + TCP_SOCKET.timer_retransmission], 0 ; disable retransmission + + push [edx + TCP_header.SequenceNumber] + pop [ebx + TCP_SOCKET.IRS] + + TCP_rcvseqinit ebx + + or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW + + mov eax, [ebx + TCP_SOCKET.SND_UNA] + cmp eax, [ebx + TCP_SOCKET.ISS] + jbe .simultaneous_open + + test [edx + TCP_header.Flags], TH_ACK + jz .simultaneous_open + + DEBUGF 1,"TCP_input: active open\n" + +;;; TODO: update stats + +; set socket state to connected + mov [ebx + SOCKET.state], SS_ISCONNECTED + mov [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED + +; Do window scaling on this connection ? + mov eax, [ebx + TCP_SOCKET.t_flags] + and eax, TF_REQ_SCALE or TF_RCVD_SCALE + cmp eax, TF_REQ_SCALE or TF_RCVD_SCALE + jne .no_scaling + + mov ax, word [ebx + TCP_SOCKET.requested_s_scale] + mov word [ebx + TCP_SOCKET.SND_SCALE], ax + .no_scaling: + +;;; TODO: reassemble packets queue + + mov eax, [ebx + TCP_SOCKET.t_rtt] + test eax, eax + je .trim_then_step6 + call TCP_xmit_timer + jmp .trim_then_step6 + + .simultaneous_open: + + DEBUGF 1,"TCP_input: simultaneous open\n" +; We have received a syn but no ACK, so we are having a simultaneous open.. + mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED + +;------------------------------------- +; Common processing for receipt of SYN + + .trim_then_step6: + + inc [edx + TCP_header.SequenceNumber] + +;;; TODO: Drop any received data that follows receive window (590) + + mov eax, [edx + TCP_header.SequenceNumber] + mov [ebx + TCP_SOCKET.RCV_UP], eax + dec eax + mov [ebx + TCP_SOCKET.SND_WL1], eax + +;------- +; step 6 + + .ack_processed: + + DEBUGF 1,"TCP_input: ACK processed\n" + +;---------------------------------------------- +; check if we need to update window information + + test [edx + TCP_header.Flags], TH_ACK + jz .no_window_update + + mov eax, [ebx + TCP_SOCKET.SND_WL1] + cmp eax, [edx + TCP_header.SequenceNumber] + jb .update_window + ja @f + + mov eax, [ebx + TCP_SOCKET.SND_WL2] + cmp eax, [edx + TCP_header.AckNumber] + jb .update_window + ja .no_window_update + @@: + + mov eax, dword [edx + TCP_header.Window] + cmp eax, [ebx + TCP_SOCKET.SND_WND] + jbe .no_window_update + + .update_window: + +;;; TODO: update stats (Keep track of pure window updates) + + mov eax, dword [edx + TCP_header.Window] + cmp eax, [ebx + TCP_SOCKET.max_sndwnd] + jbe @f + mov [ebx + TCP_SOCKET.max_sndwnd], eax + @@: + mov [ebx + TCP_SOCKET.SND_WND], eax + + DEBUGF 1,"TCP_input: Updating window to %u\n", eax + + push [edx + TCP_header.SequenceNumber] + pop [ebx + TCP_SOCKET.SND_WL1] + + push [edx + TCP_header.AckNumber] + pop [ebx + TCP_SOCKET.SND_WL2] + + or [ebx + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT + + .no_window_update: + +;----------------- +; process URG flag + + test [edx + TCP_header.Flags], TH_URG + jz .not_urgent + + cmp [edx + TCP_header.UrgentPointer], 0 + jz .not_urgent + + cmp [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT + je .not_urgent + +; Ignore bogus urgent offsets + + movzx eax, [edx + TCP_header.UrgentPointer] + add eax, [ebx + STREAM_SOCKET.rcv.size] + cmp eax, SOCKET_MAXDATA + jbe .not_urgent + + mov [edx + TCP_header.UrgentPointer], 0 + and [edx + TCP_header.Flags], not (TH_URG) + jmp .do_data + + .not_urgent: + +; processing of received urgent pointer + + ;;; TODO (1051-1093) + + +;--------------------------------------- +; process the data in the segment (1094) + + .do_data: + + cmp [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT + jae .final_processing + + test [edx + TCP_header.Flags], TH_FIN + jnz @f + + test ecx, ecx + jnz .final_processing + @@: + + +; The segment is in order? + mov eax, [edx + TCP_header.SequenceNumber] + cmp eax, [ebx + TCP_SOCKET.RCV_NXT] + jne .out_of_order + +; The reassembly queue is empty? + cmp [ebx + TCP_SOCKET.seg_next], 0 + jne .out_of_order + +; The connection is established? + cmp [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED + jne .out_of_order + +; Ok, lets do this.. Set delayed ACK flag and copy data into socket buffer + or [ebx + TCP_SOCKET.t_flags], TF_DELACK + + pusha + movzx esi, [edx + TCP_header.DataOffset] + add esi, edx + lea eax, [ebx + STREAM_SOCKET.rcv] + call SOCKET_ring_write ; Add the data to the socket buffer + add [ebx + TCP_SOCKET.RCV_NXT], ecx ; Update sequence number with number of bytes we have copied + popa + +; Wake up the sleeping process + mov eax, ebx + call SOCKET_notify + + jmp .data_done + + .out_of_order: + +; Uh-oh, some data is out of order, lets call TCP reassemble for help + + call TCP_reassemble + + DEBUGF 1, "1470\n" + or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW + + .data_done: + +;--------------- +; FIN processing + + test [edx + TCP_header.Flags], TH_FIN + jz .final_processing + + DEBUGF 1,"TCP_input: Processing FIN\n" + + cmp [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT + jae .not_first_fin + + DEBUGF 1,"TCP_input: First FIN for this connection\n" + + mov eax, ebx + call SOCKET_cant_recv_more + + mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW + inc [ebx + TCP_SOCKET.RCV_NXT] + + .not_first_fin: + mov eax, [ebx + TCP_SOCKET.t_state] + shl eax, 2 + jmp dword [eax + .FIN_sw_list] + + .FIN_sw_list: + dd .final_processing ; TCPS_CLOSED + dd .final_processing ; TCPS_LISTEN + dd .final_processing ; TCPS_SYN_SENT + dd .fin_syn_est ; TCPS_SYN_RECEIVED + dd .fin_syn_est ; TCPS_ESTABLISHED + dd .final_processing ; TCPS_CLOSE_WAIT + dd .fin_wait1 ; TCPS_FIN_WAIT_1 + dd .final_processing ; TCPS_CLOSING + dd .final_processing ; TCPS_LAST_ACK + dd .fin_wait2 ; TCPS_FIN_WAIT_2 + dd .fin_timed ; TCPS_TIMED_WAIT + + .fin_syn_est: + + mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT + jmp .final_processing + + .fin_wait1: + + mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSING + jmp .final_processing + + .fin_wait2: + + mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT + mov eax, ebx + call TCP_cancel_timers + mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL + call SOCKET_is_disconnected + jmp .final_processing + + .fin_timed: + mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL + jmp .final_processing + + + .drop_after_ack: + DEBUGF 1,"TCP_input: Drop after ACK\n" + + push edx ebx + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + pop eax edx + + test [edx + TCP_header.Flags], TH_RST + jnz .dumpit + + or [eax + TCP_SOCKET.t_flags], TF_ACKNOW + jmp .need_output + + .drop_with_reset: + DEBUGF 1,"TCP_input: Drop with reset\n" + + push ebx edx + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + pop edx ebx + + test [edx + TCP_header.Flags], TH_RST + jnz .dumpit + + ;;; if its a multicast/broadcast, also drop + + test [edx + TCP_header.Flags], TH_ACK + jnz .respond_ack + + test [edx + TCP_header.Flags], TH_SYN + jnz .respond_syn + jmp .dumpit + +;----------------- +; Final processing + + .final_processing: + DEBUGF 1,"TCP_input: Final processing\n" + + push ebx + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + pop eax + + test [eax + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT + jnz .need_output + + test [eax + TCP_SOCKET.t_flags], TF_ACKNOW + jz .dumpit + DEBUGF 1,"TCP_input: ACK now!\n" + + .need_output: + DEBUGF 1,"TCP_input: need output\n" + call TCP_output + + .dumpit: + DEBUGF 1,"TCP_input: dumping\n" + + call kernel_free + add esp, 4 + jmp .loop + +;--------- +; Respond + + .respond_ack: + push ebx + mov cl, TH_RST + call TCP_respond + pop ebx + jmp .destroy_new_socket + + .respond_syn: + push ebx + mov cl, TH_RST + TH_ACK + call TCP_respond + pop ebx + jmp .destroy_new_socket + + .respond_seg_reset: + test [edx + TCP_header.Flags], TH_RST + jnz .drop_no_socket + + ;;; TODO: if its a multicast/broadcast, also drop + + test [edx + TCP_header.Flags], TH_ACK + jnz .respond_seg_ack + + test [edx + TCP_header.Flags], TH_SYN + jnz .respond_seg_syn + + jmp .drop_no_socket + + .respond_seg_ack: + mov cl, TH_RST + call TCP_respond_segment + jmp .drop_no_socket + + .respond_seg_syn: + mov cl, TH_RST + TH_ACK + call TCP_respond_segment + jmp .drop_no_socket + +;----- +; Drop + + .drop: + DEBUGF 1,"TCP_input: Dropping segment\n" + + pusha + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + popa + + .destroy_new_socket: + test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET + jz .drop_no_socket + + mov eax, ebx + call SOCKET_free + + .drop_no_socket: + DEBUGF 1,"TCP_input: Drop (no socket)\n" + + call kernel_free + add esp, 4 + jmp .loop diff --git a/kernel/trunk/network/tcp_output.inc b/kernel/trunk/network/tcp_output.inc new file mode 100644 index 0000000000..9f3d588859 --- /dev/null +++ b/kernel/trunk/network/tcp_output.inc @@ -0,0 +1,621 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Part of the TCP/IP network stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; Based on the code of 4.4BSD ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 3289 $ + +;----------------------------------------------------------------- +; +; TCP_output +; +; IN: eax = socket pointer +; +; OUT: / +; +;----------------------------------------------------------------- +align 4 +TCP_output: + + DEBUGF 1,"TCP_output: socket=%x\n", eax + + push eax + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + pop eax + +; We'll detect the length of the data to be transmitted, and flags to be used +; If there is some data, or any critical controls to send (SYN / RST), then transmit +; Otherwise, investigate further + + mov ebx, [eax + TCP_SOCKET.SND_MAX] + cmp ebx, [eax + TCP_SOCKET.SND_UNA] + jbe .not_idle + + mov ebx, [eax + TCP_SOCKET.t_idle] + cmp ebx, [eax + TCP_SOCKET.t_rxtcur] + jbe .not_idle + +; We have been idle for a while and no ACKS are expected to clock out any data we send.. +; Slow start to get ack "clock" running again. + + mov ebx, [eax + TCP_SOCKET.t_maxseg] + mov [eax + TCP_SOCKET.SND_CWND], ebx + + .not_idle: + .again: + mov [eax + TCP_SOCKET.temp_bits], 0 + + mov ebx, [eax + TCP_SOCKET.SND_NXT] ; calculate offset (71) + sub ebx, [eax + TCP_SOCKET.SND_UNA] ; + + mov ecx, [eax + TCP_SOCKET.SND_WND] ; determine window + cmp ecx, [eax + TCP_SOCKET.SND_CWND] ; + jb @f ; + mov ecx, [eax + TCP_SOCKET.SND_CWND] ; + @@: ; + + call TCP_outflags ; flags in dl + +;------------------------ +; data being forced out ? + +; If in persist timeout with window of 0, send 1 byte. +; Otherwise, if window is small but nonzero, and timer expired, +; we will send what we can and go to transmit state + + cmp [eax + TCP_SOCKET.t_force], 0 + je .no_force + + DEBUGF 1,"TCP_output: forcing data out\n" + + test ecx, ecx + jnz .no_zero_window + + cmp ebx, [eax + STREAM_SOCKET.snd.size] + jae @f + + and dl, not (TH_FIN) + + @@: + inc ecx + jmp .no_force + + .no_zero_window: + mov [eax + TCP_SOCKET.timer_persist], 0 + mov [eax + TCP_SOCKET.t_rxtshift], 0 + + .no_force: + +;-------------------------------- +; Calculate how much data to send (106) + + mov esi, [eax + STREAM_SOCKET.snd.size] + cmp esi, ecx + jb @f + mov esi, ecx + @@: + sub esi, ebx + + +;------------------------ +; check for window shrink (107) + +; If FIN has been set, but not ACKed, but we havent been called to retransmit, esi will be -1 +; Otherwise, window shrank after we sent into it. + + jae .not_persist + +; enter persist state + xor esi, esi + +; If window shrank to 0 + test ecx, ecx + jnz @f + +; cancel pending retransmit + mov [eax + TCP_SOCKET.timer_retransmission], 0 + +; pull SND_NXT back to (closed) window, We will enter persist state below. + push [eax + TCP_SOCKET.SND_UNA] + pop [eax + TCP_SOCKET.SND_NXT] + @@: + +; If window didn't close completely, just wait for an ACK + + .not_persist: + +;--------------------------- +; Send one segment at a time (124) + + cmp esi, [eax + TCP_SOCKET.t_maxseg] + jbe @f + + mov esi, [eax + TCP_SOCKET.t_maxseg] + or [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT + @@: + +;-------------------------------------------- +; Turn of FIN flag if send buffer not emptied (128) + + mov edi, [eax + TCP_SOCKET.SND_NXT] + add edi, esi + sub edi, [eax + TCP_SOCKET.SND_UNA] + cmp edi, [eax + STREAM_SOCKET.snd.size] + jae @f + and dl, not (TH_FIN) + + @@: + +;------------------------------- +; calculate window advertisement (130) + + mov ecx, SOCKET_MAXDATA + sub ecx, [eax + STREAM_SOCKET.rcv.size] + +;------------------------------ +; Sender silly window avoidance (131) + + test esi, esi + jz .len_zero + + cmp esi, [eax + TCP_SOCKET.t_maxseg] + je TCP_send + + add ebx, esi ; offset + length + cmp ebx, [eax + STREAM_SOCKET.snd.size] + jb @f + + test [eax + TCP_SOCKET.t_flags], TF_NODELAY + jnz TCP_send + + mov ebx, [eax + TCP_SOCKET.SND_MAX] + cmp ebx, [eax + TCP_SOCKET.SND_UNA] + je TCP_send + @@: + + test [eax + TCP_SOCKET.t_force], -1 ;;; + jnz TCP_send + + mov ebx, [eax + TCP_SOCKET.max_sndwnd] + shr ebx, 1 + cmp esi, ebx + jae TCP_send + + mov ebx, [eax + TCP_SOCKET.SND_NXT] + cmp ebx, [eax + TCP_SOCKET.SND_MAX] + jb TCP_send + + .len_zero: + +;---------------------------------------- +; Check if a window update should be sent (154) + + DEBUGF 1,"TCP_output: window=%d\n", ecx + +; Compare available window to amount of window known to peer (as advertised window less next expected input) +; If the difference is at least two max size segments, or at least 50% of the maximum possible window, +; Then we want to send a window update to the peer. + + test ecx, ecx + jz .no_window + + push ecx + mov cl, [eax + TCP_SOCKET.RCV_SCALE] + mov ebx, TCP_max_win + shl ebx, cl + pop ecx + cmp ebx, ecx + jb @f + mov ebx, ecx + @@: + sub ebx, [eax + TCP_SOCKET.RCV_ADV] + add ebx, [eax + TCP_SOCKET.RCV_NXT] + + mov edi, [eax + TCP_SOCKET.t_maxseg] + shl edi, 1 + +; cmp ebx, edi +; jae TCP_send + +; cmp ebx, [eax + TCP_SOCKET.] ;;; TODO: check with receive buffer high water mark +; jae TCP_send + + .no_window: + +;-------------------------- +; Should a segment be sent? (174) + + DEBUGF 1,"TCP_output: 174\n" + + test [eax + TCP_SOCKET.t_flags], TF_ACKNOW ; we need to ACK + jnz TCP_send + + test dl, TH_SYN + TH_RST ; we need to send a SYN or RST + jnz TCP_send + + mov ebx, [eax + TCP_SOCKET.SND_UP] ; when urgent pointer is beyond start of send bufer + cmp ebx, [eax + TCP_SOCKET.SND_UNA] + ja TCP_send + + test dl, TH_FIN + jz .enter_persist ; no reason to send, enter persist state + +; FIN was set, only send if not already sent, or on retransmit + + test [eax + TCP_SOCKET.t_flags], TF_SENTFIN + jz TCP_send + + mov ebx, [eax + TCP_SOCKET.SND_NXT] + cmp ebx, [eax + TCP_SOCKET.SND_UNA] + je TCP_send + +;-------------------- +; Enter persist state (191) + + .enter_persist: + + cmp [eax + STREAM_SOCKET.snd.size], 0 ; Data ready to send? + jne @f + cmp [eax + TCP_SOCKET.timer_retransmission], 0 + jne @f + cmp [eax + TCP_SOCKET.timer_persist], 0 ; Persist timer already expired? + jne @f + + DEBUGF 1,"TCP_output: Entering persist state\n" + + mov [eax + TCP_SOCKET.t_rxtshift], 0 + call TCP_set_persist + @@: + +;---------------------------- +; No reason to send a segment (219) + + DEBUGF 1,"TCP_output: No reason to send a segment\n" + + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_unlock + popa + +; Fixme: returnvalue? + + ret + + + + + + + + + +;----------------------------------------------- +; +; Send a segment (222) +; +; eax = socket pointer +; esi = data len +; dl = flags +; +;----------------------------------------------- +align 4 +TCP_send: + + DEBUGF 1,"TCP_send: socket=%x length=%u flags=%x\n", eax, esi, dl + + push eax ; save socket ptr + push esi ; and data length too + mov edi, sizeof.TCP_header ; edi will contain headersize + +;------------------------------------ +; Send options with first SYN segment + + test dl, TH_SYN + jz .options_done + + push [eax + TCP_SOCKET.ISS] + pop [eax + TCP_SOCKET.SND_NXT] + + test [eax + TCP_SOCKET.t_flags], TF_NOOPT + jnz .options_done + + mov ecx, 1460 ;;;; FIXME: use routing blablabla to determine MSS + or ecx, TCP_OPT_MAXSEG shl 24 + 4 shl 16 + bswap ecx + push ecx + add di, 4 + + DEBUGF 1,"TCP_send: added maxseg option\n" + + test [eax + TCP_SOCKET.t_flags], TF_REQ_SCALE + jz .no_scale + + test dl, TH_ACK + jz .scale_opt + + test [eax + TCP_SOCKET.t_flags], TF_RCVD_SCALE + jz .no_scale + + .scale_opt: + mov cl, [eax + TCP_SOCKET.request_r_scale] + mov ch, TCP_OPT_NOP + pushw cx + pushw TCP_OPT_WINDOW + 3 shl 8 + add di, 4 + + DEBUGF 1,"TCP_send: added scale option\n" + + .no_scale: + .no_syn: + +;------------------------------------ +; Make the timestamp option if needed + + test [eax + TCP_SOCKET.t_flags], TF_REQ_TSTMP + jz .no_timestamp + + test dl, TH_RST + jnz .no_timestamp + + test dl, TH_ACK + jz .timestamp + + test [eax + TCP_SOCKET.t_flags], TF_RCVD_TSTMP + jz .no_timestamp + + .timestamp: + pushd 0 + pushd [timer_ticks] + pushd TCP_OPT_NOP + TCP_OPT_NOP shl 8 + TCP_OPT_TIMESTAMP shl 16 + 10 shl 24 + add di, 12 + + DEBUGF 1,"TCP_send: added timestamp\n" + + .no_timestamp: + + ; + + .options_done: + +; eax = socket ptr +; edx = flags +; edi = header size +; esi = data len + +;--------------------------------------------- +; check if we dont exceed the max segment size (270) + + add esi, edi ; total TCP segment size + cmp esi, [eax + TCP_SOCKET.t_maxseg] + jbe .no_overflow + + mov esi, [eax + TCP_SOCKET.t_maxseg] + or [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT + .no_overflow: + +;----------------------------------------------------------------- +; Start by pushing all TCP header values in reverse order on stack +; (essentially, creating the tcp header on the stack!) + + pushw 0 ; .UrgentPointer dw ? + pushw 0 ; .Checksum dw ? + pushw 0x00a0 ; .Window dw ? ;;;;;;; FIXME (370) + shl edi, 2 ; .DataOffset db ? only 4 left-most bits + shl dx, 8 + or dx, di ; .Flags db ? + pushw dx + shr edi, 2 ; .DataOffset db ? + + push [eax + TCP_SOCKET.RCV_NXT] ; .AckNumber dd ? + ntohd [esp] + + push [eax + TCP_SOCKET.SND_NXT] ; .SequenceNumber dd ? + ntohd [esp] + + push [eax + TCP_SOCKET.RemotePort] ; .DestinationPort dw ? + push [eax + TCP_SOCKET.LocalPort] ; .SourcePort dw ? + + push edi ; header size + +;--------------------- +; Create the IP packet + + mov ecx, esi + + mov ebx, [eax + SOCKET.device] + mov edx, [eax + IP_SOCKET.LocalIP] ; source ip + mov eax, [eax + IP_SOCKET.RemoteIP] ; dest ip + mov di, IP_PROTO_TCP shl 8 + 128 + call IPv4_output + jz .ip_error + +;----------------------------------------- +; Move TCP header from stack to TCP packet + + push ecx + mov ecx, [esp + 4] + lea esi, [esp + 8] + shr ecx, 2 ; count is in bytes, we will work with dwords + rep movsd + pop ecx ; full TCP packet size + + pop esi ; headersize + add esp, esi ; remove it from stack + + push edx ; packet size for send proc + push eax ; packet ptr for send proc + + mov edx, edi ; begin of data + sub edx, esi ; begin of packet (edi = begin of data) + push ecx + sub ecx, esi ; data size + +;-------------- +; Copy the data + +; eax = ptr to ring struct +; ecx = buffer size +; edi = ptr to buffer + + mov eax, [esp + 16] ; get socket ptr + + push edx + push [eax + TCP_SOCKET.SND_NXT] ; we'll need this for timing the transmission + test ecx, ecx + jz .nodata + mov edx, [eax + TCP_SOCKET.SND_NXT] + add [eax + TCP_SOCKET.SND_NXT], ecx ; update sequence number <<< CHECKME + sub edx, [eax + TCP_SOCKET.SND_UNA] ; offset + add eax, STREAM_SOCKET.snd + call SOCKET_ring_read + .nodata: + pop edi + pop esi ; begin of data + pop ecx ; full packet size + mov eax, [esp + 12] ; socket ptr + +;---------------------------------- +; initialize retransmit timer (400) + +;TODO: check t_force and persist + + test [esi + TCP_header.Flags], TH_SYN + TH_FIN ; syn and fin take a sequence number + jz @f + inc [eax + TCP_SOCKET.SND_NXT] + test [esi + TCP_header.Flags], TH_FIN + jz @f + or [eax + TCP_SOCKET.t_flags], TF_SENTFIN ; if we sent a fin, set the sentfin flag + @@: + + mov edx, [eax + TCP_SOCKET.SND_NXT] + cmp edx, [eax + TCP_SOCKET.SND_MAX] ; is this a retransmission? + jbe @f + mov [eax + TCP_SOCKET.SND_MAX], edx ; [eax + TCP_SOCKET.SND_NXT] from before we updated it + + cmp [eax + TCP_SOCKET.t_rtt], 0 ; are we currently timing anything? + je @f + mov [eax + TCP_SOCKET.t_rtt], 1 ; nope, start transmission timer + mov [eax + TCP_SOCKET.t_rtseq], edi +;TODO: update stats + @@: + +; set retransmission timer if not already set, and not doing an ACK or keepalive probe + + cmp [eax + TCP_SOCKET.timer_retransmission], 0 ;;;; FIXME + ja .retransmit_set + + cmp edx, [eax + TCP_SOCKET.SND_UNA] ; edx is still [eax + TCP_SOCKET.SND_NXT] + je .retransmit_set + + mov edx, [eax + TCP_SOCKET.t_rxtcur] + mov [eax + TCP_SOCKET.timer_retransmission], edx + + cmp [eax + TCP_SOCKET.timer_persist], 0 + jne .retransmit_set + mov [eax + TCP_SOCKET.timer_persist], 0 + mov [eax + TCP_SOCKET.t_rxtshift], 0 + + .retransmit_set: + +;-------------------- +; Create the checksum + + TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP) + mov [esi + TCP_header.Checksum], dx + +;---------------- +; Send the packet + + DEBUGF 1,"TCP_send: Sending with device %x\n", ebx + call [ebx + NET_DEVICE.transmit] + jnz .send_error + +;--------------- +; Ok, data sent! + + pop ecx + pop eax + + inc [TCP_segments_tx] ; FIXME: correct interface? + +; update advertised receive window + test ecx, ecx + jz @f + add ecx, [eax + TCP_SOCKET.RCV_NXT] + cmp ecx, [eax + TCP_SOCKET.RCV_ADV] + jbe @f + mov [eax + TCP_SOCKET.RCV_ADV], ecx + @@: + +; update last ack sent + push [eax + TCP_SOCKET.RCV_NXT] + pop [eax + TCP_SOCKET.last_ack_sent] + +; and flags + and [eax + TCP_SOCKET.t_flags], not (TF_ACKNOW + TF_DELACK) + +;-------------- +; unlock socket + + push eax + lea ecx, [eax + SOCKET.mutex] + call mutex_unlock + pop eax + +;----------------------------- +; Check if we need more output + + test [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT + jnz TCP_output.again + + DEBUGF 1,"TCP_send: success!\n" + + xor eax, eax + ret + + + .ip_error: + pop ecx + add esp, ecx + add esp, 4 + pop eax + + mov [eax + TCP_SOCKET.timer_retransmission], TCP_time_re_min + + lea ecx, [eax + SOCKET.mutex] + call mutex_unlock + + DEBUGF 1,"TCP_send: IP error\n" + + or eax, -1 + ret + + + .send_error: + add esp, 8 + + lea ecx, [eax + SOCKET.mutex] + call mutex_unlock + + DEBUGF 1,"TCP_send: sending failed\n" + + or eax, -2 + ret + + + + + + diff --git a/kernel/trunk/network/tcp_subr.inc b/kernel/trunk/network/tcp_subr.inc new file mode 100644 index 0000000000..eb133fb8fe --- /dev/null +++ b/kernel/trunk/network/tcp_subr.inc @@ -0,0 +1,546 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Part of the TCP/IP network stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; Based on the code of 4.4BSD ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 3514 $ + +align 4 +iglobal + TCP_backoff db 0,1,2,3,4,5,6,6,6,6,6,6,6 +endg + +macro TCP_checksum IP1, IP2 { + +;------------- +; Pseudoheader + + ; protocol type + mov edx, IP_PROTO_TCP + + ; source address + add dl, byte [IP1+1] + adc dh, byte [IP1+0] + adc dl, byte [IP1+3] + adc dh, byte [IP1+2] + + ; destination address + adc dl, byte [IP2+1] + adc dh, byte [IP2+0] + adc dl, byte [IP2+3] + adc dh, byte [IP2+2] + + ; size + adc dl, cl + adc dh, ch + + adc edx, 0 + +;--------------------- +; Real header and data + + push esi + call checksum_1 + call checksum_2 + pop esi + +} ; returns in dx only + + + + +macro TCP_sendseqinit ptr { + + push edi ;;;; i dont like this static use of edi + mov edi, [ptr + TCP_SOCKET.ISS] + mov [ptr + TCP_SOCKET.SND_UP], edi + mov [ptr + TCP_SOCKET.SND_MAX], edi + mov [ptr + TCP_SOCKET.SND_NXT], edi + mov [ptr + TCP_SOCKET.SND_UNA], edi + pop edi + +} + + + +macro TCP_rcvseqinit ptr { + + push edi + mov edi, [ptr + TCP_SOCKET.IRS] + inc edi + mov [ptr + TCP_SOCKET.RCV_NXT], edi + mov [ptr + TCP_SOCKET.RCV_ADV], edi + pop edi + +} + + + +macro TCP_init_socket socket { + + mov [socket + TCP_SOCKET.t_maxseg], TCP_mss_default + mov [socket + TCP_SOCKET.t_flags], TF_REQ_SCALE or TF_REQ_TSTMP + + mov [socket + TCP_SOCKET.t_srtt], TCP_time_srtt_default + mov [socket + TCP_SOCKET.t_rttvar], TCP_time_rtt_default * 4 + mov [socket + TCP_SOCKET.t_rttmin], TCP_time_re_min +;;; TODO: TCP_time_rangeset + + mov [socket + TCP_SOCKET.SND_CWND], TCP_max_win shl TCP_max_winshift + mov [socket + TCP_SOCKET.SND_SSTHRESH], TCP_max_win shl TCP_max_winshift + + +} + + +;--------------------------- +; +; TCP_pull_out_of_band +; +; IN: eax = +; ebx = socket ptr +; edx = tcp packet ptr +; +; OUT: / +; +;--------------------------- + +align 4 +TCP_pull_out_of_band: + + DEBUGF 1,"TCP_pull_out_of_band\n" + + ;;;; 1282-1305 + + ret + + + + + + + + +;------------------------- +; +; TCP_drop +; +; IN: eax = socket ptr +; ebx = error number +; +; OUT: eax = socket ptr +; +;------------------------- +align 4 +TCP_drop: + + DEBUGF 1,"TCP_drop: %x\n", eax + + cmp [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED + jb .no_syn_received + + mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED + + call TCP_output + +;;; TODO: update stats + + jmp TCP_close + + .no_syn_received: + +;;; TODO: update stats + +;;; TODO: check if error code is "Connection timed out' and handle accordingly + + mov [eax + SOCKET.errorcode], ebx + + + + + + + + +;------------------------- +; +; TCP_close +; +; IN: eax = socket ptr +; OUT: eax = socket ptr +; +;------------------------- +align 4 +TCP_close: + + DEBUGF 1,"TCP_close: %x\n", eax + +;;; TODO: update RTT and mean deviation +;;; TODO: update slow start threshold + + call SOCKET_is_disconnected + call SOCKET_free + + ret + + + + +;------------------------- +; +; TCP_outflags +; +; IN: eax = socket ptr +; +; OUT: edx = flags +; +;------------------------- +align 4 +TCP_outflags: + + mov edx, [eax + TCP_SOCKET.t_state] + movzx edx, byte [edx + .flaglist] + + DEBUGF 1,"TCP_outflags: socket=%x flags=%x\n", eax, dl + + ret + + .flaglist: + + db TH_RST + TH_ACK ; TCPS_CLOSED + db 0 ; TCPS_LISTEN + db TH_SYN ; TCPS_SYN_SENT + db TH_SYN + TH_ACK ; TCPS_SYN_RECEIVED + db TH_ACK ; TCPS_ESTABLISHED + db TH_ACK ; TCPS_CLOSE_WAIT + db TH_FIN + TH_ACK ; TCPS_FIN_WAIT_1 + db TH_FIN + TH_ACK ; TCPS_CLOSING + db TH_FIN + TH_ACK ; TCPS_LAST_ACK + db TH_ACK ; TCPS_FIN_WAIT_2 + db TH_ACK ; TCPS_TIMED_WAIT + + + + + + +;--------------------------------------- +; +; The fast way to send an ACK/RST/keepalive segment +; +; TCP_respond +; +; IN: ebx = socket ptr +; cl = flags +; +;-------------------------------------- +align 4 +TCP_respond: + + DEBUGF 1,"TCP_respond_socket: socket=%x flags=%x\n", ebx, cl + +;--------------------- +; Create the IP packet + + push cx ebx + mov eax, [ebx + IP_SOCKET.RemoteIP] + mov edx, [ebx + IP_SOCKET.LocalIP] + mov ecx, sizeof.TCP_header + mov di, IP_PROTO_TCP shl 8 + 128 + call IPv4_output + test edi, edi + jz .error + pop esi cx + push edx eax + +;----------------------------------------------- +; Fill in the TCP header by using the socket ptr + + mov ax, [esi + TCP_SOCKET.LocalPort] + stosw + mov ax, [esi + TCP_SOCKET.RemotePort] + stosw + mov eax, [esi + TCP_SOCKET.SND_NXT] + bswap eax + stosd + mov eax, [esi + TCP_SOCKET.RCV_NXT] + bswap eax + stosd + mov al, 0x50 ; Dataoffset: 20 bytes (TCP_header.DataOffset) + stosb + mov al, cl + stosb +; mov ax, [esi + TCP_SOCKET.RCV_WND] +; rol ax, 8 + mov ax, 0x00a0 ;;;;;;; FIXME + stosw ; window + xor eax, eax + stosd ; checksum + urgentpointer + +;--------------------- +; Fill in the checksum + + .checksum: + sub edi, sizeof.TCP_header + mov ecx, sizeof.TCP_header + xchg esi, edi + TCP_checksum (edi + IP_SOCKET.LocalIP), (edi + IP_SOCKET.RemoteIP) + mov [esi+TCP_header.Checksum], dx + +;-------------------- +; And send the segment + + call [ebx + NET_DEVICE.transmit] + ret + + .error: + DEBUGF 1,"TCP_respond_socket: failed\n" + add esp, 2 + 4 + + ret + + + + + + + + +;------------------------- +; TCP_respond_segment: +; +; IN: edx = segment ptr (a previously received segment) +; edi = ptr to dest and src IPv4 addresses +; cl = flags + +align 4 +TCP_respond_segment: + + DEBUGF 1,"TCP_respond_segment: frame=%x flags=%x\n", edx, cl + +;--------------------- +; Create the IP packet + + push cx edx + mov ebx, [edi + 4] + mov eax, [edi] + mov ecx, sizeof.TCP_header + mov di, IP_PROTO_TCP shl 8 + 128 + call IPv4_output + jz .error + pop esi cx + + push edx eax + +;--------------------------------------------------- +; Fill in the TCP header by using a received segment + + mov ax, [esi + TCP_header.DestinationPort] + stosw + mov ax, [esi + TCP_header.SourcePort] + stosw + mov eax, [esi + TCP_header.AckNumber] + bswap eax + stosd + xor eax, eax + stosd + mov al, 0x50 ; Dataoffset: 20 bytes (sizeof.TCP_header/4 shl 4) + stosb + mov al, cl + stosb + mov ax, 1280 + rol ax, 8 + stosw ; window + xor eax, eax + stosd ; checksum + urgentpointer + +;--------------------- +; Fill in the checksum + + lea esi, [edi - sizeof.TCP_header] + mov ecx, sizeof.TCP_header + TCP_checksum (esi - sizeof.IPv4_header + IPv4_header.DestinationAddress),\ ; FIXME + (esi - sizeof.IPv4_header + IPv4_header.SourceAddress) + mov [esi + TCP_header.Checksum], dx + +;-------------------- +; And send the segment + + call [ebx + NET_DEVICE.transmit] + ret + + .error: + DEBUGF 1,"TCP_respond_segment: failed\n" + add esp, 2+4 + + ret + + +macro TCPT_RANGESET timer, value, min, max { + +local .min +local .max +local .done + + cmp value, min + jb .min + cmp value, max + ja .max + + mov timer, value + jmp .done + + .min: + mov timer, value + jmp .done + + .max: + mov timer, value + jmp .done + + .done: +} + + +align 4 +TCP_set_persist: + + DEBUGF 1,"TCP_set_persist\n" + +; First, check if retransmit timer is not set, retransmit and persist are mutually exclusive + + cmp [eax + TCP_SOCKET.timer_retransmission], 0 + ja @f + +; calculate RTO + push ebx + mov ebx, [eax + TCP_SOCKET.t_srtt] + shr ebx, 2 + add ebx, [eax + TCP_SOCKET.t_rttvar] + shr ebx, 1 + + mov cl, [eax + TCP_SOCKET.t_rxtshift] + shl ebx, cl + +; Start/restart persistance timer. + + TCPT_RANGESET [eax + TCP_SOCKET.timer_persist], ebx, TCP_time_pers_min, TCP_time_pers_max + + pop ebx + + cmp [eax + TCP_SOCKET.t_rxtshift], TCP_max_rxtshift + jae @f + inc [eax + TCP_SOCKET.t_rxtshift] + @@: + + ret + + + +; eax = rtt +; ebx = socket ptr + +align 4 +TCP_xmit_timer: + + DEBUGF 1,"TCP_xmit_timer: socket=%x rtt=%d0ms\n", ebx, eax + +;TODO: update stats + + cmp [ebx + TCP_SOCKET.t_rtt], 0 + je .no_rtt_yet + +; srtt is stored as a fixed point with 3 bits after the binary point. +; The following magic is equivalent of the smoothing algorithm in rfc793 with an alpha of .875 +; (srtt = rtt/8 + srtt*7/8 in fixed point) +; Adjust rtt to origin 0. + + push ecx + mov ecx, [ebx + TCP_SOCKET.t_srtt] + shr ecx, TCP_RTT_SHIFT + sub eax, ecx + dec eax + pop ecx + + add [ebx + TCP_SOCKET.t_srtt], eax + ja @f + mov [ebx + TCP_SOCKET.t_srtt], 1 + @@: + +; We accumulate a smoothed rtt variance (actually, a smoothed mean difference), +; then set the retransmit timer to smoothed rtt + 4 times the smoothed variance. +; rttvar is stored as fixed point with 2 bits after the binary point. +; The following is equivalent to rfc793 smoothing with an alpha of .75 +; (rttvar = rttvar*3/4 + delta/4) (delta = eax) + +; get abs(eax) + push edx + cdq + xor eax, edx + sub eax, edx + + mov edx, [ebx + TCP_SOCKET.t_rttvar] + shr edx, TCP_RTTVAR_SHIFT + sub eax, edx + pop edx + + add [ebx + TCP_SOCKET.t_rttvar], eax + ja @f + mov [ebx + TCP_SOCKET.t_rttvar], 1 + @@: + ret + + + .no_rtt_yet: + + push ecx + mov ecx, eax + shl ecx, TCP_RTT_SHIFT + mov [ebx + TCP_SOCKET.t_srtt], ecx + + shl eax, TCP_RTTVAR_SHIFT - 1 + mov [ebx + TCP_SOCKET.t_rttvar], eax + pop ecx + + ret + + + + +; eax = max segment size +; ebx = socket ptr +align 4 +TCP_mss: + + cmp eax, 1420 ; FIXME + jbe @f + mov eax, 1420 + @@: + mov [ebx + TCP_SOCKET.t_maxseg], eax + + + ret + + + + +; ebx = socket ptr +; edx = segment ptr +align 4 +TCP_reassemble: + + + + ret + diff --git a/kernel/trunk/network/tcp_timer.inc b/kernel/trunk/network/tcp_timer.inc new file mode 100644 index 0000000000..2ab108a280 --- /dev/null +++ b/kernel/trunk/network/tcp_timer.inc @@ -0,0 +1,168 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Part of the TCP/IP network stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; Based on the code of 4.4BSD ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 3143 $ + +;---------------------- +; 160 ms timer +;---------------------- +macro TCP_timer_160ms { + +local .loop +local .exit + + mov ebx, net_sockets + .loop: + mov ebx, [ebx + SOCKET.NextPtr] + or ebx, ebx + jz .exit + + cmp [ebx + SOCKET.Domain], AF_INET4 + jne .loop + + cmp [ebx + SOCKET.Protocol], IP_PROTO_TCP + jne .loop + + test [ebx + TCP_SOCKET.t_flags], TF_DELACK + jz .loop + and [ebx + TCP_SOCKET.t_flags], not (TF_DELACK) + + push ebx + mov cl, TH_ACK + call TCP_respond +; and [ebx + TCP_SOCKET.t_flags], TF_ACKNOW ;; +; mov eax, ebx ;; +; call TCP_output ;; + pop ebx + + jmp .loop + + .exit: + +} + + +;---------------------- +; 640 ms timer +;---------------------- +macro TCP_timer_640ms { + +local .loop +local .exit + +; Update TCP sequence number + + add [TCP_sequence_num], 64000 + +; scan through all the active TCP sockets, decrementing ALL timers +; timers do not have the chance to wrap because the keepalive timer will kill the socket when it expires + + mov eax, net_sockets + .loop: + mov eax, [eax + SOCKET.NextPtr] + .check_only: + or eax, eax + jz .exit + + cmp [eax + SOCKET.Domain], AF_INET4 + jne .loop + + cmp [eax + SOCKET.Protocol], IP_PROTO_TCP + jne .loop + + inc [eax + TCP_SOCKET.t_idle] + dec [eax + TCP_SOCKET.timer_retransmission] + jnz .check_more2 + + DEBUGF 1,"socket %x: Retransmission timer expired\n", eax + + push eax + call TCP_output + pop eax + + .check_more2: + dec [eax + TCP_SOCKET.timer_keepalive] + jnz .check_more3 + + DEBUGF 1,"socket %x: Keepalive expired\n", eax + + cmp [eax + TCP_SOCKET.state], TCPS_ESTABLISHED + ja .dont_kill + + push eax + call TCP_disconnect + pop eax + jmp .loop + + .dont_kill: + test [eax + SOCKET.options], SO_KEEPALIVE + jz .reset_keepalive + + push eax + mov ebx, eax + xor cl, cl + call TCP_respond ; send keepalive + pop eax + mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval + jmp .check_more3 + + .reset_keepalive: + mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_idle + + .check_more3: + dec [eax + TCP_SOCKET.timer_timed_wait] + jnz .check_more5 + + DEBUGF 1,"socket %x: 2MSL timer expired\n", eax + + .check_more5: + dec [eax + TCP_SOCKET.timer_persist] + jnz .loop + + DEBUGF 1,"socket %x: persist timer expired\n", eax + + call TCP_set_persist + mov [eax + TCP_SOCKET.t_force], 1 + push eax + call TCP_output + pop eax + mov [eax + TCP_SOCKET.t_force], 0 + + jmp .loop + .exit: + +} + + + +; eax = socket + +TCP_cancel_timers: + + push eax edi + + lea edi, [eax + TCP_SOCKET.timer_retransmission] + xor eax, eax + stosd + stosd + stosd + stosd + stosd + + pop edi eax + + + ret \ No newline at end of file diff --git a/kernel/trunk/network/tcp_usreq.inc b/kernel/trunk/network/tcp_usreq.inc new file mode 100644 index 0000000000..b932c267f5 --- /dev/null +++ b/kernel/trunk/network/tcp_usreq.inc @@ -0,0 +1,102 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Part of the TCP/IP network stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; Based on the code of 4.4BSD ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +;------------------------- +; +; TCP_usrclose +; +; Move connection to next state, based on process close. +; +; IN: eax = socket ptr +; +;------------------------- +align 4 +TCP_usrclosed: + + DEBUGF 1,"TCP_usrclosed: %x\n", eax + + push ebx + mov ebx, [eax + TCP_SOCKET.t_state] + mov ebx, dword [.switch + ebx*4] + jmp ebx + + .switch: + + dd .close ; TCPS_CLOSED + dd .close ; TCPS_LISTEN + dd .close ; TCPS_SYN_SENT + dd .wait1 ; TCPS_SYN_RECEIVED + dd .wait1 ; TCPS_ESTABLISHED + dd .last_ack ; TCPS_CLOSE_WAIT + dd .ret ; TCPS_FIN_WAIT_1 + dd .ret ; TCPS_CLOSING + dd .ret ; TCPS_LAST_ACK + dd .disc ; TCPS_FIN_WAIT_2 + dd .disc ; TCPS_TIMED_WAIT + + + .close: + mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED + call TCP_close + pop ebx + ret + + .wait1: + mov [eax + TCP_SOCKET.t_state], TCPS_FIN_WAIT_1 + ; TODO: set timer? + pop ebx + ret + + .last_ack: + mov [eax + TCP_SOCKET.t_state], TCPS_LAST_ACK + pop ebx + ret + + .disc: + call SOCKET_is_disconnected + ; TODO: set timer? + .ret: + pop ebx + ret + + + + +;------------------------- +; +; TCP_disconnect +; +; IN: eax = socket ptr +; OUT: eax = socket ptr +; +;------------------------- +align 4 +TCP_disconnect: + + DEBUGF 1,"TCP_disconnect: %x\n", eax + + cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED + jb TCP_close + + +; TODO: implement LINGER ? + + call SOCKET_is_disconnecting + call TCP_usrclosed + call TCP_output + + ret \ No newline at end of file diff --git a/kernel/trunk/network/udp.inc b/kernel/trunk/network/udp.inc index b8a0c37865..8bd91127b1 100644 --- a/kernel/trunk/network/udp.inc +++ b/kernel/trunk/network/udp.inc @@ -1,153 +1,325 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; ;; -;; UDP.INC ;; -;; ;; -;; UDP Processes for Menuet OS TCP/IP stack ;; -;; ;; -;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; -;; ;; -;; See file COPYING for details ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; UDP.INC ;; +;; ;; +;; Part of the tcp/ip network stack for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -$Revision$ +$Revision: 2995 $ -;******************************************************************* -; Interface -; -; udp_rx Handles received IP packets with the UDP protocol -; -;******************************************************************* +struct UDP_header + + SourcePort dw ? + DestinationPort dw ? + Length dw ? ; Length of (UDP Header + Data) + Checksum dw ? + +ends -; -; UDP Payload ( Data field in IP datagram ) -; -; 0 1 2 3 -; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -; -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Source Port | Destination Port | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Length ( UDP Header + Data ) | Checksum | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | UDP Data | -; +-+-+-.......... -+ -; +align 4 +uglobal + UDP_PACKETS_TX rd MAX_NET_DEVICES + UDP_PACKETS_RX rd MAX_NET_DEVICES +endg -struc UDP_PACKET -{ .SourcePort dw ? ;+00 - .DestinationPort dw ? ;+02 - .Length dw ? ;+04 - Length of (UDP Header + Data) - .Checksum dw ? ;+06 - .Data db ? ;+08 + +;----------------------------------------------------------------- +; +; UDP_init +; +; This function resets all UDP variables +; +;----------------------------------------------------------------- +macro UDP_init { + + xor eax, eax + mov edi, UDP_PACKETS_TX + mov ecx, 2*MAX_NET_DEVICES + rep stosd } -virtual at 0 - UDP_PACKET UDP_PACKET -end virtual + +macro UDP_checksum IP1, IP2 { ; esi = ptr to udp packet, ecx = packet size, destroys: ecx, edx + +; Pseudoheader + mov edx, IP_PROTO_UDP + + add dl, [IP1+1] + adc dh, [IP1+0] + adc dl, [IP1+3] + adc dh, [IP1+2] + + adc dl, [IP2+1] + adc dh, [IP2+0] + adc dl, [IP2+3] + adc dh, [IP2+2] + + adc dl, cl ; byte[esi+UDP_header.Length+1] + adc dh, ch ; byte[esi+UDP_header.Length+0] + +; Done with pseudoheader, now do real header + adc dl, byte[esi+UDP_header.SourcePort+1] + adc dh, byte[esi+UDP_header.SourcePort+0] + + adc dl, byte[esi+UDP_header.DestinationPort+1] + adc dh, byte[esi+UDP_header.DestinationPort+0] + + adc dl, byte[esi+UDP_header.Length+1] + adc dh, byte[esi+UDP_header.Length+0] + + adc edx, 0 + +; Done with header, now do data + push esi + movzx ecx, [esi+UDP_header.Length] + rol cx , 8 + sub cx , sizeof.UDP_header + add esi, sizeof.UDP_header + + call checksum_1 + call checksum_2 + pop esi + + add [esi+UDP_header.Checksum], dx ; this final instruction will set or clear ZF :) + +} -;*************************************************************************** -; Function -; udp_rx [by Johnny_B] +;----------------------------------------------------------------- ; -; Description -; UDP protocol handler -; This is a kernel function, called by ip_rx -; IP buffer address given in edx -; IP buffer number in eax -; Free up (or re-use) IP buffer when finished +; UDP_input: ; -;*************************************************************************** +; Called by IPv4_input, +; this procedure will inject the udp data diagrams in the application sockets. +; +; IN: [esp] = Pointer to buffer +; [esp+4] = size of buffer +; ebx = ptr to device struct +; ecx = UDP Packet size +; esi = ptr to UDP header +; edi = ptr to ipv4 source and dest address +; +; OUT: / +; +;----------------------------------------------------------------- +align 4 +UDP_input: -proc udp_rx stdcall - push eax + DEBUGF 1,"UDP_input: size=%u\n", ecx - ; First validate the header & checksum. Discard buffer if error + ; First validate, checksum + + neg [esi + UDP_header.Checksum] ; substract checksum from 0 + jz .no_checksum ; if checksum is zero, it is considered valid + + ; otherwise, we will re-calculate the checksum and add it to this value, thus creating 0 when it is correct + + UDP_checksum (edi), (edi+4) + jnz .checksum_mismatch + + .no_checksum: + DEBUGF 1,"UDP_input: checksum ok\n" + + ; Convert length to little endian + + rol [esi + UDP_header.Length], 8 ; Look for a socket where ; IP Packet UDP Destination Port = local Port ; IP Packet SA = Remote IP - mov ax, [edx + 20 + UDP_PACKET.DestinationPort] ; get the local port from - ; the IP packet's UDP header - - mov ebx, net_sockets + mov cx, [esi + UDP_header.SourcePort] + mov dx, [esi + UDP_header.DestinationPort] + mov edi, [edi + 4] ; ipv4 source address + mov eax, net_sockets .next_socket: - mov ebx, [ebx + SOCKET.NextPtr] - or ebx, ebx - jz .exit ; No match, so exit - cmp [ebx + SOCKET.LocalPort], ax ; ax will hold the 'wrong' value, - ; but the comparision is correct - jne .next_socket ; Return back if no match + mov eax, [eax + SOCKET.NextPtr] + or eax, eax + jz .dump - ; For dhcp, we must allow any remote server to respond. - ; I will accept the first incoming response to be the one - ; I bind to, if the socket is opened with a destination IP address of - ; 255.255.255.255 - cmp [ebx + SOCKET.RemoteIP], 0xffffffff - je @f + cmp [eax + SOCKET.Domain], AF_INET4 + jne .next_socket - mov eax, [edx + IP_PACKET.SourceAddress] ; get the Source address from the IP packet - cmp [ebx + SOCKET.RemoteIP], eax - jne .exit ; Quit if the source IP is not valid + cmp [eax + SOCKET.Protocol], IP_PROTO_UDP + jne .next_socket - @@: ; OK - we have a valid UDP packet for this socket. - ; First, update the sockets remote port number with the incoming msg - ; - it will have changed - ; from the original ( 69 normally ) to allow further connects - mov ax, [edx + 20 + UDP_PACKET.SourcePort] ; get the UDP source port - ; ( was 69, now new ) - mov [ebx + SOCKET.RemotePort], ax + cmp [eax + UDP_SOCKET.LocalPort], dx + jne .next_socket - ; Now, copy data to socket. We have socket address as [eax + sockets]. - ; We have IP packet in edx + DEBUGF 1,"UDP_input: socket=%x\n", eax - ; get # of bytes in ecx - movzx ecx, [edx + IP_PACKET.TotalLength] ; total length of IP packet. Subtract - xchg cl, ch ; 20 + 8 gives data length - sub ecx, 28 + ;;; TODO: when packet is processed, check more sockets! - mov eax, [ebx + SOCKET.rxDataCount] ; get # of bytes already in buffer - add [ebx + SOCKET.rxDataCount], ecx ; increment the count of bytes in buffer +; cmp [eax + IP_SOCKET.RemoteIP], 0xffffffff +; je @f +; cmp [eax + IP_SOCKET.RemoteIP], edi +; jne .next_socket +; @@: +; +; FIXME: UDP should check remote IP, but not under all circumstances! - ; ecx has count, edx points to data + cmp [eax + UDP_SOCKET.firstpacket], 0 + je .updateport - add edx, 28 ; edx now points to the data - lea edi, [ebx + eax + SOCKETHEADERSIZE] - mov esi, edx + cmp [eax + UDP_SOCKET.RemotePort], cx + jne .dump - cld - rep movsb ; copy the data across + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + popa - ; flag an event to the application - mov eax, [ebx + SOCKET.PID] ; get socket owner PID - mov ecx, 1 - mov esi, TASK_DATA + TASKDATA.pid + .updatesock: + inc [UDP_PACKETS_RX] ; Fixme: correct interface? - .next_pid: - cmp [esi], eax - je .found_pid - inc ecx - add esi, 0x20 - cmp ecx, [TASK_COUNT] - jbe .next_pid + movzx ecx, [esi + UDP_header.Length] + sub ecx, sizeof.UDP_header + add esi, sizeof.UDP_header - jmp .exit + jmp SOCKET_input - .found_pid: - shl ecx, 8 - or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event + .updateport: + pusha + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + popa + + DEBUGF 1,"UDP_input: new remote port=%x\n", cx ; FIXME: find a way to print big endian values with debugf + mov [eax + UDP_SOCKET.RemotePort], cx + inc [eax + UDP_SOCKET.firstpacket] + + jmp .updatesock + + + .checksum_mismatch: + DEBUGF 2,"UDP_input: checksum mismatch\n" + + .dump: + call kernel_free + add esp, 4 ; pop (balance stack) + DEBUGF 2,"UDP_input: dumping\n" - .exit: - pop eax - call freeBuff ; Discard the packet ret -endp + + + + +;----------------------------------------------------------------- +; +; UDP_output +; +; IN: eax = socket pointer +; ecx = number of bytes to send +; esi = pointer to data +; +;----------------------------------------------------------------- + +align 4 +UDP_output: + + DEBUGF 1,"UDP_output: socket=%x bytes=%u data_ptr=%x\n", eax, ecx, esi + + mov dx, [eax + UDP_SOCKET.RemotePort] + DEBUGF 1,"UDP_output: remote port=%x, ", dx ; FIXME: find a way to print big endian values with debugf + rol edx, 16 + mov dx, [eax + UDP_SOCKET.LocalPort] + DEBUGF 1,"local port=%x\n", dx + + sub esp, 8 ; Data ptr and data size will be placed here + push edx esi + mov ebx, [eax + SOCKET.device] + mov edx, [eax + IP_SOCKET.LocalIP] + mov eax, [eax + IP_SOCKET.RemoteIP] + mov di, IP_PROTO_UDP shl 8 + 128 + add ecx, sizeof.UDP_header + call IPv4_output + jz .fail + mov [esp + 8], eax ; pointer to buffer start + mov [esp + 8 + 4], edx ; buffer size + + mov [edi + UDP_header.Length], cx + rol [edi + UDP_header.Length], 8 + + pop esi + push edi ecx + sub ecx, sizeof.UDP_header + add edi, sizeof.UDP_header + shr ecx, 2 + rep movsd + mov ecx, [esp] + and ecx, 3 + rep movsb + pop ecx edi + + pop dword [edi + UDP_header.SourcePort] + +; Checksum + mov esi, edi + mov [edi + UDP_header.Checksum], 0 + UDP_checksum (edi-4), (edi-8) ; FIXME: IPv4 packet could have options.. + + DEBUGF 1,"UDP_output: sending with device %x\n", ebx + call [ebx + NET_DEVICE.transmit] + test eax, eax + jnz @f + inc [UDP_PACKETS_TX] ; FIXME: correct device? + @@: + + ret + + .fail: + DEBUGF 1,"UDP_output: failed\n" + add esp, 4+4+8 + or eax, -1 + ret + + + +;--------------------------------------------------------------------------- +; +; UDP_API +; +; This function is called by system function 75 +; +; IN: subfunction number in bl +; device number in bh +; ecx, edx, .. depends on subfunction +; +; OUT: +; +;--------------------------------------------------------------------------- + +align 4 +UDP_api: + + movzx eax, bh + shl eax, 2 + + test bl, bl + jz .packets_tx ; 0 + dec bl + jz .packets_rx ; 1 + + .error: + mov eax, -1 + ret + + .packets_tx: + mov eax, [UDP_PACKETS_TX + eax] + ret + + .packets_rx: + mov eax, [UDP_PACKETS_RX + eax] + ret diff --git a/programs/develop/libraries/network/network.asm b/programs/develop/libraries/network/network.asm index 7e903c1237..d54fb8076e 100644 --- a/programs/develop/libraries/network/network.asm +++ b/programs/develop/libraries/network/network.asm @@ -23,13 +23,13 @@ lib_init: ;//////////////////////////////////////////////////////////////////;; ;;---------------------------------------------------------------------------;; ;< eax = 1 (fail) / 0 (ok) (library initialization result) ;; ;;===========================================================================;; - mov [mem.alloc], eax - mov [mem.free], ebx - mov [mem.realloc], ecx - mov [dll.load], edx - mov [DNSrequestID], 1 - stdcall edx, @IMPORT - ret 4 + mov [mem.alloc], eax + mov [mem.free], ebx + mov [mem.realloc], ecx + mov [dll.load], edx + mov [DNSrequestID], 1 + xor eax, eax + ret ;;===========================================================================;; ;; in_addr_t __stdcall inet_addr(__in const char* hostname); ;; @@ -42,85 +42,85 @@ inet_addr: ;; ;< eax = IP address on success / -1 on error ;; ;;===========================================================================;; ; 0. Save used registers for __stdcall. - push ebx esi edi - mov esi, [esp+16] ; esi = hostname + push ebx esi edi + mov esi, [esp+16] ; esi = hostname ; 1. Check that only allowed symbols are present. ; (hex digits, possibly letters 'x'/'X' and up to 3 dots) - push esi - xor ecx, ecx + push esi + xor ecx, ecx .calcdots_loop: ; loop for all characters in string - lodsb + lodsb ; check for end of string - cmp al, 0 - jz .calcdots_loop_done + cmp al, 0 + jz .calcdots_loop_done ; check for dot - cmp al, '.' - jz .dot + cmp al, '.' + jz .dot ; check for digit - sub al, '0' - cmp al, 9 - jbe .calcdots_loop + sub al, '0' + cmp al, 9 + jbe .calcdots_loop ; check for hex letter - sub al, 'A' - '0' ; 'A'-'F' -> 0-5, 'a'-'f' -> 20h-25h - and al, not 20h - cmp al, 'F' - 'A' - jbe .calcdots_loop + sub al, 'A' - '0' ; 'A'-'F' -> 0-5, 'a'-'f' -> 20h-25h + and al, not 20h + cmp al, 'F' - 'A' + jbe .calcdots_loop ; check for 'x'/'X' - cmp al, 'X' - 'A' - jz .calcdots_loop - jmp .fail.pop + cmp al, 'X' - 'A' + jz .calcdots_loop + jmp .fail.pop .dot: - inc ecx - jmp .calcdots_loop + inc ecx + jmp .calcdots_loop .calcdots_loop_done: - cmp ecx, 4 - jae .fail.pop + cmp ecx, 4 + jae .fail.pop ; 2. The name can be valid dotted name; try to convert, checking limit - pop esi - xor edi, edi ; edi = address - push 0xFFFFFFFF - pop edx ; edx = mask for rest of address + pop esi + xor edi, edi ; edi = address + push 0xFFFFFFFF + pop edx ; edx = mask for rest of address ; 2a. Convert name except for last group. - jecxz .ip_convert_2b + jecxz .ip_convert_2b .ip_convert_2a: - push ecx - mov ecx, 0xFF ; limit for all groups except for last - call .get_number - pop ecx - jc .fail - cmp byte [esi-1], '.' - jnz .fail - shl edi, 8 - shr edx, 8 - add edi, eax - loop .ip_convert_2a + push ecx + mov ecx, 0xFF ; limit for all groups except for last + call .get_number + pop ecx + jc .fail + cmp byte [esi-1], '.' + jnz .fail + shl edi, 8 + shr edx, 8 + add edi, eax + loop .ip_convert_2a ; 2b. Convert last group. .ip_convert_2b: - mov ecx, edx - call .get_number - jc .fail - cmp byte [esi-1], 0 - jnz .fail + mov ecx, edx + call .get_number + jc .fail + cmp byte [esi-1], 0 + jnz .fail @@: - shl edi, 8 - shr edx, 8 - jnz @b - add edi, eax + shl edi, 8 + shr edx, 8 + jnz @b + add edi, eax ; 2c. Convert to network byte order. - bswap edi + bswap edi ; 3. Set return value, restore used registers and return. - xchg eax, edi + xchg eax, edi .ret: - pop edi esi ebx - ret 4 + pop edi esi ebx + ret 4 ; 4. On error, return -1. .fail.pop: - pop esi + pop esi .fail: - push -1 - pop eax - jmp .ret + push -1 + pop eax + jmp .ret ;;===========================================================================;; ;; Internal auxiliary function for IP parsing. ;; @@ -136,56 +136,56 @@ inet_addr: ;; ;< esi -> end of number representation ;; ;;===========================================================================;; ; 0. Save edx, which is used in caller. - push edx + push edx ; 1. Initialize number, zero eax so that lodsb gets full dword. - xor eax, eax - xor edx, edx + xor eax, eax + xor edx, edx ; 2. Get used numeral system: 0x = hex, otherwise 0 = octal, otherwise decimal - push 10 - pop ebx - lodsb - cmp al, '0' - jnz .convert - push 8 - pop ebx - lodsb - cmp al, 'x' - jnz .convert - add ebx, ebx + push 10 + pop ebx + lodsb + cmp al, '0' + jnz .convert + push 8 + pop ebx + lodsb + cmp al, 'x' + jnz .convert + add ebx, ebx ; 3. Loop while digits are encountered. .convert: ; 4. Convert digit from text representation to binary value. - or al, 20h ; '0'-'9' -> '0'-'9', 'A'-'F' -> 'a'-'f' - sub al, '0' - cmp al, 9 - jbe .digit - sub al, 'a' - '0' - cmp al, 'f' - 'a' - ja .convert_done - add al, 10 + or al, 20h ; '0'-'9' -> '0'-'9', 'A'-'F' -> 'a'-'f' + sub al, '0' + cmp al, 9 + jbe .digit + sub al, 'a' - '0' + cmp al, 'f' - 'a' + ja .convert_done + add al, 10 .digit: ; 5. Digit must be less than base of numeral system. - cmp eax, ebx - jae .convert_done + cmp eax, ebx + jae .convert_done ; 6. Advance the number. - imul edx, ebx - add edx, eax - cmp edx, ecx - ja .gn_error + imul edx, ebx + add edx, eax + cmp edx, ecx + ja .gn_error ; 3b. Continue loop. - lodsb - jmp .convert + lodsb + jmp .convert .convert_done: ; 7. Invalid character, number converted, return success. - xchg eax, edx - pop edx - clc - ret + xchg eax, edx + pop edx + clc + ret .gn_error: ; 8. Too big number, return error. - pop edx - stc - ret + pop edx + stc + ret ;;===========================================================================;; ;; char* __stdcall inet_ntoa(struct in_addr in); ;; @@ -198,74 +198,74 @@ inet_ntoa: ;; ;< eax = pointer to resulting string (in static buffer) ;; ;;===========================================================================;; ; 0. Save used registers for __stdcall. - push ebx esi edi - mov bl, 0xCD ; constant for div 10 + push ebx esi edi + mov bl, 0xCD ; constant for div 10 ; 1. Write octet 4 times. - mov edi, .buffer - mov edx, [esp+16] ; eax = in - mov al, dl - call .write - mov al, dh - shr edx, 16 - call .write - mov al, dl - call .write - mov al, dh - call .write + mov edi, .buffer + mov edx, [esp+16] ; eax = in + mov al, dl + call .write + mov al, dh + shr edx, 16 + call .write + mov al, dl + call .write + mov al, dh + call .write ; 2. Replace final dot with terminating zero. - mov byte [edi-1], 0 + mov byte [edi-1], 0 ; 3. Restore used registers, set result value and return. - pop edi esi ebx - mov eax, .buffer - ret 4 + pop edi esi ebx + mov eax, .buffer + ret 4 .write: - movzx esi, al - mul bl - add esi, ('.' shl 8) + '0' - shr ah, 3 ; ah = al / 10 - movzx ecx, ah - add ecx, ecx - lea ecx, [ecx*5] - sub esi, ecx ; lobyte(esi) = al % 10, hibyte(esi) = '.' - test ah, ah - jz .1digit - cmp ah, 10 - jb .2digit - cmp ah, 20 - sbb cl, cl - add cl, '2' - mov byte [edi], cl - movzx ecx, cl - lea ecx, [ecx*5] - sub ah, cl - sub ah, cl - add ah, ('0'*11) and 255 - mov byte [edi+1], ah - mov word [edi+2], si - add edi, 4 - ret + movzx esi, al + mul bl + add esi, ('.' shl 8) + '0' + shr ah, 3 ; ah = al / 10 + movzx ecx, ah + add ecx, ecx + lea ecx, [ecx*5] + sub esi, ecx ; lobyte(esi) = al % 10, hibyte(esi) = '.' + test ah, ah + jz .1digit + cmp ah, 10 + jb .2digit + cmp ah, 20 + sbb cl, cl + add cl, '2' + mov byte [edi], cl + movzx ecx, cl + lea ecx, [ecx*5] + sub ah, cl + sub ah, cl + add ah, ('0'*11) and 255 + mov byte [edi+1], ah + mov word [edi+2], si + add edi, 4 + ret .2digit: - add ah, '0' - mov byte [edi], ah - mov word [edi+1], si - add edi, 3 - ret + add ah, '0' + mov byte [edi], ah + mov word [edi+1], si + add edi, 3 + ret .1digit: - mov word [edi], si - add edi, 2 - ret + mov word [edi], si + add edi, 2 + ret struct __gai_reqdata - socket dd ? + socketnum dd ? ; external code should not look on rest of this structure, ; it is internal for getaddrinfo_start/process/abort - reqid dw ? ; DNS request ID - socktype db ? ; SOCK_* or 0 for any - db ? - service dd ? - flags dd ? - reserved rb 16 + reqid dw ? ; DNS request ID + socktype db ? ; SOCK_* or 0 for any + db ? + service dd ? + flags dd ? + reserved rb 16 ends ;;===========================================================================;; @@ -279,72 +279,72 @@ getaddrinfo: ;; ;;---------------------------------------------------------------------------;; ;> first parameter (optional) = host name ;; ;> second parameter (optional) = service name (decimal number for now) ;; -;> third parameter (optional) = hints for socket type ;; +;> third parameter (optional) = hints for socketnum type ;; ;> fourth parameter = pointer to result (head of L1-list) ;; ;;---------------------------------------------------------------------------;; ;< eax = 0 on success / one of EAI_ codes on error ;; ;;===========================================================================;; ; 0. Save used registers for __stdcall. - push ebx esi edi - mov edi, [esp+28] ; edi = res + push ebx esi edi + mov edi, [esp+28] ; edi = res ; 1. Create and send DNS packet. - sub esp, sizeof.__gai_reqdata ; reserve stack place (1) - push esp ; fifth parameter = pointer to (1) - push edi ; fourth parameter = res - push dword [esp+32+sizeof.__gai_reqdata] ; third parameter = hints - push dword [esp+32+sizeof.__gai_reqdata] ; second parameter = servname - push dword [esp+32+sizeof.__gai_reqdata] ; first parameter = hostname - call getaddrinfo_start - test eax, eax - jns .ret ; if name resolved without network activity, return + sub esp, sizeof.__gai_reqdata ; reserve stack place (1) + push esp ; fifth parameter = pointer to (1) + push edi ; fourth parameter = res + push dword [esp+32+sizeof.__gai_reqdata] ; third parameter = hints + push dword [esp+32+sizeof.__gai_reqdata] ; second parameter = servname + push dword [esp+32+sizeof.__gai_reqdata] ; first parameter = hostname + call getaddrinfo_start + test eax, eax + jns .ret ; if name resolved without network activity, return ; 2. Wait for DNS reply. ; 2a. Ignore all events except network stack. - mcall 40, EVM_STACK - push eax ; save previous event mask (2) + mcall 40, EVM_STACK + push eax ; save previous event mask (2) ; 2b. Get upper limit for wait time. Use timeout = 5 seconds. - mcall 26, 9 ; get time stamp - xchg esi, eax ; save time stamp to esi - mov ebx, 500 ; start value for timeout - add esi, ebx + mcall 26, 9 ; get time stamp + xchg esi, eax ; save time stamp to esi + mov ebx, 500 ; start value for timeout + add esi, ebx .wait: ; 2c. Wait for event with timeout. - mcall 23 ; wait for event - must be stack event + mcall 23 ; wait for event - must be stack event ; 2d. Check for timeout. - test eax, eax - lea eax, [esp+4] ; pointer to (1) - jz .timeout + test eax, eax + lea eax, [esp+4] ; pointer to (1) + jz .timeout ; 3. Got packet. Call processing function. - push edi ; second parameter: pointer to result - push eax ; first parameter: pointer to reqdata - call getaddrinfo_process + push edi ; second parameter: pointer to result + push eax ; first parameter: pointer to reqdata + call getaddrinfo_process ; 4. Test whether wait loop must be continued. - test eax, eax - jns .ret.restore + test eax, eax + jns .ret.restore ; 2e. Recalculate timeout value. - mcall 26, 9 - mov ebx, esi - sub ebx, eax + mcall 26, 9 + mov ebx, esi + sub ebx, eax ; 2f. Check that time is not over; if not, continue wait loop - cmp ebx, 500 - jbe .wait + cmp ebx, 500 + jbe .wait .timeout: ; 5. Timeout: abort and return error - push eax - call getaddrinfo_abort - and dword [edi], 0 - push EAI_AGAIN - pop eax + push eax + call getaddrinfo_abort + and dword [edi], 0 + push EAI_AGAIN + pop eax .ret.restore: ; 6. Restore event mask. - pop ebx ; get event mask (2) - push eax ; save return code (3) - mcall 40 - pop eax ; restore return code (3) + pop ebx ; get event mask (2) + push eax ; save return code (3) + mcall 40 + pop eax ; restore return code (3) .ret: ; 7. Restore stack pointer, used registers and return. - add esp, sizeof.__gai_reqdata ; undo (1) - pop edi esi ebx - ret 16 + add esp, sizeof.__gai_reqdata ; undo (1) + pop edi esi ebx + ret 16 ;;===========================================================================;; ;; int __stdcall getaddrinfo_start(__in const char* hostname, ;; @@ -373,333 +373,351 @@ getaddrinfo_start: ;; ;; 5. Assumes that IPv4 is always configured, so AI_ADDRCONFIG has no effect.;; ;;===========================================================================;; ; 0. Create stack frame and save used registers for __stdcall. - push ebx esi edi - push ebp - mov ebp, esp + push ebx esi edi + push ebp + mov ebp, esp virtual at ebp-8 -.recent_restsize dd ? ; this is for memory alloc in ._.generate_data -.recent_page dd ? ; this is for memory alloc in ._.generate_data - rd 5 ; saved regs and return address -.hostname dd ? -.servname dd ? -.hints dd ? -.res dd ? -.reqdata dd ? +.recent_restsize dd ? ; this is for memory alloc in ._.generate_data +.recent_page dd ? ; this is for memory alloc in ._.generate_data + rd 5 ; saved regs and return address +.hostname dd ? +.servname dd ? +.hints dd ? +.res dd ? +.reqdata dd ? end virtual - xor edi, edi - push edi ; init .recent_page - push edi ; init .recent_restsize + xor edi, edi + push edi ; init .recent_page + push edi ; init .recent_restsize ; 1. Check that parameters are correct and can be handled by this implementation. ; 1a. If 'res' pointer is given, set result to zero. - mov eax, [.res] - test eax, eax - jz @f - mov [eax], edi + mov eax, [.res] + test eax, eax + jz @f + mov [eax], edi @@: ; 1b. Only AI_SUPPORTED flags are supported for hints->ai_flags. - mov ecx, [.hints] - xor edx, edx - jecxz .nohints - mov edx, [ecx+addrinfo.ai_flags] + mov ecx, [.hints] + xor edx, edx + jecxz .nohints + mov edx, [ecx+addrinfo.ai_flags] .nohints: - mov ebx, [.reqdata] - mov [ebx+__gai_reqdata.flags], edx - push EAI_BADFLAGS - pop eax - test edx, not AI_SUPPORTED - jnz .ret + mov ebx, [.reqdata] + mov [ebx+__gai_reqdata.flags], edx + push EAI_BADFLAGS + pop eax + test edx, not AI_SUPPORTED + jnz .ret ; 1c. Either hostname or servname must be given. If AI_CANONNAME is set, ; hostname must also be set. - cmp [.hostname], edi - jnz @f - test dl, AI_CANONNAME - jnz .ret - push EAI_NONAME - pop eax - cmp [.servname], edi - jz .ret + cmp [.hostname], edi + jnz @f + test dl, AI_CANONNAME + jnz .ret + push EAI_NONAME + pop eax + cmp [.servname], edi + jz .ret @@: ; 1d. Only IPv4 is supported, so hints->ai_family must be either PF_UNSPEC or PF_INET. - push EAI_FAMILY - pop eax - jecxz @f - cmp [ecx+addrinfo.ai_family], edi - jz @f - cmp [ecx+addrinfo.ai_family], PF_INET - jnz .ret + push EAI_FAMILY + pop eax + jecxz @f + cmp [ecx+addrinfo.ai_family], edi + jz @f + cmp [ecx+addrinfo.ai_family], AF_INET4 + jnz .ret @@: ; 1e. Valid combinations for ai_socktype/ai_protocol: 0/0 for any or -; SOCK_STREAM/IPPROTO_TCP, SOCK_DGRAM/IPPROTO_UDP -; (raw sockets are not yet supported by the kernel) - xor edx, edx ; assume 0=any if no hints - jecxz .socket_type_ok - mov edx, [ecx+addrinfo.ai_socktype] - mov esi, [ecx+addrinfo.ai_protocol] +; SOCK_STREAM/IPPROTO_TCP, SOCK_DGRAM/IPPROTO_UDP +; (raw socketnums are not yet supported by the kernel) + xor edx, edx ; assume 0=any if no hints + jecxz .socketnum_type_ok + mov edx, [ecx+addrinfo.ai_socktype] + mov esi, [ecx+addrinfo.ai_protocol] ; 1f. Test for ai_socktype=0 and ai_protocol=0. - test edx, edx - jnz .check_socktype - test esi, esi - jz .socket_type_ok + test edx, edx + jnz .check_socktype + test esi, esi + jz .socketnum_type_ok ; 1g. ai_socktype=0, ai_protocol is nonzero. - push EAI_SERVICE - pop eax - inc edx ; edx = SOCK_STREAM - cmp esi, IPPROTO_TCP - jz .socket_type_ok - inc edx ; edx = SOCK_DGRAM - cmp esi, IPPROTO_UDP - jz .socket_type_ok + push EAI_SERVICE + pop eax + inc edx ; edx = SOCK_STREAM + cmp esi, IPPROTO_TCP + jz .socketnum_type_ok + inc edx ; edx = SOCK_DGRAM + cmp esi, IPPROTO_UDP + jz .socketnum_type_ok .ret: ; Restore saved registers, destroy stack frame and return. - mov esp, ebp - pop ebp - pop edi esi ebx - ret 20 + mov esp, ebp + pop ebp + pop edi esi ebx + ret 20 ; 1h. ai_socktype is nonzero. .check_socktype: - push EAI_SOCKTYPE - pop eax - cmp edx, SOCK_STREAM - jz .check_tcp - cmp edx, SOCK_DGRAM - jnz .ret - test esi, esi - jz .socket_type_ok - cmp esi, IPPROTO_UDP - jz .socket_type_ok - jmp .ret + push EAI_SOCKTYPE + pop eax + cmp edx, SOCK_STREAM + jz .check_tcp + cmp edx, SOCK_DGRAM + jnz .ret + test esi, esi + jz .socketnum_type_ok + cmp esi, IPPROTO_UDP + jz .socketnum_type_ok + jmp .ret .check_tcp: - test esi, esi - jz .socket_type_ok - cmp esi, IPPROTO_TCP - jnz .ret -.socket_type_ok: - mov [ebx+__gai_reqdata.socktype], dl + test esi, esi + jz .socketnum_type_ok + cmp esi, IPPROTO_TCP + jnz .ret +.socketnum_type_ok: + mov [ebx+__gai_reqdata.socktype], dl ; 2. Resolve service. ; 2a. If no name is given, remember value -1. - push -1 - pop edx - mov esi, [.servname] - test esi, esi - jz .service_resolved + push -1 + pop edx + mov esi, [.servname] + test esi, esi + jz .service_resolved ; 2b. Loop for characters of string while digits are encountered. - xor edx, edx - xor eax, eax + xor edx, edx + xor eax, eax .serv_to_number: - lodsb - sub al, '0' - cmp al, 9 - ja .serv_to_number_done + lodsb + sub al, '0' + cmp al, 9 + ja .serv_to_number_done ; for each digit, set edx = edx*10 + - lea edx, [edx*5] - lea edx, [edx*2+eax] + lea edx, [edx*5] + lea edx, [edx*2+eax] ; check for correctness: service port must fit in word - cmp edx, 0x10000 - jae .service_not_number - jmp .serv_to_number + cmp edx, 0x10000 + jae .service_not_number + jmp .serv_to_number .serv_to_number_done: - and edx, 0xFFFF ; make sure that port fits + and edx, 0xFFFF ; make sure that port fits ; 2c. If zero character reached, name is resolved; ; otherwise, return error (no support for symbolic names yet) - cmp al, -'0' - jz .service_resolved + cmp al, -'0' + jz .service_resolved .service_not_number: - push EAI_NONAME - pop eax - jmp .ret + push EAI_NONAME + pop eax + jmp .ret .service_resolved: ; 2d. Save result to reqdata. - mov [ebx+__gai_reqdata.service], edx + mov [ebx+__gai_reqdata.service], edx ; 3. Process host name. - mov esi, [.hostname] + mov esi, [.hostname] ; 3a. If hostname is not given, -; use localhost for active sockets and INADDR_ANY for passive sockets. - mov eax, 0x0100007F ; 127.0.0.1 in network byte order - test byte [ebx+__gai_reqdata.flags], AI_PASSIVE - jz @f - xor eax, eax +; use localhost for active socketnums and INADDR_ANY for passive socketnums. + mov eax, 0x0100007F ; 127.0.0.1 in network byte order + test byte [ebx+__gai_reqdata.flags], AI_PASSIVE + jz @f + xor eax, eax @@: - test esi, esi - jz .hostname_is_ip + test esi, esi + jz .hostname_is_ip ; 3b. Check for dotted IPv4 name. - push esi - call inet_addr - cmp eax, -1 - jz .resolve_hostname + push esi + call inet_addr + cmp eax, -1 + jz .resolve_hostname .hostname_is_ip: ; 3c. hostname is valid representation of IP address, and we have resolved it. ; Generate result, if .res pointer is not NULL. - mov ebx, [.reqdata] - mov esi, [.res] - test esi, esi - jz .no_result - call getaddrinfo._.generate_data + mov ebx, [.reqdata] + mov esi, [.res] + test esi, esi + jz .no_result + call getaddrinfo._.generate_data ; 3d. Check for memory allocation error. .3d: - push EAI_MEMORY - pop eax - test esi, esi - jz .ret + push EAI_MEMORY + pop eax + test esi, esi + jz .ret ; 3e. If AI_CANONNAME is set, copy input name. - test byte [ebx+__gai_reqdata.flags], AI_CANONNAME - jz .no_result + test byte [ebx+__gai_reqdata.flags], AI_CANONNAME + jz .no_result ; 3f. Calculate length of name. - push -1 - pop ecx - mov edi, [.hostname] - xor eax, eax - repnz scasb - not ecx + push -1 + pop ecx + mov edi, [.hostname] + xor eax, eax + repnz scasb + not ecx ; 3g. Check whether it fits on one page with main data. - cmp ecx, [.recent_restsize] - jbe .name_fits + cmp ecx, [.recent_restsize] + jbe .name_fits ; 3h. If not, allocate new page. - push ecx - add ecx, 4 ; first dword contains number of objects on the page - mcall 68, 12 - pop ecx + push ecx + add ecx, 4 ; first dword contains number of objects on the page + mcall 68, 12 + pop ecx ; 3i. If allocation has failed, free addrinfo and return error. - test eax, eax - jnz .name_allocated - push [.res] - call freeaddrinfo - push EAI_MEMORY - pop eax - jmp .ret + test eax, eax + jnz .name_allocated + push [.res] + call freeaddrinfo + push EAI_MEMORY + pop eax + jmp .ret .name_allocated: ; 3j. Otherwise, set edi to allocated memory and continue to 3l. - xchg edi, eax ; put result to edi - push 1 - pop eax - stosd ; number of objects on the page = 1 - jmp .copy_name + xchg edi, eax ; put result to edi + push 1 + pop eax + stosd ; number of objects on the page = 1 + jmp .copy_name .name_fits: ; 3k. Get pointer to free memory in allocated page. - mov edi, [.recent_page] - mov eax, edi - and eax, not 0xFFF - inc dword [eax] ; increase number of objects + mov edi, [.recent_page] + mov eax, edi + and eax, not 0xFFF + inc dword [eax] ; increase number of objects .copy_name: ; 3l. Put pointer to struct addrinfo. - mov eax, [.res] - mov eax, [eax] - mov [eax+addrinfo.ai_canonname], edi + mov eax, [.res] + mov eax, [eax] + mov [eax+addrinfo.ai_canonname], edi ; 3m. Copy name. - rep movsb + rep movsb .no_result: ; 3n. Return success. - xor eax, eax - jmp .ret + xor eax, eax + jmp .ret ; 4. Host address is not dotted IP. Test whether we are allowed to contact DNS. ; Return error if no. .resolve_hostname: - push EAI_NONAME - pop eax - mov ebx, [.reqdata] - test byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST - jnz .ret + push EAI_NONAME + pop eax + mov ebx, [.reqdata] + test byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST + jnz .ret ; Host address is domain name. Contact DNS server. - mov esi, [.hostname] + mov esi, [.hostname] ; 5. Reserve stack place for UDP packet. ; According to RFC1035, maximum UDP packet size in DNS is 512 bytes. - sub esp, 512 + sub esp, 512 ; 6. Create DNS request packet. ; 6a. Set pointer to start of buffer. - mov edi, esp + mov edi, esp ; 6b. Get request ID, write it to buffer. - push 1 - pop eax -lock xadd [DNSrequestID], eax ; atomically increment ID, get old value - stosw - mov [ebx+__gai_reqdata.reqid], ax + push 1 + pop eax +lock xadd [DNSrequestID], eax ; atomically increment ID, get old value + stosw + mov [ebx+__gai_reqdata.reqid], ax ; 6c. Packed field: QR=0 (query), Opcode=0000 (standard query), -; AA=0 (ignored in requests), TC=0 (no truncation), -; RD=1 (recursion desired) - mov al, 00000001b - stosb +; AA=0 (ignored in requests), TC=0 (no truncation), +; RD=1 (recursion desired) + mov al, 00000001b + stosb ; 6d. Packed field: ignored in requests - mov al, 0 - stosb + mov al, 0 + stosb ; 6e. Write questions count = 1 and answers count = 0 ; Note that network byte order is big-endian. - mov eax, 0x00000100 - stosd + mov eax, 0x00000100 + stosd ; 6f. Write nameservers count = 0 and additional records count = 0 - xor eax, eax - stosd + xor eax, eax + stosd ; 6g. Write request data: name ; According to RFC1035, maximum length of name is 255 bytes. ; For correct names, buffer cannot overflow. - lea ebx, [esi+256] ; ebx = limit for name (including terminating zero) + lea ebx, [esi+256] ; ebx = limit for name (including terminating zero) ; translate string "www.yandex.ru" {00} to byte data {03} "www" {06} "yandex" {02} "ru" {00} -.nameloop: ; here we go in the start of each label: before "www", before "yandex", before "ru" - xor ecx, ecx ; ecx = length of current label - inc edi ; skip length, it will be filled later -.labelloop: ; here we go for each symbol of name - lodsb ; get next character - test al, al ; terminating zero? - jz .endname - cmp esi, ebx ; limit exceeded? - jae .wrongname - cmp al, '.' ; end of label? - jz .labelend - stosb ; put next character - inc ecx ; increment label length - jmp .labelloop +.nameloop: ; here we go in the start of each label: before "www", before "yandex", before "ru" + xor ecx, ecx ; ecx = length of current label + inc edi ; skip length, it will be filled later +.labelloop: ; here we go for each symbol of name + lodsb ; get next character + test al, al ; terminating zero? + jz .endname + cmp esi, ebx ; limit exceeded? + jae .wrongname + cmp al, '.' ; end of label? + jz .labelend + stosb ; put next character + inc ecx ; increment label length + jmp .labelloop .wrongname: - push EAI_NONAME - pop eax - jmp .ret + push EAI_NONAME + pop eax + jmp .ret .labelend: - test ecx, ecx ; null label can be only in the end of name - jz .wrongname + test ecx, ecx ; null label can be only in the end of name + jz .wrongname .endname: - cmp ecx, 63 - ja .wrongname + cmp ecx, 63 + ja .wrongname ; write length to byte [edi-ecx-1] - mov eax, ecx - neg eax - mov byte [edi+eax-1], cl - cmp byte [esi-1], 0 ; that was last label in the name? - jnz .nameloop + mov eax, ecx + neg eax + mov byte [edi+eax-1], cl + cmp byte [esi-1], 0 ; that was last label in the name? + jnz .nameloop ; write terminating zero if not yet - mov al, 0 - cmp byte [edi-1], al - jz @f - stosb + mov al, 0 + cmp byte [edi-1], al + jz @f + stosb @@: ; 6h. Write request data: -; query type = A (host address) = 1, -; query class = IN (internet IPv4 address) = 1 +; query type = A (host address) = 1, +; query class = IN (internet IPv4 address) = 1 ; Note that network byte order is big-endian. - mov eax, 0x01000100 - stosd + mov eax, 0x01000100 + stosd ; 7. Get DNS server address. - mcall 52, 13 - xchg esi, eax ; put server address to esi -; 8. Open UDP socket to DNS server, port 53. - mcall 53, 0, 0, 53 - cmp eax, -1 ; error? - jz .ret.dnserr - xchg ecx, eax ; put socket handle to ecx + mcall 76, API_IPv4 + 4 ; protocol IP=0, device number=0, function=get DNS address + cmp eax, -1 + je .ret.dnserr + mov esi, eax ; put server address to esi +; 8. Open UDP socketnum to DNS server, port 53. +; 8a. Create new socketnum. + mcall 75, 0, AF_INET4, SOCK_DGRAM + cmp eax, -1 ; error? + jz .ret.dnserr + mov ecx, eax ; put socketnum handle to ecx +; 8b. Create sockaddr structure on the stack. + push 0 + push 0 ; sin_zero + push esi ; sin_addr + push AF_INET4 + (53 shl 24) + ; sin_family and sin_port in network byte order +; 8c. Connect. + mcall 75, 4, , esp, sizeof.sockaddr_in +; 8d. Restore the stack, undo 8b. + add esp, esi +; 8e. Check result. + cmp eax, -1 + jz .ret.close ; 9. Send DNS request packet. - sub edi, esp ; get packet length - mcall 53, 4, , edi, esp - cmp eax, -1 - jz .ret.close - mov eax, [.reqdata] - mov [eax+__gai_reqdata.socket], ecx - push -1 - pop eax ; return status: more processing required - jmp .ret.dns + sub edi, esp ; get packet length + mov esi, edi + xor edi, edi + mcall 75, 6, , esp + cmp eax, -1 + jz .ret.close + mov eax, [.reqdata] + mov [eax+__gai_reqdata.socketnum], ecx + push -1 + pop eax ; return status: more processing required + jmp .ret.dns .ret.close: - mcall 53, 1 + mcall 75, 1 .ret.dnserr: - push EAI_AGAIN - pop eax + push EAI_AGAIN + pop eax .ret.dns: ; 6. Restore stack pointer and return. - jmp .ret + jmp .ret ;;===========================================================================;; ;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata, ;; @@ -714,202 +732,204 @@ getaddrinfo_process: ;; ;< eax = -1 if more processing required / 0 on success / >0 = error code ;; ;;===========================================================================;; ; 0. Create stack frame. - push ebp - mov ebp, esp + push ebp + mov ebp, esp virtual at ebp-.locals_size .locals_start: -.datagram rb 512 -.addrname dd ? -.name dd ? -.res_list_tail dd ? -.cname dd ? -.recent_restsize dd ? ; this is for memory alloc in ._.generate_data -.recent_page dd ? ; this is for memory alloc in ._.generate_data +.datagram rb 512 +.addrname dd ? +.name dd ? +.res_list_tail dd ? +.cname dd ? +.recent_restsize dd ? ; this is for memory alloc in ._.generate_data +.recent_page dd ? ; this is for memory alloc in ._.generate_data .locals_size = $ - .locals_start - rd 2 -.reqdata dd ? -.res dd ? + rd 2 +.reqdata dd ? +.res dd ? end virtual - xor eax, eax - push eax ; initialize .recent_page - push eax ; initialize .recent_restsize - push eax ; initialize .cname - push [.res] ; initialize .res_list_tail - sub esp, .locals_size-16 ; reserve place for other vars - mov edx, esp ; edx -> buffer for datagram + xor eax, eax + push eax ; initialize .recent_page + push eax ; initialize .recent_restsize + push eax ; initialize .cname + push [.res] ; initialize .res_list_tail + sub esp, .locals_size-16 ; reserve place for other vars + mov edx, esp ; edx -> buffer for datagram ; 1. Save used registers for __stdcall. - push ebx esi edi - mov edi, [.reqdata] + push ebx esi edi + mov edi, [.reqdata] ; 2. Read UDP datagram. - mov ecx, [edi+__gai_reqdata.socket] - mcall 53, 11, , , 512 -; 3. Ignore events for other sockets (return if no data read) - test eax, eax - jz .ret.more_processing_required + mov ecx, [edi+__gai_reqdata.socketnum] + push edi + mcall 75, 7, , , 512, 0 + pop edi +; 3. Ignore events for other socketnums (return if no data read) + test eax, eax + jz .ret.more_processing_required ; 4. Sanity check: discard too short packets. - xchg ecx, eax ; save packet length in ecx - cmp ecx, 12 - jb .ret.more_processing_required + xchg ecx, eax ; save packet length in ecx + cmp ecx, 12 + jb .ret.more_processing_required ; 5. Discard packets with ID != request ID. - mov eax, dword [edi+__gai_reqdata.reqid] - cmp ax, [edx] - jnz .ret.more_processing_required + mov eax, dword [edi+__gai_reqdata.reqid] + cmp ax, [edx] + jnz .ret.more_processing_required ; 6. Sanity check: discard query packets. - test byte [edx+2], 80h - jz .ret.more_processing_required + test byte [edx+2], 80h + jz .ret.more_processing_required ; 7. Sanity check: must be exactly one query (our). - cmp word [edx+4], 0x0100 ; note network byte order - jnz .ret.more_processing_required + cmp word [edx+4], 0x0100 ; note network byte order + jnz .ret.more_processing_required ; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other. - mov al, [edx+3] - and al, 0xF - jz @f - cmp al, 3 - jnz .ret.no_recovery - jmp .ret.no_name + mov al, [edx+3] + and al, 0xF + jz @f + cmp al, 3 + jnz .ret.no_recovery + jmp .ret.no_name @@: ; 9. Locate answers section. Exactly 1 query is present in this packet. - add ecx, edx ; ecx = limit - lea esi, [edx+12] - call .skip_name - lodsd ; skip QTYPE and QCLASS field - cmp esi, ecx - ja .ret.no_recovery + add ecx, edx ; ecx = limit + lea esi, [edx+12] + call .skip_name + lodsd ; skip QTYPE and QCLASS field + cmp esi, ecx + ja .ret.no_recovery ; 10. Loop through all answers. - movzx ebx, word [edx+6] ; get answers count - xchg bl, bh ; network -> Intel byte order + movzx ebx, word [edx+6] ; get answers count + xchg bl, bh ; network -> Intel byte order .answers_loop: - dec ebx - js .answers_done + dec ebx + js .answers_done ; 10a. Process each record. - mov [.name], esi + mov [.name], esi ; 10b. Skip name field. - call .skip_name + call .skip_name ; 10c. Get record information, handle two types for class IN (internet). - lodsd ; get type and class - cmp esi, ecx - ja .ret.no_recovery - cmp eax, 0x01000500 ; type=5, class=1? - jz .got_cname - cmp eax, 0x01000100 ; type=1, class=1? - jnz .answers_loop.next + lodsd ; get type and class + cmp esi, ecx + ja .ret.no_recovery + cmp eax, 0x01000500 ; type=5, class=1? + jz .got_cname + cmp eax, 0x01000100 ; type=1, class=1? + jnz .answers_loop.next .got_addr: ; 10d. Process record A, host address. - add esi, 10 - cmp esi, ecx - ja .ret.no_recovery - cmp word [esi-6], 0x0400 ; RDATA for A records must be 4 bytes long - jnz .ret.no_recovery - mov eax, [.name] - mov [.addrname], eax + add esi, 10 + cmp esi, ecx + ja .ret.no_recovery + cmp word [esi-6], 0x0400 ; RDATA for A records must be 4 bytes long + jnz .ret.no_recovery + mov eax, [.name] + mov [.addrname], eax ; 10e. Create corresponding record in the answer. - push ebx ecx esi - mov eax, [esi-4] ; IP address - mov esi, [.res_list_tail] ; pointer to result - test esi, esi - jz .no_result ; do not save if .res is NULL - mov ebx, [.reqdata] ; request data - call getaddrinfo._.generate_data - mov [.res_list_tail], esi - pop esi ecx ebx - cmp [.res_list_tail], 0 - jnz .answers_loop + push ebx ecx esi + mov eax, [esi-4] ; IP address + mov esi, [.res_list_tail] ; pointer to result + test esi, esi + jz .no_result ; do not save if .res is NULL + mov ebx, [.reqdata] ; request data + call getaddrinfo._.generate_data + mov [.res_list_tail], esi + pop esi ecx ebx + cmp [.res_list_tail], 0 + jnz .answers_loop ; 10f. If generate_data failed (this means memory allocation failure), abort - jmp .ret.no_memory + jmp .ret.no_memory .no_result: - pop esi ecx ebx - jmp .answers_loop + pop esi ecx ebx + jmp .answers_loop .got_cname: ; 10g. Process record CNAME, main host name. - lea eax, [esi+6] - mov [.cname], eax + lea eax, [esi+6] + mov [.cname], eax .answers_loop.next: ; 10h. Skip other record fields, advance to next record. - lodsd ; skip TTL - xor eax, eax - lodsw ; get length of RDATA field - xchg al, ah ; network -> Intel byte order - add esi, eax - cmp esi, ecx - ja .ret.no_recovery - jmp .answers_loop + lodsd ; skip TTL + xor eax, eax + lodsw ; get length of RDATA field + xchg al, ah ; network -> Intel byte order + add esi, eax + cmp esi, ecx + ja .ret.no_recovery + jmp .answers_loop .answers_done: ; 11. Check that there is at least 1 answer. - mov eax, [.res_list_tail] - cmp [.res], eax - jz .ret.no_data + mov eax, [.res_list_tail] + cmp [.res], eax + jz .ret.no_data ; 12. If canonical name was required, add it now. - mov eax, [.reqdata] - test byte [eax+__gai_reqdata.flags], AI_CANONNAME - jz .no_canon_name + mov eax, [.reqdata] + test byte [eax+__gai_reqdata.flags], AI_CANONNAME + jz .no_canon_name ; 12a. If at least one CNAME record is present, use name from last such record. ; Otherwise, use name from one of A records. - mov esi, [.cname] - test esi, esi - jnz .has_cname - mov esi, [.addrname] + mov esi, [.cname] + test esi, esi + jnz .has_cname + mov esi, [.addrname] .has_cname: ; 12b. Calculate name length. - call .get_name_length - jc .ret.no_recovery + call .get_name_length + jc .ret.no_recovery ; 12c. Check that the caller really want to get data. - cmp [.res], 0 - jz .no_canon_name + cmp [.res], 0 + jz .no_canon_name ; 12d. Allocate memory for name. - call getaddrinfo._.memalloc - test edi, edi - jz .ret.no_memory + call getaddrinfo._.memalloc + test edi, edi + jz .ret.no_memory ; 12e. Make first entry in .res list point to canonical name. - mov eax, [.res] - mov eax, [eax] - mov [eax+addrinfo.ai_canonname], edi + mov eax, [.res] + mov eax, [eax] + mov [eax+addrinfo.ai_canonname], edi ; 12f. Decode name. - call .decode_name + call .decode_name .no_canon_name: ; 13. Set status to success. - xor eax, eax - jmp .ret.close + xor eax, eax + jmp .ret.close ; Handle errors. .ret.more_processing_required: - push -1 - pop eax - jmp .ret + push -1 + pop eax + jmp .ret .ret.no_recovery: - push EAI_FAIL - pop eax - jmp .ret.destroy + push EAI_FAIL + pop eax + jmp .ret.destroy .ret.no_memory: - push EAI_MEMORY - pop eax - jmp .ret.destroy + push EAI_MEMORY + pop eax + jmp .ret.destroy .ret.no_name: .ret.no_data: - push EAI_NONAME - pop eax + push EAI_NONAME + pop eax .ret.destroy: ; 14. If an error occured, free memory acquired so far. - push eax - mov esi, [.res] - test esi, esi - jz @f - pushd [esi] - call freeaddrinfo - and dword [esi], 0 + push eax + mov esi, [.res] + test esi, esi + jz @f + pushd [esi] + call freeaddrinfo + and dword [esi], 0 @@: - pop eax + pop eax .ret.close: -; 15. Close socket. - push eax - mov ecx, [.reqdata] - mov ecx, [ecx+__gai_reqdata.socket] - mcall 53, 1 - pop eax +; 15. Close socketnum. + push eax + mov ecx, [.reqdata] + mov ecx, [ecx+__gai_reqdata.socketnum] + mcall 75, 1 + pop eax ; 16. Restore used registers, destroy stack frame and return. .ret: - pop edi esi ebx - mov esp, ebp - pop ebp - ret 8 + pop edi esi ebx + mov esp, ebp + pop ebp + ret 8 ;;===========================================================================;; ;; Internal auxiliary function for skipping names in DNS packet. ;; @@ -922,20 +942,20 @@ end virtual ;;---------------------------------------------------------------------------;; ;< esi -> end of name ;; ;;===========================================================================;; - xor eax, eax - cmp esi, ecx - jae .skip_name.done - lodsb - test al, al - jz .skip_name.done - test al, 0xC0 - jnz .skip_name.pointer - add esi, eax - jmp .skip_name + xor eax, eax + cmp esi, ecx + jae .skip_name.done + lodsb + test al, al + jz .skip_name.done + test al, 0xC0 + jnz .skip_name.pointer + add esi, eax + jmp .skip_name .skip_name.pointer: - inc esi + inc esi .skip_name.done: - ret + ret ;;===========================================================================;; ;; Internal auxiliary function for calculating length of name in DNS packet. ;; @@ -950,37 +970,37 @@ end virtual ;< eax = length of name ;; ;< CF set on error / cleared on success ;; ;;===========================================================================;; - xor ebx, ebx ; ebx will hold data length + xor ebx, ebx ; ebx will hold data length .get_name_length.zero: - xor eax, eax + xor eax, eax .get_name_length.loop: - cmp esi, ecx - jae .get_name_length.fail - lodsb - test al, al - jz .get_name_length.done - test al, 0xC0 - jnz .get_name_length.pointer - add esi, eax - inc ebx - add ebx, eax - cmp ebx, 256 - jbe .get_name_length.loop + cmp esi, ecx + jae .get_name_length.fail + lodsb + test al, al + jz .get_name_length.done + test al, 0xC0 + jnz .get_name_length.pointer + add esi, eax + inc ebx + add ebx, eax + cmp ebx, 256 + jbe .get_name_length.loop .get_name_length.fail: - stc - ret + stc + ret .get_name_length.pointer: - and al, 0x3F - mov ah, al - lodsb - lea esi, [edx+eax] - jmp .get_name_length.zero + and al, 0x3F + mov ah, al + lodsb + lea esi, [edx+eax] + jmp .get_name_length.zero .get_name_length.done: - test ebx, ebx - jz .get_name_length.fail - xchg eax, ebx - clc - ret + test ebx, ebx + jz .get_name_length.fail + xchg eax, ebx + clc + ret ;;===========================================================================;; ;; Internal auxiliary function for decoding DNS name. ;; @@ -992,26 +1012,26 @@ end virtual ;> esi -> name in packet ;; ;> edi -> buffer for decoded name ;; ;;===========================================================================;; - xor eax, eax - lodsb - test al, al - jz .decode_name.done - test al, 0xC0 - jnz .decode_name.pointer - mov ecx, eax - rep movsb - mov al, '.' - stosb - jmp .decode_name + xor eax, eax + lodsb + test al, al + jz .decode_name.done + test al, 0xC0 + jnz .decode_name.pointer + mov ecx, eax + rep movsb + mov al, '.' + stosb + jmp .decode_name .decode_name.pointer: - and al, 0x3F - mov ah, al - lodsb - lea esi, [edx+eax] - jmp .decode_name + and al, 0x3F + mov ah, al + lodsb + lea esi, [edx+eax] + jmp .decode_name .decode_name.done: - mov byte [edi-1], 0 - ret + mov byte [edi-1], 0 + ret ;;===========================================================================;; ;; Internal auxiliary function for allocating memory for getaddrinfo. ;; @@ -1026,36 +1046,36 @@ getaddrinfo._.memalloc: ;; ;< edi -> allocated memory / NULL on error ;; ;;===========================================================================;; ; 1. Set edi to result of function. - mov edi, [ebp-4] + mov edi, [ebp-4] ; 2. Check whether we need to allocate a new page. - cmp eax, [ebp-8] - jbe .no_new_page + cmp eax, [ebp-8] + jbe .no_new_page ; 2. Allocate new page if need. Reset edi to new result. - push eax ebx - mcall 68, 12, 0x1000 - xchg edi, eax ; put result to edi - pop ebx eax + push eax ebx + mcall 68, 12, 0x1000 + xchg edi, eax ; put result to edi + pop ebx eax ; 3. Check returned value of allocator. Fail if it failed. - test edi, edi - jz .ret + test edi, edi + jz .ret ; 4. Update .recent_page and .recent_restsize. - add edi, 4 - sub ecx, 4 - mov [ebp-4], edi - mov [ebp-8], ecx + add edi, 4 + sub ecx, 4 + mov [ebp-4], edi + mov [ebp-8], ecx .no_new_page: ; 5. Increase number of objects on this page. - push eax - mov eax, edi - and eax, not 0xFFF - inc dword [eax] - pop eax + push eax + mov eax, edi + and eax, not 0xFFF + inc dword [eax] + pop eax ; 6. Advance last allocated pointer, decrease memory size. - add [ebp-4], eax - sub [ebp-8], eax + add [ebp-4], eax + sub [ebp-8], eax ; 7. Return. .ret: - ret + ret ;;===========================================================================;; ;; Internal auxiliary function for freeing memory for freeaddrinfo. ;; @@ -1066,18 +1086,18 @@ getaddrinfo._.memfree: ;; ;> eax = pointer ;; ;;===========================================================================;; ; 1. Get start of page. - mov ecx, eax - and ecx, not 0xFFF + mov ecx, eax + and ecx, not 0xFFF ; 2. Decrease number of objects. - dec dword [ecx] + dec dword [ecx] ; 3. If it goes to zero, free the page. - jnz @f - push ebx - mcall 68, 13 - pop ebx + jnz @f + push ebx + mcall 68, 13 + pop ebx @@: ; 4. Done. - ret + ret ;;===========================================================================;; getaddrinfo._.generate_data: ;; @@ -1094,101 +1114,100 @@ getaddrinfo._.generate_data: ;; ;;===========================================================================;; ; 1. If no service is given, append one item with zero port. ; append one item with zero socktype/protocol/port. - cmp [ebx+__gai_reqdata.service], -1 - jnz .has_service - call .append_item + cmp [ebx+__gai_reqdata.service], -1 + jnz .has_service + call .append_item ; 1a. If neither protocol nor socktype were specified, -; leave zeroes in socktype and protocol. - mov cl, [ebx+__gai_reqdata.socktype] - test cl, cl - jz .no_socktype +; leave zeroes in socktype and protocol. + mov cl, [ebx+__gai_reqdata.socktype] + test cl, cl + jz .no_socktype ; 1b. Otherwise, set socktype and protocol to desired. - call .set_socktype + call .set_socktype .no_socktype: - ret + ret .has_service: ; 2. If TCP is allowed, append item for TCP. - cmp [ebx+__gai_reqdata.socktype], 0 - jz .tcp_ok - cmp [ebx+__gai_reqdata.socktype], SOCK_STREAM - jnz .tcp_disallowed + cmp [ebx+__gai_reqdata.socktype], 0 + jz .tcp_ok + cmp [ebx+__gai_reqdata.socktype], SOCK_STREAM + jnz .tcp_disallowed .tcp_ok: - call .append_item - mov cl, SOCK_STREAM - call .set_socktype - call .set_port + call .append_item + mov cl, SOCK_STREAM + call .set_socktype + call .set_port .tcp_disallowed: ; 3. If UDP is allowed, append item for UDP. - cmp [ebx+__gai_reqdata.socktype], 0 - jz .udp_ok - cmp [ebx+__gai_reqdata.socktype], SOCK_DGRAM - jnz .udp_disallowed + cmp [ebx+__gai_reqdata.socktype], 0 + jz .udp_ok + cmp [ebx+__gai_reqdata.socktype], SOCK_DGRAM + jnz .udp_disallowed .udp_ok: - call .append_item - mov cl, SOCK_DGRAM - call .set_socktype - call .set_port + call .append_item + mov cl, SOCK_DGRAM + call .set_socktype + call .set_port .udp_disallowed: - ret + ret .append_item: ; 1. Allocate memory for struct sockaddr_in and struct addrinfo. - push eax - push sizeof.addrinfo + sizeof.sockaddr_in - pop eax - call getaddrinfo._.memalloc + push eax + push sizeof.addrinfo + sizeof.sockaddr_in + pop eax + call getaddrinfo._.memalloc ; 2. Check for memory allocation fail. - test edi, edi - jz .no_memory + test edi, edi + jz .no_memory ; 3. Zero allocated memory. - push (sizeof.addrinfo + sizeof.sockaddr_in) / 4 - pop ecx - xor eax, eax - push edi - rep stosd - pop edi + push (sizeof.addrinfo + sizeof.sockaddr_in) / 4 + pop ecx + xor eax, eax + push edi + rep stosd + pop edi ; 4. Fill struct addrinfo. - mov eax, [ebx+__gai_reqdata.flags] - mov [edi+addrinfo.ai_flags], eax - mov byte [edi+addrinfo.ai_family], PF_INET - mov byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in - lea ecx, [edi+sizeof.addrinfo] - mov [edi+addrinfo.ai_addr], ecx + mov eax, [ebx+__gai_reqdata.flags] + mov [edi+addrinfo.ai_flags], eax + mov byte [edi+addrinfo.ai_family], AF_INET4 + mov byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in + lea ecx, [edi+sizeof.addrinfo] + mov [edi+addrinfo.ai_addr], ecx ; 5. Fill struct sockaddr_in. - mov byte [ecx+sockaddr_in.sin_len], sizeof.sockaddr_in - mov byte [ecx+sockaddr_in.sin_family], PF_INET - pop eax - mov [ecx+sockaddr_in.sin_addr], eax + mov byte [ecx+sockaddr_in.sin_family], AF_INET4 + pop eax + mov [ecx+sockaddr_in.sin_addr], eax ; 6. Append new item to the list. - mov [esi], edi - lea esi, [edi+addrinfo.ai_next] + mov [esi], edi + lea esi, [edi+addrinfo.ai_next] ; 7. Return. - ret + ret .no_memory: - pop eax - xor esi, esi - ret + pop eax + xor esi, esi + ret .set_socktype: -; Set ai_socktype and ai_protocol fields by given socket type. - mov byte [edi+addrinfo.ai_socktype], cl - dec cl - jnz .set_udp +; Set ai_socktype and ai_protocol fields by given socketnum type. + mov byte [edi+addrinfo.ai_socktype], cl + dec cl + jnz .set_udp .set_tcp: - mov byte [edi+addrinfo.ai_protocol], IPPROTO_TCP - ret + mov byte [edi+addrinfo.ai_protocol], IPPROTO_TCP + ret .set_udp: - mov byte [edi+addrinfo.ai_protocol], IPPROTO_UDP - ret + mov byte [edi+addrinfo.ai_protocol], IPPROTO_UDP + ret .set_port: ; Just copy port from input __gai_reqdata to output addrinfo. - push edx - mov edx, [ebx+__gai_reqdata.service] - xchg dl, dh ; convert to network byte order - mov [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx - pop edx - ret + push edx + mov edx, [ebx+__gai_reqdata.service] + xchg dl, dh ; convert to network byte order ;;;;; CHECKME + mov [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx + pop edx + ret ;;===========================================================================;; ;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata); ;; @@ -1199,14 +1218,14 @@ getaddrinfo_abort: ;; ;> first parameter = pointer to struct __gai_reqdata filled by ..._start ;; ;;===========================================================================;; ; 0. Save used registers for __stdcall. - push ebx -; 1. Allocated resources: only socket, so close it and return. - mov eax, [esp+8] - mov ecx, [eax+__gai_reqdata.socket] - mcall 53, 1 + push ebx +; 1. Allocated resources: only socketnum, so close it and return. + mov eax, [esp+8] + mov ecx, [eax+__gai_reqdata.socketnum] + mcall 75, 1 ; 2. Restore used registers and return. - pop ebx - ret 4 + pop ebx + ret 4 ;;===========================================================================;; ;; void __stdcall freeaddrinfo(__in struct addrinfo* ai); ;; @@ -1218,29 +1237,29 @@ freeaddrinfo: ;; ; (may be arbitrary sublist of original) ;; ;;===========================================================================;; ; 1. Loop for all items in the list. - mov edx, [esp+4] ; eax = ai + mov edx, [esp+4] ; eax = ai .loop: - test edx, edx - jz .done + test edx, edx + jz .done ; 2. Free each item. ; 2a. Free ai_canonname, if allocated. - mov eax, [edx+addrinfo.ai_canonname] - test eax, eax - jz .no_canon_name - call getaddrinfo._.memfree + mov eax, [edx+addrinfo.ai_canonname] + test eax, eax + jz .no_canon_name + call getaddrinfo._.memfree .no_canon_name: ; 2b. Remember next item -; (after freeing the field ai_next can became unavailable). - pushd [edx+addrinfo.ai_next] +; (after freeing the field ai_next can became unavailable). + pushd [edx+addrinfo.ai_next] ; 2c. Free item itself. - xchg eax, edx - call getaddrinfo._.memfree + xchg eax, edx + call getaddrinfo._.memfree ; 2d. Restore pointer to next item and continue loop. - pop edx - jmp .loop + pop edx + jmp .loop .done: ; 3. Done. - ret 4 + ret 4 ;;===========================================================================;; ;;///////////////////////////////////////////////////////////////////////////;; @@ -1253,26 +1272,16 @@ freeaddrinfo: ;; align 4 @EXPORT: -export \ - lib_init , 'lib_init' , \ - 0x00010001 , 'version' , \ - inet_addr , 'inet_addr' , \ - inet_ntoa , 'inet_ntoa' , \ - getaddrinfo , 'getaddrinfo' , \ - getaddrinfo_start , 'getaddrinfo_start' , \ - getaddrinfo_process , 'getaddrinfo_process' , \ - getaddrinfo_abort , 'getaddrinfo_abort' , \ - freeaddrinfo , 'freeaddrinfo' - -; import from libini -align 4 -@IMPORT: - -library libini, 'libini.obj' -import libini, \ - ini.get_str, 'ini_get_str', \ - ini.get_int, 'ini_get_int' - +export \ + lib_init , 'lib_init' , \ + 0x00010001 , 'version' , \ + inet_addr , 'inet_addr' , \ + inet_ntoa , 'inet_ntoa' , \ + getaddrinfo , 'getaddrinfo' , \ + getaddrinfo_start , 'getaddrinfo_start' , \ + getaddrinfo_process , 'getaddrinfo_process' , \ + getaddrinfo_abort , 'getaddrinfo_abort' , \ + freeaddrinfo , 'freeaddrinfo' section '.data' data readable writable align 16 ; uninitialized data @@ -1281,6 +1290,6 @@ mem.free dd ? mem.realloc dd ? dll.load dd ? -DNSrequestID dd ? +DNSrequestID dd ? -inet_ntoa.buffer rb 16 ; static buffer for inet_ntoa +inet_ntoa.buffer rb 16 ; static buffer for inet_ntoa diff --git a/programs/develop/libraries/network/network.inc b/programs/develop/libraries/network/network.inc index 0974db72be..efe942c9ff 100644 --- a/programs/develop/libraries/network/network.inc +++ b/programs/develop/libraries/network/network.inc @@ -1,22 +1,27 @@ ; Socket types SOCK_STREAM = 1 SOCK_DGRAM = 2 -SOCK_RAW = 3 ; not supported by the kernel +SOCK_RAW = 3 + +; Socket options +SO_NONBLOCK = 1 shl 31 ; IP protocols IPPROTO_IP = 0 -IPPROTO_ICMP = 1 ; not supported by the kernel +IPPROTO_ICMP = 1 IPPROTO_TCP = 6 IPPROTO_UDP = 17 ; Address families AF_UNSPEC = 0 -AF_INET = 2 ; IPv4 -;AF_INET6 = 28 ; IPv6 (not supported) +AF_LOCAL = 1 +AF_INET4 = 2 ; IPv4 +AF_INET6 = 28 ; IPv6 (not supported yet) PF_UNSPEC = AF_UNSPEC -PF_INET = AF_INET -;PF_INET6 = AF_INET6 +PF_LOCAL = AF_LOCAL +PF_INET4 = AF_INET4 +PF_INET6 = AF_INET6 ; Flags for addrinfo AI_PASSIVE = 1 @@ -28,9 +33,17 @@ AI_ADDRCONFIG = 0x400 ; internal definition AI_SUPPORTED = 0x40F +; for system function 76 +API_ETH = 0 shl 16 +API_IPv4 = 1 shl 16 +API_ICMP = 2 shl 16 +API_UDP = 3 shl 16 +API_TCP = 4 shl 16 +API_ARP = 5 shl 16 +API_PPPOE = 6 shl 16 + struct sockaddr_in - sin_len db ? ; uint8_t - sin_family db ? ; sa_family_t + sin_family dw ? ; sa_family_t sin_port dw ? ; in_port_t sin_addr dd ? ; struct in_addr sin_zero rb 8 ; zero @@ -43,8 +56,8 @@ struct addrinfo ai_protocol dd ? ; 0 or IPPROTO_* ai_addrlen dd ? ; length of ai_addr ai_canonname dd ? ; char* - ai_addr dd ? ; struct sockaddr* - ai_next dd ? ; struct addrinfo* + ai_addr dd ? ; struct sockaddr* + ai_next dd ? ; struct addrinfo* ends EAI_ADDRFAMILY = 1 @@ -59,3 +72,23 @@ EAI_SOCKTYPE = 10 EAI_BADHINTS = 12 EAI_PROTOCOL = 13 EAI_OVERFLOW = 14 + +socket fix 75, 0 +close fix 75, 1 +bind fix 75, 2 +listen fix 75, 3 +connect fix 75, 4 +accept fix 75, 5 +send fix 75, 6 +recv fix 75, 7 +setsockopt fix 75, 8 +getsockopt fix 75, 9 +socketpair fix 75, 10 + + +struct ARP_entry + IP dd ? + MAC dp ? + status dw ? + TTL dw ? +ends diff --git a/programs/network/arpcfg/arpcfg.asm b/programs/network/arpcfg/arpcfg.asm new file mode 100644 index 0000000000..766a514185 --- /dev/null +++ b/programs/network/arpcfg/arpcfg.asm @@ -0,0 +1,156 @@ +; +; ARPmanager for KolibriOS +; +; hidnplayr@gmail.com +; + +format binary as "" + +use32 + + org 0x0 + + db 'MENUET01' ; 8 byte id + dd 0x01 ; header version + dd START ; start of code + dd IM_END ; size of image + dd (I_END+0x100) ; memory for app + dd (I_END+0x100) ; esp + dd 0x0 , 0x0 ; I_Param , I_Icon + +include '../macros.inc' +purge mov, add, sub +include '../struct.inc' +include '../network.inc' + +START: + +redraw: + + mcall 12, 1 + mcall 0, 100 shl 16 + 520, 100 shl 16 + 240, 0x34bcbcbc, , str_name + mcall 4, 25 shl 16 + 31, 0x80000000, str_legend + mcall 12, 2 + +draw_stats: + + mov edx, 50 shl 16 + 50 + mov [last], 0 + + .loop: + mcall 76, API_ARP + 3, [last],,, arp_buf + cmp eax, -1 + je mainloop + + mcall 4, edx, 0x80000000, str_entry + mov edx, ebx + + mov eax, 47 + mov ebx, 0x00030000 + mov esi, 0x40000000 + mov edi, 0x00bcbcbc + xor ecx, ecx + + mov cl, byte[arp_buf.IP+0] + mcall + + mov cl, byte[arp_buf.IP+1] + add edx, 24 shl 16 + mcall + + mov cl, byte[arp_buf.IP+2] + add edx, 24 shl 16 + mcall + + mov cl, byte[arp_buf.IP+3] + add edx, 24 shl 16 + mcall + + + mov ebx, 0x00020100 + mov cl, byte[arp_buf.MAC+0] + add edx, 36 shl 16 + mcall + + mov cl, byte[arp_buf.MAC+1] + add edx, 18 shl 16 + mcall + + mov cl, byte[arp_buf.MAC+2] + add edx, 18 shl 16 + mcall + + mov cl, byte[arp_buf.MAC+3] + add edx, 18 shl 16 + mcall + + mov cl, byte[arp_buf.MAC+4] + add edx, 18 shl 16 + mcall + + mov cl, byte[arp_buf.MAC+5] + add edx, 18 shl 16 + mcall + + mov ebx, 0x00040000 + mov cx, [arp_buf.status] + add edx, 30 shl 16 + mcall + + mov cx, [arp_buf.TTL] + add edx, 60 shl 16 + mcall + + add dx, 20 + rol edx, 16 + mov dx, 50 + rol edx, 16 + inc [last] + + jmp .loop + + +mainloop: + + mcall 23,50 ; wait for event with timeout (0,5 s) + + cmp eax, 1 + je redraw + cmp eax, 2 + je key + cmp eax, 3 + je button + + jmp draw_stats + + +key: + mcall 2 + jmp mainloop + + +button: ; button + mcall 17 ; get id + cmp ah, 1 + je exit + jmp redraw + +exit: + mcall -1 + + + +; DATA AREA + +str_name db 'ARP manager', 0 +str_legend db '# IP-address MAC-address Status TTL', 0 +str_entry db ' . . . - - - - - s', 0 + +IM_END: + +last dd ? +arp_buf ARP_entry + +I_END: + + diff --git a/programs/network/icq/trunk/config.inc b/programs/network/config.inc similarity index 100% rename from programs/network/icq/trunk/config.inc rename to programs/network/config.inc diff --git a/programs/network/zeroconf/trunk/debug-fdo.inc b/programs/network/debug-fdo.inc similarity index 100% rename from programs/network/zeroconf/trunk/debug-fdo.inc rename to programs/network/debug-fdo.inc diff --git a/programs/network/dll.inc b/programs/network/dll.inc new file mode 100644 index 0000000000..a213dd21be --- /dev/null +++ b/programs/network/dll.inc @@ -0,0 +1,160 @@ +;----------------------------------------------------------------------------- +proc mem.Alloc size ;///////////////////////////////////////////////////////// +;----------------------------------------------------------------------------- + push ebx ecx + mov eax,[size] + lea ecx,[eax+4+4095] + and ecx, not 4095 + mcall 68,12 + test eax, eax + jz @f + add ecx,-4 + mov [eax],ecx + add eax,4 + @@: + pop ecx ebx + ret +endp + +;----------------------------------------------------------------------------- +proc mem.ReAlloc mptr,size;/////////////////////////////////////////////////// +;----------------------------------------------------------------------------- + push ebx ecx esi edi eax + mov eax,[mptr] + mov ebx,[size] + or eax,eax + jz @f + lea ecx,[ebx+4+4095] + and ecx,not 4095 + add ecx,-4 + cmp ecx,[eax-4] + je .exit + @@: mov eax,ebx + call mem.Alloc + xchg eax,[esp] + or eax,eax + jz .exit + mov esi,eax + xchg eax,[esp] + mov edi,eax + mov ecx,[esi-4] + cmp ecx,[edi-4] + jbe @f + mov ecx,[edi-4] + @@: add ecx,3 + shr ecx,2 + cld + rep movsd + xchg eax,[esp] + call mem.Free + .exit: + pop eax edi esi ecx ebx + ret +endp + +;----------------------------------------------------------------------------- +proc mem.Free mptr ;////////////////////////////////////////////////////////// +;----------------------------------------------------------------------------- + mov eax,[mptr] + or eax,eax + jz @f + push ebx ecx + lea ecx,[eax-4] + mcall 68,13 + pop ecx ebx + @@: ret +endp + + +proc dll.Load, import_table:dword + mov esi,[import_table] + .next_lib: mov edx,[esi] + or edx,edx + jz .exit + push esi + mov esi,[esi+4] + mov edi,s_libdir.fname + @@: lodsb + stosb + or al,al + jnz @b + mcall 68,19,s_libdir + or eax,eax + jz .fail + stdcall dll.Link,eax,edx + stdcall dll.Init,[eax+4] + pop esi + add esi,8 + jmp .next_lib + .exit: xor eax,eax + ret + .fail: add esp,4 + xor eax,eax + inc eax + ret +endp + +proc dll.Link, exp:dword,imp:dword + push eax + mov esi,[imp] + test esi,esi + jz .done + .next: lodsd + test eax,eax + jz .done + stdcall dll.GetProcAddress,[exp],eax + or eax,eax + jz @f + mov [esi-4],eax + jmp .next + @@: mov dword[esp],0 + .done: pop eax + ret +endp + +proc dll.Init, dllentry:dword + pushad + mov eax,mem.Alloc + mov ebx,mem.Free + mov ecx,mem.ReAlloc + mov edx,dll.Load + stdcall [dllentry] + popad + ret +endp + +proc dll.GetProcAddress, exp:dword,sz_name:dword + mov edx,[exp] + xor eax,eax + .next: or edx,edx + jz .end + cmp dword[edx],0 + jz .end + stdcall strcmp,[edx],[sz_name] + test eax,eax + jz .ok + add edx,8 + jmp .next + .ok: mov eax,[edx+4] + .end: ret +endp + +proc strcmp, str1:dword,str2:dword + push esi edi + mov esi,[str1] + mov edi,[str2] + xor eax,eax + @@: lodsb + scasb + jne .fail + or al,al + jnz @b + jmp .ok + .fail: or eax,-1 + .ok: pop edi esi + ret +endp + +s_libdir: + db '/sys/lib/' + .fname rb 32 diff --git a/programs/network/ftpd/commands.inc b/programs/network/ftpd/commands.inc new file mode 100644 index 0000000000..f5bc9bb2d2 --- /dev/null +++ b/programs/network/ftpd/commands.inc @@ -0,0 +1,1135 @@ + + +struct thread_data + rb 1024 + stack rb 0 + + home_dir rb 1024 ; home directory in wich the user is locked, asciiz + work_dir rb 1024 ; working directory, must at all times begin and end with a '/', asciiz + fpath rb 1024*3 ; file path, combination of home_dir, work_dir and filename + ; Will also be used to temporarily store username + + type db ? ; ASCII/EBDIC/IMAGE/.. + mode db ? ; active/passive + socketnum dd ? ; Commands socket + state dd ? ; disconnected/logging in/logged in/.. + passivesocknum dd ? ; when in passive mode, this is the listening socket + datasocketnum dd ? ; socket used for data transfers + permissions dd ? ; read/write/execute/.... + buffer_ptr dd ? + pid dd ? ; Process id of the current thread + + datasock sockaddr_in + + buffer rb BUFFERSIZE +ends + +;------------------------------------------------ +; parse_cmd +; +; Internal function wich uses the 'commands' +; table to call an appropriate cmd_xx function. +; +; input: esi = ptr to ascii commands +; ecx = number of bytes input +; ebp = pointer to thread_data structure +; +; output: none +; +;------------------------------------------------ +align 4 +parse_cmd: ; esi must point to command + + cmp byte [esi], 0x20 ; skip all leading characters + ja .ok + inc esi + dec ecx + cmp ecx, 3 + jb .error + jmp parse_cmd + .ok: + cmp byte [esi+3], 0x20 + ja @f + mov byte [esi+3], 0 + @@: + + mov eax, [esi] + and eax, not 0x20202020 ; convert to upper case + mov edi, commands ; list of commands to scan + .scanloop: + cmp eax, [edi] + je .got_it + + add edi, 5*4 + cmp byte [edi], 0 + jne .scanloop + + .error: + cmp [ebp + thread_data.state], STATE_ACTIVE + jb login_first + sendFTP "500 Unsupported command" + ret + + .got_it: + mov eax, [ebp + thread_data.state] + jmp dword [edi + 4 + eax] + + +align 4 +iglobal +commands: ; all commands must be in uppercase + + dd 'ABOR', login_first, login_first, login_first, cmdABOR +; dd 'ACCT', login_first, login_first, login_first, cmd_ACCT +; dd 'APPE', login_first, login_first, login_first, cmd_APPE + dd 'CDUP', login_first, login_first, login_first, cmdCDUP + dd 'CWD', login_first, login_first, login_first, cmdCWD + dd 'DELE', login_first, login_first, login_first, cmdDELE +; dd 'HELP', login_first, login_first, login_first, cmd_HELP + dd 'LIST', login_first, login_first, login_first, cmdLIST +; dd 'MDTM', login_first, login_first, login_first, cmd_MDTM +; dd 'MKD', login_first, login_first, login_first, cmd_MKD +; dd 'MODE', login_first, login_first, login_first, cmd_MODE + dd 'NLST', login_first, login_first, login_first, cmdNLST + dd 'NOOP', login_first, login_first, login_first, cmdNOOP + dd 'PASS', cmdPASS.0, cmdPASS , cmdPASS.2, cmdPASS.3 + dd 'PASV', login_first, login_first, login_first, cmdPASV + dd 'PORT', login_first, login_first, login_first, cmdPORT + dd 'PWD', login_first, login_first, login_first, cmdPWD + dd 'QUIT', cmdQUIT, cmdQUIT, cmdQUIT, cmdQUIT +; dd 'REIN', login_first, login_first, login_first, cmd_REIN +; dd 'REST', login_first, login_first, login_first, cmd_REST + dd 'RETR', login_first, login_first, login_first, cmdRETR +; dd 'RMD', login_first, login_first, login_first, cmd_RMD +; dd 'RNFR', login_first, login_first, login_first, cmd_RNFR +; dd 'RNTO', login_first, login_first, login_first, cmd_RNTO +; dd 'SITE', login_first, login_first, login_first, cmd_SITE +; dd 'SIZE', login_first, login_first, login_first, cmd_SIZE +; dd 'STAT', login_first, login_first, login_first, cmd_STAT + dd 'STOR', login_first, login_first, login_first, cmdSTOR +; dd 'STOU', login_first, login_first, login_first, cmd_STOU +; dd 'STRU', login_first, login_first, login_first, cmd_STRU + dd 'SYST', login_first, login_first, login_first, cmdSYST + dd 'TYPE', login_first, login_first, login_first, cmdTYPE + dd 'USER', cmdUSER, cmdUSER, cmdUSER, cmdUSER.2 + db 0 ; end marker +endg + +align 4 +login_first: + sendFTP "530 Please login with USER and PASS" + ret + +align 4 +permission_denied: + sendFTP "550 Permission denied" + ret + +align 4 +socketerror: + invoke con_set_flags, 0x0c + invoke con_write_asciiz, str_sockerr + invoke con_set_flags, 0x07 + + sendFTP "425 Can't open data connection" + ret + +align 4 +abort_transfer: + and [ebp + thread_data.permissions], not ABORT + mov [ebp + thread_data.mode], MODE_NOTREADY + invoke file.close, ebx + mcall close, [ebp + thread_data.datasocketnum] + + sendFTP "530 Transfer aborted" + ret + +align 4 +ip_to_dword: ; esi = ptr to str, cl = separator ('.', ',') + + call ascii_to_byte + mov bl, al + cmp byte [esi], cl + jne .err + inc esi + + call ascii_to_byte + mov bh, al + cmp byte [esi], cl + jne .err + inc esi + + shl ebx, 16 + + call ascii_to_byte + mov bl, al + cmp byte [esi], cl + jne .err + inc esi + + call ascii_to_byte + mov bh, al + + ror ebx, 16 + ret + + .err: + xor ebx, ebx + ret + +align 4 ; esi = ptr to str, output in eax +ascii_to_byte: + + xor eax, eax + push ebx + + .loop: + movzx ebx, byte[esi] + sub bl, '0' + jb .done + cmp bl, 9 + ja .done + lea eax, [eax*4 + eax] ; + shl eax, 1 ; eax = eax * 10 + add eax, ebx + inc esi + + jmp .loop + + .done: + pop ebx + ret + +align 4 +dword_to_ascii: ; edi = ptr where to write, eax is number + + push edx ebx ecx + mov ebx, 10 + xor ecx, ecx + + @@: + xor edx, edx + div ebx + add edx, '0' + pushw dx + inc ecx + test eax, eax + jnz @r + + @@: + popw ax + stosb + dec ecx + jnz @r + + pop ecx ebx edx + ret + +align 4 +create_path: ; combine home_dir and work_dir strings into fpath + + lea edi, [ebp + thread_data.fpath] + lea esi, [ebp + thread_data.home_dir] + mov ecx, 1024 + .loop1: + lodsb + cmp al, 0x20 + jb .next + stosb + loop .loop1 + .next: + + cmp byte[edi-1], '/' + jne @f + dec edi + @@: + + lea esi, [ebp + thread_data.work_dir] + mov ecx, 1024 + .loop2: + lodsb + cmp al, 0x20 + jb .done + stosb + loop .loop2 + + .done: + xor al, al + stosb + ret + + +align 4 +nextpasvport: + + inc [pasv_port] + + mov ax, [pasv_port] + cmp ax, [pasv_start] + jb .restart + cmp ax, [pasv_end] + ja .restart + + ret + + .restart: + pushw [pasv_start] + popw [pasv_port] + + ret + + +align 4 +open_datasock: + + cmp [ebp + thread_data.mode], MODE_PASSIVE_OK + je .start + +; If we are in active mode, it's time to open a data socket.. + cmp [ebp + thread_data.mode], MODE_ACTIVE + jne .not_active + mov ecx, [ebp + thread_data.datasocketnum] + lea edx, [ebp + thread_data.datasock] + mov esi, sizeof.thread_data.datasock + mcall connect + cmp eax, -1 + jne .start + + .socketerror: + add esp, 4 + jmp socketerror + +; If we are still in passive_wait, it's time we accept an incomming call.. + .not_active: + cmp [ebp + thread_data.mode], MODE_PASSIVE_WAIT + jne .socketerror + + .try_now: + mov ecx, [ebp + thread_data.passivesocknum] + lea edx, [ebp + thread_data.datasock] + mov esi, sizeof.thread_data.datasock + mcall accept + cmp eax, -1 + jne .pasv_ok + mov [ebp + thread_data.mode], MODE_PASSIVE_FAILED ; assume that we will fail + mcall 23, 200 + mcall accept + cmp eax, -1 + je .socketerror + .pasv_ok: + mov [ebp + thread_data.datasocketnum], eax + mov [ebp + thread_data.mode], MODE_PASSIVE_OK + mcall close ; [ebp + thread_data.passivesocknum] + mov [ebp + thread_data.passivesocknum], -1 + invoke con_write_asciiz, str_datasock + + .start: + ret + + +;------------------------------------------------ +; "ABOR" +; +; This command aborts the current filetransfer. +; +;------------------------------------------------ +align 4 +cmdABOR: + + or [ebp + thread_data.permissions], ABORT + sendFTP "250 Command succesul" + ret + +;------------------------------------------------ +; "CDUP" +; +; Change the directory to move up one level. +; +;------------------------------------------------ +align 4 +cmdCDUP: + + test [ebp + thread_data.permissions], PERMISSION_CD + jz permission_denied + + cmp byte [ebp + thread_data.work_dir+1], 0 ; are we in "/" ? + je .done ; if so, we cant go up.. + +; find the end of asciiz string work_dir + mov ecx, 1024 + xor al, al + lea edi, [ebp + thread_data.work_dir] + repne scasb +; return 2 characters (right before last /) + sub edi, 3 +; and now search backwards, for a '/' + mov al,'/' + neg ecx + add ecx, 1024 + std + repne scasb + cld +; terminate the string here + mov byte[edi+2], 0 + + .done: +; Print the new working dir on the console + lea eax, [ebp + thread_data.work_dir] + invoke con_write_asciiz, eax + invoke con_write_asciiz, str_newline + + sendFTP "250 Command succesul" + ret + +;------------------------------------------------ +; "CWD" +; +; Change Working Directory. +; +;------------------------------------------------ +align 4 +cmdCWD: + + test [ebp + thread_data.permissions], PERMISSION_CD + jz permission_denied + +; do we have enough parameters? + sub ecx, 4 + jbe .err + +; get ready to copy the path + add esi, 4 + mov ecx, 1024 + lea edi, [ebp + thread_data.work_dir] + +; if received dir starts with '/', we will simply copy it +; If not, we will append the current path with the received path. + cmp byte [esi], '/' + je .copyloop + +; Find the end of work_dir string. + xor al, al + .find_zero: + repne scasb + dec edi + +; and now append work_dir with received string + mov ecx, 1024 + +; scan for end byte, or '.' + .copyloop: + lodsb + cmp al, 0x20 + jb .done +;;; cmp al, '.' ; '..' means we must go up one dir TODO +;;; je .up + stosb + loop .copyloop + +; now, now make sure it ends with '/', 0 + .done: + cmp byte [edi-1], '/' + je @f + mov byte [edi], '/' + inc edi + @@: + mov byte [edi], 0 + +; Print the new working dir on the console + lea eax, [ebp + thread_data.work_dir] + invoke con_write_asciiz, eax + invoke con_write_asciiz, str_newline + + sendFTP "250 Command succesful" + ret + + .err: + sendFTP "550 Directory does not exist" + ret + +;------------------------------------------------ +; "DELE" +; +; Delete a file from the server. +; +;------------------------------------------------ +align 4 +cmdDELE: + + test [ebp + thread_data.permissions], PERMISSION_DELETE + jz permission_denied + + ret + +;------------------------------------------------ +; "LIST" +; +; List the files in the current working directory. +; +;------------------------------------------------ +align 4 +cmdLIST: + + test [ebp + thread_data.permissions], PERMISSION_EXEC + jz permission_denied + + call open_datasock + +; Create fpath from home_dir and work_dir + call create_path + + lea ebx, [ebp + thread_data.fpath] + invoke con_write_asciiz, ebx + invoke con_write_asciiz, str_newline + +; Start the search + invoke file.find.first, ebx, str_mask, FA_READONLY+FA_FOLDER+FA_ARCHIVED;+FA_NORMAL + test eax, eax + jz .nosuchdir + + lea edi, [ebp + thread_data.buffer] + .parse_file: + test eax, eax ; did we find a file? + jz .done + mov ebx, eax ; yes, save the descripter in ebx + +; first, convert the attributes + test [ebx + FileInfoA.Attributes], FA_FOLDER + jnz .folder + + test [ebx + FileInfoA.Attributes], FA_READONLY + jnz .readonly + + mov eax, '-rw-' + stosd + jmp .attr + + .folder: + mov eax, 'drwx' + stosd + jmp .attr + + .readonly: + mov eax, '-r--' + stosd + + .attr: + mov eax, 'rw-r' + stosd + mov ax, 'w-' + stosw + mov al, ' ' + stosb + +; now.. + mov ax, '1 ' + stosw + +; now write owner, everything is owned by FTP, woohoo! + mov eax, 'FTP ' + stosd + stosd + +; now the filesize in ascii + mov eax, [ebx + FileInfoA.FileSizeLow] + call dword_to_ascii + mov al, ' ' + stosb + +; then date (month/day/year) + movzx eax, [ebx + FileInfoA.DateModify + FileDateTime.month] + cmp eax, 12 + ja @f + mov eax, [months - 4 + 4*eax] + stosd + @@: + + movzx eax, [ebx + FileInfoA.DateModify + FileDateTime.day] + call dword_to_ascii + mov al, ' ' + stosb + + movzx eax, [ebx + FileInfoA.DateModify + FileDateTime.year] + call dword_to_ascii + mov al, ' ' + stosb + +; and last but not least, filename + lea esi, [ebx + FileInfoA.FileName] + mov ecx, 264 + .nameloop: + lodsb + test al, al + jz .namedone + stosb + loop .nameloop + +; insert a cr lf + .namedone: + mov ax, 0x0a0d + stosw + + test [ebp + thread_data.permissions], ABORT ; Did we receive ABOR command from client? + jnz abort_transfer + +; check next file + invoke file.find.next, ebx + jmp .parse_file + +; close file desc + .done: + invoke file.find.close, ebx ; ebx is descriptor of last file, eax will be -1 !! + +; append the string with a 0 + xor al, al + stosb + +; Warn the client we're about to send the data + push edi + sendFTP "150 Here it comes.." + pop esi + +; and send it to the client + mov ecx, [ebp + thread_data.datasocketnum] ; socket num + lea edx, [ebp + thread_data.buffer] ; buffer ptr + sub esi, edx ; length + xor edi, edi ; flags + mcall send + +; close the data socket.. + mov [ebp + thread_data.mode], MODE_NOTREADY + mcall close, [ebp + thread_data.datasocketnum] + + sendFTP "226 Transfer OK" + ret + + .nosuchdir: + sendFTP "550 Directory does not exist" + ret + +;------------------------------------------------ +; "NLST" +; +; List the filenames of the files in the current working directory. +; +;------------------------------------------------ +align 4 +cmdNLST: + + test [ebp + thread_data.permissions], PERMISSION_EXEC + jz permission_denied + + ; TODO: same as list but simpler output format + + ret + +;------------------------------------------------ +; "NOOP" +; +; No operation, just keep the connection alive. +; +;------------------------------------------------ +align 4 +cmdNOOP: + + sendFTP "200 Command OK" + ret + +;------------------------------------------------ +; "PASS" +; +; Second phase of login process, client provides password. +; +;------------------------------------------------ +align 4 +cmdPASS: + +; read the password from users.ini + lea edi, [ebp + thread_data.buffer + 512] ; temp pass + lea ebx, [ebp + thread_data.fpath] ; temp username + invoke ini.get_str, path2, ebx, str_pass, edi, 512, str_infinity + test eax, eax ; unable to read password? fail! + jnz .incorrect + cmp dword [edi], -1 ; no key, section or file found.. fail! + je .incorrect + cmp byte [edi], 0 ; zero password? ok! + je .ok + + add esi, 5 + sub ecx, 5 + jbe .incorrect ; no password given? but hey, we need one! fail.. + +; compare with received password + repe cmpsb + cmp byte [esi-1], 0x20 ; printeable characters left? + jae .incorrect + cmp byte [edi-1], 0 + jne .incorrect + + .ok: + invoke ini.get_int, path2, ebx, str_mode, 0 + mov [ebp + thread_data.permissions], eax + + invoke con_write_asciiz, str_pass_ok + mov [ebp + thread_data.state], STATE_ACTIVE + sendFTP "230 You are now logged in" + ret + + .2: + .incorrect: + invoke con_write_asciiz, str_pass_err + mov [ebp + thread_data.state], STATE_CONNECTED ; reset state + sendFTP "530 Login incorrect" + ret + + .0: + sendFTP "503 Login with USER first" + ret + + .3: + sendFTP "230 Already logged in" + ret + +;------------------------------------------------ +; "PASV" +; +; Initiate a passive dataconnection. +; +;------------------------------------------------ +align 4 +cmdPASV: + +; cmp [ebp + thread_data.passivesocknum], -1 +; je @f +; mcall close, [ebp + thread_data.passivesocknum] ; if there is still a socket open, close it +; @@: + +; Open a new TCP socket + mcall socket, AF_INET4, SOCK_STREAM, 0 + cmp eax, -1 + je socketerror + mov [ebp + thread_data.passivesocknum], eax + +; Bind it to a known local port + mov [ebp + thread_data.datasock.sin_family], AF_INET4 + mov [ebp + thread_data.datasock.sin_addr], 0 + + mov ecx, eax ; passivesocketnum + lea edx, [ebp + thread_data.datasock] + mov esi, sizeof.thread_data.datasock + + .next_port: ; TODO: break the endless loop + call nextpasvport + mov ax, [pasv_port] + xchg al, ah + mov [ebp + thread_data.datasock.sin_port], ax + + mcall bind + cmp eax, -1 + je .next_port + +; And set it to listen! + mcall listen, , 1 + cmp eax, -1 + je socketerror + +; Tell our thread we are ready to accept incoming calls + mov [ebp + thread_data.mode], MODE_PASSIVE_WAIT + +; Now tell the client where to connect to in this format: +; 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) +; where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number. + +; '227 (' + lea edi, [ebp + thread_data.buffer] + mov eax, '227 ' + stosd + mov al, '(' + stosb +; ip + movzx eax, byte [serverip] + call dword_to_ascii + mov al, ',' + stosb + movzx eax, byte [serverip+1] + call dword_to_ascii + mov al, ',' + stosb + movzx eax, byte [serverip+2] + call dword_to_ascii + mov al, ',' + stosb + movzx eax, byte [serverip+3] + call dword_to_ascii + mov al, ',' + stosb +; port + movzx eax, byte [ebp + thread_data.datasock.sin_port] + call dword_to_ascii + mov al, ',' + stosb + movzx eax, byte [ebp + thread_data.datasock.sin_port+1] + call dword_to_ascii +; ')', 13, 10, 0 + mov eax, ')' + 0x000a0d00 + stosd + + lea esi, [edi - thread_data.buffer] + sub esi, ebp + mov ecx, [ebp + thread_data.socketnum] + lea edx, [ebp + thread_data.buffer] + xor edi, edi + mcall send + + ret + +;------------------------------------------------ +; "PWD" +; +; Print the current working directory. +; +;------------------------------------------------ +align 4 +cmdPWD: + + mov dword [ebp + thread_data.buffer], '257 ' + mov byte [ebp + thread_data.buffer+4], '"' + + lea edi, [ebp + thread_data.buffer+5] + lea esi, [ebp + thread_data.work_dir] + mov ecx, 1024 + .loop: + lodsb + or al, al + jz .ok + stosb + dec ecx + jnz .loop + + .ok: + mov dword [edi], '"' + 0x000a0d00 ; '"',13,10,0 + lea esi, [edi - thread_data.buffer + 4] + sub esi, ebp + mov ecx, [ebp + thread_data.socketnum] + lea edx, [ebp + thread_data.buffer] + xor edi, edi + mcall send + +; Print the new working dir on the console + lea eax, [ebp + thread_data.work_dir] + invoke con_write_asciiz, eax + invoke con_write_asciiz, str_newline + + ret + +;------------------------------------------------ +; "PORT" +; +; Initiate an active dataconnection. +; +;------------------------------------------------ +align 4 +cmdPORT: + +; PORT a1,a2,a3,a4,p1,p2 +; IP address a1.a2.a3.a4, port p1*256+p2 + +; Convert the IP + lea esi, [esi+5] + mov cl, ',' + call ip_to_dword +; And put it in datasock + mov [ebp + thread_data.datasock.sin_addr], ebx + +; Now the same with portnumber + inc esi + call ascii_to_byte + mov byte[ebp + thread_data.datasock.sin_port], al + inc esi + call ascii_to_byte + mov byte[ebp + thread_data.datasock.sin_port+1], al + +; We will open the socket, but do not connect yet! + mov [ebp + thread_data.datasock.sin_family], AF_INET4 + mcall socket, AF_INET4, SOCK_STREAM, 0 + cmp eax, -1 + je socketerror + + mov [ebp + thread_data.datasocketnum], eax + mov [ebp + thread_data.mode], MODE_ACTIVE + + sendFTP "225 Data connection open" + ret + +;------------------------------------------------ +; "QUIT" +; +; Close the connection with client. +; +;------------------------------------------------ +align 4 +cmdQUIT: + + sendFTP "221 Bye!" + mcall close, [ebp + thread_data.datasocketnum] + mcall close, [ebp + thread_data.socketnum] + + add esp, 4 ; get rid of call return address + jmp thread_exit ; now close this thread + + +;------------------------------------------------ +; "RETR" +; +; Retrieve a file from the ftp server. +; +;------------------------------------------------ +align 4 +cmdRETR: + + test [ebp + thread_data.permissions], PERMISSION_READ + jz permission_denied + + cmp ecx, 1024 + 5 + jae .cannot_open + + sub ecx, 5 + jb .cannot_open + + call open_datasock + + call create_path + dec edi + lea esi, [ebp + thread_data.buffer + 5] + mov ecx, 1024 + cmp byte [esi], '/' + jne .loop + inc esi + .loop: + lodsb + cmp al, 0x20 + jl .done + stosb + loop .loop + .done: + xor al, al + stosb + + lea ebx, [ebp + thread_data.fpath] + invoke con_write_asciiz, ebx + invoke con_write_asciiz, str_newline + + invoke file.open, ebx, O_READ + test eax, eax + jz .cannot_open + + push eax + sendFTP "150 Here it comes.." + pop ebx + + .read_more: + test [ebp + thread_data.permissions], ABORT + jnz abort_transfer + + lea eax, [ebp + thread_data.buffer] ; FIXME: use another buffer!! if we receive something on control connection now, we screw up! + invoke file.read, ebx, eax, BUFFERSIZE + cmp eax, -1 + je .cannot_open ; FIXME: this is not the correct error + + invoke con_write_asciiz, str2 + + push eax ebx + mov esi, eax + mov ecx, [ebp + thread_data.datasocketnum] + lea edx, [ebp + thread_data.buffer] + xor edi, edi + mcall send + pop ebx ecx + cmp eax, -1 + je socketerror ; FIXME: not the correct error + +; cmp eax, ecx +; jne not_all_byes_sent ; TODO + + cmp ecx, BUFFERSIZE + je .read_more + + invoke file.close, ebx + + invoke con_write_asciiz, str2b + + mov [ebp + thread_data.mode], MODE_NOTREADY + mcall close, [ebp + thread_data.datasocketnum] + + sendFTP "226 Transfer OK, closing connection" + ret + + .cannot_open: + invoke con_set_flags, 0x0c + invoke con_write_asciiz, str_notfound + invoke con_set_flags, 0x07 + + sendFTP "550 No such file" + ret + + + +;------------------------------------------------ +; "STOR" +; +; Store a file on the server. +; +;------------------------------------------------ +align 4 +cmdSTOR: + + test [ebp + thread_data.permissions], PERMISSION_WRITE + jz permission_denied + + +;;;; + test [ebp + thread_data.permissions], ABORT + jnz abort_transfer + +;;;; + + ret + +;------------------------------------------------ +; "SYST" +; +; Send information about the system. +; +;------------------------------------------------ +align 4 +cmdSYST: + + sendFTP "215 UNIX type: L8" + ret + +;------------------------------------------------ +; "TYPE" +; +; Choose the file transfer type. +; +;------------------------------------------------ +align 4 +cmdTYPE: + + cmp ecx, 6 + jb parse_cmd.error + + mov al, byte[esi+5] + and al, not 0x20 + + cmp al, 'A' + je .ascii + cmp al, 'E' + je .ebdic + cmp al, 'I' + je .image + cmp al, 'L' + je .local + + jmp parse_cmd.error + + .ascii: + mov [ebp + thread_data.type], TYPE_ASCII + jmp .subtype + + .ebdic: + mov [ebp + thread_data.type], TYPE_EBDIC + + .subtype: + cmp ecx, 8 + jb .non_print + + mov al, byte[esi+7] + and al, not 0x20 + + cmp al, 'N' + je .non_print + cmp al, 'T' + je .telnet + cmp al, 'C' + je .asacc + cmp al, 0x20 + jb .non_print + + jmp parse_cmd.error + + .non_print: + or [ebp + thread_data.type], TYPE_NP + jmp .ok + + .telnet: + or [ebp + thread_data.type], TYPE_TELNET + jmp .ok + + .asacc: + or [ebp + thread_data.type], TYPE_ASA + jmp .ok + + .image: + mov [ebp + thread_data.type], TYPE_IMAGE + jmp .ok + + .local: + cmp ecx, 8 + jb parse_cmd.error + + mov al, byte[esi+7] + sub al, '0' + jb parse_cmd.error ; FIXME: this is not the correct errormessage + cmp al, 9 + ja parse_cmd.error ; FIXME + or al, TYPE_LOCAL + mov [ebp + thread_data.type], al + + .ok: + sendFTP "200 Command ok" + ret + +;------------------------------------------------ +; "USER" +; +; Login to the server, step one of two. ;;; TODO: prevent buffer overflow! +; +;------------------------------------------------ +align 4 +cmdUSER: + + lea esi, [esi + 5] + lea edi, [ebp + thread_data.fpath] ; temp buffer for username + .loop: + lodsb + stosb + cmp al, 0x20 + jae .loop + mov byte [edi-1], 0 + + lea esi, [ebp + thread_data.fpath] + lea eax, [ebp + thread_data.home_dir] + invoke ini.get_str, path2, esi, str_home, eax, 1024, str_infinity + cmp eax, -1 + je .login_fail + cmp dword [esi], -1 + je .login_fail + + mov word [ebp + thread_data.work_dir], "/" ; "/", 0 + + invoke con_write_asciiz, str_logged_in + mov [ebp + thread_data.state], STATE_LOGIN + .sendstr: + sendFTP "331 Please specify the password" + ret + + .login_fail: + invoke con_write_asciiz, str_pass_err + mov [ebp + thread_data.state], STATE_LOGIN_FAIL + jmp .sendstr + +align 4 + .2: + sendFTP "530 Can't change to another user" + ret diff --git a/programs/network/ftpd/ftpd.asm b/programs/network/ftpd/ftpd.asm new file mode 100644 index 0000000000..1378897f27 --- /dev/null +++ b/programs/network/ftpd/ftpd.asm @@ -0,0 +1,455 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2010-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ftpd.asm - FTP Daemon for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +DEBUG = 0 ; if set to one, program will run in a single thread + +BUFFERSIZE = 8192 + +; using multiple's of 4 +STATE_CONNECTED = 0*4 +STATE_LOGIN = 1*4 +STATE_LOGIN_FAIL = 2*4 ; When an invalid username was given +STATE_ACTIVE = 3*4 + +TYPE_UNDEF = 0 + +TYPE_ASCII = 00000100b +TYPE_EBDIC = 00001000b +; subtypes for ascii & ebdic (np = default) +TYPE_NP = 00000001b ; non printable +TYPE_TELNET = 00000010b +TYPE_ASA = 00000011b + +TYPE_IMAGE = 01000000b ; binary data +TYPE_LOCAL = 10000000b ; bits per byte must be specified + ; lower 4 bits will hold this value +MODE_NOTREADY = 0 +MODE_ACTIVE = 1 +MODE_PASSIVE_WAIT = 2 +MODE_PASSIVE_OK = 3 +MODE_PASSIVE_FAILED = 4 + +PERMISSION_EXEC = 1b ; LIST +PERMISSION_READ = 10b +PERMISSION_WRITE = 100b +PERMISSION_DELETE = 1000b +PERMISSION_CD = 10000b ; Change Directory + +ABORT = 1 shl 31 + +format binary as "" + +use32 + + org 0x0 + + db 'MENUET01' ; signature + dd 1 ; header version + dd start ; entry point + dd i_end ; initialized size + dd mem+0x1000 ; required memory + dd mem+0x1000 ; stack pointer + dd params ; parameters + dd path ; path + +include '../macros.inc' +purge mov,add,sub +include '../proc32.inc' +include '../dll.inc' +include '../struct.inc' +include '../libio.inc' + +include '../network.inc' + +macro sendFTP str { +local string, length + xor edi, edi + mcall send, [ebp + thread_data.socketnum], string, length + +iglobal +string db str, 13, 10 +length = $ - string +\} +} + +include 'commands.inc' + +start: + mcall 68, 11 ; init heap + mcall 40, 1 shl 7 ; we only want network events + +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit + +; find path to main settings file (ftpd.ini) + mov edi, path ; Calculate the length of zero-terminated string + xor al, al + mov ecx, 1024 + repne scasb + dec edi + mov esi, str_ini ; append it with '.ini', 0 + movsd + movsb + +; now create the second path (users.ini) + std + mov al, '/' + repne scasb + lea ecx, [edi - path + 2] + cld + mov esi, path + mov edi, path2 + rep movsb + mov esi, str_users + movsd + movsd + movsw + +; initialize console + invoke con_start, 1 + invoke con_init, -1, -1, -1, -1, title + +; get settings from ini + invoke ini.get_str, path, str_ftpd, str_ip, ini_buf, 16, 0 + mov esi, ini_buf + mov cl, '.' + call ip_to_dword + mov [serverip], ebx + + invoke ini.get_int, path, str_ftpd, str_port, 21 + xchg al, ah + mov [sockaddr1.port], ax + + xchg al, ah + invoke con_printf, str1, eax + add esp, 8 + +; open listening socket + mcall socket, AF_INET4, SOCK_STREAM, 0 + cmp eax, -1 + je sock_err + mov [socketnum], eax + + invoke con_write_asciiz, str2 + +; mcall setsockopt, [socketnum], SOL_SOCKET, SO_REUSEADDR, &yes, +; cmp eax, -1 +; je opt_err + + mcall bind, [socketnum], sockaddr1, sockaddr1.length + cmp eax, -1 + je bind_err + + invoke con_write_asciiz, str2 + + invoke ini.get_int, path, str_ftpd, str_conn, 1 ; Backlog (max connections) + mov edx, eax + + invoke con_write_asciiz, str2 + + mcall listen, [socketnum] + cmp eax, -1 + je listen_err + + invoke con_write_asciiz, str2b + + invoke ini.get_int, path, str_pasv, str_start, 2000 + mov [pasv_start], ax + invoke ini.get_int, path, str_pasv, str_end, 5000 + mov [pasv_end], ax + + mov [alive], 1 + +mainloop: + mcall 23, 100 ; Wait here for incoming connections on the base socket (socketnum) + ; One second timeout, we will use this to check if console is still working + + test eax, eax ; network event? + jz .checkconsole + +if DEBUG + jmp threadstart +else + mcall 51, 1, threadstart, 0 ; Start a new thread for every incoming connection + ; NOTE: upon initialisation of the thread, stack will not be available! +end if + jmp mainloop + + .checkconsole: + + invoke con_get_flags ; Is console still running? + test eax, 0x0200 + jz mainloop + mcall close, [socketnum] ; kill the listening socket + mov [alive], 0 + mcall -1 ; and exit + + diff16 "threadstart", 0, $ + +threadstart: +;;; mcall 68, 11 ; init heap + mcall 68, 12, sizeof.thread_data ; allocate the thread data struct + test eax, eax + je exit + + lea esp, [eax + thread_data.stack] ; init stack + mov ebp, eax + + mcall 40, 1 shl 7 ; we only want network events for this thread + + lea ebx, [ebp + thread_data.buffer] ; get information about the current process + or ecx, -1 + mcall 9 + mov eax, dword [ebp + thread_data.buffer + 30] ; PID is at offset 30 + mov [ebp + thread_data.pid], eax + + invoke con_set_flags, 0x03 + invoke con_printf, str8, [ebp + thread_data.pid] ; print on the console that we have created the new thread successfully + add esp, 8 ; balance stack + invoke con_set_flags, 0x07 + + mcall accept, [socketnum], sockaddr1, sockaddr1.length ; time to accept the awaiting connection.. + cmp eax, -1 + je thread_exit + mov [ebp + thread_data.socketnum], eax + +if DEBUG + mcall close, [socketnum] ; close the listening socket +end if + + mov [ebp + thread_data.state], STATE_CONNECTED + mov [ebp + thread_data.permissions], 0 + mov [ebp + thread_data.mode], MODE_NOTREADY + lea eax, [ebp + thread_data.buffer] + mov [ebp + thread_data.buffer_ptr], eax + mov [ebp + thread_data.passivesocknum], -1 + + sendFTP "220 Welcome to KolibriOS FTP daemon" + + diff16 "threadloop", 0, $ +threadloop: +; Check if our socket is still connected + mcall send, [ebp + thread_data.socketnum], 0, 0 ; Try to send zero bytes, if socket is closed, this will return -1 + cmp eax, -1 + je thread_exit + + cmp [alive], 0 ; Did main thread take a run for it? + je thread_exit + + mcall 10 ; Wait for network event + + cmp [ebp + thread_data.mode], MODE_PASSIVE_WAIT + jne .not_passive + mov ecx, [ebp + thread_data.passivesocknum] + lea edx, [ebp + thread_data.datasock] + mov esi, sizeof.thread_data.datasock + mcall accept + cmp eax, -1 + je .not_passive + mov [ebp + thread_data.datasocketnum], eax + mov [ebp + thread_data.mode], MODE_PASSIVE_OK + mcall close ; [ebp + thread_data.passivesocknum] + mov [ebp + thread_data.passivesocknum], -1 + + invoke con_write_asciiz, str_datasock + .not_passive: + + mov ecx, [ebp + thread_data.socketnum] + mov edx, [ebp + thread_data.buffer_ptr] + mov esi, sizeof.thread_data.buffer ;;; FIXME + mcall recv + inc eax ; error? (-1) + jz threadloop + dec eax ; 0 bytes read? + jz threadloop + + mov edi, [ebp + thread_data.buffer_ptr] + add [ebp + thread_data.buffer_ptr], eax + +; Check if we received a newline character, if not, wait for more data + mov ecx, eax + mov al, 13 + repne scasb + jne threadloop + +; We got a command! + mov byte [edi + 1], 0 ; append string with zero byte + lea esi, [ebp + thread_data.buffer] + mov ecx, [ebp + thread_data.buffer_ptr] + sub ecx, esi + mov [ebp + thread_data.buffer_ptr], esi ; reset buffer ptr + + invoke con_set_flags, 0x02 ; print received data to console (in green color) + invoke con_write_asciiz, str_newline + invoke con_write_asciiz, esi + invoke con_set_flags, 0x07 + + push threadloop + jmp parse_cmd + +listen_err: + invoke con_set_flags, 0x0c ; print errors in red + invoke con_write_asciiz, str3 + jmp done + +bind_err: + invoke con_set_flags, 0x0c ; print errors in red + invoke con_write_asciiz, str4 + jmp done + +sock_err: + invoke con_set_flags, 0x0c ; print errors in red + invoke con_write_asciiz, str6 + jmp done + +done: + invoke con_exit, 0 +exit: + mcall -1 + + +thread_exit: + invoke con_set_flags, 0x03 ; print thread info in blue + invoke con_printf, str_bye, [ebp + thread_data.pid] ; print on the console that we are about to kill the thread + add esp, 8 ; balance stack + mcall 68, 13, ebp ; free the memory + mcall -1 ; and kill the thread + + +; initialized data + +title db 'KolibriOS FTP daemon 0.1', 0 +str1 db 'Starting FTP daemon on port %u.', 0 +str2 db '.', 0 +str2b db ' OK!',10,0 +str3 db 'Listen error',10,0 +str4 db 10,'ERROR: local port is already in use.',10,0 +;str5 db 'Setsockopt error.',10,10,0 +str6 db 'ERROR: Could not open socket.',10,0 +str7 db 'Got data!',10,10,0 +str8 db 10,'Thread %d created',10,0 +str_bye db 10,'Thread %d killed',10,0 + +str_logged_in db 'Login ok',10,0 +str_pass_ok db 'Password ok',10,0 +str_pass_err db 'Password/Username incorrect',10,0 +str_pwd db 'Current directory is "%s"\n',0 +str_err2 db 'ERROR: cannot open the directory.',10,0 +str_datasock db 'Passive data socket connected.',10,0 +str_notfound db 'ERROR: file not found.',10,0 +str_sockerr db 'ERROR: socket error.',10,0 + +str_newline db 10, 0 +str_mask db '*', 0 +str_infinity db 0xff, 0xff, 0xff, 0xff, 0 + +months dd 'Jan ' + dd 'Feb ' + dd 'Mar ' + dd 'Apr ' + dd 'May ' + dd 'Jun ' + dd 'Jul ' + dd 'Aug ' + dd 'Sep ' + dd 'Oct ' + dd 'Nov ' + dd 'Dec ' + +str_users db 'users' +str_ini db '.ini', 0 +str_port db 'port', 0 +str_ftpd db 'ftpd', 0 +str_conn db 'conn', 0 +str_ip db 'ip', 0 +str_pass db 'pass', 0 +str_home db 'home', 0 +str_mode db 'mode', 0 +str_pasv db 'pasv', 0 +str_start db 'start', 0 +str_end db 'end', 0 + + +sockaddr1: + dw AF_INET4 + .port dw 0 + .ip dd 0 + rb 10 + .length = $ - sockaddr1 + +; import + +align 4 +@IMPORT: + +diff16 "import", 0, $ + +library console, 'console.obj',\ + libini, 'libini.obj', \ + libio, 'libio.obj' + +import console,\ + con_start, 'START',\ + con_init, 'con_init',\ + con_write_asciiz, 'con_write_asciiz',\ + con_exit, 'con_exit',\ + con_gets, 'con_gets',\ + con_cls, 'con_cls',\ + con_printf, 'con_printf',\ + con_getch2, 'con_getch2',\ + con_set_cursor_pos, 'con_set_cursor_pos',\ + con_set_flags, 'con_set_flags',\ + con_get_flags, 'con_get_flags' + +import libini,\ + ini.get_str, 'ini_get_str',\ + ini.get_int, 'ini_get_int' + +import libio,\ + file.size, 'file_size',\ + file.open, 'file_open',\ + file.read, 'file_read',\ + file.close, 'file_close',\ + file.find.first, 'file_find_first',\ + file.find.next, 'file_find_next',\ + file.find.close, 'file_find_close' + + +IncludeIGlobals + + +i_end: + +diff16 "i_end", 0, $ + +; uninitialised data + + socketnum dd ? + path rb 1024 + path2 rb 1024 + params rb 1024 + serverip dd ? + pasv_start dw ? + pasv_end dw ? + pasv_port dw ? + + ini_buf rb 3*4+3+1 + + alive db ? + +mem: + + diff --git a/programs/network/ftpd/ftpd.ini b/programs/network/ftpd/ftpd.ini new file mode 100644 index 0000000000..216d00a2c4 --- /dev/null +++ b/programs/network/ftpd/ftpd.ini @@ -0,0 +1,8 @@ +[ftpd] +port=21 +conn=10 +ip=127.0.0.1 + +[pasv] +start=2000 +end=5000 \ No newline at end of file diff --git a/programs/network/ftpd/users.ini b/programs/network/ftpd/users.ini new file mode 100644 index 0000000000..85927c4354 --- /dev/null +++ b/programs/network/ftpd/users.ini @@ -0,0 +1,20 @@ +; Access modes +; +; List = 1 +; Read = 2 +; Write = 4 +; Delete = 8 +; Change directory = 16 + + +[anonymous] +; leavy pass empty to disable it +pass= +home=/rd/1/ +mode=3 + +[test] +pass=1234 +home=/rd/1/ +mode=31 + diff --git a/programs/network/icmp/icmp.inc b/programs/network/icmp/icmp.inc new file mode 100644 index 0000000000..bcafff37e9 --- /dev/null +++ b/programs/network/icmp/icmp.inc @@ -0,0 +1,77 @@ +; ICMP types & codes + +ICMP_ECHOREPLY equ 0 ; echo reply message + +ICMP_UNREACH equ 3 +ICMP_UNREACH_NET equ 0 ; bad net +ICMP_UNREACH_HOST equ 1 ; bad host +ICMP_UNREACH_PROTOCOL equ 2 ; bad protocol +ICMP_UNREACH_PORT equ 3 ; bad port +ICMP_UNREACH_NEEDFRAG equ 4 ; IP_DF caused drop +ICMP_UNREACH_SRCFAIL equ 5 ; src route failed +ICMP_UNREACH_NET_UNKNOWN equ 6 ; unknown net +ICMP_UNREACH_HOST_UNKNOWN equ 7 ; unknown host +ICMP_UNREACH_ISOLATED equ 8 ; src host isolated +ICMP_UNREACH_NET_PROHIB equ 9 ; prohibited access +ICMP_UNREACH_HOST_PROHIB equ 10 ; ditto +ICMP_UNREACH_TOSNET equ 11 ; bad tos for net +ICMP_UNREACH_TOSHOST equ 12 ; bad tos for host +ICMP_UNREACH_FILTER_PROHIB equ 13 ; admin prohib +ICMP_UNREACH_HOST_PRECEDENCE equ 14 ; host prec vio. +ICMP_UNREACH_PRECEDENCE_CUTOFF equ 15 ; prec cutoff + +ICMP_SOURCEQUENCH equ 4 ; Packet lost, slow down + +ICMP_REDIRECT equ 5 ; shorter route, codes: +ICMP_REDIRECT_NET equ 0 ; for network +ICMP_REDIRECT_HOST equ 1 ; for host +ICMP_REDIRECT_TOSNET equ 2 ; for tos and net +ICMP_REDIRECT_TOSHOST equ 3 ; for tos and host + +ICMP_ALTHOSTADDR equ 6 ; alternate host address +ICMP_ECHO equ 8 ; echo service +ICMP_ROUTERADVERT equ 9 ; router advertisement +ICMP_ROUTERADVERT_NORMAL equ 0 ; normal advertisement +ICMP_ROUTERADVERT_NOROUTE_COMMON equ 16 ; selective routing + +ICMP_ROUTERSOLICIT equ 10 ; router solicitation +ICMP_TIMXCEED equ 11 ; time exceeded, code: +ICMP_TIMXCEED_INTRANS equ 0 ; ttl==0 in transit +ICMP_TIMXCEED_REASS equ 1 ; ttl==0 in reass + +ICMP_PARAMPROB equ 12 ; ip header bad +ICMP_PARAMPROB_ERRATPTR equ 0 ; error at param ptr +ICMP_PARAMPROB_OPTABSENT equ 1 ; req. opt. absent +ICMP_PARAMPROB_LENGTH equ 2 ; bad length + +ICMP_TSTAMP equ 13 ; timestamp request +ICMP_TSTAMPREPLY equ 14 ; timestamp reply +ICMP_IREQ equ 15 ; information request +ICMP_IREQREPLY equ 16 ; information reply +ICMP_MASKREQ equ 17 ; address mask request +ICMP_MASKREPLY equ 18 ; address mask reply +ICMP_TRACEROUTE equ 30 ; traceroute +ICMP_DATACONVERR equ 31 ; data conversion error +ICMP_MOBILE_REDIRECT equ 32 ; mobile host redirect +ICMP_IPV6_WHEREAREYOU equ 33 ; IPv6 where-are-you +ICMP_IPV6_IAMHERE equ 34 ; IPv6 i-am-here +ICMP_MOBILE_REGREQUEST equ 35 ; mobile registration req +ICMP_MOBILE_REGREPLY equ 36 ; mobile registreation reply +ICMP_SKIP equ 39 ; SKIP + +ICMP_PHOTURIS equ 40 ; Photuris +ICMP_PHOTURIS_UNKNOWN_INDEX equ 1 ; unknown sec index +ICMP_PHOTURIS_AUTH_FAILED equ 2 ; auth failed +ICMP_PHOTURIS_DECRYPT_FAILED equ 3 ; decrypt failed + + + +virtual at 0 + ICMP_Packet: + .Type db ? + .Code db ? + .Checksum dw ? + .Identifier dw ? + .SequenceNumber dw ? + .Data: +end virtual \ No newline at end of file diff --git a/programs/network/icmp/ping.asm b/programs/network/icmp/ping.asm new file mode 100644 index 0000000000..e5e26e5f16 --- /dev/null +++ b/programs/network/icmp/ping.asm @@ -0,0 +1,256 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2010-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ping.asm - ICMP echo client for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +format binary as "" + +use32 + org 0x0 + + db 'MENUET01' ; signature + dd 1 ; header version + dd start ; entry point + dd I_END ; initialized size + dd mem ; required memory + dd mem ; stack pointer + dd s ; parameters + dd 0 ; path + + +BUFFERSIZE equ 1500 +; useful includes +include '../macros.inc' +purge mov,add,sub +include '../proc32.inc' +include '../dll.inc' +include '../network.inc' + +include 'icmp.inc' + + +start: +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit +; initialize console + push 1 + call [con_start] + push title + push 25 + push 80 + push 25 + push 80 + call [con_init] +; main loop + cmp byte[s], 0 + jne resolve +main: +; write prompt + push str2 + call [con_write_asciiz] +; read string + mov esi, s + push 256 + push esi + call [con_gets] +; check for exit + test eax, eax + jz done + cmp byte [esi], 10 + jz done +; delete terminating '\n' + push esi +@@: + lodsb + test al, al + jnz @b + mov byte [esi-2], al + pop esi + +resolve: +; resolve name + push esp ; reserve stack place + push esp ; fourth parameter + push 0 ; third parameter + push 0 ; second parameter + push s ; first parameter + call [getaddrinfo] + pop esi +; test for error + test eax, eax + jnz fail + +; convert IP address to decimal notation + mov eax, [esi+addrinfo.ai_addr] + mov eax, [eax+sockaddr_in.sin_addr] + mov [sockaddr1.ip], eax + push eax + call [inet_ntoa] +; write result + mov [ip_ptr], eax + + push eax + +; free allocated memory + push esi + call [freeaddrinfo] + + push str4 + call [con_write_asciiz] + + mcall socket, AF_INET4, SOCK_RAW, IPPROTO_ICMP + cmp eax, -1 + jz fail2 + mov [socketnum], eax + + mcall connect, [socketnum], sockaddr1, 18 + + mcall 40, 1 shl 7 ; + 7 +; call [con_cls] + + mov [count], 4 + +mainloop: + push str3 + call [con_write_asciiz] + push [ip_ptr] + call [con_write_asciiz] + + mcall 26,9 + mov [time_reference], eax + mcall send, [socketnum], icmp_packet, icmp_packet.length, 0 + + mcall 23, 300 ; 3 seconds time-out + mcall 26,9 + neg [time_reference] + add [time_reference], eax + + mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, 0 + cmp eax, -1 + je .no_response + +; validate the packet + lea esi, [buffer_ptr + ICMP_Packet.Data] + mov edi, icmp_packet.data + mov ecx, 32/4 + repe cmpsd + jne .miscomp + + push [time_reference] + push str7 + call [con_printf] + + jmp continue + + .miscomp: + sub edi, icmp_packet.data + push edi + push str9 + call [con_printf] + jmp continue + + .no_response: + push str8 + call [con_write_asciiz] + + continue: + dec [count] + jz done + mcall 5, 100 ; wait a second + inc [icmp_packet.id] + jmp mainloop + + + +done: + push str10 + call [con_write_asciiz] + call [con_getch2] + push 1 + call [con_exit] +exit: + mcall -1 + +fail: + push str5 + call [con_write_asciiz] + jmp done +fail2: + push str6 + call [con_write_asciiz] + jmp done + + +; data +title db 'ICMP - echo client',0 +str2 db '> ',0 +str3 db 'Ping to ',0 +str4 db 10,0 +str5 db 'Name resolution failed.',10,0 +str6 db 'Could not open socket',10,0 +str7 db ' time= %u0ms',10,0 +str8 db ' timeout!',10,0 +str9 db ' miscompare at offset %u',10,0 +str10 db 10,'Press any key to exit',0 + +sockaddr1: + dw AF_INET4 +.port dw 0 +.ip dd 0 + rb 10 + +time_reference dd ? +ip_ptr dd ? +count dd ? + + +; import +align 4 +@IMPORT: + +library network, 'network.obj', console, 'console.obj' +import network, \ + getaddrinfo, 'getaddrinfo', \ + freeaddrinfo, 'freeaddrinfo', \ + inet_ntoa, 'inet_ntoa' + +import console, \ + con_start, 'START', \ + con_init, 'con_init', \ + con_write_asciiz, 'con_write_asciiz', \ + con_printf, 'con_printf', \ + con_exit, 'con_exit', \ + con_gets, 'con_gets',\ + con_cls, 'con_cls',\ + con_getch2, 'con_getch2',\ + con_set_cursor_pos, 'con_set_cursor_pos' + +socketnum dd ? + +icmp_packet: db 8 ; type + db 0 ; code + dw 0 ; + .id dw 0x0000 ; identifier + .seq dw 0x0001 ; sequence number + .data db 'abcdefghijklmnopqrstuvwxyz012345678' + .length = $ - icmp_packet + +I_END: + +buffer_ptr rb BUFFERSIZE + +s rb 1024 + rb 4096 ; stack +mem: diff --git a/programs/network/ircc/encodings.inc b/programs/network/ircc/encodings.inc new file mode 100644 index 0000000000..220ef9ec2a --- /dev/null +++ b/programs/network/ircc/encodings.inc @@ -0,0 +1,317 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +get_next_byte: +; Load next byte from the packet, translating to cp866 if necessary +; At input esi = pointer to data, edx = limit of data +; Output is either (translated) byte in al with CF set or CF cleared. + mov eax, [encoding] + jmp [get_byte_table+eax*4] + +get_byte_cp866: + cmp esi, edx + jae .nothing + lodsb +.nothing: + ret + +get_byte_cp1251: + cmp esi, edx + jae .nothing + lodsb + cmp al, 0x80 + jb @f + and eax, 0x7F + mov al, [cp1251_table+eax] +@@: + stc +.nothing: + ret + +get_byte_utf8: +; UTF8 decoding is slightly complicated. +; One character can occupy one or more bytes. +; The boundary in packets theoretically can be anywhere in data, +; so this procedure keeps internal state between calls and handles +; one byte at a time, looping until character is read or packet is over. +; Globally, there are two distinct tasks: decode byte sequence to unicode char +; and convert this unicode char to our base encoding (that is cp866). +; 1. Check that there are data. + cmp esi, edx + jae .nothing +; 2. Load byte. + lodsb + movzx ecx, al +; 3. Bytes in an UTF8 sequence can be of any of three types. +; If most significant bit is cleared, sequence is one byte and usual ASCII char. +; First byte of a sequence must be 11xxxxxx, other bytes are 10yyyyyy. + and al, 0xC0 + jns .single_byte + jp .first_byte +; 4. This byte is not first in UTF8 sequence. +; 4a. Check that the sequence was started. If no, it is invalid byte +; and we simply ignore it. + cmp [utf8_bytes_rest], 0 + jz get_byte_utf8 +; 4b. Otherwise, it is really next byte and it gives some more bits of char. + mov eax, [utf8_char] + shl eax, 6 + lea eax, [eax+ecx-0x80] +; 4c. Decrement number of bytes rest in the sequence. +; If it goes to zero, character is read, so return it. + dec [utf8_bytes_rest] + jz .got_char + mov [utf8_char], eax + jmp get_byte_utf8 +; 5. If the byte is first in UTF8 sequence, calculate the number of leading 1s +; - it equals total number of bytes in the sequence; some other bits rest for +; leading bits in the character. +.first_byte: + mov eax, -1 +@@: + inc eax + add cl, cl + js @b + mov [utf8_bytes_rest], eax + xchg eax, ecx + inc ecx + shr al, cl + mov [utf8_char], eax + jmp get_byte_utf8 +; 6. If the byte is ASCII char, it is the character. +.single_byte: + xchg eax, ecx +.got_char: +; We got the character, now abandon a possible sequence in progress. + and [utf8_bytes_rest], 0 +; Now second task. The unicode character is in eax, and now we shall convert it +; to cp866. + cmp eax, 0x80 + jb .done +; 0x410-0x43F -> 0x80-0xAF, 0x440-0x44F -> 0xE0-0xEF, 0x401 -> 0xF0, 0x451 -> 0xF1 + cmp eax, 0x401 + jz .YO + cmp eax, 0x451 + jz .yo + cmp eax, 0x410 + jb .unrecognized + cmp eax, 0x440 + jb .part1 + cmp eax, 0x450 + jae .unrecognized + sub al, (0x40-0xE0) and 0xFF + ret +.part1: + sub al, 0x10-0x80 +.nothing: +.done: + ret +.unrecognized: + mov al, '?' + stc + ret +.YO: + mov al, 0xF0 + stc + ret +.yo: + mov al, 0xF1 + stc + ret + + + +print_character: + + pusha + + cmp bl, 13 ; line beginning + jne nobol + + mov ecx, [pos] + inc ecx + boll1: + dec ecx + mov eax, ecx + xor edx, edx + mov ebx, [textbox_width] + div ebx + test edx, edx + jnz boll1 + mov [pos], ecx + jmp newdata + nobol: + + cmp bl, 10 ; line down + jne nolf + + addx1: + inc [pos] + mov eax, [pos] + xor edx, edx + mov ecx, [textbox_width] + div ecx + test edx, edx + jnz addx1 + mov eax, [pos] + jmp cm1 + nolf: + no_lf_ret: + + + cmp bl, 15 ; character + jbe newdata + + mov eax, [irc_data] + shl eax, 8 + mov al, bl + mov [irc_data], eax + + mov eax, [pos] + ;---- draw data + pusha + + and ebx, 0xff + add eax, [text_start] + mov [eax], bl + + popa + ;---- draw data + + mov eax, [pos] + inc eax + cm1: + mov ebx, [scroll+4] + imul ebx, [textbox_width] + cmp eax, ebx + jb noeaxz + + mov esi, [text_start] + add esi, [textbox_width] + + mov edi, [text_start] + mov ecx, ebx + rep movsb + + mov esi, [text_start] + mov ecx, [textbox_width] + imul ecx, 61 + add esi, ecx + + mov edi, [text_start] + mov ecx, [textbox_width] + imul ecx, 60 + add edi, ecx + mov ecx, ebx + rep movsb + + mov eax, ebx + sub eax, [textbox_width] + noeaxz: + mov [pos], eax + + newdata: + mov eax, [window_print] + or [eax + window.flags], FLAG_UPDATED + + popa + ret + + + +recode_to_cp866: + rep movsb + ret + +recode_to_cp1251: + xor eax, eax + jecxz .nothing + .loop: + lodsb + cmp al,0x80 + jb @f + mov al, [cp866_table-0x80+eax] + @@: stosb + loop .loop + .nothing: + ret + +recode_to_utf8: + jecxz .nothing + .loop: + lodsb + cmp al, 0x80 + jb .single_byte + and eax, 0x7F + mov ax, [utf8_table+eax*2] + stosw + loop .loop + ret + .single_byte: + stosb + loop .loop + .nothing: + ret + +recode: + mov eax, [encoding] + jmp [recode_proc+eax*4] + + + +encoding dd UTF8 +recode_proc dd recode_to_cp866, recode_to_cp1251, recode_to_utf8 +get_byte_table dd get_byte_cp866, get_byte_cp1251, get_byte_utf8 + + +cp1251_table: + db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; 8 + db '?','?','?','?','?',$F9,'?','?' , '?','?','?','?','?','?','?','?' ; 9 + db '?',$F6,$F7,'?',$FD,'?','?','?' , $F0,'?',$F2,'?','?','?','?',$F4 ; A + db $F8,'?','?','?','?','?','?',$FA , $F1,$FC,$F3,'?','?','?','?',$F5 ; B + db $80,$81,$82,$83,$84,$85,$86,$87 , $88,$89,$8A,$8B,$8C,$8D,$8E,$8F ; C + db $90,$91,$92,$93,$94,$95,$96,$97 , $98,$99,$9A,$9B,$9C,$9D,$9E,$9F ; D + db $A0,$A1,$A2,$A3,$A4,$A5,$A6,$A7 , $A8,$A9,$AA,$AB,$AC,$AD,$AE,$AF ; E + db $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7 , $E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF ; F + +; 0 1 2 3 4 5 6 7 8 9 A B C D E F + +utf8_table: + times 80h dw 0x98C3 ; default placeholder + +; 0x80-0xAF -> 0x90D0-0xBFD0 +repeat 0x30 + store byte 0xD0 at utf8_table+2*(%-1) + store byte 0x90+%-1 at utf8_table+2*%-1 +end repeat + +; 0xE0-0xEF -> 0x80D1-0x8FD1 +repeat 0x10 + store byte 0xD1 at utf8_table+2*(0xE0-0x80+%-1) + store byte 0x80+%-1 at utf8_table+2*(0xE0-0x80+%)-1 +end repeat + +; 0xF0 -> 0x81D0, 0xF1 -> 0x91D1 + store dword 0x91D181D0 at utf8_table+2*(0xF0-0x80) + +cp866_table: + db $C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7 , $C8,$C9,$CA,$CB,$CC,$CD,$CE,$CF ; 8 + db $D0,$D1,$D2,$D3,$D4,$D5,$D6,$D7 , $D8,$D9,$DA,$DB,$DC,$DD,$DE,$DF ; 9 + db $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7 , $E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF ; A + db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; B + db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; C + db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; D + db $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7 , $F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF ; E + db $A8,$B8,$AA,$BA,$AF,$BF,$A1,$A2 , $B0,$95,$B7,'?',$B9,$A4,'?','?' ; F + +; 0 1 2 3 4 5 6 7 8 9 A B C D E F + diff --git a/programs/network/ircc/gui.inc b/programs/network/ircc/gui.inc new file mode 100644 index 0000000000..ffad315fe3 --- /dev/null +++ b/programs/network/ircc/gui.inc @@ -0,0 +1,316 @@ +draw_window: + + pusha + + mcall 9, thread_info, -1 ; get current window size + mov eax, dword[thread_info+42] ; window xsize + mov ebx, dword[thread_info+46] ; ysize + mov edx, dword[thread_info+62] ; work area xsize + mov esi, dword[thread_info+66] ; ysize + sub eax, edx + sub ebx, esi + + cmp edx, WIN_MIN_X + jae .x_ok + mov edx, WIN_MIN_X + .x_ok: + mov [xsize], edx + add edx, eax + + cmp esi, WIN_MIN_Y + jae .y_ok + mov esi, WIN_MIN_Y + .y_ok: + mov [ysize], esi + add esi, ebx + mcall 67, -1, -1 ; set the new sizes + + mcall 12, 1 + xor eax, eax ; draw window + mov ebx, WIN_MIN_X + mov ecx, WIN_MIN_Y + mov edx, [colors.work] + add edx, 0x33000000 + mov edi, str_programname + mcall + mcall 12, 2 ;; when do we actually need this?? + + mov ebx, [xsize] + mov ecx, [ysize] + sub cx, 15 ;;;; + push cx + shl ecx, 16 + pop cx + mov edx, [colors.work_graph] + mcall 38 ; draw line + + mov ecx, TOP_Y SHL 16 + TOP_Y + mcall + + mov edi, [window_open] + cmp [edi + window.type], WINDOWTYPE_CHANNEL + jne .not_channel + + ; draw a vertical separator line + mov ebx, [xsize] + sub ebx, USERLIST_X + SCROLLBAR_WIDTH + 3 + push bx + shl ebx, 16 + pop bx + mov ecx, [ysize] + add ecx, TOP_Y SHL 16 -(15) ;;;; + mcall + + call redraw_channel_list + + .not_channel: + mov edx, [edi + window.data_ptr] + add edx, window_data.text + call draw_channel_text + +; editbox + + mov eax, [ysize] + sub eax, 12 ;;;;;; + mov [edit1.top], eax + + mov eax, [xsize] + mov [edit1.width], eax + + push dword edit1 + call [edit_box_draw] + +; tabs + + call draw_windownames + + popa + ret + + + +redraw_channel_list: + +; First, calculate scrollbar + + mov ebx, [window_open] + mov eax, [ebx + window.users] ; number of users in the open window + mov [scroll1.max_area], eax + + mov eax, [ysize] + sub eax, TOP_Y + 15 ;;;; + push eax + mov [scroll1.y_size], ax + + mov eax, [xsize] + sub eax, SCROLLBAR_WIDTH + mov [scroll1.x_pos], ax + + pop eax ; scrollbar height + xor edx, edx + mov ecx, 10 + div ecx + mov [scroll1.cur_area], eax + + ; Do we need a scrollbar? + cmp eax, [scroll1.max_area] + jae .noscroll + + ; Is the current position greater then the max position? + cmp eax, [scroll1.position] + ja @f + mov [scroll1.position], eax + @@: + + ; OK, draw the scrollbar + mov [scroll1.all_redraw], 1 + + push dword scroll1 + call [scrollbar_v_draw] + + jmp print_channel_list + + .noscroll: + mov [scroll1.position], 0 + + + +print_channel_list: + + pusha +; Now, draw the usernames themselves + +; first, draw an invisible button + mov ebx, [xsize] + sub ebx, USERLIST_X + SCROLLBAR_WIDTH + shl ebx, 16 + push ebx + mov bx, USERLIST_X + mov ecx, [ysize] + add ecx, TEXT_Y shl 16 - (TEXT_Y + 15) ;;;;; + 10??? + push ecx ebx + mov edx, 50 + 1 shl 29 + 1 shl 30 + mcall 8 + +; now draw rectangle to clear the names + pop ebx ecx + mov edx, [colors.work] + mcall 13 + +; now draw the names according with scrollbar position and window size + mov eax, [scroll1.position] + xor edx, edx + mov ecx, MAX_NICK_LEN + mul ecx + mov edx, eax + mov eax, [window_open] + mov ebp, [eax + window.selected] + add edx, [eax + window.data_ptr] + sub ebp, [scroll1.position] + add edx, window_data.names + + pop ebx + mov bx, TEXT_Y + mov ecx, [colors.work_text] + or ecx, 0x80000000 ; ASCIIZ string + mov eax, 4 ; draw text + + mov edi, [ysize] ; Calculate how many names will fit on screen + sub edi, TEXT_Y + 15 ;+ 10 ;;;;; + .loop: + cmp byte[edx], 0 ; end of list? + je .done + + dec ebp ; is this name selected? + jnz .nothighlight + ; yes, highlight it + pusha + mov cx, bx + mov bx, USERLIST_X + shl ecx, 16 + mov cx, 10 - 1 + mov edx, 0x00000055 ; blue! + mcall 13 + popa + + mov ecx, 0x8000ffff ; cyan! + mcall + + mov ecx, [colors.work_text] + or ecx, 0x80000000 ; ASCIIZ string + jmp .next + + .nothighlight: + mcall + + .next: + add edx, MAX_NICK_LEN ; next name + add ebx, 10 ; height distance between lines + sub edi, 10 + ja .loop + + .done: + popa + + ret + + + + +draw_channel_text: + + pusha + + mov eax, 4 ; draw text + mov ebx, TEXT_X shl 16 + TEXT_Y + mov ecx, 12 ; 12 lines max ? + mov esi, [textbox_width] + + .dct: + pusha + mov cx, bx + shl ecx, 16 + mov cx, 9 ; character height + mov eax, 13 ; draw rectangle + mov ebx, TEXT_X shl 16 + mov bx, word[textbox_width] + imul bx, 6 ; character width + mov edx, [colors.work] + mcall + popa + + push ecx + mov ecx, [colors.work_text] + cmp word[edx], '* ' + jne .no_red + mov ecx, 0x00aa0000 + jmp .draw + .no_red: + + cmp word[edx], '**' + jne .no_light_blue + cmp byte[edx+2], '*' + jne .no_light_blue + mov ecx, 0x000000aa + jmp .draw + .no_light_blue: + + cmp byte[edx], '#' + jne .no_blue + mov ecx, 0x0000aa00 +; jmp .draw + .no_blue: + + .draw: + mcall + add edx, [textbox_width] + add ebx, 10 ; height distance between lines + + pop ecx + loop .dct + + popa + ret + + + +draw_windownames: + + mov eax, 8 + mov ebx, 5 shl 16 + 120 + mov ecx, 12 shl 16 + 12 + mov edx, WINDOW_BTN_START + mov edi, windows + .more_btn: + mov esi, [colors.work_button] + cmp [window_open], edi + jne @f + not esi + and esi, 0x00ffffff + @@: + mcall + inc edx + add ebx, 125 shl 16 + add edi, sizeof.window + cmp [edi + window.data_ptr], 0 + jne .more_btn + + mov eax, 4 + mov ebx, 10 shl 16 + 15 + mov ecx, [colors.work_button_text] + or ecx, 0x80000000 ; ASCIIZ string + lea edx, [windows + window.name] + mov esi, MAX_WINDOWS + .more: + mcall + add edx, sizeof.window + cmp byte[edx], 0 + je .enough + add ebx, 125 shl 16 + dec esi + jnz .more + .enough: + + ret + + diff --git a/programs/network/ircc/ircc.asm b/programs/network/ircc/ircc.asm new file mode 100644 index 0000000000..c4d831bd90 --- /dev/null +++ b/programs/network/ircc/ircc.asm @@ -0,0 +1,476 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; IRC client for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org, ;; +;; text encoder/decoder by Clevermouse. ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +version equ '0.1' + +; connection status +STATUS_DISCONNECTED = 0 +STATUS_RESOLVING = 1 +STATUS_CONNECTING = 2 +STATUS_CONNECTED = 3 + +; window flags +FLAG_UPDATED = 1 shl 0 +FLAG_CLOSE = 1 shl 1 +FLAG_RECEIVING_NAMES = 1 shl 2 + +; window types +WINDOWTYPE_SERVER = 0 +WINDOWTYPE_CHANNEL = 1 +WINDOWTYPE_CHAT = 2 +WINDOWTYPE_LIST = 3 +WINDOWTYPE_DCC = 4 + +; supported encodings +CP866 = 0 +CP1251 = 1 +UTF8 = 2 + +; settings +USERCMD_MAX_SIZE = 400 + +WIN_MIN_X = 600 +WIN_MIN_Y = 165 + +TEXT_X = 5 +TEXT_Y = 30 + +TOP_Y = 25 + +MAX_WINDOWS = 20 +MAX_USERS = 4096 + +MAX_NICK_LEN = 32 +MAX_REAL_LEN = 32 ; realname +MAX_SERVER_NAME = 256 + +MAX_CHANNEL_LEN = 40 +MAX_CHANNELS = 37 + +MAX_COMMAND_LEN = 512 + +TIMESTAMP = 3 ; 3 = hh:mm:ss, 2 = hh:mm, 0 = no timestamp + +MAX_WINDOWNAME_LEN = 256 + +WINDOW_BTN_START = 100 + +SCROLLBAR_WIDTH = 12 + +USERLIST_X = 98 + + +format binary as "" + +use32 + + org 0x0 + + db 'MENUET01' ; 8 byte id + dd 1 ; header version + dd START ; program start + dd I_END ; program image size + dd IM_END+2048 ; required amount of memory + dd IM_END+2048 + dd param + dd path + +include "../macros.inc" +include "../proc32.inc" +include "../dll.inc" +include "../network.inc" +include "../struct.inc" +include '../../../../../programs/develop/libraries/box_lib/trunk/box_lib.mac' + +struct window + data_ptr dd ? ; zero if not used + flags db ? + type db ? + name rb MAX_WINDOWNAME_LEN + users dd ? + users_scroll dd ? + selected dd ? ; selected user, 0 if none selected +ends + +struct window_data + text rb 120*60 + title rb 256 + names rb MAX_NICK_LEN * MAX_USERS + usertext rb 256 + usertextlen dd ? +ends + +include "encodings.inc" +include "window.inc" ; also contains text print routines +include "serverparser.inc" +include "userparser.inc" +include "socket.inc" +include "gui.inc" +include "users.inc" + + +START: + + mcall 68, 11 ; init heap so we can allocate memory dynamically + +; wanted events + mcall 40, EVM_REDRAW + EVM_KEY + EVM_BUTTON + EVM_STACK + EVM_MOUSE + +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit + +; find path to main settings file (ircc.ini) + mov edi, path ; Calculate the length of zero-terminated string + xor al, al + mov ecx, 1024 + repne scasb + dec edi + mov eax, '.ini' + stosd + xor al, al + stosb + +; Fill the window buffer with zeros + mov edi, windows + mov ecx, (sizeof.window*MAX_WINDOWS+3)/4 + xor eax, eax + rep stosd + +; clear command area too + mov edi, servercommand + mov ecx, 600/4 + rep stosd + +; allocate window data block + call window_create + mov ebx, windows + mov [ebx + window.data_ptr], eax + mov [ebx + window.flags], 0 + mov [ebx + window.type], WINDOWTYPE_SERVER + add eax, window_data.text + mov [text_start], eax + + call window_refresh + +; get system colors + mcall 48, 3, colors, 40 + +; set edit box and scrollbar colors + mov eax, [colors.work] + mov [scroll1.bg_color], eax + + mov eax, [colors.work_button] + mov [scroll1.front_color], eax + + mov eax, [colors.work_text] + mov [scroll1.line_color], eax + +; get settings from ini + invoke ini.get_str, path, str_user, str_nick, user_nick, MAX_NICK_LEN, default_nick + invoke ini.get_str, path, str_user, str_real, user_real_name, MAX_REAL_LEN, default_real + +; Welcome user + mov esi, str_welcome + call print_text2 + + call draw_window ;;; FIXME (gui is not correctly drawn first time) + +redraw: + call draw_window + +still: + +; wait here for event + mcall 10 + + dec eax + jz redraw + + dec eax + jz main_window_key + + dec eax + jz button + + cmp al, 3 + je mouse + + call process_network_event + + mov edx, [window_open] + test [edx + window.flags], FLAG_UPDATED + jz .no_update + and [edx + window.flags], not FLAG_UPDATED + mov edx, [edx + window.data_ptr] + add edx, window_data.text + call draw_channel_text + .no_update: + call print_channel_list + + jmp still + +button: + + mcall 17 ; get id + shr eax, 8 + + cmp ax, 1 ; close program + je exit + + cmp ax, 50 + jne @f + + mcall 37, 1 ; Get mouse position + sub ax, TEXT_Y + mov bl, 10 + div bl + and eax, 0x000000ff + inc eax + add eax, [scroll1.position] + mov ebx, [window_open] + mov [ebx + window.selected], eax + + call print_channel_list + + jmp still + + @@: + sub ax, WINDOW_BTN_START + jb exit + + cmp ax, MAX_WINDOWS + ja exit + + mov dx, sizeof.window + mul dx + shl edx, 16 + mov dx, ax + add edx, windows + cmp [edx + window.data_ptr], 0 + je exit + mov [window_open], edx + call window_refresh + call draw_window + + jmp still +exit: + mcall -1 + + + +main_window_key: + + mcall 2 + + push dword edit1 + call [edit_box_key] + + cmp ah, 13 ; enter + jne no_send2 + + call user_parser + + mov [edit1.size], 0 + mov [edit1.pos], 0 + + push dword edit1 + call [edit_box_draw] + + mov edx, [window_open] + mov edx, [edx + window.data_ptr] + add edx, window_data.text + call draw_channel_text + + jmp still + no_send2: + + jmp still + +mouse: + push dword edit1 + call [edit_box_mouse] + +; TODO: check if scrollbar is active + push [scroll1.position] + push dword scroll1 + call [scrollbar_v_mouse] + pop eax + cmp eax, [scroll1.position] ; did the scrollbar move? + je @f + call print_channel_list + @@: + + jmp still + + +; DATA AREA + +encoding_text: +db 'CP866 ' +db 'CP1251' +db 'UTF-8 ' +encoding_text_len = 6 + +action_header db '*** ', 0 +action_header_short db '* ', 0 +ctcp_header db '-> [',0 +ctcp_version db '] VERSION',10,0 +ctcp_ping db '] PING',10,0 +ctcp_time db '] TIME',10,0 +has_left_channel db ' has left ', 0 +joins_channel db ' has joined ', 0 +is_now_known_as db ' is now known as ', 0 +has_quit_irc db ' has quit IRC', 10, 0 +sets_mode db ' sets mode ', 0 +kicked db ' is kicked from ', 0 +str_talking db 'Now talking in ',0 +str_topic db 'Topic is ',0 +str_setby db 'Set by ',0 + +str_version db 'VERSION ' +str_programname db 'KolibriOS IRC client ', version, 0 + +str_user db 'user', 0 +str_nick db 'nick', 0 +str_real db 'realname', 0 +str_email db 'email', 0 + +default_nick db 'kolibri_user', 0 +default_real db 'Kolibri User', 0 + +str_welcome db 10 + db ' ______________________ __ __ __',10 + db '| \______ \_ ___ \ ____ | | |__| ____ _____/ |_',10 + db '| || _/ \ \/ _/ ___\| | | |/ __ \ / \ __\',10 + db '| || | \ \____ \ \___| |_| \ ___/| | \ |',10 + db '|___||____|_ /\______ / \___ >____/__|\___ >___| /__|',10 + db ' \/ \/ \/ \/ \/',10 + db 10 + db 'Welcome to IRC client ',version,' for KolibriOS',10 + db 10 + db 'Type /help for help',10,0 + +str_nickchange db 'Nickname is now ',0 +str_realchange db 'Real name is now ',0 +str_dotnewline db '.',10, 0 +str_newline db 10, 0 +str_connecting db 10,'* Connecting to ',0 +str_help db 10,'following commands are available:',10 + db 10 + db '/nick : change nickname to ',10 + db '/real : change real name to ',10 + db '/server
: connect to server
',10 + db '/code : change codepage to cp866, cp1251, or utf8',10,0 + +str_1 db ' -',0 +str_2 db '- ',0 + +str_sockerr db 'Socket Error',10,0 +str_dnserr db 'Unable to resolve hostname.',10,0 +str_refused db 'Connection refused',10,0 + +sockaddr1: + dw AF_INET4 +.port dw 0x0b1a ; 6667 +.ip dd 0 + rb 10 + + +status dd STATUS_DISCONNECTED + +text_start dd ? ; pointer to current textbox data +irc_data dd 0x0 ; encoder +textbox_width dd 80 ; in characters, not pixels ;) +pos dd 66 * 11 ; encoder + +window_open dd windows +window_print dd windows + +scroll dd 1 + dd 12 + +align 4 +@IMPORT: + +library network, 'network.obj',\ + libini, 'libini.obj',\ + boxlib, 'box_lib.obj' + +import network,\ + getaddrinfo, 'getaddrinfo',\ + freeaddrinfo, 'freeaddrinfo',\ + inet_ntoa, 'inet_ntoa' + +import libini,\ + ini.get_str, 'ini_get_str',\ + ini.get_int, 'ini_get_int' + +import boxlib,\ + edit_box_draw ,'edit_box' ,\ + edit_box_key ,'edit_box_key' ,\ + edit_box_mouse ,'edit_box_mouse' ,\ + scrollbar_v_draw ,'scrollbar_v_draw' ,\ + scrollbar_v_mouse,'scrollbar_v_mouse' + + +usercommand db '/server chat.freenode.net', 0 + rb MAX_COMMAND_LEN + +I_END: + + ; width, left, top +edit1 edit_box 0, 0, 0, 0xffffff, 0x6f9480, 0, 0, 0, USERCMD_MAX_SIZE, usercommand, mouse_dd, ed_focus, 25, 25 + ; xsize, xpos, ysize, ypos, max, cur, pos, bgcol, frcol, linecol +scroll1 scrollbar SCROLLBAR_WIDTH, 300, 150, TOP_Y, 10, 100, 0, 0, 0, 0, 0, 1 +scroll2 scrollbar SCROLLBAR_WIDTH, 300, 150, TOP_Y, 10, 100, 0, 0, 0, 0, 0, 1 + +main_PID dd ? ; identifier of main thread +utf8_bytes_rest dd ? ; bytes rest in current UTF8 sequence +utf8_char dd ? ; first bits of current UTF8 character +gai_reqdata rb 32 ; buffer for getaddrinfo_start/process +ip_list dd ? ; will be filled as pointer to addrinfo list +packetbuf rb 1024 ; buffer for packets to server +path rb 1024 +param rb 1024 + +socketnum dd ? + +servercommand rb 600 + +thread_info rb 1024 +xsize dd ? +ysize dd ? + +colors system_colors + +irc_server_name rb MAX_SERVER_NAME + +user_nick rb MAX_NICK_LEN +user_real_name rb MAX_REAL_LEN + +windows rb MAX_WINDOWS*sizeof.window + +mouse_dd dd ? + +IM_END: + + + + + + + diff --git a/programs/network/ircc/ircc.ini b/programs/network/ircc/ircc.ini new file mode 100644 index 0000000000..6232627005 --- /dev/null +++ b/programs/network/ircc/ircc.ini @@ -0,0 +1,8 @@ +[user] +nick = kolibri_user +realname = tetten + +[colors] +action1 = 0x000000aa +action2 = 0x0000aa00 +action3 = 0x00aa0000 \ No newline at end of file diff --git a/programs/network/ircc/serverparser.inc b/programs/network/ircc/serverparser.inc new file mode 100644 index 0000000000..cdde091532 --- /dev/null +++ b/programs/network/ircc/serverparser.inc @@ -0,0 +1,928 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +server_parser: + + mov esi, servercommand + + cmp byte [esi], ':' + jne .parse + + .spaceloop: + lodsb + test al, al + jz .fail + cmp al, ' ' + jne .spaceloop + + .parse: + mov eax, [esi] + or eax, 0x20202020 + mov edi, server_commands + mov ecx, server_commands.number + + .loop: + scasd + je .got_cmd + add edi, 4 + dec ecx + jnz .loop + + .fail: + ret + + .got_cmd: + jmp dword[edi] + + +server_commands: + + dd '322 ', cmd_322 ; RPL_LIST + dd '323 ', cmd_323 ; RPL_LISTEND + dd '328 ', cmd_328 + dd '332 ', cmd_topic + dd '333 ', cmd_333 ; nickname and time of topic + dd '353 ', cmd_353 ; name reply + dd '366 ', cmd_366 ; end of names list + dd '372 ', cmd_372 ; motd + dd '375 ', cmd_375 ; start of motd + dd '376 ', cmd_376 ; end of motd + dd '421 ', cmd_421 ; unknown command + dd 'join', cmd_join + dd 'kick', cmd_kick + dd 'mode', cmd_mode + dd 'nick', cmd_nick + dd 'part', cmd_part + dd 'ping', cmd_ping + dd 'priv', cmd_privmsg + dd 'quit', cmd_quit + dd 'noti', cmd_notice + + .number = ($ - server_commands) / 8 + + +align 4 +compare_to_nick: + + push esi + mov ecx, MAX_NICK_LEN + mov esi, user_nick + .loop: + lodsb + cmp al, ' ' + jbe .done + cmp al, 'a' + jb .ok + cmp al, 'z' + ja .ok + sub al, 0x20 + .ok: + + mov bl, byte[edi] + cmp bl, 'a' + jb .ok2 + cmp bl, 'z' + ja .ok2 + sub bl, 0x20 + .ok2: + cmp bl, al + jne .not_equal + inc edi + dec ecx + jnz .loop + + .done: + xor eax, eax + pop esi + ret + + .not_equal: + or eax, -1 + pop esi + ret + +align 4 +skip_nick: + +; First: skip the NICK (maybe we should verify it?) + .nick: + lodsb + cmp al, ' ' + je .skip + cmp al, ':' + je .skip + jmp .nick + +; skip all leading spaces and semicolons + .skip: + lodsb + cmp al, ' ' + je .skip + cmp al, ':' + je .skip + dec esi + + ret + + +align 4 +find_window: ; esi is ptr to windowname + + push esi + + mov edi, esi + call compare_to_nick + jne .nochat + + mov esi, servercommand+1 + .nochat: + +; now search for window in list + mov ebx, windows + mov [window_print], ebx ; set first window (server window) as default output window + .scanloop: + cmp [ebx + window.data_ptr], 0 + je .create_it + push esi + lea edi, [ebx + window.name] + mov ecx, MAX_WINDOWNAME_LEN + repe cmpsb + pop esi + cmp byte[edi-1], 0 + je .got_it + add ebx, sizeof.window + ; TODO: check buffer limits ? + jmp .scanloop + +; create channel window - search for empty slot + .create_it: + mov ebx, windows + mov ecx, MAX_WINDOWS + .scanloop2: + cmp [ebx + window.data_ptr], 0 + je .free_found + add ebx, sizeof.window + dec ecx + jnz .scanloop2 +; Error: no more available windows! + jmp .just_skip + + .free_found: + push ebx + call window_create + pop ebx + test eax, eax + jz .just_skip + mov [ebx + window.data_ptr], eax + mov [ebx + window.type], WINDOWTYPE_CHAT + mov [ebx + window.flags], 0 + + call window_set_name + + mov [window_open], ebx + mov [window_print], ebx + call window_refresh + + call draw_windownames + jmp .just_skip + +; found it! + .got_it: + mov [window_print], ebx + call window_refresh + + .just_skip: + pop esi + .skip1: +; skip text + lodsb + test al, al + jz .quit + cmp al, ' ' + jne .skip1 + dec esi +; now skip trailing spaces and semicolons + .skip2: + lodsb + test al, al + jz .quit + cmp al, ' ' + je .skip2 + cmp al, ':' + je .skip2 + dec esi + + .quit: + ret + + + + + + +cmd_328: +cmd_421: +cmd_372: +cmd_375: +cmd_376: + add esi, 4 + jmp cmd_notice.loop + +cmd_notice: + + cmp byte[servercommand], ':' + jne .gogogo + + mov byte [esi-1], 0 + push esi + mov esi, str_1 + call print_text2 + mov esi, servercommand+1 + call print_text2 + mov esi, str_2 + call print_text2 + pop esi + + .gogogo: + add esi, 6 + + .loop: + inc esi + cmp byte [esi], 0 + je .fail + cmp byte [esi], ' ' + jne .loop + + .loop2: + inc esi + cmp byte [esi], 0 + je .fail + cmp byte [esi], ' ' + je .loop2 + cmp byte [esi], ':' + je .loop2 + + call print_text2 + mov esi, str_newline + call print_text2 + + .fail: + + ret + + + +cmd_ping: + +; Just change PING to PONG + mov dword[esi], 'PONG' + +; Find the end of the command + lea edi, [esi + 5] + xor al, al + repne scasb + +; Now send it back + mov edx, esi + mov esi, edi + mov word [esi], 0x0d0a + inc esi + inc esi + sub esi, edx + mcall send, [socketnum], , , 0 + + ret + + + +cmd_privmsg: + + add esi, 8 ; skip 'PRIVMSG ' + call find_window ; esi now points to end of destination name + + cmp byte[esi], 1 + je cmd_ctcp + + cmp dword[esi], 'ACTI' ; Action? + je .action + +; nope, just plain old privmsg +if TIMESTAMP + call print_timestamp +end if + + push esi + mov bl, '<' + call print_character + + mov eax, servercommand+1 + mov dl, '!' + call print_text + + mov bl, '>' + call print_character + + mov bl, ' ' + call print_character + + pop esi + call print_text2 + + mov bl, 10 + call print_character + + .fail: + ret + + .action: + add esi, 8 + push esi + if TIMESTAMP + call print_timestamp + end if + + mov esi, action_header_short + call print_text2 + + mov eax, servercommand+1 + mov dl, ' ' + call print_text + + mov bl, ' ' + call print_character + + pop esi + call print_text2 + + mov bl, 10 + call print_character + + ret + +cmd_ctcp: + inc esi + + cmp dword[esi], 'VERS' + je .version + + cmp dword[esi], 'TIME' + je .time + + cmp dword[esi], 'PING' + je .ping + + ret + + .time: + mov byte [esi+4], ' ' + lea edi, [esi+5] + + ; TODO: add system date (fn 29) in human readable format + + mcall 3 ; get system time + + mov ecx, 3 + .timeloop: + mov bl, al + shr al, 4 + add al, '0' + stosb + + mov al, bl + and al, 0x0f + add al, '0' + stosb + + dec ecx + jz .timedone + + mov al, ':' + stosb + shr eax, 8 + jmp .timeloop + + .timedone: + xor al, al + stosb + call ctcp_reply + + if TIMESTAMP + call print_timestamp + end if + + mov esi, ctcp_header + call print_text2 + + mov esi, servercommand+1 + call print_text2 + + mov esi, ctcp_time + call print_text2 + + ret + + .version: + mov esi, str_version + call ctcp_reply + + if TIMESTAMP + call print_timestamp + end if + + mov esi, ctcp_header + call print_text2 + + mov esi, servercommand+1 + call print_text2 + + mov esi, ctcp_version + call print_text2 + + ret + + .ping: + call ctcp_reply + + if TIMESTAMP + call print_timestamp + end if + + mov esi, ctcp_header + call print_text2 + + mov esi, servercommand+1 + call print_text2 + + mov esi, ctcp_ping + call print_text2 + + ret + + + +ctcp_reply: + + push esi + + mov dword [usercommand], 'NOTI' + mov dword [usercommand+4], 'CE ' + + mov esi, servercommand+1 + mov edi, usercommand+7 + .nickloop: + lodsb + cmp al, '!' + je .done + cmp al, ' ' + je .done + test al, al + je .fail + stosb + jmp .nickloop + .done: + mov byte [esi-1], 0 + mov ax, ' :' + stosw + mov al, 1 + stosb + + pop esi + .replyloop: + lodsb + cmp al, 1 + jbe .done2 + stosb + jmp .replyloop + .done2: + + mov al, 1 + stosb + mov ax, 0x0a0d + stosw + + lea esi, [edi - usercommand] + mcall send, [socketnum], usercommand, , 0 + .fail: + ret + + + +cmd_part: + add esi, 5 ; skip 'PART ' + push esi + call skip_nick + call find_window + pop esi + +; Is it me who parted? + mov edi, servercommand+1 + call compare_to_nick + jne .dont_close + +; yes, close the window + mov edi, [window_print] + mov [edi + window.flags], FLAG_UPDATED + FLAG_CLOSE + + ret + +; somebody else parted, just print message + .dont_close: + push esi + mov esi, action_header + call print_text2 + + mov eax, servercommand+1 + mov dl, '!' + mov cl, ' ' + call print_text + + mov esi, has_left_channel + call print_text2 + + pop esi + call print_text2 + + mov esi, str_newline + call print_text2 + + mov ebx, [window_print] + mov esi, servercommand+1 + call user_remove + + ret + + + +cmd_join: + add esi, 5 ; skip 'JOIN ' + +; compare nick: did we join a channel? + mov edi, servercommand+1 + call compare_to_nick + jne .no_new_window + +; create channel window - search for empty slot + mov ebx, windows + mov ecx, MAX_WINDOWS + .loop: + cmp [ebx + window.data_ptr], 0 + je .free_found + add ebx, sizeof.window + dec ecx + jnz .loop +; Error: no more available windows!! ;;;;; TODO + .fail: + ret + + .free_found: + push ebx + call window_create + pop ebx + test eax, eax + jz .fail + mov [ebx + window.data_ptr], eax + mov [ebx + window.type], WINDOWTYPE_CHANNEL + mov [ebx + window.flags], 0 + + call window_set_name + + mov [window_open], ebx + mov [window_print], ebx + call window_refresh + + push esi + mov esi, action_header + call print_text2 + + mov esi, str_talking + call print_text2 + + pop eax + mov dl, ' ' + call print_text + + mov esi, str_dotnewline + call print_text2 + + call draw_window + + ret + + .no_new_window: + push esi + call find_window + + mov esi, action_header + call print_text2 + + mov eax, servercommand+1 + mov dl, '!' + call print_text + + mov esi, joins_channel + call print_text2 + + pop esi + call print_text2 + + mov esi, str_newline + call print_text2 + + mov ebx, [window_print] + mov esi, servercommand+1 + call user_add + + ret + + + + +cmd_nick: +; NOTE: This command applies to a user, and thus has no specific channel + add esi, 5 ; skip 'NICK ' + + cmp byte[esi], ':' ; TODO: skip all spaces and semicolons? + jne @f + inc esi + @@: + +; Change the nick in the current userlist. TODO: check other channels too! + push esi + mov ebx, [window_print] + + mov esi, servercommand+1 + call user_remove + + mov esi, [esp] + call user_add + + call redraw_channel_list + +; Is it me who changed nick? + mov edi, servercommand+1 + call compare_to_nick + pop esi + jne .not_me + + mov ecx, MAX_NICK_LEN-1 + push esi + .copyloop: + lodsb + test al, al + jz .copydone + cmp al, ' ' + je .copydone + stosb + dec ecx + jnz .copyloop + .copydone: + xor al, al + stosb + pop esi + .not_me: + +; Now print a message on the current channel + push esi + mov esi, action_header_short + call print_text2 + + mov eax, servercommand+1 + mov dl, '!' + call print_text + + mov esi, is_now_known_as + call print_text2 + + pop esi + call print_text2 + + mov esi, str_newline + call print_text2 + + ret + + + + +cmd_kick: + add esi, 5 ; skip 'KICK ' +; Is it me who got kicked? + mov edi, servercommand+1 + call compare_to_nick + jne .not_me + +; TODO: mark channel as disconnected + + .not_me: +; find the channel user has been kicked from + push esi + call skip_nick + call find_window + + mov esi, action_header_short + call print_text2 + + mov eax, servercommand+1 + mov dl, '!' + call print_text + + mov esi, kicked + call print_text2 + + pop esi + call print_text2 + + mov esi, str_newline + call print_text2 + + mov ebx, [window_print] + mov esi, servercommand+1 + call user_remove + + ret + + + +cmd_quit: +; NOTE: This command applies to a user, and thus has no specific channel + + mov esi, action_header + call print_text2 + + mov eax, servercommand+1 + mov dl, '!' + call print_text + + mov esi, has_quit_irc + call print_text2 + +; TODO: check other channels on same server too! + mov ebx, [window_print] + mov esi, servercommand+1 + call user_remove + + ret + + + +cmd_mode: + + add esi, 5 ; skip 'MODE ' + + push esi + mov esi, action_header_short + call print_text2 + + mov eax, servercommand+1 + mov dl, ' ' + call print_text + + mov esi, sets_mode + call print_text2 + + pop esi + call print_text2 + + mov esi, str_newline + call print_text2 + +;;; TODO: change username if needed + + ret + + +cmd_353: ; channel usernames reply + + add esi, 4 ; skip '353 ' + call skip_nick + inc esi ; channel type '*', '=' or '@' + inc esi ; ' ' + call find_window + +; now find window ptr and check if this is the first 353 message + mov ebx, [window_print] + test [ebx + window.flags], FLAG_RECEIVING_NAMES + jnz .add + + or [ebx + window.flags], FLAG_RECEIVING_NAMES +; mov [ebx + window.users], 0 + ; TODO: remove all users? + + .add: + push esi + call user_add + pop esi + + .namesloop: + lodsb + test al, al + jz .done + cmp al, ' ' ; names list is separated with spaces + jne .namesloop + jmp .add + + .done: + call redraw_channel_list + + ret + + + + + +cmd_366: ; channel usernames end + + add esi, 4 ; skip '366 ' + call skip_nick + call find_window + + mov ebx, [window_print] + and [ebx + window.flags], not FLAG_RECEIVING_NAMES + + ret + + + + +cmd_topic: + + add esi, 4 ; skip '332 ' + call skip_nick + call find_window + + push esi + mov esi, action_header + call print_text2 + + mov esi, str_topic + call print_text2 + + pop esi + call print_text2 + + mov esi, str_newline + call print_text2 + + ret + + +cmd_333: + + add esi, 4 ; skip '333 ' + call skip_nick ;;;; + call find_window + +; mov ecx, 2 ; number of spaces to find ;;; CHECKME +; .loop: +; lodsb +; test al, al +; je .fail +; cmp al, ' ' +; jne .loop +; dec ecx +; jnz .loop ; find some more spaces + + push esi + mov esi, action_header + call print_text2 + + mov esi, str_setby + call print_text2 + +; pop esi +; call print_text2 + + pop eax + mov dl, '!' + call print_text + + mov esi, str_newline + call print_text2 + + .fail: + ret + +cmd_322: + add esi, 4 + + call skip_nick + + call print_text2 + + mov esi, str_newline + call print_text2 + + ret + +cmd_323: + + ret \ No newline at end of file diff --git a/programs/network/ircc/socket.inc b/programs/network/ircc/socket.inc new file mode 100644 index 0000000000..3b11930716 --- /dev/null +++ b/programs/network/ircc/socket.inc @@ -0,0 +1,242 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +socket_connect: + +; cmp [status], STATUS_CONNECTED ; TODO +; je disconnect + +; ignore if status is not "disconnected" + cmp [status], STATUS_DISCONNECTED + jne .nothing + + mov esi, str_connecting + call print_text2 + mov esi, irc_server_name + call print_text2 + mov esi, str_dotnewline + call print_text2 + +; update status + inc [status] ; was STATUS_DISCONNECTED, now STATUS_RESOLVING + +; resolve name + push esp ; reserve stack place + push esp ; fourth parameter + push 0 ; third parameter + push 0 ; second parameter + push irc_server_name + call [getaddrinfo] + pop esi +; test for error + test eax, eax + jnz .fail_dns + +; fill in ip in sockstruct + mov eax, [esi + addrinfo.ai_addr] + mov eax, [eax + sockaddr_in.sin_addr] + mov [sockaddr1.ip], eax + +; free allocated memory + push esi + call [freeaddrinfo] + +; update status + inc [status] + +; connect + mcall socket, AF_INET4, SOCK_STREAM, 0 + cmp eax, -1 + jz .fail + mov [socketnum], eax + + mcall connect, [socketnum], sockaddr1, 18 + cmp eax, -1 + jz .fail_refused + + .nothing: + ret + + .fail: + mov [status], STATUS_DISCONNECTED + + mov esi, str_sockerr + call print_text2 + + ret + + .fail_dns: + mov [status], STATUS_DISCONNECTED + + mov esi, str_dnserr + call print_text2 + + ret + + .fail_refused: + mov [status], STATUS_DISCONNECTED + + mov esi, str_refused + call print_text2 + + ret + + + +socket_write_userinfo: + +; create packet in packetbuf + mov edi, packetbuf + + mov eax, 'NICK' + stosd + mov al, ' ' + stosb + mov esi, user_nick + mov ecx, MAX_NICK_LEN + .loop: + lodsb + test al, al + jz .done + stosb + dec ecx + jnz .loop + .done: + mov ax, 0x0d0a + stosw + + mov eax, 'USER' + stosd + mov al, ' ' + stosb + mov esi, user_nick + mov ecx, MAX_NICK_LEN + .loop2: + lodsb + test al, al + jz .done2 + stosb + dec ecx + jnz .loop2 + .done2: + mov eax, ' 8 *' + stosd + mov ax, ' :' + stosw + mov al, ' ' + stosb + mov esi, user_real_name + mov ecx, MAX_REAL_LEN + .loop3: + lodsb + test al, al + jz .done3 + stosb + dec ecx + jnz .loop3 + .done3: + mov ax, 0x0d0a + stosw + + lea esi, [edi - packetbuf] + mcall send, [socketnum], packetbuf, , 0 + + ret + + + + +process_network_event: +; values for status: 0, 1, 2, 3 + mov eax, [status] + dec eax +; 0 = STATUS_DISCONNECTED - do nothing +; (ignore network events if we are disconnected from network) + js .nothing +; 1 = STATUS_RESOLVING + jz .nothing +; 2 = STATUS_CONNECTING + dec eax + jz .connecting +; 3 = STATUS_CONNECTED + jmp .connected + + .nothing: + ret + + .connecting: + call socket_write_userinfo + +; The connection has been established, change status from "connecting" to "connected". + inc [status] + + .connected: + call read_incoming_data + ret + + +disconnect: + + cmp [status], STATUS_DISCONNECTED + je .nothing + + mcall close, [socketnum] + + mov [status], STATUS_DISCONNECTED + + .nothing: + ret + + + +read_incoming_data: + + pusha + +; TODO: read more data if we receive one full packet + + .nextpacket: + mcall recv, [socketnum], packetbuf, 1024 ; read a packet + inc eax ; check if we got one + jz .done + dec eax + jz .done + +; ok we have data, now feed it to the recoder + + lea edx, [packetbuf + eax] ; edx = end pointer + mov esi, packetbuf ; esi = start pointer + .nextcommand: + mov edi, servercommand + .byteloop: + call get_next_byte ; reads byte from [esi] to al + jnc .nextpacket ; if CF is set, we need more data + cmp al, 10 + je .got_command + cmp al, 13 + je .got_command + stosb + jmp .byteloop + +; we have a command, call the serverparser + + .got_command: + mov byte[edi], 0 ; mark the end of the command + push esi edx + call server_parser + pop edx esi + jmp .nextcommand + + .done: + popa + + ret \ No newline at end of file diff --git a/programs/network/ircc/userparser.inc b/programs/network/ircc/userparser.inc new file mode 100644 index 0000000000..bddfdb34a0 --- /dev/null +++ b/programs/network/ircc/userparser.inc @@ -0,0 +1,318 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +user_parser: + + mov eax, [edit1.size] + mov word [usercommand + eax], 0x0a0d ; terminate the line + + cmp byte[usercommand], '/' ; is it a server command ? + je server_command + +; Ignore data commands when not connected. + cmp [status], STATUS_CONNECTED + jne sdts_ret + +; Ok, we said something, print it to our textbox + +; TODO: dont send if it's a server window? + + push [window_open] ; print to the current window + pop [window_print] + call window_refresh + + if TIMESTAMP + call print_timestamp + end if + + mov bl, '<' + call print_character + + mov esi, user_nick + call print_text2 + + mov bl,'>' + call print_character + mov bl,' ' + call print_character + + mov eax, [edit1.size] + mov byte[usercommand + eax],0 + + mov esi, usercommand + call print_text2 + + mov bl, 10 + call print_character + +; and now send it to the server + + mov dword[packetbuf], 'priv' + mov dword[packetbuf+4], 'msg ' + + mov esi, [window_open] + add esi, window.name + mov edi, packetbuf+8 + mov ecx, MAX_WINDOWNAME_LEN + .loop: + lodsb + test al, al + jz .done + stosb + dec ecx + jnz .loop + .done: + + mov ax, ' :' + stosw + + mov esi, usercommand + mov ecx, [edit1.size] + inc ecx + call recode + + mov al, 10 + stosb + + lea esi, [edi - packetbuf] + mcall send, [socketnum], packetbuf, , 0 + +sdts_ret: + + ret + + + +user_commands: + dd 'nick', cmd_usr_nick + dd 'real', cmd_usr_real + dd 'serv', cmd_usr_server + dd 'help', cmd_usr_help + dd 'code', cmd_usr_code +; TODO: All other commands require a connection to the server. + dd 'quer', cmd_usr_quer + dd 'quit', cmd_usr_quit + + .number = ($ - user_commands) / 8 + + + +server_command: + + mov eax, dword[usercommand+1] + or eax, 0x20202020 + + mov edi, user_commands + mov ecx, user_commands.number + .loop: + scasd + je .got_cmd + add edi, 4 + dec ecx + jnz .loop + jmp cmd_usr_send ; If none of the previous commands, just send to server + + .got_cmd: + jmp dword[edi] + + + + + +cmd_usr_quit: + + cmp [edit1.size], 5 + je .ok + jb cmd_usr_send + cmp byte[usercommand+5], ' ' + jne cmd_usr_send + + .ok: + call cmd_usr_send + + mcall close, [socketnum] + + mov ecx, MAX_WINDOWS + mov edi, windows + .loop: + mov [edi + window.flags], FLAG_CLOSE + add edi, sizeof.window + dec ecx + jnz .loop + + ret + + + + +cmd_usr_nick: + + cmp [edit1.size], 5 + je .justprint + cmp byte[usercommand+5], ' ' + jne cmd_usr_send + + mov ecx, MAX_NICK_LEN + mov esi, usercommand+6 + mov edi, user_nick + .loop: + lodsb + cmp al, 13 + je .done + stosb + dec ecx + jnz .loop + .done: + xor al, al + stosb + + cmp [socketnum], 0 + je .justprint + + lea esi, [edi - usercommand] + mcall send, [socketnum], usercommand+1, , 0 + + .justprint: + mov esi, str_nickchange + call print_text2 + mov esi, user_nick + call print_text2 + mov esi, str_dotnewline + call print_text2 + + ret + + + +cmd_usr_real: + + cmp byte[usercommand+5], ' ' + jne cmd_usr_send + + mov ecx, MAX_REAL_LEN + mov esi, usercommand+6 + mov edi, user_real_name + .loop: + lodsb + cmp al, 13 + je .done + stosb + dec ecx + jnz .loop + .done: + xor al, al + stosb + + mov esi, str_realchange + call print_text2 + mov esi, user_real_name + call print_text2 + mov esi, str_dotnewline + call print_text2 + + ret + + + +cmd_usr_server: + + mov eax, dword[usercommand+5] ; check for 'er ', we only checked 'serv' + or eax, 0x00002020 + and eax, 0x00ffffff + cmp eax, 'er ' + jne cmd_usr_send + + mov ecx, [edit1.size] ; ok now set the address + sub ecx, 8 + + mov esi, usercommand+8 + push esi + mov edi, irc_server_name + rep movsb + xor al, al + stosb + pop esi + +; set it also in window name + mov ebx, [window_print] + call window_set_name + +; now connect + call socket_connect + + ret + + +cmd_usr_quer: + + mov ecx, MAX_WINDOWS + mov ebx, windows + .loop: + cmp [ebx + window.data_ptr], 0 + je .found + add ebx, sizeof.window + dec ecx + jnz .loop + +; error: no available channels ! FIXME + + ret + + + .found: + call window_create + test eax, eax + jz .error + mov [ebx + window.data_ptr], eax + + mov esi, usercommand+7 + call window_set_name + + mov [ebx + window.type], WINDOWTYPE_CHAT + mov [ebx + window.flags], 0 + + .error: + + ret + + + +cmd_usr_help: + + mov esi, str_help + call print_text2 + + ret + + + +cmd_usr_code: + + ; TODO + + ret + + + +cmd_usr_send: + + mov esi, usercommand+1 + mov ecx, [edit1.size] + inc ecx + mov edi, packetbuf + call recode + + lea esi, [edi - packetbuf] + mcall send, [socketnum], packetbuf, , 0 + + ret + diff --git a/programs/network/ircc/users.inc b/programs/network/ircc/users.inc new file mode 100644 index 0000000000..f84a67111d --- /dev/null +++ b/programs/network/ircc/users.inc @@ -0,0 +1,164 @@ + + +; esi is ptr to nick +; ebx is ptr to window +align 4 +user_add: + + cmp [ebx + window.users], MAX_USERS + jae fail + + mov edi, [ebx + window.data_ptr] + add edi, window_data.names + mov ebp, [ebx + window.users] + inc ebp ; CHECKME + + push esi edi + .restart: + mov ecx, MAX_NICK_LEN + .loop1: + lodsb + cmp al, '@' + jne @f + mov al, ' ' ; give @ highest priority + @@: + cmp al, 'A' + jb @f + cmp al, 'Z' + ja @f + add al, 'a' - 'A' ; convert to lowercase + @@: + dec ecx + jz .got_it + + .loop2: + mov dl, [edi] + cmp dl, 0 + je .got_it + cmp dl, '@' + jne @f + mov dl, ' ' ; give @ highest priority + @@: + cmp dl, 'A' + jb @f + cmp dl, 'Z' + ja @f + add dl, 'a' - 'A' ; convert to lowercase + @@: + cmp al, dl + jb .got_it + je .check_next + + pop edi esi + add edi, MAX_NICK_LEN + push esi edi + + dec ebp + jnz .restart + + .check_next: + inc edi + jmp .loop1 + + .got_it: + pop edi esi + +; OK, insert it here.. + +; mov all trailing usernames by MAX_NICK_LEN bytes + push esi edi + mov esi, [ebx + window.data_ptr] + add esi, window_data.names + MAX_NICK_LEN * (MAX_USERS - 1) + + mov ecx, esi + sub ecx, edi + add ecx, MAX_NICK_LEN + shr ecx, 2 + lea edi, [esi + MAX_NICK_LEN] + std + rep movsd + cld + pop edi esi + +; Now insert our new username + mov ecx, MAX_NICK_LEN-1 + .fill: + lodsb + cmp al, ' ' + je .done + cmp al, '!' + je .done + stosb + loop .fill + .done: + xor al, al + stosb + + inc [ebx + window.users] + + ret + + + + + +; esi is ptr to nick +; ebx is ptr to window +align 4 +user_remove: + + call user_find + jz fail + + lea esi, [edi + MAX_NICK_LEN] + mov ecx, [ebx + window.data_ptr] + add ecx, window_data.names + MAX_NICK_LEN * MAX_USERS + sub ecx, esi + shr ecx, 2 + rep movsd + + dec [ebx + window.users] + xor eax, eax + + ret + + + +; IN: +; esi is ptr to nick +; ebx is ptr to window +; OUT: +; edi is ptr to nick in userlist +align 4 +user_find: + + mov eax, [ebx + window.users] + test eax, eax + jz fail + mov edi, [ebx + window.data_ptr] + add edi, window_data.names + + .loop: + push esi edi + mov ecx, MAX_NICK_LEN + repe cmpsb + cmp byte[edi-1], 0 + je .got_it + ; TODO: check byte[esi] too! + pop edi esi + add edi, MAX_NICK_LEN + dec eax + jnz .loop + jmp fail + + .got_it: + pop edi esi + test edi, edi ; to clear zero flag + + ret + + +fail: + + xor edi, edi + ret \ No newline at end of file diff --git a/programs/network/ircc/window.inc b/programs/network/ircc/window.inc new file mode 100644 index 0000000000..5065b60cef --- /dev/null +++ b/programs/network/ircc/window.inc @@ -0,0 +1,167 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +window_create: + +; allocate the window data block + mcall 68, 12, sizeof.window_data + test eax, eax + jz .fail + +; fill it with all zeros + push eax + mov edi, eax + mov ecx, (sizeof.window_data+3)/4 + xor eax, eax + rep stosd + pop eax + + .fail: + ret + + +window_set_name: ; esi = ptr to name, ebx = window ptr + + pusha + +; Skip heading spaces + .spaceloop: + cmp byte[esi], ' ' + jne .done + inc esi + jmp .spaceloop + .done: + +; Now copy it + lea edi, [ebx + window.name] + mov ecx, MAX_WINDOWNAME_LEN + .loop: + lodsb + cmp al, 0x21 + jbe .addzero + stosb + dec ecx + jnz .loop + .addzero: + xor al, al + stosb + + call draw_windownames ; redraw it + + popa + + ret + + + +window_refresh: + +; set the correct buffer pointers ; FIXME: what is it good for? + mov eax, [textbox_width] ; + imul eax, 11 ; + mov [pos], eax ; + + mov eax, [window_print] + mov eax, [eax + window.data_ptr] + add eax, window_data.text + mov [text_start], eax + + ret + + +window_updated: + + mov edi, [window_print] + test [edi + window.flags], FLAG_UPDATED + jnz .skip + + or [edi + window.flags], FLAG_UPDATED + +; now play a sound :) + + .skip: + + ret + + +print_text: ; eax = start ptr + ; dl = end char + pusha + ptr2: + mov bl, [eax] + + cmp bl, dl + je ptr_ret + cmp bl, 0 + je ptr_ret + call print_character + + inc eax + jmp ptr2 + + ptr_ret: + popa + ret + + +print_text2: ; esi = ptr to ASCIIZ string + + pusha + .loop: + lodsb + test al, al + jz .done + mov bl, al + call print_character + jmp .loop + + .done: + popa + ret + + +if TIMESTAMP +print_timestamp: + + pusha + mcall 3 ; get system time + + mov bl, '[' + call print_character + mov ecx, TIMESTAMP + .loop: + mov bl, al + shr bl, 4 + add bl, '0' + call print_character + + mov bl, al + and bl, 0x0f + add bl, '0' + call print_character + + dec ecx + jz .done + + mov bl, ':' + call print_character + shr eax, 8 + jmp .loop + .done: + mov bl, ']' + call print_character + mov bl, ' ' + call print_character + + popa + ret +end if \ No newline at end of file diff --git a/programs/network/libio.inc b/programs/network/libio.inc new file mode 100644 index 0000000000..220203b24f --- /dev/null +++ b/programs/network/libio.inc @@ -0,0 +1,113 @@ +;;================================================================================================;; +;;//// libio.inc //// (c) mike.dld, 2007-2008 ////////////////////////////////////////////////////;; +;;================================================================================================;; +;; ;; +;; This file is part of Common development libraries (Libs-Dev). ;; +;; ;; +;; Libs-Dev is free software: you can redistribute it and/or modify it under the terms of the GNU ;; +;; Lesser General Public License as published by the Free Software Foundation, either version 2.1 ;; +;; of the License, or (at your option) any later version. ;; +;; ;; +;; Libs-Dev is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without ;; +;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; +;; Lesser General Public License for more details. ;; +;; ;; +;; You should have received a copy of the GNU Lesser General Public License along with Libs-Dev. ;; +;; If not, see . ;; +;; ;; +;;================================================================================================;; + + +O_BINARY = 00000000b +O_READ = 00000001b +O_WRITE = 00000010b +O_CREATE = 00000100b +O_SHARE = 00001000b +O_TEXT = 00010000b + +SEEK_SET = 0 +SEEK_CUR = 1 +SEEK_END = 2 + +struct FileDateTime + union + time dd ? + struct + sec db ? + min db ? + hour db ? + ends + ends + union + date dd ? + struct + day db ? + month db ? + year dw ? + ends + ends +ends + +struct FileInfoBlock + Function dd ? + Position dd ? + Flags dd ? + Count dd ? + Buffer dd ? + db ? + FileName dd ? +ends + +struct FileInfoHeader + Version dd ? + FilesRead dd ? + FilesCount dd ? + rd 5 +ends + +struct FileInfoA + Attributes dd ? + Flags dd ? + DateCreate FileDateTime + DateAccess FileDateTime + DateModify FileDateTime + union + FileSize dq ? + struct + FileSizeLow dd ? + FileSizeHigh dd ? + ends + ends + FileName rb 264 +ends + +struct FileInfoW + Attributes dd ? + Flags dd ? + DateCreate FileDateTime + DateAccess FileDateTime + DateModify FileDateTime + union + FileSize dq ? + struct + FileSizeLow dd ? + FileSizeHigh dd ? + ends + ends + FileName rw 264 +ends + +virtual at 0 + FileInfo FileInfoA + FileInfo fix FileInfoA + sizeof.FileInfo fix sizeof.FileInfoA +end virtual + +FA_READONLY = 00000001b +FA_HIDDEN = 00000010b +FA_SYSTEM = 00000100b +FA_LABEL = 00001000b +FA_FOLDER = 00010000b +FA_ARCHIVED = 00100000b +FA_NORMAL = 01000000b +FA_ANY = 01111111b diff --git a/programs/network/macros.inc b/programs/network/macros.inc new file mode 100644 index 0000000000..d6568ca0eb --- /dev/null +++ b/programs/network/macros.inc @@ -0,0 +1,588 @@ +@^ fix macro comment { +^@ fix } + +; ------------------------- +macro library [lname,fname] +{ + forward + dd __#lname#_library_table__,__#lname#_library_name__ + common + dd 0 + forward + align 4 + __#lname#_library_name__ db fname,0 +} + +macro import lname,[name,sname] +{ + common + align 4 + __#lname#_library_table__: + forward + if used name + name dd __#name#_import_name__ + end if + common + dd 0 + forward + if used name + align 4 + __#name#_import_name__ db sname,0 + end if +} + +macro export [name,sname] +{ + forward + dd __#name#_export_name__,name + common + dd 0 + forward + align 4 + __#name#_export_name__ db sname,0 +} +; ------------------------- + +macro m2m dest,src { + push src + pop dest +} + + +macro iglobal { + IGlobals equ IGlobals, + macro __IGlobalBlock { } + +macro uglobal { + UGlobals equ UGlobals, + macro __UGlobalBlock { } + +endg fix } ; Use endg for ending iglobal and uglobal blocks. + + +macro IncludeIGlobals{ + macro IGlobals dummy,[n] \{ __IGlobalBlock + purge __IGlobalBlock \} + match I, IGlobals \{ I \} } + +macro IncludeUGlobals{ + macro UGlobals dummy,[n] \{ + \common + \local begin, size + begin = $ + virtual at $ + \forward + __UGlobalBlock + purge __UGlobalBlock + \common + size = $ - begin + end virtual + rb size + \} + match U, UGlobals \{ U \} } + +uglobal +endg + +iglobal +endg + + +; new application structure +macro meos_app_start + { + use32 + org 0x0 + + db 'MENUET01' + dd 0x01 + dd __start + dd __end + dd __memory + dd __stack + + if used __params & ~defined __params + dd __params + else + dd 0x0 + end if + + dd 0x0 + } +MEOS_APP_START fix meos_app_start + +macro code + { + __start: + } +CODE fix code + +macro data + { + __data: + IncludeIGlobals + } +DATA fix data + +macro udata + { + if used __params & ~defined __params + __params: + db 0 + __end: + rb 255 + else + __end: + end if + __udata: + IncludeUGlobals + } +UDATA fix udata + +macro meos_app_end + { + align 32 + rb 2048 + __stack: + __memory: + } +MEOS_APP_END fix meos_app_end + + +; macro for defining multiline text data +struc mstr [sstring] + { + forward + local ssize + virtual at 0 + db sstring + ssize = $ + end virtual + dd ssize + db sstring + common + dd -1 + } + +; macro for defining multiline text data +struc mls [sstring] + { + forward + local ssize + virtual at 0 + db sstring ; mod + ssize = $ + end virtual + db ssize + db sstring + common + db -1 ; mod + } + + + +; strings +macro sz name,[data] { ; from MFAR [mike.dld] + common + if used name + name db data + .size = $-name + end if +} + +macro lsz name,[lng,data] { ; from MFAR [mike.dld] + common + if used name + label name + forward + if lang eq lng + db data + end if + common + .size = $-name + end if +} + +macro szc name,elsz,[data] { ; from MFAR [mike.dld] + common + local s,m + m = 0 + if used name + label name + forward + virtual at 0 + db data + s = $ + end virtual + d#elsz s + if m < s + m = s + end if + db data + common + .size = $-name + .maxl = m + end if +} + +macro lszc name,elsz,[lng,data] { ; from MFAR [mike.dld] + common + local s,m,c + m = 0 + c = 0 + if used name + label name + forward + if lang eq lng + virtual at 0 + db data + s = $ + end virtual + d#elsz s + if m < s + m = s + end if + db data + c = c+1 + end if + common + .size = $-name + .maxl = m + .count = c + end if +} + + +; easy system call macro +macro mpack dest, hsrc, lsrc +{ + if (hsrc eqtype 0) & (lsrc eqtype 0) + mov dest, (hsrc) shl 16 + lsrc + else + if (hsrc eqtype 0) & (~lsrc eqtype 0) + mov dest, (hsrc) shl 16 + add dest, lsrc + else + mov dest, hsrc + shl dest, 16 + add dest, lsrc + end if + end if +} + +macro __mov reg,a,b { ; mike.dld + if (~a eq)&(~b eq) + mpack reg,a,b + else if (~a eq)&(b eq) + mov reg,a + end if +} + + +include 'config.inc' +;__CPU_type equ p5 +SYSENTER_VAR equ 0 + +macro mcall a,b,c,d,e,f { ; mike.dld, updated by Ghost for Fast System Calls + local ..ret_point + __mov eax,a + __mov ebx,b + __mov ecx,c + __mov edx,d + __mov esi,e + __mov edi,f + + if __CPU_type eq p5 + int 0x40 + else + if __CPU_type eq p6 + push ebp + mov ebp, esp + push ..ret_point ; it may be 2 or 5 byte + sysenter + ..ret_point: + pop edx + pop ecx + + else + if __CPU_type eq k6 + push ecx + syscall + pop ecx + else + display 'ERROR : unknown CPU type (set to p5)', 10, 13 + __CPU_type equ p5 + int 0x40 + end if + end if + end if +} + + +; ------------------------- +macro header a,[b] { + common + use32 + org 0 + db 'MENUET',a + forward + if b eq + dd 0 + else + dd b + end if } +macro section name { align 16 + label name } +macro func name { + if ~used name + display 'FUNC NOT USED: ',`name,13,10 + else + align 4 + name: + ;diff16 `name,0,name +;pushad +;pushfd +;dps `name +;newline +;mcall 5,1 +;popfd +;popad +} +macro endf { end if } + +macro diff16 title,l1,l2 + { + local s,d + s = l2-l1 + display title,': 0x' + repeat 8 + d = '0' + s shr ((8-%) shl 2) and $0F + if d > '9' + d = d + 'A'-'9'-1 + end if + display d + end repeat + display 13,10 + } + +macro diff10 title,l1,l2 + { + local s,d,z,m + s = l2-l1 + z = 0 + m = 1000000000 + display title,': ' + repeat 10 + d = '0' + s / m + s = s - (s/m)*m + m = m / 10 + if d <> '0' + z = 1 + end if + if z <> 0 + display d + end if + end repeat + display 13,10 + } + +; optimize the code for size +__regs fix + +macro add arg1,arg2 + { + if (arg2 eqtype 0) + if (arg2) = 1 + inc arg1 + else + add arg1,arg2 + end if + else + add arg1,arg2 + end if + } + +macro sub arg1,arg2 + { + if (arg2 eqtype 0) + if (arg2) = 1 + dec arg1 + else + sub arg1,arg2 + end if + else + sub arg1,arg2 + end if + } + +macro mov arg1,arg2 + { + if (arg1 in __regs) & ((arg2 eqtype 0) | (arg2 eqtype '0')) + if (arg2) = 0 + xor arg1,arg1 + else if (arg2) = 1 + xor arg1,arg1 + inc arg1 + else if (arg2) = -1 + or arg1,-1 + else if (arg2) > -128 & (arg2) < 128 + push arg2 + pop arg1 + else + mov arg1,arg2 + end if + else + mov arg1,arg2 + end if + } + + +macro RGB [a] { + common + match (r=,g=,b),a \{ + \dd ((r) shl 16) or ((g) shl 8) or (b) + \} +} + + +struc POINT _t,_dx,_dy { + .x _t _dx + .y _t _dy +} + +; structure definition helper +include 'struct.inc' + +struct RECT + left dd ? + top dd ? + right dd ? + bottom dd ? +ends + +struct BOX + left dd ? + top dd ? + width dd ? + height dd ? +ends + +; structures used in MeOS +struct process_information + cpu_usage dd ? ; +0 + window_stack_position dw ? ; +4 + window_stack_value dw ? ; +6 + dw ? ; +8 + process_name rb 12 ; +10 + memory_start dd ? ; +22 + used_memory dd ? ; +26 + PID dd ? ; +30 + box BOX ; +34 + slot_state dw ? ; +50 + dw ? ; +52 + client_box BOX ; +54 + wnd_state db ? ; +70 + rb (1024-71) +ends + +struct system_colors + frame dd ? + grab dd ? + grab_button dd ? + grab_button_text dd ? + grab_text dd ? + work dd ? + work_button dd ? + work_button_text dd ? + work_text dd ? + work_graph dd ? +ends + +struct FILEDATE + Second db ? + Minute db ? + Hour db ? + db ? + Day db ? + Month db ? + Year dw ? +ends + +struct FILEINFO + Attributes dd ? + IsUnicode db ? + db 3 dup(?) + DateCreate FILEDATE + DateAccess FILEDATE + DateModify FILEDATE + Size dq ? +ends + + +if __CPU_type eq p5 ; CMOVcc isnt supported on the P5 + +cmove fix cmovz +macro cmovz reg1, reg2 { + +local .jumpaddr + + jnz .jumpaddr + mov reg1, reg2 + .jumpaddr: +} + +cmovne fix cmovnz +macro cmovnz reg1, reg2 { + +local .jumpaddr + + jz .jumpaddr + mov reg1, reg2 + .jumpaddr: +} + +macro cmovg reg1, reg2 { + +local .jumpaddr + + jle .jumpaddr + mov reg1, reg2 + .jumpaddr: +} + +macro cmovl reg1, reg2 { + +local .jumpaddr + + jge .jumpaddr + mov reg1, reg2 + .jumpaddr: +} + +end if + +; constants + +; events +EV_IDLE = 0 +EV_TIMER = 0 +EV_REDRAW = 1 +EV_KEY = 2 +EV_BUTTON = 3 +EV_EXIT = 4 +EV_BACKGROUND = 5 +EV_MOUSE = 6 +EV_IPC = 7 +EV_STACK = 8 + +; event mask bits for function 40 +EVM_REDRAW = 1b +EVM_KEY = 10b +EVM_BUTTON = 100b +EVM_EXIT = 1000b +EVM_BACKGROUND = 10000b +EVM_MOUSE = 100000b +EVM_IPC = 1000000b +EVM_STACK = 10000000b +EVM_DEBUG = 100000000b +EVM_STACK2 = 1000000000b diff --git a/programs/network/netcfg/drivers.inc b/programs/network/netcfg/drivers.inc new file mode 100644 index 0000000000..e06bc8fa64 --- /dev/null +++ b/programs/network/netcfg/drivers.inc @@ -0,0 +1,198 @@ +driverlist: +db 'RTL8139',0 +dd 0x813910ec +dd 0x813810ec +dd 0x12111113 +dd 0x13601500 +dd 0x13604033 +dd 0x13001186 +dd 0x13401186 +dd 0xab0613d1 +dd 0xa1171259 +dd 0xa11e1259 +dd 0xab0614ea +dd 0xab0714ea +dd 0x123411db +dd 0x91301432 +dd 0x101202ac +dd 0x0106018a +dd 0x1211126c +dd 0x81391743 +dd 0x8139021b +dd 0x0 ; end + +db 'RTL8029',0 +dd 0x802910ec +dd 0x0 + +db 'I8255X',0 +dd 0x12098086 +dd 0x10298086 +dd 0x12298086 +dd 0x10308086 +dd 0x24498086 +dd 0x0 + +db 'RTL8169',0 +dd 0x816810ec +dd 0x816910ec +dd 0x011616ec +dd 0x43001186 +dd 0x813610ec +dd 0x0 + +db '3C59X',0 +dd 0x590010b7 +dd 0x592010b7 +dd 0x597010b7 +dd 0x595010b7 +dd 0x595110b7 +dd 0x595210b7 +dd 0x900010b7 +dd 0x900110b7 +dd 0x900410b7 +dd 0x900510b7 +dd 0x900610b7 +dd 0x900A10b7 +dd 0x905010b7 +dd 0x905110b7 +dd 0x905510b7 +dd 0x905810b7 +dd 0x905A10b7 +dd 0x920010b7 +dd 0x980010b7 +dd 0x980510b7 +dd 0x764610b7 +dd 0x505510b7 +dd 0x605510b7 +dd 0x605610b7 +dd 0x5b5710b7 +dd 0x505710b7 +dd 0x515710b7 +dd 0x525710b7 +dd 0x656010b7 +dd 0x656210b7 +dd 0x656410b7 +dd 0x450010b7 +dd 0x0 + +db 'SIS900',0 +dd 0x09001039 +dd 0x70161039 +dd 0x0 + +db 'PCNET32',0 +dd 0x20001022 +dd 0x26251022 +dd 0x20011022 +dd 0x0 + +db 'FORCEDETH',0 +dd 0x006610de +dd 0x01c310de +dd 0x00D610de +dd 0x008610de +dd 0x008c10de +dd 0x00e610de +dd 0x00df10de +dd 0x005610de +dd 0x005710de +dd 0x003710de +dd 0x003810de +dd 0x026810de +dd 0x026910de +dd 0x037210de +dd 0x037310de +dd 0x03e510de +dd 0x03e610de +dd 0x03ee10de +dd 0x03ef10de +dd 0x045010de +dd 0x045110de +dd 0x045210de +dd 0x045310de +dd 0x054c10de +dd 0x054d10de +dd 0x054e10de +dd 0x054f10de +dd 0x07dc10de +dd 0x07dd10de +dd 0x07de10de +dd 0x07df10de +dd 0x076010de +dd 0x076110de +dd 0x076210de +dd 0x076310de +dd 0x0ab010de +dd 0x0ab110de +dd 0x0ab210de +dd 0x0ab310de +dd 0x0d7d10de +dd 0x0 + +db 'MTD80X',0 +dd 0x08031516 +dd 0x08001516 +dd 0x08911516 +dd 0x0 + +db 'dec21x4x',0 +dd 0x00091011 +dd 0x00191011 +dd 0x09851317 +dd 0x0 + +db 'R6040',0 +dd 0x604017F3 +dd 0x0 + +db 'i8254x',0 +dd 0x10008086 ; 82542 (Fiber) +dd 0x10018086 ; 82543GC (Fiber) +dd 0x10048086 ; 82543GC (Copper) +dd 0x10088086 ; 82544EI (Copper) +dd 0x10098086 ; 82544EI (Fiber) +dd 0x100A8086 ; 82540EM +dd 0x100C8086 ; 82544GC (Copper) +dd 0x100D8086 ; 82544GC (LOM) +dd 0x100E8086 ; 82540EM +dd 0x100F8086 ; 82545EM (Copper) +dd 0x10108086 ; 82546EB (Copper) +dd 0x10118086 ; 82545EM (Fiber) +dd 0x10128086 ; 82546EB (Fiber) +dd 0x10138086 ; 82541EI +dd 0x10148086 ; 82541ER +dd 0x10158086 ; 82540EM (LOM) +dd 0x10168086 ; 82540EP (Mobile) +dd 0x10178086 ; 82540EP +dd 0x10188086 ; 82541EI +dd 0x10198086 ; 82547EI +dd 0x101a8086 ; 82547EI (Mobile) +dd 0x101d8086 ; 82546EB +dd 0x101e8086 ; 82540EP (Mobile) +dd 0x10268086 ; 82545GM +dd 0x10278086 ; 82545GM +dd 0x10288086 ; 82545GM +dd 0x105b8086 ; 82546GB (Copper) +dd 0x10758086 ; 82547GI +dd 0x10768086 ; 82541GI +dd 0x10778086 ; 82541GI +dd 0x10788086 ; 82541ER +dd 0x10798086 ; 82546GB +dd 0x107a8086 ; 82546GB +dd 0x107b8086 ; 82546GB +dd 0x107c8086 ; 82541PI +dd 0x10b58086 ; 82546GB (Copper) +dd 0x11078086 ; 82544EI +dd 0x11128086 ; 82544GC +dd 0x0 + +db 'RHINE', 0 ; VIA Rhine +dd 0x30431106 +dd 0x61001106 +dd 0x30651106 +dd 0x31061106 +dd 0x30531106 +dd 0x0 + +dd 0x0 ; driverlist end \ No newline at end of file diff --git a/programs/network/netcfg/netcfg.asm b/programs/network/netcfg/netcfg.asm new file mode 100644 index 0000000000..6ae678e6e9 --- /dev/null +++ b/programs/network/netcfg/netcfg.asm @@ -0,0 +1,548 @@ +; +; Netcfg v1.02 +; +; Application to load network drivers in KolibriOS +; +; By hidnplayr +; + +format binary as "" + +use32 + org 0x0 + + db 'MENUET01' ; 8 byte id + dd 0x01 ; header version + dd START ; start of code + dd IM_END ; size of image + dd (I_END+0x100) ; memory for app + dd (I_END+0x100) ; esp + dd param, 0x0 ; I_Param , I_Icon + +type_ethernet equ 1 + +include '../macros.inc' + +START: + ; first, check boot parameters + + cmp byte[param], 0 + je .noparams + + mcall 40, 0 + + push .exit + cmp byte[param], 'A' ; A for All + je Get_PCI_Info + + cmp byte[param], 'F' ; F for First + je Get_PCI_Info + + ret + + .exit: + mcall -1 + + .noparams: + call draw_window + +still: + mcall 10 ; wait here for event + dec eax ; redraw request ? + jz red + dec eax ; key in buffer ? + jz key + dec eax ; button in buffer ? + jz button + jmp still + +red: ; redraw + mcall 9, Proc_Info, -1 ; window redraw requested so get new window coordinates and size + mov eax, [Proc_Info.box.left]; store the window coordinates into the Form Structure + mov [Form + 2], ax ; x start position + mov eax, [Proc_Info.box.top]; + mov [Form + 6], ax ; ystart position + mov eax, [Proc_Info.box.width] ; + mov [Form], ax ; window width + mov eax, [Proc_Info.box.height] ; + mov [Form + 4] ,ax ; window height + call draw_window ; go redraw window now + jmp still + +key: ; key + mcall 2 ; just read it and ignore + jmp still +button: ; button + mcall 17 ; get id + + cmp ah, 1 ; button id = 1 ? + jne @f +exit: mcall -1 ; close this program + @@: + cmp eax,0x0000ff00 + jg load_drv + + cmp ah, 4 + je hook + + cmp ah, 5 + je reset + + cmp ah, 6 + je unload + + jmp still + + +load_drv: + shr eax, 16 + mov word [selected], ax + + mov bl , 6 ; get a dword + mov bh , ah ; bus + mov ch , al ; dev + mov cl , 0 ; offset to device/vendor id + mcall 62 ; get ID's + + mov word [PCI_Vendor], ax + shr eax, 16 + mov word [PCI_Device], ax + call get_drv_ptr + + mov ecx, eax + mcall 68, 16 + + mov [IOCTL.handle], eax + + call draw_window + + cmp [IOCTL.handle], 0 + jne still + + mcall 4, 20 shl 16 + 30, 1 shl 31 + 0x00ff0000 , load_error + + jmp still + + +hook: + mov ax , [selected] + test ax , ax + jz still + + mov [hardwareinfo.pci_dev], al + mov [hardwareinfo.pci_bus], ah + + mov [IOCTL.io_code], 1 ; SRV_HOOK + mov [IOCTL.inp_size], 3 + mov [IOCTL.input], hardwareinfo + mov [IOCTL.out_size], 0 + mov [IOCTL.output], 0 + + mcall 68, 17, IOCTL + + mov byte[drivernumber], al + + jmp still + +reset: + movzx ebx, byte[drivernumber] + mcall 74,,2 + + jmp still + +unload: + movzx ebx, byte[drivernumber] + mcall 74,,3 + + jmp still + +draw_window: + mcall 12, 1 ; start of draw + mcall 0, dword [Form], dword [Form + 4], 0x13ffffff, 0x805080d0, title + + call Get_PCI_Info ; get pci version and last bus, scan for and draw each pci device + + cmp edx, 20 shl 16 + 110 + je .nonefound + + mcall 4, 20 shl 16 + 100, 1 shl 31 + 0x00000000 , caption + + cmp [selected], 0 + jz .done + cmp [IOCTL.handle] ,0 + jz .done + + mcall 8, 18 shl 16 + 100, 35 shl 16 + 18, 4, 0x00007f00 + mcall ,, 55 shl 16 + 18, 5, 0x0000007f + mcall ,, 75 shl 16 + 18, 6, 0x007f0000 + + mcall 4, 33 shl 16 + 42, 1 shl 31 + 0x00ffffff , btn_start + mcall , 33 shl 16 + 62, , btn_reset + mcall , 36 shl 16 + 82, , btn_stop + + jmp .done + + .nonefound: + mcall 4, 20 shl 16 + 30, 1 shl 31 + 0x00ff0000 , nonefound + .done: + mcall 12, 2 ; end of draw + ret + + + + + +;------------------------------------------------------------------ +;* Gets the PCI Version and Last Bus +Get_PCI_Info: + mcall 62, 0 + mov word [PCI_Version], ax + mcall 62, 1 + mov byte [PCI_LastBus], al + ;---------------------------------------------------------- + ;* Get all devices on PCI Bus + mov edx, 20 shl 16 + 110 ; set start write position + cmp al , 0xff ; 0xFF means no pci bus found + jne Pci_Exists ; + ret ; if no bus then leave +Pci_Exists: + mov byte [V_Bus], 0 ; reset varibles + mov byte [V_Dev], 0 ; +Start_Enum: + mov bl , 6 ; get a dword + mov bh , byte [V_Bus] ; bus of pci device + mov ch , byte [V_Dev] ; device number/function + mov cl , 0 ; offset to device/vendor id + mcall 62 ; get ID's + + cmp ax, 0 ; Vendor ID should not be 0 or 0xFFFF + je nextDev ; check next device if nothing exists here + cmp ax, 0xffff ; + je nextDev ; + + mov word [PCI_Vendor], ax ; There is a device here, save the ID's + shr eax, 16 ; + mov word [PCI_Device], ax ; + mov bl , 4 ; Read config byte + mov bh , byte [V_Bus] ; Bus # + mov ch , byte [V_Dev] ; Device # on bus + mov cl , 0x08 ; Register to read (Get Revision) + mcall 62 ; Read it + mov byte [PCI_Rev], al ; Save it + mov cl , 0x0b ; Register to read (Get class) + mcall 62 ; Read it + + mov byte [PCI_Class], al ; Save it + mov cl , 0x0a ; Register to read (Get Subclass) + mcall 62 ; Read it + mov byte [PCI_SubClass], al ; Save it + mov cl , 0x09 ; Register to read (Get Interface) + mcall 62 ; Read it + mov [PCI_Interface], al ; Save it + mov cl , 0x3c ; Register to read (Get IRQ) +@@: mcall 62 ; Read it + mov [PCI_IRQ], al ; Save it + +; cmp byte [PCI_Class], 0 ; device from before class codes +; je @f + + cmp byte [PCI_Class], 2 ; network controller + jne nextDev +; @@: + + cmp byte[param], 0 + jne load_and_start + + mov cl, 0x0e + mcall 62 + + push eax + call Print_New_Device ; print device info to screen + pop eax + test al, al + js nextDev + +nextdev2: + test byte [V_Dev], 7 + jnz nextDev + + or byte [V_Dev], 7 + +nextDev: + inc [V_Dev] ; lower 3 bits are the function number + + jnz Start_Enum ; jump until we reach zero + mov byte [V_Dev], 0 ; reset device number + inc byte [V_Bus] ; next bus + mov al , byte [PCI_LastBus] ; get last bus + cmp byte [V_Bus], al ; was it last bus + jbe Start_Enum ; if not jump to keep searching + ret + + + +load_and_start: + + call get_drv_ptr + cmp eax, lbl_none + je .next + + mov ecx, eax + mcall 68, 16 + test eax, eax + jz .next + mov [IOCTL.handle], eax + + mov al, [V_Dev] + mov [hardwareinfo.pci_dev], al + mov al, [V_Bus] + mov [hardwareinfo.pci_bus], al + + mov [IOCTL.io_code], 1 ; SRV_HOOK + mov [IOCTL.inp_size], 3 + mov [IOCTL.input], hardwareinfo + mov [IOCTL.out_size], 0 + mov [IOCTL.output], 0 + + mcall 68, 17, IOCTL + + .next: + cmp byte[param], 'A' + je nextdev2 + jmp exit + + + +;------------------------------------------------------------------ +;* Print device info to screen +Print_New_Device: + + push edx ; Magic ! (to print a button...) + + mov ebx, 18 shl 16 + mov bx , [Form] + sub bx , 36 + + mov cx , dx + dec cx + shl ecx, 16 + add ecx, 9 + + movzx edx, byte [V_Bus] + shl dx , 8 + mov dl , byte [V_Dev] + + mov esi, 0x0000c0ff ; color: yellow if selected, blue otherwise + cmp word [selected], dx + jne @f + mov esi, 0x00c0c000 + @@: + + shl edx, 8 + or dl , 0xff + + mcall 8 + pop edx + + xor esi, esi ; Color of text + movzx ecx, word [PCI_Vendor] ; number to be written + mcall 47, 0x00040100 ; Write Vendor ID + + add edx, (4*6+18) shl 16 + movzx ecx, word [PCI_Device] ; get Vendor ID + mcall ; Draw Vendor ID to Window + + add edx, (4*6+18) shl 16 + movzx ecx, byte [V_Bus] ; get bus number + mcall ,0x00020100 ; draw bus number to screen + + add edx, (2*6+18) shl 16 + movzx ecx, byte [V_Dev] ; get device number + shr ecx, 3 ; device number is bits 3-7 + mcall ; Draw device Number To Window + + add edx, (2*6+18) shl 16 + movzx ecx, byte [PCI_Rev] ; get revision number + mcall ; Draw Revision to screen + + add edx, (2*6+18) shl 16 + movzx ecx, [PCI_IRQ] + cmp cl , 0x0f ; IRQ must be between 0 and 15 + ja @f + mcall +@@: +; + ;Write Names + movzx ebx, dx ; Set y position + or ebx, 230 shl 16 ; set Xposition + +;------------------------------------------------------------------ +; Prints the Vendor's Name based on Vendor ID +;------------------------------------------------------------------ + mov edx, VendorsTab + mov cx , word[PCI_Vendor] + +.fn: mov ax , [edx] + add edx, 6 + test ax , ax + jz .find + cmp ax , cx + jne .fn +.find: mov edx, [edx - 4] + mcall 4,, 0x80000000 ; lets print the vendor Name + +;------------------------------------------------------------------ +; Get description based on Class/Subclass +;------------------------------------------------------------------ + mov eax, dword [PCI_Class] + and eax, 0xffffff + xor edx, edx + xor esi, esi +.fnc: inc esi + mov ecx, [Classes + esi * 8 - 8] + cmp cx , 0xffff + je .endfc + cmp cx , ax + jne .fnc + test ecx, 0xff000000 + jz @f + mov edx, [Classes + esi * 8 - 4] + jmp .fnc +@@: cmp eax, ecx + jne .fnc + xor edx, edx +.endfc: test edx, edx + jnz @f + mov edx, [Classes + esi * 8 - 4] +@@: + add ebx, 288 shl 16 + mcall 4,, 0x80000000,, 32 ; draw the text + movzx edx, bx ; get y coordinate + add edx, 0x0014000A ; add 10 to y coordinate and set x coordinate to 20 + +;------------------------------------------------------------------ +; Print Driver Name +;------------------------------------------------------------------ + push edx + add ebx, 120 shl 16 + push ebx + + call get_drv_ptr + mov edx, eax + pop ebx + mcall 4,,0x80000000 ; lets print the vendor Name + pop edx + ret + +get_drv_ptr: + mov eax, driverlist ; eax will be the pointer to latest driver title + mov ebx, driverlist ; ebx is the current pointer + mov ecx, dword[PCI_Vendor] ; the device/vendor id of we want to find + + driverloop: + inc ebx + + cmp byte[ebx],0 + jne driverloop + + inc ebx ; the device/vendor id list for the driver eax is pointing to starts here. + + deviceloop: + cmp dword[ebx],0 + je nextdriver + + cmp dword[ebx],ecx + je driverfound + + add ebx,4 + jmp deviceloop + + nextdriver: + add ebx,4 + + cmp dword[ebx],0 + je nodriver + + mov eax,ebx + jmp driverloop + + nodriver: + mov eax, lbl_none ; lets print the vendor Name + ret + + driverfound: + ret + +include 'vendors.inc' +include 'drivers.inc' + + +;------------------------------------------------------------------ +; DATA AREA + + +DATA + + +Form: dw 800 ; window width (no more, special for 800x600) + dw 100 ; window x start + dw 220 ; window height + dw 100 ; window y start + +title db 'Network Driver Control Center', 0 + +caption db 'Vendor Device Bus Dev Rev IRQ Company Description DRIVER',0 +nonefound db 'No compatible devices were found!',0 +btn_start db 'Start device',0 +btn_reset db 'Reset device',0 +btn_stop db 'Stop device',0 +lbl_none db 'none',0 +load_error db 'Could not load driver!',0 + +hardwareinfo: + .type db 1 ; pci + .pci_bus db ? + .pci_dev db ? + + +IM_END: + +;------------------------------------------------------------------ +; UNINITIALIZED DATA AREA + + +IOCTL: + .handle dd ? + .io_code dd ? + .input dd ? + .inp_size dd ? + .output dd ? + .out_size dd ? + +drivernumber db ? +MAC dp ? + + +type db ? +selected dw ? +V_Bus db ? +V_Dev db ? +PCI_Version dw ? +PCI_LastBus db ? +PCI_Vendor dw ? +PCI_Device dw ? +PCI_Bus db ? +PCI_Dev db ? +PCI_Rev db ? +; don`t change order!!! +PCI_Class db ? +PCI_SubClass db ? +PCI_Interface db ? +PCI_IRQ db ? + +Proc_Info process_information + +param rb 1024 + + +I_END: \ No newline at end of file diff --git a/programs/network/netcfg/vendors.inc b/programs/network/netcfg/vendors.inc new file mode 100644 index 0000000000..7acdb6d7d3 --- /dev/null +++ b/programs/network/netcfg/vendors.inc @@ -0,0 +1,1072 @@ +; AUTHOR: Victor Alberto Gil Hancco Laquita +; This list might content mistakes, plz report it +; There are 865 Lists of Vendors' Names +; Date: 8/14/2005 +; +; maybe this list is outdated... +; (the source was from 2004 list) + +; changed 11/05/2006: + 3 vendors and no more label 'PREVIOUSVERSIONLIST' +; so the total quantity of vendors is 875 now (changes by Sergey Kuzmin) + +; changed 16/08/2006: + 122 vendors +; so the total quantity of vendors is 987 now (changes by Sergey Kuzmin) + +; changed ??/04/2007: +; size optimezed +; total quantity of vendors is 997 now (changes by Mihailov Ilia) + + +macro VendorID a,b { ; by mike.dld + dw a + dd _vtmp#a + \iglobal + _vtmp#a db b + db 0 + \};endg +} + +macro ClassID a,b,c,d { + db a + db b + local tt + + if c eq + db 0 + db 1 + tt = 'x' + else + db c + db 0 + tt = c + end if + + dd _ctmp#a#b#tt + \iglobal + _ctmp#a#b#tt db d + db 0 + \};endg +} + +;-------------------------------------- +VendorsTab: +VendorID 0x0033, 'PARADYNE CORP.' +VendorID 0x003D, 'Lockheed Martin Corp' +VendorID 0x0100, 'NCIPHER CORP. LTD' +VendorID 0x0675, 'DYNALINK' +VendorID 0x0571, 'BERKOM' +VendorID 0x0A89, 'BREA TECHNOLOGIES INC' +VendorID 0x0E11, 'COMPAQ COMPUTER CORP.' +VendorID 0x1000, 'SYMBIOS LOGIC INC/LSI Logic' +VendorID 0x1001, 'KOLTER ELECTRONIC' +VendorID 0x1002, 'ATI TECHNOLOGIES INC' +VendorID 0x1003, 'ULSI' +VendorID 0x1004, 'VLSI TECHNOLOGY INC' +VendorID 0x1005, 'ADL' +VendorID 0x100B, 'NATIONAL SEMICONDUCTOR CORPORATION' +VendorID 0x100C, 'Tseng Labs' +VendorID 0x100E, 'Weitek' +VendorID 0x1010, 'VIDEO LOGIC LTD' +VendorID 0x1011, 'Digital Equipment Corporation' +VendorID 0x1013, 'Cirrus Logic' +VendorID 0x1014, 'IBM' +VendorID 0x1017, 'Spea Software AG' +VendorID 0x1018, 'UNISYS CORPORATION' +VendorID 0x1019, 'ELITEGROUP COMPUTER SYS' +VendorID 0x101A, 'NCR Corporation' +VendorID 0x101E, 'AMERICAN MEGATRENDS' +VendorID 0x1020, 'HITACHI COMPUTER PRODUCTS' +VendorID 0x1021, 'OKI ELECTRIC INDUSTRY CO. LTD.' +VendorID 0x1022, 'Advanced Micro Devices' +VendorID 0x1023, 'TRIDENT MICROSYSTEMS' +VendorID 0x1025, 'Acer Incorporated' +VendorID 0x1028, 'DELL COMPUTER CORPORATION' +VendorID 0x102A, 'LSI LOGIC CORPORATION' +VendorID 0x102B, 'MATROX GRAPHICS' +VendorID 0x102C, 'Asiliant (Chips And Technologies)' +VendorID 0x102D, 'Wyse Technologies' +VendorID 0x102F, 'TOSHIBA AMERICA' +VendorID 0x1031, 'miro Computer Products AG' +VendorID 0x1033, 'NEC CORPORATION' +VendorID 0x1036, 'Future Domain' +VendorID 0x1038, 'AMP' +VendorID 0x1039, 'SILICON INTEGRATED SYSTEMS' +VendorID 0x103C, 'Hewlett-Packard Company' +VendorID 0x103F, 'SYNOPSYS/LOGIC MODELING GROUP' +VendorID 0x1042, 'Micron Electronics' +VendorID 0x1043, 'ASUSTEK COMPUTER' +VendorID 0x1044, 'DISTRIBUTED PROCESSING TECHNOLOGY' +VendorID 0x1045, 'OPTI INC.' +VendorID 0x1048, 'ELSA AG' +VendorID 0x1049, 'FOUNTAIN TECHNOLOGIES' +VendorID 0x104A, 'STMicroelectronics' +VendorID 0x104B, 'BusLogic' +VendorID 0x104C, 'TEXAS INSTRUMENTS' +VendorID 0x104D, 'SONY CORPORATION' +VendorID 0x104E, 'Oak Technology' +VendorID 0x104F, 'Co-Time Computer Ltd.' +VendorID 0x1050, 'WINBOND ELECTRONICS CORP' +VendorID 0x1051, 'Anigma Corp.' +VendorID 0x1054, 'HITACHI' +VendorID 0x1055, 'Standard Microsystems Corp.' +VendorID 0x1057, 'Motorola' +VendorID 0x1058, 'ETRI' +VendorID 0x1059, 'TEKNOR INDUSTRIAL COMPUTERS INC' +VendorID 0x105A, 'PROMISE TECHNOLOGY' +VendorID 0x105B, 'FOXCONN INTERNATIONAL INC' +VendorID 0x105D, 'NUMBER 9 VISUAL TECHNOLOGY' +VendorID 0x105F, 'INFOTRONIC AMERICA INC' +VendorID 0x1060, 'United Microelectronics' +VendorID 0x1061, '8x8 Inc.' +VendorID 0x1063, 'OCEAN MANUFACTURING LTD' +VendorID 0x1064, 'ALCATEL' +VendorID 0x1065, 'Texas Microsystems' +VendorID 0x1066, 'Picopower Technology' +VendorID 0x1067, 'MITSUBISHI ELECTRIC AMERICA' +VendorID 0x1068, 'DIVERSIFIED TECHNOLOGY' +VendorID 0x1069, 'MYLEX CORPORATION' +VendorID 0x106B, 'APPLE COMPUTER INC.' +VendorID 0x106C, 'Hyundai Electronics America' +VendorID 0x106D, 'SEQUENT COMPUTER SYSTEMS' +VendorID 0x1070, 'DAEWOO TELECOM LTD' +VendorID 0x1071, 'MITAC' +VendorID 0x1073, 'YAMAHA CORPORATION' +VendorID 0x1074, 'Nexgen Microsystems' +VendorID 0x1076, 'Chaintech Comp.' +VendorID 0x1077, 'QLOGIC Corporation' +VendorID 0x1078, 'Cyrix Corporation' +VendorID 0x1079, 'I-BUS' +VendorID 0x107B, 'GATEWAY 2000' +VendorID 0x107D, 'Leadtek Research' +VendorID 0x107E, 'INTERPHASE CORPORATION' +VendorID 0x107F, 'Data Technology Corporation' +VendorID 0x1080, 'Cypress Semiconductor' +VendorID 0x1081, 'Radius Inc.' +VendorID 0x1083, 'Forex Computer Corporation' +VendorID 0x1085, 'Tulip Computers International BV' +VendorID 0x1087, 'Cache Computer' +VendorID 0x108A, 'SBS Operations' +VendorID 0x108D, 'OLICOM' +VendorID 0x108E, 'Sun Microsystems' +VendorID 0x1091, 'Intergraph Corporation' +VendorID 0x1092, 'Diamond Computer Systems' +VendorID 0x1093, 'National Instruments' +VendorID 0x1095, 'SILICON IMAGE (WAS CMD TECHNOLOGY INC)' +VendorID 0x1096, 'ALACRON' +VendorID 0x1097, 'APPIAN Graphics/ETMA' +VendorID 0x1098, 'Quantum Designs Ltd.' +VendorID 0x109A, 'PACKARD BELL NEC' +VendorID 0x109E, 'BROOKTREE CORPORATION' +VendorID 0x109F, 'TRIGEM COMPUTER INC.' +VendorID 0x10A0, 'MEIDENSHA CORPORATION' +VendorID 0x10A2, 'QUANTUM EFFECT DESIGN' +VendorID 0x10A4, 'Globe Manufacturing Sales' +VendorID 0x10A8, 'Sierra Semiconductor' +VendorID 0x10A9, 'SILICON GRAPHICS' +VendorID 0x10AC, 'HONEYWELL IAC' +VendorID 0x10AD, 'Winbond Systems Labs' +VendorID 0x10AF, 'MICRO COMPUTER SYSTEMS INC' +VendorID 0x10B5, 'PLX TECHNOLOGY.' +VendorID 0x10B6, 'MADGE NETWORKS' +VendorID 0x10B7, '3COM Corp, Networking Division' +VendorID 0x10B8, 'Standard Microsystems Corporation' +VendorID 0x10B9, 'ACER LABS Incorp.' +VendorID 0x10BA, 'MITSUBISHI ELECTRIC CORP.' +VendorID 0x10BD, 'Surecom Technology' +VendorID 0x10C2, 'AUSPEX SYSTEMS INC.' +VendorID 0x10C3, 'Samsung Semiconductors' +VendorID 0x10C4, 'Award Software International Inc.' +VendorID 0x10C8, 'NEOMAGIC CORPORATION' +VendorID 0x10CA, 'FUJITSU MICROELECTRONIC' +VendorID 0x10CB, 'OMRON CORPORATION' +VendorID 0x10CD, 'ADVANCED SYSTEM PRODUCTS' +VendorID 0x10CF, 'FUJITSU LIMITED' +VendorID 0x10D1, 'FUTUREPLUS SYSTEMS CORP.' +VendorID 0x10D2, 'MOLEX INCORPORATED' +VendorID 0x10D9, 'Macronix International Co. Ltd.' +VendorID 0x10DB, 'ROHM LSI SYSTEMS' +VendorID 0x10DC, 'CERN-European Lab. for Particle Physics' +VendorID 0x10DD, 'EVANS & SUTHERLAND' +VendorID 0x10DE, 'NVIDIA CORPORATION' +VendorID 0x10DF, 'EMULEX CORPORATION' +VendorID 0x10E1, 'TEKRAM TECHNOLOGY CO.LTD.' +VendorID 0x10E3, 'TUNDRA SEMICONDUCTOR CORP' +VendorID 0x10E5, 'MICRO INDUSTRIES CORPORATION' +VendorID 0x10E8, 'Applied Micro Circuits Corp.' +VendorID 0x10EA, 'Tvia, Inc.' +VendorID 0x10EB, 'Artist Graphics' +VendorID 0x10EC, 'REALTEK SEMICONDUCTOR CORP.' +VendorID 0x10ED, 'Ascii Corporation' +VendorID 0x10EE, 'XILINX' +VendorID 0x10EF, 'Racore Computer Products' +VendorID 0x10F0, 'Curtiss-Wright Controls Embedded Computing' +VendorID 0x10F1, 'TYAN COMPUTER' +VendorID 0x10F4, 'S-Mos Systems' +VendorID 0x10F5, 'NKK CORPORATION' +VendorID 0x10F6, 'Creative Electronic Systems SA' +VendorID 0x10FA, 'Truevision' +VendorID 0x10FB, 'Thesys Microelectronics' +VendorID 0x10FC, 'I-O DATA DEVICE' +VendorID 0x10FE, 'FAST MULTIMEDIA AG' +VendorID 0x1101, 'INITIO CORPORATION' +VendorID 0x1102, 'Creative Labs' +VendorID 0x1105, 'SIGMA DESIGNS' +VendorID 0x1106, 'VIA TECHNOLOGIES' +VendorID 0x1107, 'ASCEND COMMUNICATIONS/Stratus Computer' +VendorID 0x1108, 'Proteon Inc.' +VendorID 0x1109, 'Adaptec/Cogent Data Technologies Inc' +VendorID 0x110A, 'SIEMENS PC SYSTEME GMBH' +VendorID 0x110B, 'Chromatic Research Inc' +VendorID 0x1111, 'SANTA CRUZ OPERATION' +VendorID 0x1112, 'Osicom Technologies Inc.' +VendorID 0x1113, 'ACCTON TECHNOLOGY' +VendorID 0x1114, 'Atmel Corp.' +VendorID 0x1116, 'Media 100, Inc.' +VendorID 0x1117, 'Datacube Inc.' +VendorID 0x1118, 'FCI ELECTRONICS' +VendorID 0x1119, 'ICP-VORTEX COMPUTERSYSTEM GMBH' +VendorID 0x111A, 'EFFICIENT NETWORKS' +VendorID 0x111C, 'Tricord Systems Inc.' +VendorID 0x111D, 'INTEGRATED DEVICE TECH' +VendorID 0x111F, 'Precision Digital Images' +VendorID 0x1120, 'EMC CORPORATION' +VendorID 0x1127, 'FORE SYSTEMS INC' +VendorID 0x112A, 'HERMES ELECTRONICS COMPANY' +VendorID 0x112E, 'Infomedia' +VendorID 0x112F, 'IMAGING TECHNOLOGY' +VendorID 0x1131, 'PHILIPS SEMICONDUCTORS' +VendorID 0x1132, 'MITEL CORP' +VendorID 0x1133, 'Eicon Networks Corporation' +VendorID 0x1134, 'MERCURY COMPUTER SYSTEMS' +VendorID 0x1135, 'FUJI XEROX CO LTD' +VendorID 0x1136, 'MOMENTUM DATA SYSTEMS' +VendorID 0x1137, 'CISCO SYSTEMS INC' +VendorID 0x1138, 'ZIATECH CORPORATION' +VendorID 0x113C, 'CYCLONE MICROSYSTEMS.' +VendorID 0x113E, 'SANYO ELECTRIC CO-Information Systems Division' +VendorID 0x113F, 'Equinox Systems' +VendorID 0x1141, 'CREST MICROSYSTEM INC.' +VendorID 0x1142, 'Alliance Semiconductor CA - USA' +VendorID 0x1144, 'Cincinnati Milacron' +VendorID 0x1145, 'WORKBIT CORPORATION' +VendorID 0x1146, 'FORCE COMPUTERS GMBH' +VendorID 0x1147, 'Interface Corp' +VendorID 0x1148, 'SYSKONNECT/Marvell' +VendorID 0x114A, 'VMIC' +VendorID 0x114C, 'ANNABOOKS' +VendorID 0x114F, 'DIGI INTERNATIONAL' +VendorID 0x1154, 'MELCO INC' +VendorID 0x1155, 'Pine Technology Ltd' +VendorID 0x1158, 'Voarx R&D Inc' +VendorID 0x1159, 'Mutech' +VendorID 0x115C, 'PHOTRON LTD.' +VendorID 0x115D, 'XIRCOM' +VendorID 0x1161, 'PFU LIMITED' +VendorID 0x1163, 'RENDITION' +VendorID 0x1165, 'Imagraph Corporation' +VendorID 0x1166, 'Reliance Computer Corp./ServerWorks' +VendorID 0x1169, 'Centre f/Dev. of Adv. Computing' +VendorID 0x116A, 'Polaris Communications' +VendorID 0x116E, 'ELECTRONICS FOR IMAGING' +VendorID 0x1170, 'INVENTEC CORPORATION' +VendorID 0x1171, 'BLUE WAVE SYSTEMS' +VendorID 0x1172, 'ALTERA CORPORATION' +VendorID 0x1176, 'SBE' +VendorID 0x1178, 'Alfa Inc' +VendorID 0x1179, 'TOSHIBA AMERICA INFO SYSTEMS' +VendorID 0x117B, 'GCE-8320B' +VendorID 0x117E, 'T/R Systems' +VendorID 0x1180, 'RICOH CO LTD' +VendorID 0x1185, 'Dataworld' +VendorID 0x1186, 'D-LINK SYSTEM INC' +VendorID 0x1187, 'ADVANCED TECHNOLOGY LABORATORIES' +VendorID 0x1189, 'MATSUSHITA ELECTIC INDUSTRIAL CO LTD' +VendorID 0x118B, 'PLATYPUS TECHNOLOGY PTY LTD' +VendorID 0x118C, 'Corollary Inc' +VendorID 0x118D, 'BitFlow Inc' +VendorID 0x118E, 'Hermstedt AG' +VendorID 0x1190, 'Tripace' +VendorID 0x1191, 'ACARD TECHNOLOGY' +VendorID 0x1193, 'ZeitNet' +VendorID 0x1195, 'RATOC SYSTEMS INC' +VendorID 0x1197, 'Gage Applied Technologies' +VendorID 0x1199, 'Attachmate Corp.' +VendorID 0x119A, 'MINDSHARE.' +VendorID 0x119B, 'Omega Micro Inc.' +VendorID 0x119D, 'BUG.' +VendorID 0x119E, 'FUJITSU MICROELECTRONICS LTD.' +VendorID 0x119F, 'BULL HN INFORMATION SYSTEMS' +VendorID 0x11A1, 'HAMAMATSU PHOTONICS K.K.' +VendorID 0x11A8, 'Systech Corp.' +VendorID 0x11A9, 'InnoSys Inc.' +VendorID 0x11AA, 'ACTEL' +VendorID 0x11AB, 'GALILEO TECHNOLOGY LTD/Marvell Semiconductor, Inc.' +VendorID 0x11AD, 'LITE-ON COMMUNICATIONS INC' +VendorID 0x11AE, 'SCITEX CORPORATION' +VendorID 0x11AF, 'AVID TECHNOLOGY INC' +VendorID 0x11B0, 'V3 SEMICONDUCTOR INC./Quicklogic Corp' +VendorID 0x11B2, 'EASTMAN KODAK' +VendorID 0x11B3, 'BARR SYSTEMS INC.' +VendorID 0x11B5, 'Radstone Technology Ltd.' +VendorID 0x11B8, 'Xpoint Technologies Inc' +VendorID 0x11B9, 'Pathlight Technology Inc.' +VendorID 0x11BC, 'Network Peripherals Inc' +VendorID 0x11BD, 'Pinnacle Systems Inc.' +VendorID 0x11BF, 'ASTRODESIGN' +VendorID 0x11C1, 'AGERE/LUCENT' +VendorID 0x11C6, 'DAINIPPON SCREEN MFG. CO. LTD' +VendorID 0x11C8, 'DOLPHIN INTERCONNECT SOLUTIONS AS' +VendorID 0x11C9, 'MAGMA' +VendorID 0x11CA, 'LSI SYSTEMS' +VendorID 0x11CB, 'SPECIALIX INTERNATIONAL LTD' +VendorID 0x11CE, 'NETACCESS/Primary Rate Inc' +VendorID 0x11D0, 'LOCKHEED MARTIN-Electronics & Communications' +VendorID 0x11D1, 'AuraVision Corporation' +VendorID 0x11D2, 'INTERCOM INC.' +VendorID 0x11D4, 'Analog Devices, Inc.' +VendorID 0x11D5, 'IKON CORPORATION/Tahoma Technology' +VendorID 0x11D9, 'TOSHIBA TEC CORPORATION' +VendorID 0x11DA, 'NOVELL' +VendorID 0x11DB, 'Sega Enterprises Ltd' +VendorID 0x11DE, 'Zoran Corporation' +VendorID 0x11DF, 'NEW WAVE PDG' +VendorID 0x11E3, 'QUICKLOGIC CORPORATION' +VendorID 0x11EC, 'CORECO INC' +VendorID 0x11EE, 'DOME IMAGING SYSTEMS INC' +VendorID 0x11F0, 'Compu-Shack GmbH' +VendorID 0x11F4, 'Kinetic Systems Corporation' +VendorID 0x11F6, 'Powermatic Data Systems Ltd' +VendorID 0x11F8, 'PMC-SIERRA INC' +VendorID 0x11FE, 'Comtrol Corp' +VendorID 0x1202, 'Network General Corp' +VendorID 0x1203, 'AGFA CORPORATION' +VendorID 0x1206, 'AMDAHL CORPORATION' +VendorID 0x1208, 'Parsytec GmbH' +VendorID 0x1209, 'Sci Systems Inc' +VendorID 0x120E, 'Cyclades Corporation' +VendorID 0x120F, 'ESSENTIAL COMMUNICATIONS' +VendorID 0x1214, 'PERFORMANCE TECHNOLOGIES.' +VendorID 0x1216, 'PURUP-EskoFot A/S' +VendorID 0x1217, 'O2MICRO.' +VendorID 0x121A, '3DFX INTERACTIVE' +VendorID 0x121B, 'VIRATA LTD' +VendorID 0x1220, 'Ariel Corporation' +VendorID 0x1221, 'CONTEC CO. LTD' +VendorID 0x1223, 'ARTESYN COMMUNICATIONS PRODUCTS INC' +VendorID 0x1224, 'Interactive Images' +VendorID 0x1227, 'TECH-SOURCE' +VendorID 0x122C, 'SICAN GMBH' +VendorID 0x122D, 'Aztech System Ltd' +VendorID 0x1232, 'MARCONI COMMUNICATIONS LTD' +VendorID 0x1236, 'Sigma Designs, Inc' +VendorID 0x124C, 'Solitron Technologies Inc.' +VendorID 0x124D, 'Stallion Technologies' +VendorID 0x124F, 'Infortrend Technology Inc' +VendorID 0x1256, 'Perceptive Solutions Inc.' +VendorID 0x1258, 'Gilbarco Inc.' +VendorID 0x125B, 'Asix Electronics Corp.' +VendorID 0x1266, 'Microdyne Corp.' +VendorID 0x1267, 'S.A. Telecommunications' +VendorID 0x1361, 'SOLITON SYSTEMS K.K.' +VendorID 0x123C, 'CENTURY SYSTEMS.' +VendorID 0x123D, 'Engineering Design Team Inc.' +VendorID 0x123F, 'C-CUBE MICROSYSTEMS' +VendorID 0x1242, 'JAYCOR NETWORKS INC./JNI Corporation' +VendorID 0x1244, 'AVM AUDIOVISUELLES MKTG & COMPUTER SYSTEM GMBH' +VendorID 0x124B, 'SBS TECHNOLOGIES' +VendorID 0x1250, 'Hitachi Microcomputer System Ltd.' +VendorID 0x1253, 'GUZIK TECHNICAL ENTERPRISES' +VendorID 0x1255, 'OPTIBASE LTD' +VendorID 0x1259, 'ALLIED TELESYN INTERNATIONAL' +VendorID 0x125C, 'AURORA TECHNOLOGIES.' +VendorID 0x125D, 'ESS TECHNOLOGY, INC.' +VendorID 0x125F, 'CONCURRENT TECHNOLOGIES' +VendorID 0x1260, 'INTERSIL CORP' +VendorID 0x1261, 'MATSUSHITA-KOTOBUKI ELECTRONICS' +VendorID 0x1264, 'AVAL NAGASAKI CORPORATION' +VendorID 0x1268, 'TEKTRONIX' +VendorID 0x126C, 'Nortel Networks Corp.' +VendorID 0x126D, 'SPLASH TECHNOLOGY.' +VendorID 0x126E, 'SUMITOMO METAL INDUSTRIES' +VendorID 0x126F, 'SILICON MOTION.' +VendorID 0x1270, 'OLYMPUS OPTICAL CO. LTD.' +VendorID 0x1274, 'Creative Labs (was Ensoniq, Malvern)' +VendorID 0x1275, 'NETWORK APPLIANCE CORPORATION' +VendorID 0x1278, 'Transtech Parallel Systems' +VendorID 0x1279, 'TRANSMETA CORPORATION' +VendorID 0x127A, 'CONEXANT, ROCKWELL' +VendorID 0x127D, 'VELA RESEARCH LP' +VendorID 0x127F, 'FUJIFILM' +VendorID 0x1281, 'YOKOGAWA ELECTRIC CORPORATION' +VendorID 0x1283, 'Integrated Technology Express Inc.' +VendorID 0x1286, 'MAZET GMBH' +VendorID 0x128B, 'TRANSWITCH CORPORATION' +VendorID 0x128D, 'G2 Networks Inc.' +VendorID 0x128F, 'TATENO DENNOU.' +VendorID 0x1290, 'TOSHIBA PERSONAL COMPUTER SYSTEM CORP.' +VendorID 0x1291, 'NCS COMPUTER ITALIA SRL' +VendorID 0x1292, 'TRITECH MICROELECTRONICS INC' +VendorID 0x1297, 'SHUTTLE COMPUTER' +VendorID 0x1299, 'KNOWLEDGE TECHNOLOGY LAB.' +VendorID 0x129A, 'VMETRO Inc.' +VendorID 0x129E, 'VICTOR COMPANY OF JAPAN' +VendorID 0x12A0, 'ALLEN- BRADLEY COMPANY' +VendorID 0x12A3, 'Lucent Technologies AMR' +VendorID 0x12A7, 'AMO GMBH' +VendorID 0x12A9, 'XIOTECH CORPORATION' +VendorID 0x12AB, 'YUAN YUAN ENTERPRISE CO. LTD.' +VendorID 0x12AE, 'Alteon Networks Inc.' +VendorID 0x12B6, 'NATURAL MICROSYSTEMS' +VendorID 0x12B7, 'COGNEX MODULAR VISION SYSTEMS DIV.-ACUMEN INC.' +VendorID 0x12B9, '3Com Corp, Modem Division' +VendorID 0x12BC, 'ARRAY MICROSYSTEMS' +VendorID 0x12BE, 'ANCHOR CHIPS INC.' +VendorID 0x12BF, 'Fujifilm Microdevices' +VendorID 0x12C0, 'INFIMED' +VendorID 0x12C3, 'Holtek Microelectronics Inc.' +VendorID 0x12C4, 'Connect Tech Inc' +VendorID 0x12C6, 'Mitan Corporation' +VendorID 0x12C7, 'Dialogic Corp' +VendorID 0x12CA, 'Integrated Computing Engines' +VendorID 0x12CD, 'Aims Lab' +VendorID 0x12D2, 'NVIDIA (WAS: STB,SGS THOMPSON)' +VendorID 0x12D3, 'GE VINGMED ULTRASOUND AS' +VendorID 0x12D4, 'COMVERSE NETWORKS SYSTEM & Ulticom, Inc.' +VendorID 0x12D5, 'Equator Technologies' +VendorID 0x12D6, 'Analogic Corp' +VendorID 0x12D8, 'PERICOM SEMICONDUCTOR' +VendorID 0x12D9, 'Aculab PLC' +VendorID 0x12DA, 'True Time Inc.' +VendorID 0x12DE, 'Rainbow Technologies' +VendorID 0x12DF, 'SBS Technologies Inc' +VendorID 0x12E0, 'Chase Research PLC' +VendorID 0x12E2, 'Datum Inc. Bancomm-Timing Division' +VendorID 0x12E4, 'Brooktrout Technology Inc' +VendorID 0x12E7, 'Sebring Systems' +VendorID 0x12EA, 'Real Vision' +VendorID 0x12EB, 'Aureal Semiconductor' +VendorID 0x12EC, '3A' +VendorID 0x12F0, 'PENTEK' +VendorID 0x12F7, 'COGNEX INC.' +VendorID 0x12FB, 'Spectrum Signal Processing' +VendorID 0x12FC, 'CAPITAL EQUIPMENT CORP' +VendorID 0x12FE, 'ESD Electronic System Design GmbH' +VendorID 0x1304, 'Juniper Networks Inc.' +VendorID 0x1307, 'Computer Boards' +VendorID 0x1308, 'LEVEL ONE COMMUNICATIONS/Jato Technologies Inc.' +VendorID 0x130A, 'Mitsubishi Electric MicroComputer' +VendorID 0x130B, 'Colorgraphic Communications Corp' +VendorID 0x130F, 'Advanet Inc' +VendorID 0x1310, 'GESPAC' +VendorID 0x1313, 'YASKAWA ELECTRIC CO.' +VendorID 0x1316, 'TERADYNE INC.' +VendorID 0x1317, 'ADMTEK INC' +VendorID 0x1318, 'Packet Engines Inc.' +VendorID 0x1319, 'ForteMedia' +VendorID 0x131F, 'SIIG Inc' +VendorID 0x1325, 'SALIX TECHNOLOGIES INC' +VendorID 0x1326, 'SeaChange International' +VendorID 0x1331, 'RadiSys Corp.' +VendorID 0x133D, 'PRISA NETWORKS' +VendorID 0x133F, 'SCM MICROSYSTEMS' +VendorID 0x1342, 'PROMAX SYSTEMS INC' +VendorID 0x1344, 'MICRON TECHNOLOGY INC' +VendorID 0x134A, 'Domex' +VendorID 0x134B, 'ARK RESEARCH CORP.' +VendorID 0x134C, 'CHORI JOHO SYSTEM CO. LTD' +VendorID 0x134D, 'PC-TEL INC' +VendorID 0x135A, 'BRAIN BOXES LIMITED' +VendorID 0x135C, 'QUATECH INC' +VendorID 0x135E, 'SEALEVEL SYSTEMS INC' +VendorID 0x135F, 'I-DATA INTERNATIONAL A-S' +VendorID 0x1360, 'MEINBERG FUNKUHREN' +VendorID 0x1363, 'PHOENIX TECHNOLOGIES LTD' +VendorID 0x1365, 'HYPERCOPE' +VendorID 0x1367, 'HITACHI ZOSEN CORPORATION' +VendorID 0x1368, 'SKYWARE CORPORATION' +VendorID 0x1369, 'DIGIGRAM' +VendorID 0x136B, 'KAWASAKI STEEL CORPORATION' +VendorID 0x136C, 'ADTEK SYSTEM SCIENCE CO LTD' +VendorID 0x1375, 'BOEING-SUNNYVALE' +VendorID 0x1376, 'LAN Media Corporation' +VendorID 0x1377, 'ELECTRONIC EQUIPMENT PRODUCTION & DISTRIBUTION' +VendorID 0x137A, 'MARK OF THE UNICORN INC' +VendorID 0x137B, 'PPT VISION' +VendorID 0x137C, 'IWATSU ELECTRIC CO LTD' +VendorID 0x137D, 'DYNACHIP CORPORATION' +VendorID 0x1380, 'SANRITZ AUTOMATION CO LTC' +VendorID 0x1381, 'BRAINS CO. LTD' +VendorID 0x1383, 'CONTROLNET INC' +VendorID 0x1384, 'STELLAR SEMICONDUCTOR INC' +VendorID 0x1385, 'NETGEAR' +VendorID 0x1387, 'SYSTRAN CORP' +VendorID 0x1388, 'HITACHI INFORMATION TECHNOLOGY CO LTD' +VendorID 0x1389, 'APPLICOM INTERNATIONAL' +VendorID 0x138A, 'SITERA' +VendorID 0x138B, 'TOKIMEC INC' +VendorID 0x138E, 'BASLER GMBH' +VendorID 0x138F, 'PATAPSCO DESIGNS INC' +VendorID 0x1393, 'MOXA TECHNOLOGIES CO LTD' +VendorID 0x1394, 'LEVEL ONE COMMUNICATIONS' +VendorID 0x1395, 'AMBICOM INC' +VendorID 0x1396, 'CIPHER SYSTEMS INC' +VendorID 0x1397, 'COLOGNE CHIP DESIGNS GMBH' +VendorID 0x1398, 'CLARION CO. LTD' +VendorID 0x1399, 'RIOS SYSTEMS CO LTD' +VendorID 0x139A, 'ALACRITECH INC' +VendorID 0x139C, 'QUANTUM 3D INC' +VendorID 0x139D, 'XSTREAMS PLC/ EPL LIMITED' +VendorID 0x139E, 'ECHOSTAR DATA NETWORKS' +VendorID 0x139F, 'AETHRA S.R.L.' +VendorID 0x13A0, 'CRYSTAL GROUP INC' +VendorID 0x13A1, 'KAWASAKI HEAVY INDUSTRIES LTD' +VendorID 0x13A2, 'OSITECH COMMUNICATIONS INC' +VendorID 0x13A4, 'RASCOM INC' +VendorID 0x13A7, 'TELES AG' +VendorID 0x13A8, 'EXAR CORP.' +VendorID 0x13A9, 'SIEMENS MEDICAL SYSTEMS' +VendorID 0x13AA, 'NORTEL NETWORKS-BWA DIVISION' +VendorID 0x13AF, 'T.SQWARE' +VendorID 0x13B1, 'TAMURA CORPORATION' +VendorID 0x13B4, 'WELLBEAN CO INC' +VendorID 0x13B5, 'ARM Ltd' +VendorID 0x13B6, 'DLoG GMBH' +VendorID 0x13B8, 'NOKIA TELECOMMUNICATIONS OY' +VendorID 0x13BD, 'SHARP CORPORATION' +VendorID 0x13BF, 'SHAREWAVE INC' +VendorID 0x13C0, 'Microgate Corp.' +VendorID 0x13C1, '3ware Inc.' +VendorID 0x13C2, 'TECHNOTREND SYSTEMTECHNIK GMBH' +VendorID 0x13C3, 'JANZ COMPUTER AG' +VendorID 0x13C6, 'CONDOR ENGINEERING INC' +VendorID 0x13C7, 'BLUE CHIP TECHNOLOGY LTD' +VendorID 0x13CA, 'IOMEGA CORPORATION' +VendorID 0x13CC, 'METHEUS CORPORATION' +VendorID 0x13CF, 'STUDIO AUDIO & VIDEO LTD' +VendorID 0x13D0, 'B2C2' +VendorID 0x13D1, 'ABOCOM SYSTEMS' +VendorID 0x13D2, 'SHARK MULTIMEDIA INC' +VendorID 0x13D3, 'IMC NETWORKS' +VendorID 0x13D4, 'GRAPHICS MICROSYSTEMS INC' +VendorID 0x13D6, 'K.I. TECHNOLOGY CO LTD' +VendorID 0x13D7, 'TOSHIBA ENGINEERING CORPORATION' +VendorID 0x13D8, 'PHOBOS CORPORATION' +VendorID 0x13D9, 'APEX INC' +VendorID 0x13DC, 'NETBOOST CORPORATION' +VendorID 0x13DE, 'ABB ROBOTICS PRODUCTS' +VendorID 0x13DF, 'E-TECH INC' +VendorID 0x13E0, 'GVC CORPORATION' +VendorID 0x13E3, 'NEST INC' +VendorID 0x13E4, 'CALCULEX INC' +VendorID 0x13E5, 'TELESOFT DESIGN LTD' +VendorID 0x13E9, 'INTRASERVER TECHNOLOGY INC' +VendorID 0x13EA, 'DALLAS SEMICONDUCTOR' +VendorID 0x13F0, 'SUNDANCE TECHNOLOGY INC' +VendorID 0x13F1, 'OCE-TECHNOLOGIES B.V.' +VendorID 0x13F2, 'FORD MICROELECTRONICS INC' +VendorID 0x13F4, 'TROIKA NETWORKS INC' +VendorID 0x13F6, 'C-MEDIA ELECTRONICS INC' +VendorID 0x13F9, 'NTT ADVANCED TECHNOLOGY CORP.' +VendorID 0x13FB, 'AYDIN CORP' +VendorID 0x13FD, 'MICRO SCIENCE INC' +VendorID 0x1400, 'ARTX INC' +VendorID 0x1402, 'Meilhaus Electronic GmbH Germany' +VendorID 0x1404, 'FUNDAMENTAL SOFTWARE INC' +VendorID 0x1406, 'OCE PRINTING SYSTEMS GmbH' +VendorID 0x1407, 'LAVA COMPUTER MFG INC' +VendorID 0x1408, 'ALOKA CO. LTD' +VendorID 0x140A, 'DSP RESEARCH INC' +VendorID 0x140B, 'RAMIX INC' +VendorID 0x140D, 'MATSUSHITA ELECTRIC WORKS LTD' +VendorID 0x1412, 'ICEnsemble' +VendorID 0x1413, 'ADDONICS' +VendorID 0x1415, 'OXFORD SEMICONDUCTOR LTD' +VendorID 0x1418, 'KYUSHU ELECTRONICS SYSTEMS INC' +VendorID 0x1419, 'EXCEL SWITCHING CORP' +VendorID 0x141B, 'ZOOM TELEPHONICS INC' +VendorID 0x141E, 'FANUC LTD' +VendorID 0x1420, 'PSION DACOM PLC' +VendorID 0x1428, 'EDEC CO LTD' +VendorID 0x1429, 'UNEX TECHNOLOGY CORP' +VendorID 0x142A, 'KINGMAX TECHNOLOGY INC' +VendorID 0x142B, 'RADIOLAN' +VendorID 0x142C, 'MINTON OPTIC INDUSTRY CO LTD' +VendorID 0x142D, 'PIXSTREAM INC' +VendorID 0x1430, 'ITT AEROSPACE/COMMUNICATIONS DIVISION' +VendorID 0x1433, 'ELTEC ELEKTRONIK GMBH' +VendorID 0x1436, 'CIS TECHNOLOGY INC' +VendorID 0x1437, 'NISSIN INC CO' +VendorID 0x1438, 'ATMEL-DREAM' +VendorID 0x143F, 'LIGHTWELL CO LTD-ZAX DIVISION' +VendorID 0x1441, 'AGIE SA' +VendorID 0x1445, 'LOGICAL CO LTD' +VendorID 0x1446, 'GRAPHIN CO. LTD' +VendorID 0x1447, 'AIM GMBH' +VendorID 0x144A, 'ADLINK Technology Inc' +VendorID 0x144B, 'LORONIX INFORMATION SYSTEMS INC' +VendorID 0x144D, 'SAMSUNG ELECTRONICS CO LTD' +VendorID 0x1450, 'OCTAVE COMMUNICATIONS IND.' +VendorID 0x1451, 'SP3D CHIP DESIGN GMBH' +VendorID 0x1453, 'MYCOM INC' +VendorID 0x1455, 'LOGIC PLUS PLUS INC' +VendorID 0x1458, 'GIGA-BYTE TECHNOLOGY' +VendorID 0x145C, 'CRYPTEK' +VendorID 0x145F, 'BALDOR ELECTRIC COMPANY' +VendorID 0x1460, 'DYNARC INC' +VendorID 0x1461, 'AVERMEDIA Tech.' +VendorID 0x1462, 'MICRO-STAR INTERNATIONAL CO LTD' +VendorID 0x1463, 'FAST CORPORATION' +VendorID 0x1464, 'INTERACTIVE CIRCUITS & SYSTEMS LTD' +VendorID 0x1465, 'GN NETTEST TELECOM DIV.' +VendorID 0x1468, 'AMBIT MICROSYSTEMS CORP.' +VendorID 0x1469, 'CLEVELAND MOTION CONTROLS' +VendorID 0x146C, 'RUBY TECH CORP.' +VendorID 0x146D, 'TACHYON' +VendorID 0x146E, 'WILLIAMS ELECTRONICS GAMES.' +VendorID 0x1471, 'INTEGRATED TELECOM EXPRESS INC' +VendorID 0x1473, 'ZAPEX TECHNOLOGIES INC' +VendorID 0x1474, 'DOUG CARSON & ASSOCIATES' +VendorID 0x1477, 'NET INSIGHT' +VendorID 0x1478, 'DIATREND CORPORATION' +VendorID 0x147B, 'ABIT Computer' +VendorID 0x147F, 'NIHON UNISYS' +VendorID 0x1482, 'ISYTEC-Integrierte Systemtechnik Gmbh' +VendorID 0x1483, 'LABWAY COPORATION' +VendorID 0x1485, 'ERMA-ELECTRONIC GMBH' +VendorID 0x1489, 'KYE SYSTEMS CORPORATION' +VendorID 0x148A, 'OPTO 22' +VendorID 0x148B, 'INNOMEDIALOGIC INC.' +VendorID 0x148E, 'OSI PLUS CORPORATION' +VendorID 0x148F, 'PLANT EQUIPMENT.' +VendorID 0x1490, 'TC LABS PTY LTD.' +VendorID 0x1493, 'MAKER COMMUNICATIONS' +VendorID 0x1495, 'TOKAI COMMUNICATIONS INDUSTRY CO. LTD' +VendorID 0x1496, 'JOYTECH COMPUTER CO. LTD.' +VendorID 0x1497, 'SMA REGELSYSTEME GMBH' +VendorID 0x1499, 'EMTEC CO. LTD' +VendorID 0x149A, 'ANDOR TECHNOLOGY LTD' +VendorID 0x149B, 'SEIKO INSTRUMENTS INC' +VendorID 0x149C, 'OVISLINK CORP.' +VendorID 0x149D, 'NEWTEK INC' +VendorID 0x149E, 'MAPLETREE NETWORKS INC.' +VendorID 0x149F, 'LECTRON CO LTD' +VendorID 0x14A0, 'SOFTING GMBH' +VendorID 0x14A1, 'SYSTEMBASE CO LTD' +VendorID 0x14A2, 'MILLENNIUM ENGINEERING INC' +VendorID 0x14A3, 'MAVERICK NETWORKS' +VendorID 0x14A4, 'GVC/BCM ADVANCED RESEARCH' +VendorID 0x14A5, 'XIONICS DOCUMENT TECHNOLOGIES INC.' +VendorID 0x14A6, 'INOVA COMPUTERS GMBH & CO KG' +VendorID 0x14A8, 'FEATRON TECHNOLOGIES CORPORATION' +VendorID 0x14A9, 'HIVERTEC INC.' +VendorID 0x14AB, 'MENTOR GRAPHICS CORP.' +VendorID 0x14AC, 'NOVAWEB TECHNOLOGIES INC' +VendorID 0x14AD, 'TIME SPACE RADIO AB' +VendorID 0x14AE, 'CTI PET Systems' +VendorID 0x14AF, 'GUILLEMOT CORPORATION' +VendorID 0x14B0, 'BST COMMUNICATION TECHNOLOGY LTD' +VendorID 0x14B1, 'NEXTCOM K.K.' +VendorID 0x14B2, 'ENNOVATE NETWORKS INC' +VendorID 0x14B3, 'XPEED INC.' +VendorID 0x14B4, 'PHILIPS BUSINESS ELECTRONICS B.V.' +VendorID 0x14B5, 'CREAMWARE GMBH' +VendorID 0x14B6, 'QUANTUM DATA CORP.' +VendorID 0x14B7, 'PROXIM INC' +VendorID 0x14B8, 'TECHSOFT TECHNOLOGY CO LTD' +VendorID 0x14B9, 'AIRONET WIRELESS COMMUNICATIONS' +VendorID 0x14BA, 'INTERNIX INC.' +VendorID 0x14BB, 'SEMTECH CORPORATION' +VendorID 0x14BC, 'GLOBESPAN SEMICONDUCTOR INC.' +VendorID 0x14BD, 'CARDIO CONTROL N.V.' +VendorID 0x14BE, 'L3 COMMUNICATIONS' +VendorID 0x14BF, 'SPIDER COMMUNICATIONS INC.' +VendorID 0x14C0, 'COMPAL ELECTRONICS INC' +VendorID 0x14C1, 'MYRICOM INC.' +VendorID 0x14C2, 'DTK COMPUTER' +VendorID 0x14C3, 'MEDIATEK CORP.' +VendorID 0x14C4, 'IWASAKI INFORMATION SYSTEMS CO LTD' +VendorID 0x14C5, 'ABB AUTOMATION PRODUCTS' +VendorID 0x14C6, 'DATA RACE INC' +VendorID 0x14C7, 'MODULAR TECHNOLOY HOLDINGS LTD' +VendorID 0x14C8, 'TURBOCOMM TECH. INC.' +VendorID 0x14C9, 'ODIN TELESYSTEMS INC' +VendorID 0x14CA, 'PE LOGIC CORP.' +VendorID 0x14CB, 'Billionton Systems Inc./Cadmus Micro Inc.' +VendorID 0x14CC, 'NAKAYO TELECOMMUNICATIONS INC' +VendorID 0x14CD, 'UNIVERSAL SCIENTIFIC IND' +VendorID 0x14CE, 'WHISTLE COMMUNICATIONS' +VendorID 0x14CF, 'TEK MICROSYSTEMS INC.' +VendorID 0x14D0, 'ERICSSON AXE R & D' +VendorID 0x14D1, 'COMPUTER HI-TECH CO LTD' +VendorID 0x14D2, 'TITAN ELECTRONICS INC' +VendorID 0x14D3, 'CIRTECH (UK) LTD' +VendorID 0x14D4, 'PANACOM TECHNOLOGY CORP' +VendorID 0x14D5, 'NITSUKO CORPORATION' +VendorID 0x14D6, 'ACCUSYS' +VendorID 0x14D7, 'HIRAKAWA HEWTECH CORP' +VendorID 0x14D8, 'HOPF ELEKTRONIK GMBH' +VendorID 0x14D9, 'ALPHA PROCESSOR INC' +VendorID 0x14DA, 'NATIONAL AEROSPACE LABORATORIES' +VendorID 0x14DB, 'AVLAB TECHNOLOGY INC' +VendorID 0x14DC, 'AMPLICON LIVELINE LTD' +VendorID 0x14DD, 'IMODL INC.' +VendorID 0x14DE, 'APPLIED INTEGRATION CORPORATION' +VendorID 0x14DF, 'BASIS COMMUNICATIONS CORP' +VendorID 0x14E1, 'INVERTEX' +VendorID 0x14E2, 'INFOLIBRIA' +VendorID 0x14E3, 'AMTELCO' +VendorID 0x14E4, 'BROADCOM CORPORATION' +VendorID 0x14E5, 'PIXELFUSION LTD' +VendorID 0x14E6, 'SHINING TECHNOLOGY INC' +VendorID 0x14E7, '3CX' +VendorID 0x14E8, 'RAYCER INC' +VendorID 0x14E9, 'GARNETS SYSTEM CO LTD' +VendorID 0x14EA, 'PLANEX COMMUNICATIONS INC' +VendorID 0x14EB, 'SEIKO EPSON CORPORATION' +VendorID 0x14EC, 'ACQIRIS' +VendorID 0x14ED, 'DATAKINETICS LTD' +VendorID 0x14EE, 'MASPRO KENKOH CORP' +VendorID 0x14EF, 'CARRY COMPUTER ENG. CO LTD' +VendorID 0x14F0, 'CANON RESEACH CENTRE FRANCE' +VendorID 0x14F1, 'Conexant Systems, Inc' +VendorID 0x14F2, 'Mobility Electronics, Inc.' +VendorID 0x14F3, 'BROADLOGIC' +VendorID 0x14F4, 'TOKYO ELECTRONIC INDUSTRY CO LTD' +VendorID 0x14F5, 'SOPAC LTD' +VendorID 0x14F6, 'COYOTE TECHNOLOGIES LLC' +VendorID 0x14F7, 'WOLF TECHNOLOGY INC' +VendorID 0x14F8, 'AUDIOCODES INC' +VendorID 0x14F9, 'AG COMMUNICATIONS' +VendorID 0x14FA, 'WAVETEK WANDEL & GOLTERMANN' +VendorID 0x14FB, 'TRANSAS MARINE (UK) LTD' +VendorID 0x14FC, 'QUADRICS SUPERCOMPUTERS WORLD' +VendorID 0x14FD, 'JAPAN COMPUTER INDUSTRY INC.' +VendorID 0x14FE, 'ARCHTEK TELECOM CORP.' +VendorID 0x14FF, 'TWINHEAD INTERNATIONAL CORP' +VendorID 0x1500, 'LANTECH COMPUTER COMPANY' +VendorID 0x1501, 'BANKSOFT CANADA LTD' +VendorID 0x1502, 'MITSUBISHI ELECTRIC LOGISTICS SUPPORT CO' +VendorID 0x1503, 'KAWASAKI LSI USA INC' +VendorID 0x1504, 'KAISER ELECTRONICS' +VendorID 0x1505, 'ITA INGENIEURBURO FUR TESTAUFGABEN GMBH' +VendorID 0x1506, 'CHAMELEON SYSTEMS INC' +VendorID 0x1507, 'HTEC LTD' +VendorID 0x1508, 'HONDA CONNECTORS/MHOTRONICS INC' +VendorID 0x1509, 'FIRST INTERNATIONAL COMPUTER INC' +VendorID 0x150A, 'FORVUS RESEARCH INC' +VendorID 0x150B, 'YAMASHITA SYSTEMS CORP' +VendorID 0x150C, 'KYOPAL CO LTD' +VendorID 0x150D, 'WARPSPPED INC' +VendorID 0x150E, 'C-PORT CORPORATION' +VendorID 0x150F, 'INTEC GMBH' +VendorID 0x1510, 'BEHAVIOR TECH COMPUTER CORP' +VendorID 0x1511, 'CENTILLIUM TECHNOLOGY CORP' +VendorID 0x1512, 'ROSUN TECHNOLOGIES INC' +VendorID 0x1513, 'RAYCHEM' +VendorID 0x1514, 'TFL LAN INC' +VendorID 0x1515, 'ICS ADVENT' +VendorID 0x1516, 'MYSON TECHNOLOGY INC' +VendorID 0x1517, 'ECHOTEK CORPORATION' +VendorID 0x1518, 'PEP MODULAR COMPUTERS GMBH' +VendorID 0x1519, 'TELEFON AKTIEBOLAGET LM Ericsson' +VendorID 0x151A, 'GLOBETEK INC' +VendorID 0x151B, 'COMBOX LTD' +VendorID 0x151C, 'DIGITAL AUDIO LABS INC' +VendorID 0x151D, 'FUJITSU COMPUTER PRODUCTS OF AMERICA' +VendorID 0x151E, 'MATRIX CORP.' +VendorID 0x151F, 'TOPIC SEMICONDUCTOR CORP' +VendorID 0x1520, 'CHAPLET SYSTEM INC' +VendorID 0x1521, 'BELL CORPORATION' +VendorID 0x1522, 'MAINPINE LIMITED' +VendorID 0x1523, 'MUSIC SEMICONDUCTORS' +VendorID 0x1524, 'ENE TECHNOLOGY INC' +VendorID 0x1525, 'IMPACT TECHNOLOGIES' +VendorID 0x1526, 'ISS' +VendorID 0x1527, 'SOLECTRON' +VendorID 0x1528, 'ACKSYS' +VendorID 0x1529, 'AMERICAN MICROSYSTEMS INC' +VendorID 0x152A, 'QUICKTURN DESIGN SYSTEMS' +VendorID 0x152B, 'FLYTECH TECHNOLOGY CO LTD' +VendorID 0x152C, 'MACRAIGOR SYSTEMS LLC' +VendorID 0x152D, 'QUANTA COMPUTER INC' +VendorID 0x152E, 'MELEC INC' +VendorID 0x152F, 'PHILIPS-CRYPTO' +VendorID 0x1530, 'ACQIS TECHNOLOGY' +VendorID 0x1531, 'CHRYON CORP.' +VendorID 0x1532, 'ECHELON CORPORATION' +VendorID 0x1533, 'BALTIMORE' +VendorID 0x1534, 'ROAD CORPORATION' +VendorID 0x1535, 'EVERGREEN TECHNOLOGIES INC' +VendorID 0x1537, 'DATALEX COMMUNCATIONS' +VendorID 0x1538, 'ARALION INC.' +VendorID 0x1539, 'ATELIER INFORMATIQUES et ELECTRONIQUE ETUDES S.A.' +VendorID 0x153A, 'ONO SOKKI' +VendorID 0x153B, 'TERRATEC ELECTRONIC GMBH' +VendorID 0x153C, 'ANTAL ELECTRONIC' +VendorID 0x153D, 'FILANET CORPORATION' +VendorID 0x153E, 'TECHWELL INC' +VendorID 0x153F, 'MIPS DENMARK' +VendorID 0x1540, 'PROVIDEO MULTIMEDIA CO LTD' +VendorID 0x1541, 'TELOSITY INC.' +VendorID 0x1542, 'VIVID TECHNOLOGY INC' +VendorID 0x1543, 'SILICON LABORATORIES' +VendorID 0x1544, 'DCM DATA SYSTEMS' +VendorID 0x1545, 'VISIONTEK' +VendorID 0x1546, 'IOI TECHNOLOGY CORP.' +VendorID 0x1547, 'MITUTOYO CORPORATION' +VendorID 0x1548, 'JET PROPULSION LABORATORY' +VendorID 0x1549, 'INTERCONNECT SYSTEMS SOLUTIONS' +VendorID 0x154A, 'MAX TECHNOLOGIES INC.' +VendorID 0x154B, 'COMPUTEX CO LTD' +VendorID 0x154C, 'VISUAL TECHNOLOGY INC.' +VendorID 0x154D, 'PAN INTERNATIONAL INDUSTRIAL CORP' +VendorID 0x154E, 'SERVOTEST LTD' +VendorID 0x154F, 'STRATABEAM TECHNOLOGY' +VendorID 0x1550, 'OPEN NETWORK CO LTD' +VendorID 0x1551, 'SMART ELECTRONIC DEVELOPMENT GMBH' +VendorID 0x1552, 'RACAL AIRTECH LTD' +VendorID 0x1553, 'CHICONY ELECTRONICS CO LTD' +VendorID 0x1554, 'PROLINK MICROSYSTEMS CORP.' +VendorID 0x1555, 'GESYTEC GMBH' +VendorID 0x1556, 'PLD APPLICATIONS' +VendorID 0x1557, 'MEDIASTAR CO. LTD' +VendorID 0x1558, 'CLEVO/KAPOK COMPUTER' +VendorID 0x1559, 'SI LOGIC LTD' +VendorID 0x155A, 'INNOMEDIA INC' +VendorID 0x155B, 'PROTAC INTERNATIONAL CORP' +VendorID 0x155C, 'CEMAX-ICON INC' +VendorID 0x155D, 'MAC SYSTEM CO LTD' +VendorID 0x155E, 'LP ELEKTRONIK GMBH/KUKA Controls GmbH' +VendorID 0x155F, 'PERLE SYSTEMS LIMITED' +VendorID 0x1560, 'TERAYON COMMUNICATIONS SYSTEMS' +VendorID 0x1561, 'VIEWGRAPHICS INC' +VendorID 0x1562, 'Symbol Technologies, Inc.' +VendorID 0x1563, 'A-TREND' +VendorID 0x1564, 'YAMAKATSU ELECTRONICS INDUSTRY CO LTD' +VendorID 0x1565, 'BIOSTAR MICROTECH INT CORP' +VendorID 0x1566, 'ARDENT TECHNOLOGIES INC' +VendorID 0x1567, 'JUNGSOFT' +VendorID 0x1568, 'DDK ELECTRONICS INC' +VendorID 0x1569, 'PALIT MICROSYSTEMS INC' +VendorID 0x156A, 'AVTEC SYSTEMS' +VendorID 0x156B, '2WIRE' +VendorID 0x156C, 'VIDAC ELECTRONICS GMBH' +VendorID 0x156D, 'ALPHA-TOP CORP' +VendorID 0x156E, 'ALFA INC' +VendorID 0x156F, 'M-SYSTEMS FLASH DISK PIONEERS LTD' +VendorID 0x1570, 'LECROY CORPORATION' +VendorID 0x1571, 'CONTEMPORARY CONTROLS' +VendorID 0x1572, 'OTIS ELEVATOR COMPANY' +VendorID 0x1573, 'LATTICE-VANTIS' +VendorID 0x1574, 'FAIRCHILD SEMICONDUCTOR' +VendorID 0x1575, 'VOLTAIRE ADVANCED DATA SECURITY LTD' +VendorID 0x1576, 'VIEWCAST COM' +VendorID 0x1578, 'HITT' +VendorID 0x1579, 'DUAL TECHNOLOGY CORPORATION' +VendorID 0x157A, 'JAPAN ELECRONICS IND. INC' +VendorID 0x157B, 'STAR MULTIMEDIA CORP.' +VendorID 0x157C, 'EUROSOFT (UK) LTD' +VendorID 0x157D, 'GEMFLEX NETWORKS' +VendorID 0x157E, 'TRANSITION NETWORKS' +VendorID 0x157F, 'PX INSTRUMENTS TECHNOLOGY LTD' +VendorID 0x1580, 'PRIMEX AEROSPACE CO.' +VendorID 0x1581, 'SEH COMPUTERTECHNIK GMBH' +VendorID 0x1582, 'CYTEC CORPORATION' +VendorID 0x1583, 'INET TECHNOLOGIES INC' +VendorID 0x1584, 'UNIWILL COMPUTER CORP' +VendorID 0x1585, 'LOGITRON' +VendorID 0x1586, 'LANCAST INC' +VendorID 0x1587, 'KONICA CORPORATION' +VendorID 0x1588, 'SOLIDUM SYSTEMS CORP' +VendorID 0x1589, 'ATLANTEK MICROSYSTEMS PTY LTD' +VendorID 0x158A, 'DIGALOG SYSTEMS INC' +VendorID 0x158B, 'ALLIED DATA TECHNOLOGIES' +VendorID 0x158C, 'HITACHI SEMICONDUCTOR & DEVICES SALES CO LTD' +VendorID 0x158D, 'POINT MULTIMEDIA SYSTEMS' +VendorID 0x158E, 'LARA TECHNOLOGY INC' +VendorID 0x158F, 'DITECT COOP' +VendorID 0x1590, '3PARDATA' +VendorID 0x1591, 'ARN' +VendorID 0x1592, 'SYBA TECH LIMITED' +VendorID 0x1593, 'BOPS INC' +VendorID 0x1594, 'NETGAME LTD' +VendorID 0x1595, 'DIVA SYSTEMS CORP.' +VendorID 0x1596, 'FOLSOM RESEARCH INC' +VendorID 0x1597, 'MEMEC DESIGN SERVICES' +VendorID 0x1598, 'GRANITE MICROSYSTEMS' +VendorID 0x1599, 'DELTA ELECTRONICS INC' +VendorID 0x159A, 'GENERAL INSTRUMENT' +VendorID 0x159B, 'FARADAY TECHNOLOGY CORP' +VendorID 0x159C, 'STRATUS COMPUTER SYSTEMS' +VendorID 0x159D, 'NINGBO HARRISON ELECTRONICS CO LTD' +VendorID 0x159E, 'A-MAX TECHNOLOGY' +VendorID 0x159F, 'GALEA NETWORK SECURITY' +VendorID 0x15A0, 'COMPUMASTER SRL' +VendorID 0x15A1, 'GEOCAST NETWORK SYSTEMS INC' +VendorID 0x15A2, 'CATALYST ENTERPRISES INC' +VendorID 0x15A3, 'ITALTEL' +VendorID 0x15A4, 'X-NET OY' +VendorID 0x15A5, 'TOYOTA MACS INC' +VendorID 0x15A6, 'SUNLIGHT ULTRASOUND TECHNOLOGIES LTD' +VendorID 0x15A7, 'SSE TELECOM INC' +VendorID 0x15A8, 'SHANGHAI COMMUNICATIONS TECHNOLOGIES CENTER' +VendorID 0x15AA, 'MORETON BAY' +VendorID 0x15AB, 'BLUESTEEL NETWORKS INC' +VendorID 0x15AC, 'NORTH ATLANTIC INSTRUMENTS' +VendorID 0x15AD, 'VMware Inc.' +VendorID 0x15AE, 'AMERSHAM PHARMACIA BIOTECH' +VendorID 0x15B0, 'ZOLTRIX INTERNATIONAL LIMITED' +VendorID 0x15B1, 'SOURCE TECHNOLOGY INC' +VendorID 0x15B2, 'MOSAID TECHNOLOGIES INC.' +VendorID 0x15B3, 'MELLANOX TECHNOLOGY' +VendorID 0x15B4, 'CCI/TRIAD' +VendorID 0x15B5, 'CIMETRICS INC' +VendorID 0x15B6, 'TEXAS MEMORY SYSTEMS INC' +VendorID 0x15B7, 'SANDISK CORP.' +VendorID 0x15B8, 'ADDI-DATA GMBH' +VendorID 0x15B9, 'MAESTRO DIGITAL COMMUNICATIONS' +VendorID 0x15BA, 'IMPACCT TECHNOLOGY CORP' +VendorID 0x15BB, 'PORTWELL INC' +VendorID 0x15BC, 'AGILENT TECHNOLOGIES' +VendorID 0x15BD, 'DFI INC.' +VendorID 0x15BE, 'SOLA ELECTRONICS' +VendorID 0x15BF, 'HIGH TECH COMPUTER CORP (HTC)' +VendorID 0x15C0, 'BVM LIMITED' +VendorID 0x15C1, 'QUANTEL' +VendorID 0x15C2, 'NEWER TECHNOLOGY INC' +VendorID 0x15C3, 'TAIWAN MYCOMP CO LTD' +VendorID 0x15C4, 'EVSX' +VendorID 0x15C5, 'PROCOMP INFORMATICS LTD' +VendorID 0x15C6, 'TECHNICAL UNIVERSITY OF BUDAPEST' +VendorID 0x15C7, 'TATEYAMA SYSTEM LABORATORY CO LTD' +VendorID 0x15C8, 'PENTA MEDIA CO. LTD' +VendorID 0x15C9, 'SEROME TECHNOLOGY INC' +VendorID 0x15CA, 'BITBOYS OY' +VendorID 0x15CB, 'AG ELECTRONICS LTD' +VendorID 0x15CC, 'HOTRAIL INC.' +VendorID 0x15CD, 'DREAMTECH CO LTD' +VendorID 0x15CE, 'GENRAD INC.' +VendorID 0x15CF, 'HILSCHER GMBH' +VendorID 0x15D1, 'INFINEON TECHNOLOGIES AG' +VendorID 0x15D2, 'FIC (FIRST INTERNATIONAL COMPUTER INC)' +VendorID 0x15D3, 'NDS TECHNOLOGIES ISRAEL LTD' +VendorID 0x15D4, 'IWILL CORPORATION' +VendorID 0x15D5, 'TATUNG CO.' +VendorID 0x15D6, 'ENTRIDIA CORPORATION' +VendorID 0x15D7, 'Rockwell-Collins Inc' +VendorID 0x15D8, 'CYBERNETICS TECHNOLOGY CO LTD' +VendorID 0x15D9, 'SUPER MICRO COMPUTER INC' +VendorID 0x15DA, 'CYBERFIRM INC.' +VendorID 0x15DB, 'APPLIED COMPUTING SYSTEMS INC.' +VendorID 0x15DC, 'LITRONIC INC' +VendorID 0x15DD, 'SIGMATEL INC.' +VendorID 0x15DE, 'MALLEABLE TECHNOLOGIES INC' +VendorID 0x15DF, 'INFINILINK CORP.' +VendorID 0x15E0, 'CACHEFLOW INC' +VendorID 0x15E1, 'VOICE TECHNOLOGIES GROUP INC' +VendorID 0x15E2, 'QUICKNET TECHNOLOGIES INC' +VendorID 0x15E3, 'NETWORTH TECHNOLOGIES INC' +VendorID 0x15E4, 'VSN SYSTEMEN BV' +VendorID 0x15E5, 'VALLEY TECHNOLOGIES INC' +VendorID 0x15E6, 'AGERE INC.' +VendorID 0x15E7, 'GET ENGINEERING CORP.' +VendorID 0x15E8, 'NATIONAL DATACOMM CORP.' +VendorID 0x15E9, 'PACIFIC DIGITAL CORP.' +VendorID 0x15EA, 'TOKYO DENSHI SEKEI K.K.' +VendorID 0x15EB, 'DRSEARCH GMBH' +VendorID 0x15EC, 'BECKHOFF GMBH' +VendorID 0x15ED, 'MACROLINK INC' +VendorID 0x15EE, 'IN WIN DEVELOPMENT INC.' +VendorID 0x15EF, 'INTELLIGENT PARADIGM INC' +VendorID 0x15F0, 'B-TREE SYSTEMS INC' +VendorID 0x15F1, 'TIMES N SYSTEMS INC' +VendorID 0x15F2, 'DIAGNOSTIC INSTRUMENTS INC' +VendorID 0x15F3, 'DIGITMEDIA CORP.' +VendorID 0x15F4, 'VALUESOFT' +VendorID 0x15F5, 'POWER MICRO RESEARCH' +VendorID 0x15F6, 'EXTREME PACKET DEVICE INC' +VendorID 0x15F7, 'BANCTEC' +VendorID 0x15F8, 'KOGA ELECTRONICS CO' +VendorID 0x15F9, 'ZENITH ELECTRONICS CORPORATION' +VendorID 0x15FA, 'J P AXZAM CORPORATION' +VendorID 0x15FB, 'ZILOG INC.' +VendorID 0x15FC, 'TECHSAN ELECTRONICS CO LTD' +VendorID 0x15FD, 'N-CUBED.NET' +VendorID 0x15FE, 'KINPO ELECTRONICS INC' +VendorID 0x15FF, 'FASTPOINT TECHNOLOGIES INC.' +VendorID 0x1600, 'NORTHROP GRUMMAN-CANADA LTD' +VendorID 0x1601, 'TENTA TECHNOLOGY' +VendorID 0x1602, 'PROSYS-TEC INC.' +VendorID 0x1603, 'NOKIA WIRELESS BUSINESS COMMUNICATIONS' +VendorID 0x1604, 'CENTRAL SYSTEM RESEARCH CO LTD' +VendorID 0x1605, 'PAIRGAIN TECHNOLOGIES' +VendorID 0x1606, 'EUROPOP AG' +VendorID 0x1607, 'LAVA SEMICONDUCTOR MANUFACTURING INC.' +VendorID 0x1608, 'AUTOMATED WAGERING INTERNATIONAL' +VendorID 0x1609, 'SCIEMETRIC INSTRUMENTS INC' +VendorID 0x166D, 'Broadcom -SiByte' +VendorID 0x168C, 'Atheros Communications Inc.' +VendorID 0x1695, 'EPOX Computer Co' +VendorID 0x17F2, 'ALBATRON Corp.' +VendorID 0x1813, 'AMBIENT TECHNOLOGIES INC' +VendorID 0x1849, 'ASROCK Inc' +VendorID 0x1B13, 'Jaton Corp' +VendorID 0x2001, 'TEMPORAL RESEARCH LTD' +VendorID 0x270F, 'CHAINTECH COMPUTER CO. LTD' +VendorID 0x3388, 'HINT CORP' +VendorID 0x3411, 'QUANTUM DESIGNS (H.K.) INC.' +VendorID 0x4005, 'AVANCE LOGIC INC' +VendorID 0x4033, 'DELTA NETWORKS INC' +VendorID 0x416C, 'ALADDIN KNOWLEDGE SYSTEMS' +VendorID 0x4444, 'CONEXANT (WAS ICOMPRESION INC.)' +VendorID 0x4943, 'GROWTH NETWORKS' +VendorID 0x4CA1, 'SEANIX TECHNOLOGY INC' +VendorID 0x4D51, 'MEDIAQ INC.' +VendorID 0x4D54, 'MICROTECHNICA CO LTD' +VendorID 0x5136, 'S S TECHNOLOGIES' +VendorID 0x5333, 'S3 Graphics Co., Ltd.' +VendorID 0x544C, 'TERALOGIC INC' +VendorID 0x5555, 'GENROCO INC' +VendorID 0x6409, 'LOGITEC CORP.' +VendorID 0x6666, 'DECISION COMPUTER INTERNATIONAL CO.' +VendorID 0x8086, 'Intel Corp.' +VendorID 0x8888, 'SILICON MAGIC CORP.' +VendorID 0x8E0E, 'COMPUTONE CORPORATION' +VendorID 0x9004, 'Adaptec Inc' +VendorID 0x919A, 'GIGAPIXEL CORP' +VendorID 0x9412, 'HOLTEK' +VendorID 0x9699, 'OMNI MEDIA TECHNOLOGY INC.' +VendorID 0x9710, 'NetMos' +VendorID 0xA0A0, 'AOPEN INC.' +VendorID 0xA259, 'HEWLETT PACKARD' +VendorID 0xAC1E, 'DIGITAL RECEIVER TECHNOLOGY INC' +VendorID 0xC0DE, 'MOTOROLA' +VendorID 0xC0FE, 'MOTION ENGINEERING.' +VendorID 0xCA50, 'VARIAN AUSTRIALIA PTY LTD' +VendorID 0xCAFE, 'CHRYSALIS-ITS' +VendorID 0xCCCC, 'CATAPULT COMMUNICATIONS' +VendorID 0xD4D4, 'DY4 Systems Inc/Curtiss-Wright Controls Embed. Com' +VendorID 0xE159, 'TigerJet' +VendorID 0xE4BF, 'EKF ELEKTRONIK GMBH' +VendorID 0xEA01, 'EAGLE TECHNOLOGY' +VendorID 0xFA57, 'FAST SEARCH & TRANSFER ASA' +VendorID 0xFEDA, 'EPIGRAM INC' +VendorID 0, 'Unknown' ; <- terminator + +;-------------------------------------- +Classes: +; Class, Subclass, [Interface], Name +ClassID 2, 0, , 'Ethernet' +ClassID 2, 1, , 'Token Ring' +ClassID 2, 2, , 'FDDI' +ClassID 2, 3, , 'ATM' +ClassID 2, 4, , 'ISDN' +ClassID 2, 5, , 'WorldFip' +ClassID 2, 6, , 'PICMG 2.14' +ClassID 2, 0x80, , 'misc' + +ClassID 0x0d, 0x20, , 'Wlan (802.11a)' +ClassID 0x0d, 0x21, , 'Wlan (802.11b)' + + +ClassID 0xff, 0xff, , 'Unknown' ; <- terminator \ No newline at end of file diff --git a/programs/network/netstat/netstat.asm b/programs/network/netstat/netstat.asm new file mode 100644 index 0000000000..6fe4a29c1a --- /dev/null +++ b/programs/network/netstat/netstat.asm @@ -0,0 +1,614 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2010-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; netstat.asm - Network Status Tool for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format binary as "" + +use32 + + org 0x0 + + db 'MENUET01' ; 8 byte id + dd 0x01 ; header version + dd START ; start of code + dd I_END ; size of image + dd (I_END+0x100) ; memory for app + dd (I_END+0x100) ; esp + dd I_PARAM , 0x0 ; I_Param , I_Icon + +include '..\macros.inc' +include '..\network.inc' + +START: + mcall 40, EVM_REDRAW + EVM_BUTTON + EVM_STACK2 + +redraw: + mcall 12, 1 + mcall 0, 100 shl 16 + 600, 100 shl 16 + 240, 0x34bcbcbc, , name ; draw window + + call draw_interfaces + + mov edx, 101 + mov esi, 0x00aaaaff + mov edi, 0x00aaffff + + cmp dl, [mode] + cmove esi, edi + mcall 8, 25 shl 16 + 65, 25 shl 16 + 20 + + .morebuttons: + inc edx + add ebx, 75 shl 16 + mov esi, 0x00aaaaff + + cmp dl, [mode] + cmove esi, edi + mcall + + cmp edx, 105 + jle .morebuttons + + mcall 4, 28 shl 16 + 31, 0x80000000, modes + + cmp [mode], 101 + jne .no_eth + + mcall 4, 20 shl 16 + 75, 0x80000000, str_packets_tx + add ebx, 18 + mov edx, str_packets_rx + mcall + add ebx, 18 + mov edx, str_bytes_tx + mcall + add ebx, 18 + mov edx, str_bytes_rx + mcall + add ebx, 18 + mov edx, str_MAC + mcall + add ebx, 18 + mov edx, str_link + mcall + + mov ebx, API_ETH + 4 + mov bh, [device] + mcall 76 + push eax + push bx + + mov edx, 135 shl 16 + 75 + 4*18 + call draw_mac + jmp end_of_draw + + .no_eth: + + cmp [mode], 102 + jne .no_ip + + mcall 4, 20 shl 16 + 75, 0x80000000, str_packets_tx + add ebx, 18 + mov edx, str_packets_rx + mcall + add ebx, 18 + mov edx, str_ip + mcall + add ebx, 18 + mov edx, str_dns + mcall + add ebx, 18 + mov edx, str_subnet + mcall + add ebx, 18 + mov edx, str_gateway + mcall + + + mov ebx, API_IPv4 + 8 + mov bh, [device] + mcall 76 + push eax + + dec bl + dec bl + mcall 76 + push eax + + dec bl + dec bl + mcall 76 + push eax + + dec bl + dec bl + mcall 76 + push eax + + mov edx, 135 shl 16 + 75 + 2*18 + call draw_ip + + add edx, 18 + call draw_ip + + add edx, 18 + call draw_ip + + add edx, 18 + call draw_ip + + jmp end_of_draw + + .no_ip: + + cmp [mode], 103 + jne .no_arp + + mcall 4, 20 shl 16 + 75, 0x80000000, str_packets_tx + add ebx, 18 + mov edx, str_packets_rx + mcall + add ebx, 18 + mov edx, str_arp + mcall + add ebx, 18 + mov edx, str_conflicts + mcall + + jmp end_of_draw + + .no_arp: + + mcall 4, 20 shl 16 + 75, 0x80000000, str_packets_tx + + add ebx, 18 + mov edx, str_packets_rx + mcall + + cmp [mode], 106 + jne end_of_draw + + add ebx, 18 + mov edx, str_missed + mcall + + add ebx, 18 + mov edx, str_dumped + mcall + + + +end_of_draw: + mcall 12, 2 + +draw_stats: + + cmp [mode], 101 + jne not_101 + + mov ebx, API_ETH + mov bh, [device] + @@: + push ebx + mcall 76 + pop ebx + push eax + inc bl + cmp bl, 3 + jbe @r + inc bl + mcall 76 + push eax + + mov ebx, 0x000a0000 + pop ecx + mov edx, 135 shl 16 + 75 + 5*18 + mov esi, 0x40000000 + mov edi, 0x00bcbcbc + mcall 47 + + sub edx, 18*2 + pop ecx + mcall + + sub edx, 18 + pop ecx + mcall + + sub edx, 18 + pop ecx + mcall + + sub edx, 18 + pop ecx + mcall + + jmp mainloop + + +not_101: + + cmp [mode], 102 + jne not_102 + + mov ebx, API_IPv4 + mov bh, [device] + push ebx + mcall 76 + pop ebx + push eax + + inc bl + push ebx + mcall 76 + pop ebx + push eax + + + mov ebx, 0x000a0000 + pop ecx + mov edx, 135 shl 16 + 75 + 18 + mov esi, 0x40000000 + mov edi, 0x00bcbcbc + mcall 47 + + sub edx, 18 + pop ecx + mcall + + jmp mainloop + + +not_102: + + cmp [mode], 103 + jne not_103 + + mov ebx, API_ARP + mov bh, [device] + push ebx + mcall 76 + pop ebx + push eax + + inc bl + push ebx + mcall 76 + pop ebx + push eax + + inc bl + push ebx + mcall 76 + pop ebx + push eax + + mov bl, 7 + push ebx + mcall 76 + pop ebx + push eax + + mov ebx, 0x000a0000 + pop ecx + mov edx, 135 shl 16 + 75 + 3*18 + mov esi, 0x40000000 + mov edi, 0x00bcbcbc + mcall 47 + + sub edx, 18 + pop ecx + mcall + + sub edx, 18 + pop ecx + mcall + + sub edx, 18 + pop ecx + mcall + + jmp mainloop + +not_103: + + cmp [mode], 104 + jne not_104 + + mov ebx, API_ICMP + mov bh, [device] + push ebx + mcall 76 + pop ebx + push eax + + inc bl + push ebx + mcall 76 + pop ebx + push eax + + mov ebx, 0x000a0000 + pop ecx + mov edx, 135 shl 16 + 75 + 18 + mov esi, 0x40000000 + mov edi, 0x00bcbcbc + mcall 47 + + sub edx, 18 + pop ecx + mcall + + jmp mainloop + +not_104: + + cmp [mode], 105 + jne not_105 + + mov ebx, API_UDP + mov bh, [device] + push ebx + mcall 76 + pop ebx + push eax + + inc bl + push ebx + mcall 76 + pop ebx + push eax + + mov ebx, 0x000a0000 + pop ecx + mov edx, 135 shl 16 + 75 + 18 + mov esi, 0x40000000 + mov edi, 0x00bcbcbc + mcall 47 + + sub edx, 18 + pop ecx + mcall + + jmp mainloop + +not_105: + + cmp [mode], 106 + jne not_106 + + mov ebx, API_TCP + mov bh, [device] + push ebx + mcall 76 + pop ebx + push eax + + inc bl + push ebx + mcall 76 + pop ebx + push eax + + inc bl + push ebx + mcall 76 + pop ebx + push eax + + inc bl + push ebx + mcall 76 + pop ebx + push eax + + mov ebx, 0x000a0000 + pop ecx + mov edx, 135 shl 16 + 75 + 18*3 + mov esi, 0x40000000 + mov edi, 0x00bcbcbc + mcall 47 + + sub edx, 18 + pop ecx + mcall + + sub edx, 18 + pop ecx + mcall + + sub edx, 18 + pop ecx + mcall + + jmp mainloop + +not_106: + +mainloop: + + mcall 23, 50 ; wait for event with timeout (0,5 s) + + cmp eax, 1 + je redraw + cmp eax, 3 + je button + cmp eax, 11 + je redraw + + jmp draw_stats + +button: ; button + mcall 17 ; get id + cmp ah, 1 + je exit + cmp ah, 0 + je .interface + mov [mode], ah + jmp redraw + + .interface: + shr eax, 16 + mov [device], al + jmp redraw + +exit: + mcall -1 + + + +draw_mac: + + mov eax, 47 + mov ebx, 0x00020100 + mov esi, 0x40000000 + mov edi, 0x00bcbcbc + + mov cl, [esp+4] + mcall + + mov cl, [esp+4+1] + add edx, 15 shl 16 + mcall + + mov cl, [esp+4+2] + add edx, 15 shl 16 + mcall + + mov cl, [esp+4+3] + add edx, 15 shl 16 + mcall + + mov cl, [esp+4+4] + add edx, 15 shl 16 + mcall + + mov cl, [esp+4+5] + add edx, 15 shl 16 + mcall + + sub edx, 5*15 shl 16 + + ret 6 + + +draw_ip: + + mov eax, 47 + mov ebx, 0x00030000 + mov esi, 0x40000000 + mov edi, 0x00bcbcbc + + xor ecx, ecx + + mov cl, [esp+4] + mcall + + mov cl, [esp+4+1] + add edx, 30 shl 16 + mcall + + mov cl, [esp+4+2] + add edx, 30 shl 16 + mcall + + mov cl, [esp+4+3] + add edx, 30 shl 16 + mcall + + sub edx, 3*30 shl 16 + ret 4 + + +draw_interfaces: + + mov [.btnpos], 8 shl 16 + 20 + mov [.txtpos], 490 shl 16 + 15 + + mcall 74, -1 ; get number of active network devices + mov ecx, eax + + xor ebx, ebx ; get device type + .loop: + mcall 74 + cmp eax, 1 ; ethernet? + je .hit + inc bh + jb .loop ; tried all 256? + ret + + + .hit: + push ecx ebx + movzx edx, bh + shl edx, 8 + mov esi, 0x00aaaaff + cmp bh, [device] + cmove esi, 0x00aaffff + mcall 8, 485 shl 16 + 100, [.btnpos] + mov ebx, [esp] + inc bl + mov ecx, namebuf + mov edx, namebuf + mcall 74 ; get device name + cmp eax, -1 + jne @f + mov edx, str_unknown + @@: + mcall 4, [.txtpos], 0x80000000 ; print the name + pop ebx ecx + + inc bh + + add [.btnpos], 25 shl 16 + add [.txtpos], 25 + + dec ecx + jnz .loop + + ret + + .btnpos dd ? + .txtpos dd ? + + + + +; DATA AREA + +name db 'Netstat', 0 +mode db 101 +device db 0 +modes db 'Ethernet IPv4 ARP ICMP UDP TCP', 0 + +str_packets_tx db 'Packets sent:', 0 +str_packets_rx db 'Packets received:', 0 +str_bytes_tx db 'Bytes sent:', 0 +str_bytes_rx db 'Bytes received:', 0 +str_MAC db 'MAC address:', 0 +str_ip db 'IP address:', 0 +str_dns db 'DNS address:', 0 +str_subnet db 'Subnet mask:', 0 +str_gateway db 'Standard gateway:', 0 +str_arp db 'ARP entrys:', 0 +str_conflicts db 'ARP conflicts:', 0 +str_unknown db 'unknown', 0 +str_missed db 'Packets missed:',0 +str_dumped db 'Packets dumped:',0 +str_link db 'Link state:',0 + +namebuf rb 64 + +I_PARAM rb 1024 + +I_END: + + diff --git a/programs/network/network.inc b/programs/network/network.inc new file mode 100644 index 0000000000..efe942c9ff --- /dev/null +++ b/programs/network/network.inc @@ -0,0 +1,94 @@ +; Socket types +SOCK_STREAM = 1 +SOCK_DGRAM = 2 +SOCK_RAW = 3 + +; Socket options +SO_NONBLOCK = 1 shl 31 + +; IP protocols +IPPROTO_IP = 0 +IPPROTO_ICMP = 1 +IPPROTO_TCP = 6 +IPPROTO_UDP = 17 + +; Address families +AF_UNSPEC = 0 +AF_LOCAL = 1 +AF_INET4 = 2 ; IPv4 +AF_INET6 = 28 ; IPv6 (not supported yet) + +PF_UNSPEC = AF_UNSPEC +PF_LOCAL = AF_LOCAL +PF_INET4 = AF_INET4 +PF_INET6 = AF_INET6 + +; Flags for addrinfo +AI_PASSIVE = 1 +AI_CANONNAME = 2 +AI_NUMERICHOST = 4 +AI_NUMERICSERV = 8 +AI_ADDRCONFIG = 0x400 + +; internal definition +AI_SUPPORTED = 0x40F + +; for system function 76 +API_ETH = 0 shl 16 +API_IPv4 = 1 shl 16 +API_ICMP = 2 shl 16 +API_UDP = 3 shl 16 +API_TCP = 4 shl 16 +API_ARP = 5 shl 16 +API_PPPOE = 6 shl 16 + +struct sockaddr_in + sin_family dw ? ; sa_family_t + sin_port dw ? ; in_port_t + sin_addr dd ? ; struct in_addr + sin_zero rb 8 ; zero +ends + +struct addrinfo + ai_flags dd ? ; bitmask of AI_* + ai_family dd ? ; PF_* + ai_socktype dd ? ; SOCK_* + ai_protocol dd ? ; 0 or IPPROTO_* + ai_addrlen dd ? ; length of ai_addr + ai_canonname dd ? ; char* + ai_addr dd ? ; struct sockaddr* + ai_next dd ? ; struct addrinfo* +ends + +EAI_ADDRFAMILY = 1 +EAI_AGAIN = 2 +EAI_BADFLAGS = 3 +EAI_FAIL = 4 +EAI_FAMILY = 5 +EAI_MEMORY = 6 +EAI_NONAME = 8 +EAI_SERVICE = 9 +EAI_SOCKTYPE = 10 +EAI_BADHINTS = 12 +EAI_PROTOCOL = 13 +EAI_OVERFLOW = 14 + +socket fix 75, 0 +close fix 75, 1 +bind fix 75, 2 +listen fix 75, 3 +connect fix 75, 4 +accept fix 75, 5 +send fix 75, 6 +recv fix 75, 7 +setsockopt fix 75, 8 +getsockopt fix 75, 9 +socketpair fix 75, 10 + + +struct ARP_entry + IP dd ? + MAC dp ? + status dw ? + TTL dw ? +ends diff --git a/programs/network/nslookup/nslookup.asm b/programs/network/nslookup/nslookup.asm new file mode 100644 index 0000000000..94704101d0 --- /dev/null +++ b/programs/network/nslookup/nslookup.asm @@ -0,0 +1,136 @@ +format binary as "" + +use32 +; standard header + db 'MENUET01' ; signature + dd 1 ; header version + dd start ; entry point + dd i_end ; initialized size + dd mem ; required memory + dd mem ; stack pointer + dd 0 ; parameters + dd 0 ; path + +; useful includes +include '../macros.inc' +purge mov,add,sub +include '../proc32.inc' +include '../dll.inc' + +include '../network.inc' + +; entry point +start: +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit +; initialize console + push 1 + call [con_start] + push title + push -1 + push -1 + push -1 + push -1 + call [con_init] +; main loop +main: +; write prompt + push str1 + call [con_write_asciiz] +; read string + mov esi, s + push 256 + push esi + call [con_gets] +; check for exit + test eax, eax + jz done + cmp byte [esi], 10 + jz done +; delete terminating '\n' + push esi +@@: + lodsb + test al, al + jnz @b + mov byte [esi-2], al + pop esi +; resolve name + push esp ; reserve stack place + push esp ; fourth parameter + push 0 ; third parameter + push 0 ; second parameter + push esi ; first parameter + call [getaddrinfo] + pop esi +; test for error + test eax, eax + jnz fail +; write results + push str2 + call [con_write_asciiz] + mov edi, esi +addrloop: +; before all subsequent addresses print comma + cmp edi, esi + jz @f + push str3 + call [con_write_asciiz] +@@: +; convert IP address to decimal notation + mov eax, [edi+addrinfo.ai_addr] + pushd [eax+sockaddr_in.sin_addr] + call [inet_ntoa] +; write result + push eax + call [con_write_asciiz] +; advance to next item + mov edi, [edi+addrinfo.ai_next] + test edi, edi + jnz addrloop +; free allocated memory + push esi + call [freeaddrinfo] +; write newline and continue main loop + push str4 +@@: + call [con_write_asciiz] + jmp main +fail: + push str5 + jmp @b +done: + push 1 + call [con_exit] +exit: + mcall -1 + +; data +title db 'Names resolver',0 +str1 db 'Host name to resolve: ',0 +str2 db 'IP address(es): ',0 +str3 db ', ',0 +str4 db 10,0 +str5 db 'Name resolution failed.',10,0 +; import +align 4 +@IMPORT: + +library network, 'network.obj', console, 'console.obj' +import network, \ + getaddrinfo, 'getaddrinfo', \ + freeaddrinfo, 'freeaddrinfo', \ + inet_ntoa, 'inet_ntoa' +import console, \ + con_start, 'START', \ + con_init, 'con_init', \ + con_write_asciiz, 'con_write_asciiz', \ + con_exit, 'con_exit', \ + con_gets, 'con_gets' +i_end: +s rb 256 +align 4 +rb 4096 ; stack +mem: diff --git a/programs/network/pppoe/pppoe.asm b/programs/network/pppoe/pppoe.asm new file mode 100644 index 0000000000..af9b51b8b9 --- /dev/null +++ b/programs/network/pppoe/pppoe.asm @@ -0,0 +1,362 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; pppoe.asm - PPPoE dialer for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format binary as "" + +use32 + + db 'MENUET01' ; signature + dd 1 ; header version + dd start ; entry point + dd i_end ; initialized size + dd mem ; required memory + dd mem ; stack pointer + dd 0 ; parameters + dd 0 ; path + +include '../macros.inc' +purge mov,add,sub +include '../proc32.inc' +include '../dll.inc' +include '../network.inc' +include '../struct.inc' + +; Ethernet protocol numbers +ETHER_PPP_DISCOVERY = 0x6388 +ETHER_PPP_SESSION = 0x6488 + +; PPP protocol numbers +PPP_LCP = 0x21c0 ; Link Configure Protocol +PPP_CBCP = 0x29c0 ; CallBack Control Protocol +PPP_PAP = 0x23c0 ; Password Authenication Protocol packet +PPP_CHAP = 0x23c2 ; Challenge Handshake Authentication Protocol +PPP_IPCP = 0x2180 ; Internet Protocol Configure Protocol (maybe this should be in kernel?) +PPP_CCP = 0xfd80 ; Compression Configure Protocol + +; PPP Active Discovery... +PPPoE_PADI = 0x09 ; .. Initiation +PPPoE_PADO = 0x07 ; .. Offer +PPPoE_PADR = 0x19 ; .. Request +PPPoE_PADS = 0x65 ; .. Session-confirmation +PPPoE_PADT = 0xa7 ; .. Terminate + +TAG_EOL = 0x0000 +TAG_SERVICE_NAME= 0x0101 +TAG_AC_NAME = 0x0201 +TAG_HOST_UNIQ = 0x0301 +TAG_AC_COOKIE = 0x0401 + +LCP_config_request = 1 +LCP_config_ack = 2 +LCP_config_nak = 3 +LCP_config_reject = 4 +LCP_terminate_request = 5 +LCP_terminate_ack = 6 +LCP_code_reject = 7 +LCP_protocol_reject = 8 +LCP_echo_request = 9 +LCP_echo_reply = 10 +LCP_discard_request = 11 + +struct ETH_frame + DestMac dp ? + SrcMac dp ? + Type dw ? +ends + +struct PPPoE_frame ETH_frame + VersionAndType db ? + Code db ? + SessionID dw ? + Length dw ? ; Length of payload, does NOT include the length PPPoE header. + Payload rb 0 +ends + +struct PPP_frame PPPoE_frame + Protocol dw ? +ends + +struct LCP_frame PPP_frame + LCP_Code db ? + LCP_Identifier db ? + LCP_Length dw ? + LCP_Data rb 0 +ends + +; entry point +start: +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit +; initialize console + push 1 + call [con_start] + push title + push 25 + push 80 + push 25 + push 80 + call [con_init] + +main: + mcall 40, 1 shl 7 + + call [con_cls] +; Welcome user + push str1 + call [con_write_asciiz] + + mcall socket, 777, 3, 666 + mov [socketnum], eax + mcall send, [socketnum], PADI, PADI.length, 0 + +mainloop: + mcall 10 + + call [con_get_flags] + test eax, 0x200 ; con window closed? + jnz close_conn + + mcall recv, [socketnum], buffer, 4096 + cmp eax, sizeof.PPPoE_frame + jb mainloop + + cmp word [buffer + ETH_frame.Type], ETHER_PPP_SESSION + je SESSION_input + + cmp word [buffer + ETH_frame.Type], ETHER_PPP_DISCOVERY + jne mainloop + + cmp [buffer + PPPoE_frame.Code], PPPoE_PADO + je pado + + cmp [buffer + PPPoE_frame.Code], PPPoE_PADS + je pads + + cmp [buffer + PPPoE_frame.Code], PPPoE_PADT + je padt + + jmp mainloop + +pado: + + push str2 + call [con_write_asciiz] + + lea esi, [buffer + ETH_frame.SrcMac] ; source mac -> dest mac + lea edi, [buffer + ETH_frame.DestMac] + movsw + movsd + + mov byte [buffer + PPPoE_frame.Code], PPPoE_PADR ; change packet type to PADR + + mov al, byte [buffer + PPPoE_frame.Length + 1] ; get packet size + mov ah, byte [buffer + PPPoE_frame.Length + 0] + movzx esi, ax + add esi, sizeof.PPPoE_frame + mcall send, [socketnum], buffer, , 0 ; now send it! + + jmp mainloop + + +pads: + + push str3 + call [con_write_asciiz] + + mov edx, dword [buffer + ETH_frame.SrcMac] ; source mac -> dest mac + mov si, word [buffer + ETH_frame.SrcMac + 4] + mov dword [PADT.mac], edx + mov word [PADT.mac + 4], si + + mov cx, word [buffer + PPPoE_frame.SessionID] ; and Session ID + mov [PADT.sid], cx + + mcall 76, API_PPPOE + 0 ; Start PPPoE session + + jmp mainloop + +padt: + + push str4 + call [con_write_asciiz] + + mcall 76, API_PPPOE + 1 ; Stop PPPoE session + +exit: + mcall close, [socketnum] + mcall -1 + + +close_conn: + + mcall send, [socketnum], PADT, PADT.length, 0 + jmp exit + + +SESSION_input: + + mov ax, word[buffer + PPP_frame.Protocol] + + cmp ax, PPP_LCP + je LCP_input + + cmp ax, PPP_CBCP + je CBCP_input + + cmp ax, PPP_PAP + je PAP_input + + cmp ax, PPP_CHAP + je CHAP_input + + cmp ax, PPP_IPCP + je IPCP_input + + cmp ax, PPP_CCP + je CCP_input + + jmp mainloop + + + +LCP_input: + + stdcall con_write_asciiz, str_lcp + + cmp [buffer + LCP_frame.LCP_Code], LCP_echo_request + je .echo + + .dump: + jmp mainloop + + .echo: + mov [buffer + LCP_frame.LCP_Code], LCP_echo_reply + + lea esi, [buffer + ETH_frame.SrcMac] ; source mac -> dest mac + lea edi, [buffer + ETH_frame.DestMac] + movsw + movsd + + mov esi, eax + mcall send, [socketnum], buffer, , 0 ; now send it back! + + jmp mainloop + +CBCP_input: + + stdcall con_write_asciiz, str_cbcp + + jmp mainloop + +PAP_input: + + stdcall con_write_asciiz, str_pap + + jmp mainloop + +CHAP_input: + + stdcall con_write_asciiz, str_chap + + jmp mainloop + +IPCP_input: + + stdcall con_write_asciiz, str_ipcp + + jmp mainloop + +CCP_input: + + stdcall con_write_asciiz, str_ccp + + jmp mainloop + +; data +title db 'PPPoE',0 +str1 db 'Sending PADI',13,10,0 +str2 db 'Got PADO',13,10,'Sending PADR',13,10,0 +str3 db 'Got PADS',13,10,'starting PPPoE session',13,10,0 +str4 db 'Got PADT - connection terminated by Access Concentrator',13,10,0 +str_lcp db 'Got LCP packet',13,10,0 +str_cbcp db 'got CBCP packet',13,10,0 +str_pap db 'got PAP packet',13,10,0 +str_chap db 'got CHAP packet',13,10,0 +str_ipcp db 'got IPCP packet',13,10,0 +str_ccp db 'got CCP packet',13,10,0 + + +PADI: + dp 0xffffffffffff ; dest mac: broadcast + dp 0 ; source mac (overwritten by kernel) + dw ETHER_PPP_DISCOVERY ; type + + db 0x11 ; Version and Type + db PPPoE_PADI ; Code + dw 0 ; session ID + dw 20 shl 8 ; Payload Length + + dw TAG_SERVICE_NAME ; tag + dw 0x0000 ; length + + dw TAG_HOST_UNIQ ; tag + dw 0x0c00 ; length = 12 bytes + + dd 0xdead ; some random id + dd 0xbeef + dd 0x1337 + + .length = $ - PADI + +PADT: + + .mac dp 0 ; Dest mac, to be filled in + dp 0 ; source mac (overwritten by kernel) + dw ETHER_PPP_DISCOVERY ; Type + + db 0x11 ; Version and Type + db PPPoE_PADT ; Code: terminate connection + .sid dw 0 ; session id, to be filled in + dw 0 ; PAyload length = 0 + + .length = $ - PADT + + +; import +align 4 +@IMPORT: + +library console, 'console.obj' +import console, \ + con_start, 'START', \ + con_init, 'con_init', \ + con_write_asciiz, 'con_write_asciiz', \ + con_exit, 'con_exit', \ + con_gets, 'con_gets',\ + con_cls, 'con_cls',\ + con_getch2, 'con_getch2',\ + con_set_cursor_pos, 'con_set_cursor_pos',\ + con_write_string, 'con_write_string',\ + con_get_flags, 'con_get_flags' + + +i_end: + +socketnum dd ? + +buffer rb 4096 + rb 4096 ; stack +mem: diff --git a/programs/network/icq/trunk/proc32.inc b/programs/network/proc32.inc similarity index 100% rename from programs/network/icq/trunk/proc32.inc rename to programs/network/proc32.inc diff --git a/programs/network/socketdbg/socket.inc b/programs/network/socketdbg/socket.inc new file mode 100644 index 0000000000..c612467bf1 --- /dev/null +++ b/programs/network/socketdbg/socket.inc @@ -0,0 +1,164 @@ +struct LHEAD + next dd ? ;next object in list + prev dd ? ;prev object in list +ends + +struct MUTEX + lhead LHEAD + count dd ? +ends + + +struct SOCKET + + NextPtr dd ? ; pointer to next socket in list + PrevPtr dd ? ; pointer to previous socket in list + Number dd ? ; socket number + + mutex MUTEX + + PID dd ? ; application process id + Domain dd ? ; INET/UNIX/.. + Type dd ? ; RAW/STREAM/DGRAP + Protocol dd ? ; ICMP/IPv4/ARP/TCP/UDP + errorcode dd ? + device dd ? + + options dd ? + state dd ? + backlog dw ? ; how many incomming connections that can be queued + + snd_proc dd ? + rcv_proc dd ? + +ends + +struct IP_SOCKET SOCKET + + LocalIP rd 4 ; network byte order + RemoteIP rd 4 ; network byte order + +ends + +struct TCP_SOCKET IP_SOCKET + + LocalPort dw ? ; network byte order + RemotePort dw ? ; network byte order + + t_state dd ? ; TCB state + t_rxtshift db ? + rb 3 ; align + t_rxtcur dd ? + t_dupacks dd ? + t_maxseg dd ? + t_force dd ? + t_flags dd ? + +;--------------- +; RFC783 page 21 + +; send sequence + SND_UNA dd ? ; sequence number of unack'ed sent Packets + SND_NXT dd ? ; next send sequence number to use + SND_UP dd ? ; urgent pointer + SND_WL1 dd ? ; window minus one + SND_WL2 dd ? ; + ISS dd ? ; initial send sequence number + SND_WND dd ? ; send window + +; receive sequence + RCV_WND dd ? ; receive window + RCV_NXT dd ? ; next receive sequence number to use + RCV_UP dd ? ; urgent pointer + IRS dd ? ; initial receive sequence number + +;--------------------- +; Additional variables + +; receive variables + RCV_ADV dd ? + +; retransmit variables + SND_MAX dd ? + +; congestion control + SND_CWND dd ? + SND_SSTHRESH dd ? + +;---------------------- +; Transmit timing stuff + t_idle dd ? + t_rtt dd ? + t_rtseq dd ? + t_srtt dd ? + t_rttvar dd ? + t_rttmin dd ? + max_sndwnd dd ? + +;----------------- +; Out-of-band data + t_oobflags dd ? + t_iobc dd ? + t_softerror dd ? + + +;--------- +; RFC 1323 ; the order of next 4 elements may not change + + SND_SCALE db ? + RCV_SCALE db ? + requested_s_scale db ? + request_r_scale db ? + + ts_recent dd ? ; a copy of the most-recent valid timestamp from the other end + ts_recent_age dd ? + last_ack_sent dd ? + + +;------- +; Timers + timer_retransmission dd ? ; rexmt + timer_persist dd ? + timer_keepalive dd ? ; keepalive/syn timeout + timer_timed_wait dd ? ; also used as 2msl timer + +; extra + + ts_ecr dd ? ; timestamp echo reply + ts_val dd ? + temp_bits db ? + +ends + +struct UDP_SOCKET IP_SOCKET + + LocalPort dw ? ; network byte order + RemotePort dw ? ; network byte order + firstpacket db ? + +ends + + +struct ICMP_SOCKET IP_SOCKET + + Identifier dw ? + +ends + + +struct RING_BUFFER + + start_ptr dd ? ; Pointer to start of buffer + end_ptr dd ? ; pointer to end of buffer + read_ptr dd ? ; Read pointer + write_ptr dd ? ; Write pointer + size dd ? ; Number of bytes buffered + +ends + +struct STREAM_SOCKET TCP_SOCKET + + rcv RING_BUFFER + snd RING_BUFFER + +ends \ No newline at end of file diff --git a/programs/network/socketdbg/socketdbg.asm b/programs/network/socketdbg/socketdbg.asm new file mode 100644 index 0000000000..7723d23787 --- /dev/null +++ b/programs/network/socketdbg/socketdbg.asm @@ -0,0 +1,100 @@ +format binary as "" + +use32 +; standard header + db 'MENUET01' ; signature + dd 1 ; header version + dd start ; entry point + dd i_end ; initialized size + dd mem ; required memory + dd mem ; stack pointer + dd 0 ; parameters + dd 0 ; path + +; useful includes +include '../macros.inc' +purge mov,add,sub +include '../proc32.inc' +include '../dll.inc' + +include '../struct.inc' + +include 'socket.inc' + +; entry point +start: + mcall 40, 0 ; we dont want any events +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit +; initialize console + push 1 + call [con_start] + push title + push -1 + push -1 + push -1 + push -1 + call [con_init] +; main loop +main: + mcall 75, 255, 0, socket_list ; get current socket list + + call [con_cls] + + mov esi, socket_list + .loop: + lodsd + test eax, eax + jz .done + + mov ecx, eax + mcall 75, 255, , socket_buf + + pushd [socket_buf + SOCKET.state] + pushd [socket_buf + SOCKET.PID] + pushd [socket_buf + SOCKET.Number] + push str_sock + call [con_printf] + add esp, 4 + + jmp .loop + + .done: + + mcall 23, 50 + + jmp main + + + push 0 + call [con_exit] +exit: + mcall -1 + +; data +title db 'Socket debugger', 0 + +str_sock db 'Socket=%d PID=%d state=%d', 10, 0 + +; import +align 4 +@IMPORT: + +library console, 'console.obj' + +import console, \ + con_start, 'START', \ + con_init, 'con_init', \ + con_cls, 'con_cls', \ + con_exit, 'con_exit', \ + con_printf, 'con_printf' +i_end: + +socket_list rd 4096 +socket_buf rd 4096 + +align 4 +rb 4096 ; stack +mem: diff --git a/programs/network/struct.inc b/programs/network/struct.inc new file mode 100644 index 0000000000..37f0b65b72 --- /dev/null +++ b/programs/network/struct.inc @@ -0,0 +1,240 @@ + +; Macroinstructions for defining data structures + +macro struct name + { virtual at 0 + fields@struct equ name + match child parent, name \{ fields@struct equ child,fields@\#parent \} + sub@struct equ + struc db [val] \{ \common define field@struct .,db, + fields@struct equ fields@struct,field@struct \} + struc dw [val] \{ \common define field@struct .,dw, + fields@struct equ fields@struct,field@struct \} + struc du [val] \{ \common define field@struct .,du, + fields@struct equ fields@struct,field@struct \} + struc dd [val] \{ \common define field@struct .,dd, + fields@struct equ fields@struct,field@struct \} + struc dp [val] \{ \common define field@struct .,dp, + fields@struct equ fields@struct,field@struct \} + struc dq [val] \{ \common define field@struct .,dq, + fields@struct equ fields@struct,field@struct \} + struc dt [val] \{ \common define field@struct .,dt, + fields@struct equ fields@struct,field@struct \} + struc rb count \{ define field@struct .,db,count dup (?) + fields@struct equ fields@struct,field@struct \} + struc rw count \{ define field@struct .,dw,count dup (?) + fields@struct equ fields@struct,field@struct \} + struc rd count \{ define field@struct .,dd,count dup (?) + fields@struct equ fields@struct,field@struct \} + struc rp count \{ define field@struct .,dp,count dup (?) + fields@struct equ fields@struct,field@struct \} + struc rq count \{ define field@struct .,dq,count dup (?) + fields@struct equ fields@struct,field@struct \} + struc rt count \{ define field@struct .,dt,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro db [val] \{ \common \local anonymous + define field@struct anonymous,db, + fields@struct equ fields@struct,field@struct \} + macro dw [val] \{ \common \local anonymous + define field@struct anonymous,dw, + fields@struct equ fields@struct,field@struct \} + macro du [val] \{ \common \local anonymous + define field@struct anonymous,du, + fields@struct equ fields@struct,field@struct \} + macro dd [val] \{ \common \local anonymous + define field@struct anonymous,dd, + fields@struct equ fields@struct,field@struct \} + macro dp [val] \{ \common \local anonymous + define field@struct anonymous,dp, + fields@struct equ fields@struct,field@struct \} + macro dq [val] \{ \common \local anonymous + define field@struct anonymous,dq, + fields@struct equ fields@struct,field@struct \} + macro dt [val] \{ \common \local anonymous + define field@struct anonymous,dt, + fields@struct equ fields@struct,field@struct \} + macro rb count \{ \local anonymous + define field@struct anonymous,db,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro rw count \{ \local anonymous + define field@struct anonymous,dw,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro rd count \{ \local anonymous + define field@struct anonymous,dd,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro rp count \{ \local anonymous + define field@struct anonymous,dp,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro rq count \{ \local anonymous + define field@struct anonymous,dq,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro rt count \{ \local anonymous + define field@struct anonymous,dt,count dup (?) + fields@struct equ fields@struct,field@struct \} + macro union \{ fields@struct equ fields@struct,,union,< + sub@struct equ union \} + macro struct \{ fields@struct equ fields@struct,,substruct,< + sub@struct equ substruct \} } + +macro ends + { match , sub@struct \{ restruc db,dw,du,dd,dp,dq,dt + restruc rb,rw,rd,rp,rq,rt + purge db,dw,du,dd,dp,dq,dt + purge rb,rw,rd,rp,rq,rt + purge union,struct + match name tail,fields@struct, \\{ if $ + display 'Error: definition of ',\\`name,' contains illegal instructions.',0Dh,0Ah + err + end if \\} + match name=,fields,fields@struct \\{ fields@struct equ + make@struct name,fields + define fields@\\#name fields \\} + end virtual \} + match any, sub@struct \{ fields@struct equ fields@struct> \} + restore sub@struct } + +macro make@struct name,[field,type,def] + { common + local define + define equ name + forward + local sub + match , field \{ make@substruct type,name,sub def + define equ define,.,sub, \} + match any, field \{ define equ define,.#field,type, \} + common + match fields, define \{ define@struct fields \} } + +macro define@struct name,[field,type,def] + { common + virtual + db `name + load initial@struct byte from 0 + if initial@struct = '.' + display 'Error: name of structure should not begin with a dot.',0Dh,0Ah + err + end if + end virtual + local list + list equ + forward + if ~ field eq . + name#field type def + sizeof.#name#field = $ - name#field + else + label name#.#type + rb sizeof.#type + end if + local value + match any, list \{ list equ list, \} + list equ list + common + sizeof.#name = $ + restruc name + match values, list \{ + struc name value \\{ \\local \\..base + match any, fields@struct \\\{ fields@struct equ fields@struct,.,name, \\\} + match , fields@struct \\\{ label \\..base + forward + match , value \\\\{ field type def \\\\} + match any, value \\\\{ field type value + if ~ field eq . + rb sizeof.#name#field - ($-field) + end if \\\\} + common label . at \\..base \\\} + \\} + macro name value \\{ + match any, fields@struct \\\{ \\\local anonymous + fields@struct equ fields@struct,anonymous,name, \\\} + match , fields@struct \\\{ + forward + match , value \\\\{ type def \\\\} + match any, value \\\\{ \\\\local ..field + ..field = $ + type value + if ~ field eq . + rb sizeof.#name#field - ($-..field) + end if \\\\} + common \\\} \\} \} } + +macro enable@substruct + { macro make@substruct substruct,parent,name,[field,type,def] + \{ \common + \local define + define equ parent,name + \forward + \local sub + match , field \\{ match any, type \\\{ enable@substruct + make@substruct type,parent,sub def + purge make@substruct + define equ define,.,sub, \\\} \\} + match any, field \\{ define equ define,.\#field,type, \\} + \common + match fields, define \\{ define@\#substruct fields \\} \} } + +enable@substruct + +macro define@union parent,name,[field,type,def] + { common + virtual at parent#.#name + forward + if ~ field eq . + virtual at parent#.#name + parent#field type def + sizeof.#parent#field = $ - parent#field + end virtual + if sizeof.#parent#field > $ - parent#.#name + rb sizeof.#parent#field - ($ - parent#.#name) + end if + else + virtual at parent#.#name + label parent#.#type + type def + end virtual + label name#.#type at parent#.#name + if sizeof.#type > $ - parent#.#name + rb sizeof.#type - ($ - parent#.#name) + end if + end if + common + sizeof.#name = $ - parent#.#name + end virtual + struc name [value] \{ \common + label .\#name + last@union equ + forward + match any, last@union \\{ virtual at .\#name + field type def + end virtual \\} + match , last@union \\{ match , value \\\{ field type def \\\} + match any, value \\\{ field type value \\\} \\} + last@union equ field + common rb sizeof.#name - ($ - .\#name) \} + macro name [value] \{ \common \local ..anonymous + ..anonymous name value \} } + +macro define@substruct parent,name,[field,type,def] + { common + virtual at parent#.#name + forward + if ~ field eq . + parent#field type def + sizeof.#parent#field = $ - parent#field + else + label parent#.#type + rb sizeof.#type + end if + common + sizeof.#name = $ - parent#.#name + end virtual + struc name value \{ + label .\#name + forward + match , value \\{ field type def \\} + match any, value \\{ field type value + if ~ field eq . + rb sizeof.#parent#field - ($-field) + end if \\} + common \} + macro name value \{ \local ..anonymous + ..anonymous name \} } diff --git a/programs/network/synergyc/synergyc.asm b/programs/network/synergyc/synergyc.asm new file mode 100644 index 0000000000..b2c20fb3be --- /dev/null +++ b/programs/network/synergyc/synergyc.asm @@ -0,0 +1,384 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2010-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; Synergyc.asm - Synergy client for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format binary as "" + +use32 + org 0x0 + + db 'MENUET01' ; signature + dd 1 ; header version + dd start ; entry point + dd i_end ; initialized size + dd mem+0x1000 ; required memory + dd mem+0x1000 ; stack pointer + dd 0 ; parameters + dd path ; path + +__DEBUG__ equ 1 ; enable/disable +__DEBUG_LEVEL__ equ 1 ; 1 = all, 2 = errors + + +BUFFERSIZE equ 1024 +DEFAULTPORT equ 24800 + +include '../macros.inc' +purge mov,add,sub +include '../proc32.inc' +include '../dll.inc' + +include '../network.inc' + +start: + + cld + mov edi, path ; Calculate the length of zero-terminated string + xor al, al + mov ecx, 1024 + repne scasb + dec edi + mov esi, filename ; append the path with '.ini' + movsd + movsb + + mcall 68, 11 + + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit + + push 1 + call [con_start] + + push title + push 25 + push 80 + push 25 + push 80 + call [con_init] + + push path + call [con_write_asciiz] + + push newline + call [con_write_asciiz] + + push newline + call [con_write_asciiz] + + invoke ini.get_str, path, str_remote, str_ip, buffer_ptr, 16, 0 + test eax, eax + jnz error + + invoke ini.get_int, path, str_remote, str_port, DEFAULTPORT + xchg al, ah + mov [sockaddr1.port], ax + + push str1 + call [con_write_asciiz] + + push buffer_ptr + call [con_write_asciiz] + + push newline + call [con_write_asciiz] + + mcall socket, AF_INET4, SOCK_STREAM, 0 + cmp eax, -1 + je error + + mov [socketnum], eax + + push buffer_ptr ; hostname + call [inet_addr] + cmp eax, -1 + je error + mov [sockaddr1.ip], eax + + mcall connect, [socketnum], sockaddr1, 18 + + push str7 + call [con_write_asciiz] + + mcall 40, 1 shl 7; + 7 + +login: + call wait_for_data + + push buffer_ptr + 4 + call [con_write_asciiz] + + cmp dword [buffer_ptr], 11 shl 24 + jne login + cmp dword [buffer_ptr + 4], 'Syne' + jne login + cmp word [buffer_ptr + 8], 'rg' + jne login + cmp byte [buffer_ptr + 10], 'y' + jne login + + push str2 + call [con_write_asciiz] + + lea edi, [buffer_ptr + 11 + 4 + 4] + invoke ini.get_str, path, str_local, str_name, edi, 255, 0 + xor al , al + mov ecx, 256 + repne scasb + sub edi, buffer_ptr + 1 + 4 + mov esi, edi + bswap edi + mov dword [buffer_ptr], edi + mov edi, esi + sub edi, 11 + 4 + bswap edi + mov dword [buffer_ptr + 11 + 4], edi + add esi, 4 + + mcall send, [socketnum], buffer_ptr, , 0 + +mainloop: + call wait_for_data + mov edi, buffer_ptr + + .command: + push eax edi + + cmp dword [edi + 4], 'QINF' ; query screen info + je .qinf + + cmp dword [edi + 4], 'CALV' ; alive ? + je .calv + + cmp dword [edi + 4], 'CINN' ; mouse moved into screen + je .cinn + + cmp dword [edi + 4], 'DCLP' ; Clipboard event + je .dclp + + cmp dword [edi + 4], 'DMMV' ; Mouse moved + je .dmmv + + cmp dword [edi + 4], 'COUT' ; leave screen + je .cout + + cmp dword [edi + 4], 'DMDN' ; mouse button down + je .dmdn + + cmp dword [edi + 4], 'DMUP' ; mouse button released + je .dmup + + cmp dword [edi + 4], 'CNOP' ; no operation + je .next + + cmp dword [edi + 4], 'CIAK' ; resolution changed? + je .ciak + + push str3 + call [con_write_asciiz] + + mov byte[edi+8],0 + add edi, 4 + push edi + call [con_write_asciiz] + + push newline + call [con_write_asciiz] + + .next: + pop edi eax + + mov ecx, dword [edi] + bswap ecx + add ecx, 4 + sub eax, ecx + jle mainloop + add edi, ecx + jmp .command + + + .qinf: + mcall 14 ; get screen info + add eax, 0x00010001 + bswap eax + mov dword [screeninfo.size], eax + mcall send, [socketnum], screeninfo, screeninfo.length, 0 ; send client name + jmp .next + + + .calv: + mcall send, [socketnum], calv, calv.length, 0 ; looks like ping-pong event + jmp .next + + + .cinn: + mov edx, [edi + 8] + bswap edx + mcall 18, 19, 4 + ; ignore sequence number and modify key mask for now + push str6 + call [con_write_asciiz] + jmp .next + + .dclp: + + jmp .next + + .dmmv: + mov edx, [edi + 8] + bswap edx + mcall 18, 19, 4 + mcall send, [socketnum], cnop, cnop.length, 0 ; reply with NOP + push str4 + call [con_write_asciiz] + jmp .next + + .cout: + jmp .next + + .dmdn: + movzx eax, byte [edi + 8] + or [mousestate], eax + mcall 18, 19, 5, [mousestate] + mcall send, [socketnum], cnop, cnop.length, 0 ; reply with NOP + push str5 + call [con_write_asciiz] + jmp .next + + .dmup: + movzx eax, byte [edi + 8] + not eax + and [mousestate], eax + mcall 18, 19, 5, [mousestate] + mcall send, [socketnum], cnop, cnop.length, 0 ; reply with NOP + push str5 + call [con_write_asciiz] + jmp .next + + .ciak: + jmp .next + +error: + push str_err + call [con_write_asciiz] + + call [con_gets] + + push 1 + call [con_exit] + + mcall close, [socketnum] +exit: + + mcall -1 + + +wait_for_data: + mcall 10 ; wait for data + + mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, 0 + cmp eax, -1 + je wait_for_data + + cmp eax, 8 + jl wait_for_data + + ret + + + +; data +title db 'Synergy client',0 +str1 db 'Connecting to: ',0 +str7 db 'Connected!',13,10,0 +str2 db 13,10,'Handshake received',13,10,0 +str3 db 'Unsupported command: ',0 +newline db 13,10,0 +str4 db 'mouse moved',13,10,0 +str5 db 'mouse buttons changed',13,10,0 +str6 db 'Enter screen',13,10,0 +str_err db 'Error occured !',13,10,'Press any key to quit',0 + +screeninfo: + dd (screeninfo.length - 4) shl 24 + db 'DINF' + dw 0 ; coordinate of leftmost pixel + dw 0 ; coordiante of topmost pixel + .size: + dw 0 ; width + dw 0 ; height + + dw 0 ; size of warp zone + + dw 0xb88b ; x position of the mouse on the secondary screen (no idea what it means) + dw 0xbcfb ; y position of the mouse on the secondary screen + .length = $ - screeninfo + +calv: + dd (4) shl 24 + db 'CALV' + .length = $ - calv + 8 ; also send cnop + +cnop: + dd (4) shl 24 + db 'CNOP' + .length = $ - cnop + +mousestate dd 0 + + +sockaddr1: + dw AF_INET4 +.port dw 0 +.ip dd 192 + 168 shl 8 + 1 shl 16 + 115 shl 24 + rb 10 + +filename db '.ini', 0 +str_local db 'local', 0 +str_name db 'name', 0 +str_remote db 'remote', 0 +str_port db 'port', 0 +str_ip db 'ip', 0 + +; import +align 16 +@IMPORT: + +library console, 'console.obj',\ + network, 'network.obj',\ + libini, 'libini.obj' + +import network,\ + inet_addr, 'inet_addr' + +import console, \ + con_start, 'START',\ + con_init, 'con_init',\ + con_write_asciiz, 'con_write_asciiz',\ + con_exit, 'con_exit',\ + con_gets, 'con_gets',\ + con_cls, 'con_cls',\ + con_getch2, 'con_getch2',\ + con_set_cursor_pos, 'con_set_cursor_pos' + +import libini,\ + ini.get_str, 'ini_get_str',\ + ini.get_int, 'ini_get_int' + +align 4 +i_end: +socketnum dd ? +buffer_ptr rb BUFFERSIZE +path rb 4096 ; stack +mem: \ No newline at end of file diff --git a/programs/network/synergyc/synergyc.ini b/programs/network/synergyc/synergyc.ini new file mode 100644 index 0000000000..35acd986a4 --- /dev/null +++ b/programs/network/synergyc/synergyc.ini @@ -0,0 +1,6 @@ +[local] +name = karaboeia + +[remote] +ip = 192.168.1.115 +port = 24800 diff --git a/programs/network/tcpserv/tcpserv.asm b/programs/network/tcpserv/tcpserv.asm new file mode 100644 index 0000000000..6e71f2b468 --- /dev/null +++ b/programs/network/tcpserv/tcpserv.asm @@ -0,0 +1,168 @@ +format binary as "" + +use32 +; standard header + db 'MENUET01' ; signature + dd 1 ; header version + dd start ; entry point + dd i_end ; initialized size + dd mem ; required memory + dd mem ; stack pointer + dd 0 ; parameters + dd 0 ; path + + +BUFFERSIZE equ 1500 +; useful includes +include '../macros.inc' +purge mov,add,sub +include '../proc32.inc' +include '../dll.inc' + +include '../network.inc' + +; entry point +start: +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit + +; initialize console + push 1 + call [con_start] + push title + push 25 + push 80 + push 25 + push 80 + call [con_init] + + mcall 40, 1 shl 7 ; we only want network events + + push str1 + call [con_write_asciiz] + + mcall socket, AF_INET4, SOCK_STREAM, 0 + cmp eax, -1 + je sock_err + + mov [socketnum], eax + +;; mcall setsockopt, [socketnum], SOL_SOCKET, SO_REUSEADDR, &yes, +;; cmp eax, -1 +;; je opt_err + + mcall bind, [socketnum], sockaddr1, sockaddr1.length + cmp eax, -1 + je bind_err + + mcall listen, [socketnum], 10 ; Backlog = 10 + cmp eax, -1 + je listen_err + + push str2 + call [con_write_asciiz] + + mcall 10 + + mcall accept, [socketnum], sockaddr1, sockaddr1.length + cmp eax, -1 + je acpt_err + + mov [socketnum2], eax + +;; mcall close, [socketnum] + + mcall send, [socketnum2], hello, hello.length + + .loop: + mcall 10 + + mcall recv, [socketnum2], buffer, buffer.length + cmp eax, -1 + je .loop + + mov byte [buffer + eax], 0 + + push buffer + call [con_write_asciiz] + + jmp .loop + +acpt_err: + push str8 + call [con_write_asciiz] + jmp done + +listen_err: + push str3 + call [con_write_asciiz] + jmp done + +bind_err: + push str4 + call [con_write_asciiz] + jmp done + +sock_err: + push str6 + call [con_write_asciiz] + jmp done + +done: + call [con_getch2] + push 1 + call [con_exit] +exit: + mcall -1 + + + +; data +title db 'TCP stream server - test',0 +str1 db 'Opening socket',10, 0 +str2 db 'Listening for incoming connections...',10,0 +str3 db 'Listen error',10,10,0 +str4 db 'Bind error',10,10,0 +str5 db 'Setsockopt error.',10,10,0 +str6 db 'Could not open socket',10,10,0 +str7 db 'Got data!',10,10,0 +str8 db 'Error accepting connection',10,10,0 + +hello db 'Hello world!',0 +.length = $ - hello + +sockaddr1: + dw AF_INET4 +.port dw 0x1700 ; 23 +.ip dd 0 + rb 10 +.length = $ - sockaddr1 + +; import +align 4 +@IMPORT: + +library console, 'console.obj' + +import console, \ + con_start, 'START', \ + con_init, 'con_init', \ + con_write_asciiz, 'con_write_asciiz', \ + con_exit, 'con_exit', \ + con_gets, 'con_gets',\ + con_cls, 'con_cls',\ + con_printf, 'con_printf',\ + con_getch2, 'con_getch2',\ + con_set_cursor_pos, 'con_set_cursor_pos' +i_end: + +socketnum dd ? +socketnum2 dd ? +buffer rb BUFFERSIZE +.length = BUFFERSIZE + +align 4 +rb 4096 ; stack +mem: diff --git a/programs/network/telnet/telnet.asm b/programs/network/telnet/telnet.asm new file mode 100644 index 0000000000..2fc34048c6 --- /dev/null +++ b/programs/network/telnet/telnet.asm @@ -0,0 +1,305 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2010-2012. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; telnet.asm - Telnet client for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format binary as "" + +__DEBUG__ equ 0 +__DEBUG_LEVEL__ equ 1 +BUFFERSIZE equ 4096 + +use32 +; standard header + db 'MENUET01' ; signature + dd 1 ; header version + dd start ; entry point + dd i_end ; initialized size + dd mem ; required memory + dd mem ; stack pointer + dd s ; parameters + dd 0 ; path + +include '../macros.inc' +purge mov,add,sub +include '../proc32.inc' +include '../dll.inc' +include '../debug-fdo.inc' +include '../network.inc' + +; entry point +start: +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit +; initialize console + push 1 + call [con_start] + push title + push 25 + push 80 + push 25 + push 80 + call [con_init] + +; Check for parameters + cmp byte [s], 0 + jne resolve + +main: + call [con_cls] +; Welcome user + push str1 + call [con_write_asciiz] + +; write prompt + push str2 + call [con_write_asciiz] +; read string + mov esi, s + push 256 + push esi + call [con_gets] +; check for exit + test eax, eax + jz done + cmp byte [esi], 10 + jz done + +resolve: + +; delete terminating '\n' + mov esi, s + @@: + lodsb + cmp al, 0x20 + ja @r + mov byte [esi-1], 0 + + call [con_cls] + push str3 + call [con_write_asciiz] + push s + call [con_write_asciiz] + +; resolve name + push esp ; reserve stack place + push esp ; fourth parameter + push 0 ; third parameter + push 0 ; second parameter + push s ; first parameter + call [getaddrinfo] + pop esi +; test for error + test eax, eax + jnz fail + +; write results + push str8 + call [con_write_asciiz] +; mov edi, esi + +; convert IP address to decimal notation + mov eax, [esi+addrinfo.ai_addr] + mov eax, [eax+sockaddr_in.sin_addr] + mov [sockaddr1.ip], eax + push eax + call [inet_ntoa] +; write result + push eax + call [con_write_asciiz] +; free allocated memory + push esi + call [freeaddrinfo] + + push str9 + call [con_write_asciiz] + + mcall socket, AF_INET4, SOCK_STREAM, 0 + cmp eax, -1 + jz fail2 + mov [socketnum], eax + + mcall connect, [socketnum], sockaddr1, 18 + + mcall 40, 1 shl 7 ; + 7 + call [con_cls] + + mcall 18, 7 + push eax + mcall 51, 1, thread, mem - 2048 + pop ecx + mcall 18, 3 + +mainloop: + DEBUGF 1, 'TELNET: Waiting for events\n' + mcall 10 + DEBUGF 1, 'TELNET: EVENT %x !\n', eax + + call [con_get_flags] + test eax, 0x200 ; con window closed? + jnz exit + + mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, 0 + cmp eax, -1 + je mainloop + + DEBUGF 1, 'TELNET: got %u bytes of data !\n', eax + + mov esi, buffer_ptr + lea edi, [esi + eax] + mov byte [edi], 0 + + .scan_cmd: + cmp byte [esi], 0xff ; Interpret As Command + jne .no_cmd + ; TODO: parse options, for now, we will reply with 'WONT' to everything + mov byte [esi + 1], 252 ; WONT + add esi, 3 ; a command is always 3 bytes + jmp .scan_cmd + .no_cmd: + + cmp esi, buffer_ptr + je .print_loop + + DEBUGF 1, 'TELNET: sending data\n' + + push esi edi + sub esi, buffer_ptr + mcall send, [socketnum], buffer_ptr, , 0 + pop edi esi + + .print_loop: + DEBUGF 1, 'TELNET: printloop\n' + cmp esi, edi + jae mainloop + + cmp byte [esi], 0x1b ; escape character + jne .print_byte + inc esi + + cmp word [esi], 0x485b ; move cursor to beginning + jne @f + inc esi + inc esi + + DEBUGF 1, 'TELNET: resetting cursor \n' + + push 0 + push 0 + call [con_set_cursor_pos] + jmp .print_loop + + @@: + inc esi + inc esi + jmp .print_loop + + .print_byte: + push dword 1 + push esi ; next string to print + inc esi + call [con_write_string] + jmp .print_loop + + +fail2: + push str6 + call [con_write_asciiz] + + jmp fail.wait + +fail: + push str5 + call [con_write_asciiz] + .wait: + push str10 + call [con_write_asciiz] + call [con_getch2] + jmp main + +done: + push 1 + call [con_exit] +exit: + + mcall close, [socketnum] + mcall -1 + + + +thread: + mcall 40, 0 + .loop: + call [con_getch2] + mov byte [send_data], al + mcall send, [socketnum], send_data, 1 + + call [con_get_flags] + test eax, 0x200 ; con window closed? + jz .loop + mcall -1 + +; data +title db 'Telnet',0 +str1 db 'Telnet for KolibriOS v0.11',10,10,'Please enter URL of telnet server (for example: towel.blinkenlights.nl)',10,10,0 +str2 db '> ',0 +str3 db 'Connecting to: ',0 +str4 db 10,0 +str5 db 10,'Name resolution failed.',10,0 +str6 db 10,'Could not open socket.',10,0 +str8 db ' (',0 +str9 db ')',10,0 +str10 db 'Push any key to continue.',0 + +sockaddr1: + dw AF_INET4 +.port dw 0x1700 ; 23 +.ip dd 0 + rb 10 + +include_debug_strings ; ALWAYS present in data section + + + +; import +align 4 +@IMPORT: + +library network, 'network.obj', console, 'console.obj' +import network, \ + getaddrinfo, 'getaddrinfo', \ + freeaddrinfo, 'freeaddrinfo', \ + inet_ntoa, 'inet_ntoa' +import console, \ + con_start, 'START', \ + con_init, 'con_init', \ + con_write_asciiz, 'con_write_asciiz', \ + con_exit, 'con_exit', \ + con_gets, 'con_gets',\ + con_cls, 'con_cls',\ + con_getch2, 'con_getch2',\ + con_set_cursor_pos, 'con_set_cursor_pos',\ + con_write_string, 'con_write_string',\ + con_get_flags, 'con_get_flags' + + +i_end: + +socketnum dd ? +buffer_ptr rb BUFFERSIZE+1 +send_data rb 100 + +s rb 1024 + rb 4096 ; stack +mem: diff --git a/programs/network/tftpc/tftpc.asm b/programs/network/tftpc/tftpc.asm new file mode 100644 index 0000000000..ff0ef744bf --- /dev/null +++ b/programs/network/tftpc/tftpc.asm @@ -0,0 +1,566 @@ +format binary as "" + +use32 + org 0x0 + + db 'MENUET01' + dd 0x1 + dd START + dd I_END + dd IM_END + dd IM_END + dd 0, 0 + +include '../proc32.inc' +include '../macros.inc' +include '../libio.inc' +include '../dll.inc' +include '../../../../../programs/develop/libraries/box_lib/trunk/box_lib.mac' + +include '../network.inc' + + +filebuffer_size equ 4*4096 ; 16kb (dont try to change it yet..) +TIMEOUT equ 100 +buffer_len equ 1500 + +AF_INET4 equ 2 +IP_PROTO_UDP equ 17 + +opcode_rrq equ 1 +opcode_wrq equ 2 +opcode_data equ 3 +opcode_ack equ 4 +opcode_error equ 5 + +; read/write request packet +; +; 2 bytes string 1 byte string 1 byte +; ------------------------------------------------ +; | Opcode | Filename | 0 | Mode | 0 | +; ------------------------------------------------ + +; data packet +; +; 2 bytes 2 bytes n bytes +; ---------------------------------- +; | Opcode | Block # | Data | +; ---------------------------------- + +; acknowledgement packet +; +; 2 bytes 2 bytes +; --------------------- +; | Opcode | Block # | +; --------------------- + +; error packet +; +; 2 bytes 2 bytes string 1 byte +; ---------------------------------------- +; | Opcode | ErrorCode | ErrMsg | 0 | +; ---------------------------------------- + + +START: + + mcall 68, 11 + + stdcall dll.Load, @IMPORT + or eax, eax + jnz exit + +stop_transfer: + mcall 40, 00100111b + +red_win: + call draw_window + +align 4 +still: + mcall 10 + + dec eax + jz red_win + + dec eax + jz key + + dec eax + jz button + + push dword edit1 + call [edit_box_mouse] + + push dword edit2 + call [edit_box_mouse] + + push dword edit3 + call [edit_box_mouse] + + push dword edit4 + call [edit_box_mouse] + + push dword Option_boxs1 + call [option_box_mouse] + + push dword Option_boxs2 + call [option_box_mouse] + + jmp still + +button: + mcall 17 + + cmp ah,0x10 + je start_transfer + + + test ah , ah + jz still + +exit: mcall -1 +key: + mcall 2 + + push dword edit1 + call [edit_box_key] + + push dword edit2 + call [edit_box_key] + + push dword edit3 + call [edit_box_key] + + push dword edit4 + call [edit_box_key] + + jmp still + + +align 4 +draw_window: + mcall 12,1 + mcall 0, (50*65536+400), (30*65536+180), 0x34AABBCC, 0x085080DD, str_title + + mcall 4, 35*65536+10, 0x80000000, str_server + + mov ebx, 5*65536+30 + mov edx, str_source + mcall + + mov ebx, 11*65536+50 + mov edx, str_destination + mcall + + mov ebx, 47*65536+72 + mov edx, str_mode + mcall + + mov ebx, 160*65536+72 + mov edx, str_method + mcall + + mov ebx, 270*65536+72 + mov edx, str_blocksize + mcall + + push dword edit1 + call [edit_box_draw] + + push dword edit2 + call [edit_box_draw] + + push dword edit3 + call [edit_box_draw] + + push dword edit4 + call [edit_box_draw] + + push dword Option_boxs1 + call [option_box_draw] + + push dword Option_boxs2 + call [option_box_draw] + + mcall 8,210*65536+170, 105*65536+16,0x00000010,0x085080DD + + mcall 4,260*65536+110, 0x80000000, str_transfer + + mcall 38,10*65536+380, 130*65536+130,0x00000000 + + mcall 4,350*65536+137, 0x80000000, str_kb_s + + mcall 47,1 shl 31 + 7 shl 16 + 1,kbps,305*65536+137,0x00000000 + + mcall 4,50*65536+137, 0x80000000, str_complete + + mcall 47,1 shl 31 + 3 shl 16 + 1,done,25*65536+137,0x00000000 + + mcall 12,2 + + ret + + + + + +start_transfer: + + ; first, resolve the hostname + + push esp ; reserve stack place + + push esp ; fourth parameter + push 0 ; third parameter + push 0 ; second parameter + push dword SRV ; first parameter + call [getaddrinfo] + + pop esi + +; test for error + test eax, eax + jnz still + + mov esi, [esi] + mov esi, [esi + sockaddr_in.sin_addr] + mov dword [IP], esi + + mcall socket, AF_INET4, SOCK_DGRAM, 0 ; socket_open + cmp eax, -1 + je still + + mov [socketnum], eax + + mcall connect, [socketnum], sockaddr, sockaddr_len ; socket_connect + cmp eax, -1 + je still + + mov word [I_END], opcode_rrq + cmp [option_group2],op3 + je @f + mov word [I_END], opcode_wrq + @@: + + xor al , al + mov edi, remote_addr + mov ecx, 250 + repnz scasb + sub edi, remote_addr-1 + mov ecx, edi + mov edi, I_END+2 + mov esi, remote_addr + rep movsb + + cmp [option_group1], op1 + je .ascii + + mov esi, octet + movsd + movsb + + jmp .send_request + + .ascii: + + mov esi, netascii + movsd + movsd + + .send_request: + + xor al, al + stosb + + sub edi, I_END + mov esi, edi + mcall send, [socketnum], I_END + + mcall 40, 10000101b + + mov [last_ack], 0 + + + + + + +receive_data_loop: + + mcall 23, TIMEOUT + + dec eax + jz .red + + dec eax + jz .key + + + mcall recv, [socketnum], buffer, buffer_len, 0 ; receive data + + cmp word[buffer], opcode_data + jne .error + + mov bx, [last_ack] + cmp word [buffer + 2], bx + jne .packet_got_lost + inc [last_ack] + + cmp eax, 4+512 + je .continue + +; last packet, or something else +.error: + +.packet_got_lost: + + + +.continue: + + mov word[buffer], opcode_ack ; send ack + mcall send, [socketnum], buffer, 4, 0 + + jmp receive_data_loop + +.red: + + call draw_window + + jmp receive_data_loop + + +.key: + mcall 2 + cmp ah, 2 + jz exit + + ; close socket ? + + jmp receive_data_loop + + + + + + +;-------------------------------- + + +send_: + + invoke file_open, local_addr, O_READ + or eax, eax + jz .exit + mov [fh], eax + + stdcall mem.Alloc, filebuffer_size + or eax, eax + jz .exit + mov [fb], eax + + mov [last_ack], 0 + mov [fo], 0 + +.read_chunk: + + invoke file_seek, [fh], [fo], SEEK_END + cmp eax, -1 + je .exit + invoke file_read, [fh], [fb], filebuffer_size + cmp eax, -1 + je .exit + add [fo], filebuffer_size + cmp eax, filebuffer_size + je .packet + + ; ijhidfhfdsndsfqk + +.packet: + + movzx esi, [last_ack] + and esi, 0x000000001f ; last five bits BUFFER SIZE MUST BE 16 kb for this to work !!! + shl esi, 9 ; = * 512 + add esi, [fb] + mov edi, buffer + mov ax, opcode_data + stosw + mov ax, [last_ack] + stosw + mov ecx, 512/4 + rep movsd + + mcall send, [socketnum], buffer, 4+512, 0 ; send data + + +.loop: + + mcall 23, TIMEOUT + + dec eax + jz .red + + dec eax + jz .key + + mcall recv, [socketnum], buffer, buffer_len, 0 ; receive ack + + cmp word[buffer], opcode_ack + jne .exit + + mov ax, [last_ack] + cmp word[buffer+2], ax + jne .packet + inc [last_ack] + test [last_ack],0x001f + jz .read_chunk + jmp .packet + + +.red: + + call draw_window + + jmp .loop + + +.key: + mcall 2 + cmp ah, 2 + jz exit + + ; close socket ? + + jmp .loop + +.exit: + invoke file_close, [fh] + jmp still + + + + + +;------------------------- +; DATA + +socketnum dd 0 +kbps dd 0 +done dd 0 + +sockaddr: + dw AF_INET4 + dw 0x4500 ; 69 +IP db 192,168,1,115 +sockaddr_len = $ - sockaddr + +align 16 +@IMPORT: + +library box_lib , 'box_lib.obj', \ + io_lib , 'libio.obj', \ + network , 'network.obj' + +import box_lib ,\ + edit_box_draw ,'edit_box' ,\ + edit_box_key ,'edit_box_key' ,\ + edit_box_mouse ,'edit_box_mouse' ,\ + version_ed ,'version_ed' ,\ + init_checkbox ,'init_checkbox2' ,\ + check_box_draw ,'check_box_draw2' ,\ + check_box_mouse ,'check_box_mouse2' ,\ + version_ch ,'version_ch2' ,\ + option_box_draw ,'option_box_draw' ,\ + option_box_mouse ,'option_box_mouse' ,\ + version_op ,'version_op' + +import io_lib ,\ + file_find_first , 'file_find_first' ,\ + file_find_next , 'file_find_next' ,\ + file_find_close , 'file_find_close' ,\ + file_size , 'file_size' ,\ + file_open , 'file_open' ,\ + file_read , 'file_read' ,\ + file_write , 'file_write' ,\ + file_seek , 'file_seek' ,\ + file_tell , 'file_tell' ,\ + file_eof? , 'file_iseof' ,\ + file_seteof , 'file_seteof' ,\ + file_truncate , 'file_truncate' ,\ + file_close , 'file_close' + +import network ,\ + inet_ntoa , 'inet_ntoa' ,\ + getaddrinfo , 'getaddrinfo' ,\ + freeaddrinfo , 'freeaddrinfo' + + +edit1 edit_box 300,80,5 ,0xffffff,0x6f9480,0,0,0,99 ,SRV,mouse_dd,ed_focus, 11,11 +edit2 edit_box 300,80,25,0xffffff,0x6a9480,0,0,0,99 ,remote_addr,mouse_dd,ed_figure_only, 5,5 +edit3 edit_box 300,80,45,0xffffff,0x6a9480,0,0,0,99 ,local_addr,mouse_dd,ed_figure_only, 27,27 +edit4 edit_box 40,340,68,0xffffff,0x6a9480,0,0,0,5 ,BLK,mouse_dd,ed_figure_only, 3,3 + +op1 option_box option_group1,80,68,6,12,0xffffff,0,0,netascii,octet-netascii +op2 option_box option_group1,80,85,6,12,0xFFFFFF,0,0,octet,get-octet + +op3 option_box option_group2,210,68,6,12,0xffffff,0,0,get,put-get +op4 option_box option_group2,210,85,6,12,0xFFFFFF,0,0,put,BLK-put + +option_group1 dd op1 +option_group2 dd op3 +Option_boxs1 dd op1,op2,0 +Option_boxs2 dd op3,op4,0 + +str_title db 'TFTP client for KolibriOS',0 +str_server db 'Server:',0 +str_source db 'Remote file:',0 +str_destination db 'Local file:',0 +str_mode db 'Mode:',0 +str_method db 'Method:',0 +str_blocksize db 'Blocksize:',0 +str_kb_s db 'kb/s',0 +str_complete db '% complete',0 +str_transfer db 'Transfer',0 + +str_error: +._0 db 'Not defined, see error message (if any).',0 +._1 db 'File not found.',0 +._2 db 'Access violation.',0 +._3 db 'Disk full or allocation exceeded.',0 +._4 db 'Illegal TFTP operation.',0 +._5 db 'Unknown transfer ID.',0 +._6 db 'File already exists.',0 +._7 db 'No such user.',0 + + +netascii db 'NetASCII' +octet db 'Octet' +get db 'GET' +put db 'PUT' + +BLK db "512",0,0,0 + +last_ack dw ? + +fh dd ? ; file handle +fo dd ? ; file offset +fb dd ? ; file buffer + +SRV db "192.168.1.115",0 +rb (SRV + 256 - $) + +remote_addr db "IMG00",0 +rb (remote_addr + 256 - $) + +local_addr db "/hd0/1/KolibriOS/kernel.mnt",0 +rb (local_addr + 256 - $) + +I_END: +mouse_dd dd ? +buffer: +rb buffer_len + +rb 0x1000 ; stack + +IM_END: \ No newline at end of file diff --git a/programs/network/vncc/logon.inc b/programs/network/vncc/logon.inc new file mode 100644 index 0000000000..4e9c049cd7 --- /dev/null +++ b/programs/network/vncc/logon.inc @@ -0,0 +1,257 @@ +red_logon: + call draw_window_logon ; at first, draw the window + +still_logon: ; main cycle of application begins here + mov eax,10 ; wait here for event + mcall + +checkevent_logon: ; Check what event was called _logon: this will be used to return from textbox focus + + dec eax ; redraw request ? + jz red_logon + dec eax ; key in buffer ? + jz key_logon + dec eax ; button in buffer ? + jz button_logon + + jmp still_logon + + key_logon: ; key event handler + mov al,2 ; eax was zero so will now be 2 + mcall ; just read it and ignore + + cmp ah,13 + jne still_logon ; return to main loop + + ret ; enter key was pressed => return to logon + + button_logon: ; eax was zero so will now be 17 + mov al,17 ; get id + mcall + + cmp ah,1 ; close ? + jz close_logon + cmp ah,2 ; logon ? + je connect_logon + cmp ah,5 ; first ? + jz dstbtn_logon + + srcbtn_logon: + mov dword[addr],first + jmp rk_logon + + dstbtn_logon: + mov dword[addr],second + + rk_logon: + mov edi,[addr] ; load the address of the string + xor al,al ; mov al,0 ; the symbol we will search for + mov ecx,STRLEN+1 ; length of the string (+1) + cld ; search forward + repne scasb ; do search now + inc ecx ; we've found a zero or ecx became 0 + mov eax,STRLEN+1 + sub eax,ecx ; eax = address of <0> character + mov [temp],eax ; position + + cmp dword[addr],dword second + jne @f + mov dword [passlen],eax + @@: + + call print_text_logon + + mov edi,[addr] ; address of string + add edi,[temp] ; cursor position + + .waitev_logon: + mov eax,10 ; wait for event + mcall + cmp eax,2 ; button presed ? + jne checkevent_logon ; a key is pressed or redraw is nessesary, goto checkevent + mcall ; eax = 2, read button + shr eax,8 + cmp eax,8 + jnz .nobs_logon ; BACKSPACE + cmp edi,[addr] + jz .waitev_logon + dec edi + mov byte[edi],0 + + cmp dword[addr],second + jne @f + dec [passlen] + @@: + + call print_text_logon + jmp .waitev_logon + .nobs_logon: + cmp eax,13 ; ENTER + je still_logon + cmp eax,192 + jne .noclear_logon + xor al,al + mov edi,[addr] + mov ecx,STRLEN + rep stosb + mov edi,[addr] + call print_text_logon + jmp .waitev_logon + + .noclear_logon: + mov [edi],al + + cmp dword[addr],second + jne @f + inc [passlen] + @@: + + call print_text_logon + + inc edi + mov esi,[addr] + add esi,STRLEN + cmp esi,edi + jnz .waitev_logon + + jmp still_logon + + +; print strings (source & destination) +print_text_logon: +pusha + + mov eax, 8 + mov ebx, 105*65536+200 + mov ecx, 31*65536+13 + mov edx, 4 + mov esi, 0xEBEBEB + mcall + + cmp byte[mode],0 + je @f + + mov ecx, 49*65536+12 + inc edx + mcall + + @@: + mov eax, 4 ; function 4 _logon: write text to window + mov ebx, 107*65536+34 ; [x start] *65536 + [y start] + xor ecx, ecx ; color of text RRGGBB + mov edx, first ; pointer to text beginning + mov esi, STRLEN ; text length + mcall + + cmp byte[mode],0 + je dont_draw_pass + + add ebx,16 + mov edi,[passlen] + + @@: + cmp edi,0 + jle dont_draw_pass + + dec edi + mov edx, passchar + mov esi, 1 + mcall + add ebx,6*65536 + jmp @r + + dont_draw_pass: + +popa + ret + +close_logon: + or eax,-1 + mcall + +connect_logon: + ret + +draw_window_logon: + + mcall 12, 1 ; start window draw + pusha + ; DRAW WINDOW + xor eax, eax ; function 0 _logon: define and draw window + mov ebx, 160*65536+330 ; [x start] *65536 + [x size] + mov ecx, 160*65536+100 ; [y start] *65536 + [y size] + mov edx, 0x13DDDDDD ; color of work area RRGGBB + mov edi, title ; WINDOW LABEL + mcall + + mov eax, 8 ; LOGON BUTTON + mov ebx, 220*65536+85 + mov ecx, 63*65536+16 + mov edx, 2 + mov esi, 0xCCCCCC + mcall + + + call print_text_logon + + cmp byte[mode], 0 + je servermode_ + + mov eax, 4 ; function 4 write text to window + mov ebx, 25*65536+33 ; [x start] *65536 + [y start] + xor ecx, ecx + mov edx, userstr ; pointer to text beginning + mov esi, passstr-userstr ; text length + mcall + + add bl,19 + mov edx, passstr ; pointer to text beginning + mov esi, connectstr-passstr ; text length + mcall + + jmp drawtherest_ + + servermode_: + + mov eax, 4 ; function 4 write text to window + mov ebx, 25*65536+33 ; [x start] *65536 + [y start] + xor ecx, ecx + mov edx, serverstr ; pointer to text beginning + mov esi, userstr-serverstr ; text length + mcall + + drawtherest_: + + mov ebx, 240*65536+67 ; [x start] *65536 + [y start] + mov edx, connectstr ; pointer to text beginning + mov esi, connect_e-connectstr ; text length + mcall + + popa + inc ebx + mcall + + ret + + +; DATA AREA +title db 'Kolibrios VNC client by HIDNPLAYR',0 + +first: db '192.168.1.5' + rb STRLEN +second: rb STRLEN + +passchar db '*' +passlen dd 0 + +addr dd 0 +temp dd 0 +mode db 0 ; 0 = connection details, 1 = authentication + +serverstr: db 'server:' +userstr: db 'username:' +passstr: db 'password:' +connectstr: db 'connect !' +connect_e: + +I_END_logon: diff --git a/programs/network/VNCclient/raw.inc b/programs/network/vncc/raw.inc similarity index 100% rename from programs/network/VNCclient/raw.inc rename to programs/network/vncc/raw.inc diff --git a/programs/network/vncc/structs.inc b/programs/network/vncc/structs.inc new file mode 100644 index 0000000000..507bf6ca93 --- /dev/null +++ b/programs/network/vncc/structs.inc @@ -0,0 +1,22 @@ + +struct pixel_format + bpp db ? + depth db ? + big_endian db ? + true_color db ? + red_max dw ? + green_max dw ? + blue_max dw ? + red_shift db ? + green_shift db ? + blue_shift db ? + padding rb 3 +ends + +struct framebuffer + width dw ? + height dw ? + pixelformat pixel_format + name_length dd ? + name rb 256 +ends \ No newline at end of file diff --git a/programs/network/vncc/thread.inc b/programs/network/vncc/thread.inc new file mode 100644 index 0000000000..7bb7e3d8c5 --- /dev/null +++ b/programs/network/vncc/thread.inc @@ -0,0 +1,239 @@ + +thread_start: + + DEBUGF 1, 'I am the thread!\n' + + mcall 40, 1 shl 7 + +; resolve name + push esp ; reserve stack place + invoke getaddrinfo, first, 0, 0, esp + pop esi +; test for error + test eax, eax + jnz exit + + mov eax, [esi+addrinfo.ai_addr] + mov eax, [eax+sockaddr_in.sin_addr] + mov [sockaddr1.ip], eax + +; DEBUGF 1, 'Connecting to %u.%u.%u.%u:%u\n', \ +; [server_ip]:1, [server_ip+1]:1, \ +; [server_ip+2]:1, [server_ip+3]:1, \ +; [server_port]:2 + + mcall socket, AF_INET4, SOCK_STREAM, 0 + mov [socketnum], eax + mcall connect, [socketnum], sockaddr1, 18 + + call wait_for_data + + cmp dword [receive_buffer], 'RFB ' + jne no_rfb + DEBUGF 1, 'received: %s\n', receive_buffer + mcall send, [socketnum], handshake, 12, 0 + DEBUGF 1, 'Sending handshake: protocol version\n' + + call wait_for_data + + cmp dword [receive_buffer], 0x00000000 + je invalid_security + + cmp dword [receive_buffer], 0x01000000 + je no_security + + cmp dword [receive_buffer], 0x02000000 + je vnc_security + + jmp exit + +vnc_security: + mov byte[mode], 1 + call red_logon + +no_security: + mcall send, [socketnum], shared, 1, 0 + DEBUGF 1, 'Sending handshake: shared session?\n' + + mcall 23, 100*TIMEOUT + + call wait_for_data ; now the server should send init message + + DEBUGF 1, 'Serverinit: bpp: %u depth: %u bigendian: %u truecolor: %u\n', \ + [receive_buffer+framebuffer.pixelformat.bpp]:1, \ + [receive_buffer+framebuffer.pixelformat.depth]:1, \ + [receive_buffer+framebuffer.pixelformat.big_endian]:1, \ + [receive_buffer+framebuffer.pixelformat.true_color]:1 + + mov eax, dword [receive_buffer] + mov dword [fbur.width], eax + bswap eax + mov dword [screen], eax + + mcall send, [socketnum], pixel_format8, 20, 0 + DEBUGF 1, 'Sending pixel format\n' + call read_data + +; eth.write_tcp [socket],8,encodings +; DEBUGF 1,'Sending encoding info\n' +; call read_data + + mov byte [thread_ready], 1 + +request_rfb: + mov [fbur.inc], 2 + mcall send, [socketnum], fbur, 10, 0 + +thread_loop: + mcall 23, 100 + + call read_data ; Read the data into the buffer + +; cmp eax, 2 +; jb mainloop + + DEBUGF 1,'Data received, %u bytes\n', eax + + cmp byte [receive_buffer],0 + je framebufferupdate + + cmp byte [receive_buffer],1 + je setcolourmapentries + + cmp byte [receive_buffer],2 + je bell + + cmp byte [receive_buffer],3 + je servercuttext + + jmp thread_loop + +align 4 +framebufferupdate: + + mov ax, word [receive_buffer+2] + xchg al, ah + mov di, ax + DEBUGF 1, 'Framebufferupdate: %u frames\n', di + mov esi, receive_buffer+4 + jmp rectangle_loop + + +next_rectangle: + call drawbuffer + + dec di + test di, di + jz request_rfb + +rectangle_loop: + + mov edx, [esi] + bswap edx + mov ebx, edx + shr edx, 16 + mov [frame.x], dx + mov [frame.y], bx + add esi, 4 + mov ecx, [esi] + bswap ecx + mov eax, ecx + shr ecx, 16 + mov [frame.width], cx + mov [frame.height], ax + add esi, 4 + mov eax, [esi] + add esi, 4 + + mov ebx, esi + sub ebx, receive_buffer+12 + DEBUGF 1, 'frame: width=%u height=%u x=%u y=%u offset:%u encoding:',\ + [frame.width]:2, [frame.height]:2, [frame.x]:2, [frame.y]:2, ebx + + cmp eax, 0 + je encoding_raw +; cmp eax, 1 +; je encoding_copyrect + cmp eax, 2 + je encoding_RRE + cmp eax, 5 + je encoding_hextile + cmp eax, 16 + je encoding_ZRLE + + mov ebx, esi + sub ebx, receive_buffer+8 + DEBUGF 1, '\nunknown encoding: %u (offset %u)\n', eax, ebx + jmp bell + jmp thread_loop + +encoding_RRE: + + DEBUGF 1, 'RRE\n' + + jmp next_rectangle + +encoding_hextile: + + DEBUGF 1, 'hextile\n' + + jmp next_rectangle + +encoding_ZRLE: + + DEBUGF 1, 'ZRLE\n' + + jmp next_rectangle + +setcolourmapentries: + + DEBUGF 1, 'Server sent SetColourMapEntries message\n' + + jmp thread_loop + + +bell: + mcall 55, 55, , , beep + + jmp thread_loop + + +servercuttext: + + DEBUGF 1, 'Server cut text\n' + + jmp thread_loop + + +read_data: + + mov [datapointer], receive_buffer + .loop: + mcall 23, 100*TIMEOUT + mcall recv, [socketnum], [datapointer], 4096, 0 + cmp eax, -1 + je .done + + add [datapointer], eax + + cmp eax, 4096 + je .loop + + .done: + mov eax, [datapointer] + sub eax, receive_buffer + ret + + + +wait_for_data: + + mcall 23, 500 + mcall recv, [socketnum], receive_buffer, 4096, 0 + cmp eax, -1 + je wait_for_data + test eax, eax + jz wait_for_data + + ret + diff --git a/programs/network/vncc/vncc.asm b/programs/network/vncc/vncc.asm new file mode 100644 index 0000000000..9887fa1b6f --- /dev/null +++ b/programs/network/vncc/vncc.asm @@ -0,0 +1,283 @@ +; +; +; VNC Client for kolibrios by hidnplayr +; +; hidnplayr@gmail.com +; + +format binary as "" + +use32 + + org 0x0 + + db 'MENUET01' ; 8 byte id + dd 0x01 ; header version + dd START ; start of code + dd I_END ; size of image + dd IM_END ; memory for app + dd IM_END ; esp + dd 0x0 , 0x0 ; I_Param , I_Path + +__DEBUG__ equ 1 +__DEBUG_LEVEL__ equ 1 + +STRLEN = 64 ; password and server max length +xpos = 4 ; coordinates of image +ypos = 22 ; + +TIMEOUT = 5 ; timeout in seconds + +include '../macros.inc' +include '../debug-fdo.inc' +include '../proc32.inc' +include '../dll.inc' +include '../struct.inc' +include '../network.inc' + +include 'structs.inc' +include 'logon.inc' +include 'raw.inc' +include 'thread.inc' + +START: + + mcall 68, 11 ; init heap + +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit + + call red_logon + + mcall 40, 0 ; no events + mcall 67, 0, 0, 0, 0 ; resize the window (hide it) + mcall 51, 1, thread_start, thread_stack + + DEBUGF 1,'Thread created: %u\n', eax + + @@: + mcall 5, 10 + cmp byte [thread_ready], 0 + je @r + + mcall 40, 100111b ; mouse, button, key, redraw + + + mov edx, dword [screen] + movzx esi, dx + shr edx, 16 + add edx, 2*xpos + add esi, ypos+xpos + mcall 67, 10, 10 ; resize the window + +mainloop: + mcall 23, 50 ; wait for event, 0,5s timeout + + dec eax + jz redraw + + dec eax + jz key + + dec eax + jz button + + sub eax, 3 + jz mouse + + jmp mainloop + +key: + + DEBUGF 1,'Sending key event\n' + + mcall 2 + mov byte [keyevent.key+3], ah + + mcall send, [socketnum], keyevent, 8, 0 + jmp mainloop + +mouse: + + DEBUGF 1,'Sending mouse event\n' + + mcall 37, 1 ; get mouse pos + sub eax, xpos shl 16 + ypos + bswap eax + mov [pointerevent.x], ax + shr eax, 16 + mov [pointerevent.y], ax + + mcall 37, 2 ; get mouse buttons + test al, 00000010b ; test if right button was pressed (bit 1 in kolibri) + jz @f + add al, 00000010b ; in RFB protocol it is bit 2, so if we add bit 2 again, we'll get bit 3 and bit 1 will remain the same + @@: + mov [pointerevent.mask],al + + mcall send, [socketnum], pointerevent, 6, 0 + jmp mainloop + +redraw: + + DEBUGF 1,'Drawing window\n' + + mcall 12, 1 + + mov ebx, dword[screen] + movzx ecx, bx + shr ebx, 16 + mov edx, 0x74ffffff + mov edi, name + mcall 0 ; draw window + + call drawbuffer + + mcall 12, 2 + + jmp mainloop + +drawbuffer: + + mcall 7, framebuffer_data, dword[screen], 0 + ret + + +button: + mcall 17 ; get id + +exit: + DEBUGF 1, 'Closing time!\n' + mcall close, [socketnum] + mcall -1 + +no_rfb: + DEBUGF 1, 'This is no vnc server!\n' + jmp exit + +invalid_security: + DEBUGF 1, 'Security error: %s\n', receive_buffer+5 + jmp exit + + +; DATA AREA + +include_debug_strings ; ALWAYS present in data section + +handshake db 'RFB 003.003', 10 +shared db 0 +beep db 0x85,0x25,0x85,0x40,0 + +pixel_format32 db 0 ; setPixelformat + rb 3 ; padding +.bpp db 32 ; bits per pixel +.depth db 32 ; depth +.big_endian db 0 ; big-endian flag +.true_color db 1 ; true-colour flag +.red_max db 0,255 ; red-max +.green_max db 0,255 ; green-max +.blue_max db 0,255 ; blue-max +.red_shif db 0 ; red-shift +.green_shift db 8 ; green-shift +.blue_shift db 16 ; blue-shift + rb 3 ; padding + +pixel_format16 db 0 ; setPixelformat + rb 3 ; padding +.bpp db 16 ; bits per pixel +.depth db 15 ; depth +.big_endian db 0 ; big-endian flag +.true_color db 1 ; true-colour flag +.red_max db 0,31 ; red-max +.green_max db 0,31 ; green-max +.blue_max db 0,31 ; blue-max +.red_shif db 0 ; red-shift +.green_shift db 5 ; green-shift +.blue_shift db 10 ; blue-shift + rb 3 ; padding + +pixel_format8 db 0 ; setPixelformat + rb 3 ; padding +.bpp db 8 ; bits per pixel +.depth db 6 ; depth +.big_endian db 0 ; big-endian flag +.true_color db 1 ; true-colour flag +.red_max db 0,3 ; red-max +.green_max db 0,3 ; green-max +.blue_max db 0,3 ; blue-max +.red_shif db 0 ; red-shift +.green_shift db 2 ; green-shift +.blue_shift db 4 ; blue-shift + rb 3 ; padding + +encodings db 2 ; setEncodings + rb 1 ; padding + db 1,0 ; number of encodings + db 0,0,0,0 ; raw encoding (DWORD, Big endian order) + db 1,0,0,0 ; Copyrect encoding + +fbur db 3 ; frame buffer update request +.inc db 0 ; incremental +.x dw 0 +.y dw 0 +.width dw 0 +.height dw 0 + +keyevent db 4 ; keyevent +.down db 0 ; down-flag + dw 0 ; padding +.key dd 0 ; key + +pointerevent db 5 ; pointerevent +.mask db 0 ; button-mask +.x dw 0 ; x-position +.y dw 0 ; y-position + + +sockaddr1: + dw AF_INET4 +.port dw 0x0c17 ; 5900 +.ip dd 0 + rb 10 + +thread_ready db 0 +; import +align 4 +@IMPORT: + +library network, 'network.obj' +import network, \ + getaddrinfo, 'getaddrinfo', \ + freeaddrinfo, 'freeaddrinfo', \ + inet_ntoa, 'inet_ntoa' + +name db 'VNC client', 0 + +I_END: + +socketnum dd ? +datapointer dd ? + +frame: +.width dw ? +.height dw ? +.x dw ? +.y dw ? + +screen: +.height dw ? +.width dw ? + +receive_buffer rb 5*1024*1024 ; 5 mb buffer for received data (incoming frbupdate etc) +framebuffer_data rb 1024*768*3 ; framebuffer + + + rb 0x1000 +thread_stack: + + rb 0x1000 +IM_END: + + diff --git a/programs/network/zeroconf/trunk/dhcp.inc b/programs/network/zeroconf/dhcp.inc similarity index 100% rename from programs/network/zeroconf/trunk/dhcp.inc rename to programs/network/zeroconf/dhcp.inc diff --git a/programs/network/zeroconf/zeroconf.asm b/programs/network/zeroconf/zeroconf.asm new file mode 100644 index 0000000000..3fde8df43b --- /dev/null +++ b/programs/network/zeroconf/zeroconf.asm @@ -0,0 +1,620 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2010-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; zeroconfig.asm - Zeroconfig service for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; Some code contributed by Derpenguin ;; +;; ;; +;; DHCP code is based on that by Mike Hibbet ;; +; (DHCP client for menuetos) ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format binary as "" + +use32 + org 0x0 + + db 'MENUET01' ; 8 byte id + dd 0x01 ; header version + dd START ; start of code + dd IM_END ; size of image + dd (I_END+0x100) ; memory for app + dd (I_END+0x100) ; esp + dd 0, 0 ; I_Param, I_Path + +; CONFIGURATION + +TIMEOUT = 60 ; in seconds +BUFFER = 1024 ; in bytes +__DEBUG__ = 1 ; enable/disable +__DEBUG_LEVEL__ = 1 ; 1 = all, 2 = errors + +; CONFIGURATION FOR LINK-LOCAL + +PROBE_WAIT = 1 ; second (initial random delay) +PROBE_MIN = 1 ; second (minimum delay till repeated probe) +PROBE_MAX = 2 ; seconds (maximum delay till repeated probe) +PROBE_NUM = 3 ; (number of probe packets) + +ANNOUNCE_NUM = 2 ; (number of announcement packets) +ANNOUNCE_INTERVAL = 2 ; seconds (time between announcement packets) +ANNOUNCE_WAIT = 2 ; seconds (delay before announcing) + +MAX_CONFLICTS = 10 ; (max conflicts before rate limiting) + +RATE_LIMIT_INTERVAL = 60 ; seconds (delay between successive attempts) + +DEFEND_INTERVAL = 10 ; seconds (min. wait between defensive ARPs) + + +include '../proc32.inc' +include '../macros.inc' +include '../debug-fdo.inc' +include '../network.inc' +include 'dhcp.inc' +include '../dll.inc' + + +Ip2dword: + push edx + + ; This code validates if the query is an IP containing 4 numbers and 3 dots + + xor al, al ; make al (dot count) zero + + @@: + cmp byte[edx],'0' ; check if this byte is a number, if not jump to no_IP + jl no_IP ; + cmp byte[edx],'9' ; + jg no_IP ; + + inc edx ; the byte was a number, so lets check the next byte + + cmp byte[edx],0 ; is this byte zero? (have we reached end of query?) + jz @f ; jump to next @@ then + cmp byte[edx],':' + jz @f + + cmp byte[edx],'.' ; is this byte a dot? + jne @r ; if not, jump to previous @@ + + inc al ; the byte was a dot so increment al(dot count) + inc edx ; next byte + jmp @r ; lets check for numbers again (jump to previous @@) + + @@: ; we reach this when end of query reached + cmp al,3 ; check if there where 3 dots + jnz no_IP ; if not, jump to no_IP + + ; The following code will convert this IP into a dword and output it in eax + ; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1 + + pop esi ; edx (query address) was pushed onto stack and is now popped in esi + + xor edx, edx ; result + xor eax, eax ; current character + xor ebx, ebx ; current byte + + .outer_loop: + shl edx, 8 + add edx, ebx + xor ebx, ebx + .inner_loop: + lodsb + test eax, eax + jz .finish + cmp al, '.' + jz .outer_loop + sub eax, '0' + imul ebx, 10 + add ebx, eax + jmp .inner_loop + .finish: + shl edx, 8 + add edx, ebx + + bswap edx ; we want little endian order + + ret + +no_IP: + pop edx + xor edx, edx + + ret + + + + + + +START: + mcall 40, EVM_STACK2 + + DEBUGF 1,">Zero-config service loaded\n" + + .wait: + mcall 76, API_ETH + 4 ; get MAC of ethernet interface 0 + cmp eax, -1 + jne .start + + mcall 10 + jmp .wait + + .start: + mov word[MAC], bx + mov dword[MAC+2], eax + DEBUGF 1,"->MAC: %x-%x-%x-%x-%x-%x\n", [MAC+0]:2, [MAC+1]:2, [MAC+2]:2, [MAC+3]:2, [MAC+4]:2, [MAC+5]:2 + + mcall 40, EVM_STACK + + mcall 68, 11 + + stdcall dll.Load,@IMPORT + or eax, eax + jnz try_dhcp + + invoke ini.get_str, path, str_ipconfig, str_type, inibuf, 16, 0 + + cmp dword[inibuf], 'stat' + jne try_dhcp + + invoke ini.get_str, path, str_ipconfig, str_ip, inibuf, 16, 0 + mov edx, inibuf + call Ip2dword + mcall 76, API_IPv4 + 3, edx + + invoke ini.get_str, path, str_ipconfig, str_gateway, inibuf, 16, 0 + mov edx, inibuf + call Ip2dword + mcall 76, API_IPv4 + 9, edx + + invoke ini.get_str, path, str_ipconfig, str_dns, inibuf, 16, 0 + mov edx, inibuf + call Ip2dword + mcall 76, API_IPv4 + 5, edx + + invoke ini.get_str, path, str_ipconfig, str_subnet, inibuf, 16, 0 + mov edx, inibuf + call Ip2dword + mcall 76, API_IPv4 + 7, edx + + + mcall -1 + + +try_dhcp: + + DEBUGF 1,"->Trying DHCP\n" + + mcall 75, 0, AF_INET4, SOCK_DGRAM, 0 ; open socket (parameters: domain, type, reserved) + cmp eax, -1 + je error + mov [socketNum], eax + + DEBUGF 1,"->Socket %x opened\n", eax + + mcall 75, 2, [socketNum], sockaddr1, 18 ; bind socket to local port 68 + cmp eax, -1 + je error + + DEBUGF 1,"->Socket Bound to local port 68\n" + + mcall 75, 4, [socketNum], sockaddr2, 18 ; connect to 255.255.255.255 on port 67 + cmp eax, -1 + je error + + DEBUGF 1,"->Connected to 255.255.255.255 on port 67\n" + + mov [dhcpMsgType], 0x01 ; DHCP discover + mov [dhcpLease], esi ; esi is still -1 (-1 = forever) + + mcall 26, 9 ; Get system time + imul eax, 100 + mov [currTime], eax + +build_request: ; Creates a DHCP request packet. + + DEBUGF 1,"->Building request\n" + + stdcall mem.Alloc, BUFFER + mov [dhcpMsg], eax + test eax, eax + jz dhcp_error + + ;;; todo: skip this bullcrap + + mov edi, eax + mov ecx, BUFFER + xor eax, eax + rep stosb + + ;; todo: put this in a buffer instead of writing bytes and words! + + mov edx, [dhcpMsg] + + ; Boot protocol legacy + mov [edx], byte 0x01 ; Boot request + mov [edx+1], byte 0x01 ; Ethernet + mov [edx+2], byte 0x06 ; Ethernet h/w len + mov [edx+4], dword 0x11223344 ; xid ;;;;;;; + mov eax, [currTime] + mov [edx+8], eax ; secs, our uptime + mov [edx+10], byte 0x80 ; broadcast flag set + mov eax, dword [MAC] ; first 4 bytes of MAC + mov [edx+28],dword eax + mov ax, word [MAC+4] ; last 2 bytes of MAC + mov [edx+32],word ax + + ; DHCP extension + mov [edx+236], dword 0x63538263 ; magic cookie + mov [edx+240], word 0x0135 ; option DHCP msg type + mov al, [dhcpMsgType] + mov [edx+240+2], al + mov [edx+240+3], word 0x0433 ; option Lease time = infinity + mov eax, [dhcpLease] + mov [edx+240+5], eax + mov [edx+240+9], word 0x0432 ; option requested IP address + mov eax, [dhcp.ip] + mov [edx+240+11], eax + mov [edx+240+15], word 0x0437 ; option request list + mov [edx+240+17], dword 0x0f060301 + + cmp [dhcpMsgType], byte 0x01 ; Check which msg we are sending + jne request_options + + mov [edx+240+21], byte 0xff ; "Discover" options + + mov [dhcpMsgLen], dword 262 ; end of options marker + jmp send_dhcpmsg + +request_options: + mov [edx+240+21], word 0x0436 ; server IP + mov eax, [dhcpServerIP] + mov [edx+240+23], eax + + mov [edx+240+27], byte 0xff ; end of options marker + + mov [dhcpMsgLen], dword 268 + +send_dhcpmsg: + mcall 75, 6, [socketNum], [dhcpMsg], [dhcpMsgLen] ; write to socket ( send broadcast request ) + + mov eax, [dhcpMsg] ; Setup the DHCP buffer to receive response + mov [dhcpMsgLen], eax ; Used as a pointer to the data + + mcall 23, TIMEOUT*10 ; wait for data + +read_data: ; we have data - this will be the response + mcall 75, 7, [socketNum], [dhcpMsg], BUFFER ; read data from socket + + DEBUGF 1,"->%d bytes received\n", eax + + cmp eax, -1 + je dhcp_error + + mov [dhcpMsgLen], eax + +; depending on which msg we sent, handle the response +; accordingly. +; If the response is to a dhcp discover, then: +; 1) If response is DHCP OFFER then +; 1.1) record server IP, lease time & IP address. +; 1.2) send a request packet +; If the response is to a dhcp request, then: +; 1) If the response is DHCP ACK then +; 1.1) extract the DNS & subnet fields. Set them in the stack + + cmp [dhcpMsgType], 0x01 ; did we send a discover? + je discover + + cmp [dhcpMsgType], 0x03 ; did we send a request? + je request + + call dhcp_end ; we should never reach here ;) + jmp exit + +discover: + call parse_response + + cmp [dhcpMsgType], 0x02 ; Was the response an offer? + je send_request + + call dhcp_end + jmp link_local + +send_request: + mov [dhcpMsgType], 0x03 ; make it a request + jmp build_request + +request: + call parse_response + + cmp [dhcpMsgType], 0x05 ; Was the response an ACK? It should be + jne read_data ; NO - read next packets + + call dhcp_end + + mcall 76, API_IPv4 + 3, [dhcp.ip] ; ip + mcall 76, API_IPv4 + 5, [dhcp.dns] ; dns + mcall 76, API_IPv4 + 7, [dhcp.subnet] ; subnet + mcall 76, API_IPv4 + 9, [dhcp.gateway] ; gateway + + jmp exit + +dhcp_end: + mcall close, [socketNum] + stdcall mem.Free, [dhcpMsg] + + ret + +;*************************************************************************** +; Function +; parseResponse +; +; Description +; extracts the fields ( client IP address and options ) from +; a DHCP response +; The values go into +; dhcpMsgType,dhcpLease,dhcpClientIP,dhcpServerIP, +; dhcpDNSIP, dhcpSubnet +; The message is stored in dhcpMsg +; +;*************************************************************************** +parse_response: + + DEBUGF 1,"Data received, parsing response\n" + mov edx, [dhcpMsg] + + push dword [edx+16] + pop [dhcp.ip] + DEBUGF 1,"Client: %u.%u.%u.%u\n", [edx+16]:1, [edx+17]:1, [edx+18]:1, [edx+19]:1 + +; TODO: check if there really are options + + mov al, 240 ; Point to first option + movzx ecx, al + + .next_option: + add edx, ecx + + mov al, [edx] ; get message identifier + + cmp al, 0xff ; End of options? + je .done + + cmp al, 0 + je .pad + +; TODO: check if we still are inside the buffer + + inc edx + movzx ecx, byte [edx] ; get data length + inc edx ; point to data + + cmp al, dhcp_msg_type ; Msg type is a single byte option + je .msgtype + + cmp al, dhcp_dhcp_server_id + je .server + + cmp al, dhcp_address_time + je .lease + + cmp al, dhcp_subnet_mask + je .subnet + + cmp al, dhcp_router + je .router + + cmp al, dhcp_domain_server + je .dns + + DEBUGF 1,"Unsupported DHCP option: %u\n", al + + jmp .next_option + + .pad: + xor ecx, ecx + inc ecx + jmp .next_option + + .msgtype: + mov al, [edx] + mov [dhcpMsgType], al + + DEBUGF 1,"DHCP Msg type: %u\n", al + jmp .next_option ; Get next option + + .server: + mov eax, [edx] + mov [dhcpServerIP], eax + DEBUGF 1,"Server: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 + jmp .next_option + + .lease: + pusha + mov eax,[edx] + bswap eax + mov [dhcpLease],eax + DEBUGF 1,"lease: %d\n",eax + popa + jmp .next_option + + .subnet: + push dword [edx] + pop [dhcp.subnet] + DEBUGF 1,"Subnet: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 + jmp .next_option + + .router: + push dword [edx] + pop [dhcp.gateway] + DEBUGF 1,"Gateway: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 + jmp .next_option + + .dns: + push dword [edx] + pop [dhcp.dns] + DEBUGF 1,"DNS: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 + jmp .next_option + + .done: + ret + + + +dhcp_error: + call dhcp_end + +link_local: + call random + mov cx, ax + shl ecx, 16 + mov cx, 0xfea9 ; IP 169.254.0.0 link local net, see RFC3927 + mcall 76, API_IPv4 + 3, ecx ; mask is 255.255.0.0 + DEBUGF 1,"Link Local IP assinged: 169.254.%u.%u\n", [generator+0]:1, [generator+1]:1 + mcall 76, API_IPv4 + 7, 0xffff + mcall 76, API_IPv4 + 9, 0x0 + mcall 76, API_IPv4 + 5, 0x0 + + mcall 5, PROBE_WAIT*100 + + xor esi, esi + probe_loop: + call random ; create a pseudo random number in eax (seeded by MAC) + + cmp al, PROBE_MIN*100 ; check if al is bigger then PROBE_MIN + jae @f ; all ok + add al, (PROBE_MAX-PROBE_MIN)*100 ; al is too small + @@: + + cmp al, PROBE_MAX*100 + jbe @f + sub al, (PROBE_MAX-PROBE_MIN)*100 + @@: + + movzx ebx,al + DEBUGF 1,"Waiting %u0ms\n",ebx + mcall 5 + + DEBUGF 1,"Sending Probe\n" + mcall 76, API_ARP + 6 + inc esi + + cmp esi, PROBE_NUM + jb probe_loop + +; now we wait further ANNOUNCE_WAIT seconds and send ANNOUNCE_NUM ARP announces. If any other host has assingned +; IP within this time, we should create another adress, that have to be done later + + DEBUGF 1,"Waiting %us\n", ANNOUNCE_WAIT + mcall 5, ANNOUNCE_WAIT*100 + xor esi, esi + announce_loop: + + DEBUGF 1,"Sending Announce\n" + mcall 76, API_ARP + 6 + + inc esi + cmp esi,ANNOUNCE_NUM + je @f + + DEBUGF 1,"Waiting %us\n", ANNOUNCE_INTERVAL + mcall 5, ANNOUNCE_INTERVAL*100 + jmp announce_loop + @@: + + +error: + DEBUGF 1,"Socket error\n" +exit: ; we should, instead of closing, detect ARP conflicts and detect if cable keeps connected ;) + mcall -1 + + +random: ; Pseudo random actually + + mov eax, [generator] + add eax, -43ab45b5h + ror eax, 1 + bswap eax + xor eax, dword[MAC] + ror eax, 1 + xor eax, dword[MAC+2] + mov [generator], eax + + ret + +; DATA AREA + +align 16 +@IMPORT: + +library \ + libini,'libini.obj' + +import libini, \ + ini.get_str,'ini_get_str' + +include_debug_strings + +str_ip db 'ip', 0 +str_subnet db 'subnet', 0 +str_gateway db 'gateway', 0 +str_dns db 'dns', 0 +str_ipconfig db 'ipconfig', 0 +str_type db 'type', 0 + + +sockaddr1: + + dw AF_INET4 + dw 68 shl 8 ; local port + dd 0 ; local IP + + rb 10 + + +sockaddr2: + + dw AF_INET4 + dw 67 shl 8 ; destination port + dd -1 ; destination IP + + rb 10 + +path db '/sys/network.ini' + +IM_END: + +inibuf rb 16 + +dhcpMsgType db ? +dhcpLease dd ? +dhcpServerIP dd ? + +dhcp: +.ip dd ? +.subnet dd ? +.dns dd ? +.gateway dd ? + + +dhcpMsgLen dd ? +socketNum dd ? + +MAC dp ? + +currTime dd ? +generator dd ? + +dhcpMsg dd ? + +I_END: \ No newline at end of file diff --git a/programs/network/VNCclient/ETH.INC b/programs/network_old/VNCclient/ETH.INC similarity index 100% rename from programs/network/VNCclient/ETH.INC rename to programs/network_old/VNCclient/ETH.INC diff --git a/programs/network/VNCclient/VNCclient.asm b/programs/network_old/VNCclient/VNCclient.asm similarity index 100% rename from programs/network/VNCclient/VNCclient.asm rename to programs/network_old/VNCclient/VNCclient.asm diff --git a/programs/network/VNCclient/build.bat b/programs/network_old/VNCclient/build.bat similarity index 100% rename from programs/network/VNCclient/build.bat rename to programs/network_old/VNCclient/build.bat diff --git a/programs/network/VNCclient/copyrect.inc b/programs/network_old/VNCclient/copyrect.inc similarity index 100% rename from programs/network/VNCclient/copyrect.inc rename to programs/network_old/VNCclient/copyrect.inc diff --git a/programs/network/VNCclient/fdo.inc b/programs/network_old/VNCclient/fdo.inc similarity index 100% rename from programs/network/VNCclient/fdo.inc rename to programs/network_old/VNCclient/fdo.inc diff --git a/programs/network/VNCclient/logon.inc b/programs/network_old/VNCclient/logon.inc similarity index 100% rename from programs/network/VNCclient/logon.inc rename to programs/network_old/VNCclient/logon.inc diff --git a/programs/network_old/VNCclient/raw.inc b/programs/network_old/VNCclient/raw.inc new file mode 100644 index 0000000000..9ba6d6e0a8 --- /dev/null +++ b/programs/network_old/VNCclient/raw.inc @@ -0,0 +1,153 @@ + encoding_raw: + DEBUGF 1,'RAW\n' + + mov ax,[frame.y] ; + mov bx,[screen.width] ; + mul bx ; + shl edx,16 ; + mov dx,ax ; [screen.width]*[frame.y] + movzx eax,[frame.x] + add edx,eax ; [screen.width]*[frame.y]+[frame.x] + + mov eax,3 ; + mul edx ; ([screen.width]*[frame.y]+[frame.x])*3 + + add eax,framebuffer_data ; + push eax ; framebuffer_data+([screen.width]*[frame.y]+[frame.x])*3 + + mov ax,[frame.width] ; + mov bx,3 ; + mul bx ; + shl edx,16 ; + mov dx,ax ; [frame.width]*3 + + pop eax ; + add edx,eax ; framebuffer_data+([screen.width]*[frame.y]+[frame.x])*3+[frame.width]*3 + push eax ; + push edx ; + + mov ax,[frame.height] ; + dec ax ; + mov bx,3 ; + mul bx ; + mov bx,[screen.width] ; + mul bx ; + shl edx,16 ; + mov dx,ax ; + mov ecx,edx ; + pop edx ; + add ecx,edx ; mov ecx,edx+([frame.height]-1)*[screen.width]*3 + pop ebx + + .pixelloop32: + cmp ebx,ecx + jge next_rectangle + +; add esi,2 ; 32 bit code RAW - OK +; mov al,[esi] ; +; mov [ebx],al ; +; inc ebx ; +; dec esi ; +; ; +; mov al,[esi] ; +; mov [ebx],al ; +; inc ebx ; +; dec esi ; +; ; +; mov al,[esi] ; +; mov [ebx],al ; +; inc ebx ; +; add esi,4 ; + +; push ecx ; 16 bit code RAW +; mov cl,51 +; +; mov ax,[esi] ; +; xchg al,ah +; and al,00011111b ; +; xchg al,ah +; mul cl +; mov [ebx],al ; +; inc ebx ; +; +; mov ax,[esi] ; +; xchg al,ah +; shr ax,5 ; +; xchg al,ah +; and al,00011111b ; +; mul cl +; mov [ebx],al ; +; inc ebx ; +; +; mov ax,[esi] ; +; xchg al,ah +; shr ax,10 ; +; and al,00011111b ; +; mul cl +; mov [ebx],al ; +; inc ebx ; +; +; inc esi ; +; inc esi ; +; pop ecx + + push ecx ; 8 bit code RAW - OK + mov cl,85 ; + ; + mov al,[esi] ; + shr al,4 ; + and al,3 ; + mul cl ; + mov [ebx],al ; + inc ebx ; + ; + mov al,[esi] ; + shr al,2 ; + and al,3 ; + mul cl ; + mov [ebx],al ; + inc ebx ; + ; + mov al,[esi] ; + and al,3 ; + mul cl ; + mov byte[ebx],al ; + inc ebx ; + inc esi ; + pop ecx ; + + + cmp ebx,edx + jl .pixelloop32 + + push edx + push ebx + mov ax,[screen.width] + mov bx,3 + mul bx + shl edx,16 + mov dx,ax + mov eax,edx + pop ebx + pop edx + + add ebx,eax ; eax = [screen.width]*3 + add edx,eax + + push edx + push ebx + mov ax,[frame.width] + mov bx,3 + mul bx + shl edx,16 + mov dx,ax + mov eax,edx + pop ebx + pop edx + + sub ebx,eax ; eax = [frame.width]*3 + + jmp .pixelloop32 + + + diff --git a/programs/network/VNCclient/thread.inc b/programs/network_old/VNCclient/thread.inc similarity index 100% rename from programs/network/VNCclient/thread.inc rename to programs/network_old/VNCclient/thread.inc diff --git a/programs/network/airc/trunk/airc.asm b/programs/network_old/airc/trunk/airc.asm similarity index 100% rename from programs/network/airc/trunk/airc.asm rename to programs/network_old/airc/trunk/airc.asm diff --git a/programs/network/airc/trunk/build_en.bat b/programs/network_old/airc/trunk/build_en.bat similarity index 100% rename from programs/network/airc/trunk/build_en.bat rename to programs/network_old/airc/trunk/build_en.bat diff --git a/programs/network/airc/trunk/build_ru.bat b/programs/network_old/airc/trunk/build_ru.bat similarity index 100% rename from programs/network/airc/trunk/build_ru.bat rename to programs/network_old/airc/trunk/build_ru.bat diff --git a/programs/network/airc/trunk/eth.inc b/programs/network_old/airc/trunk/eth.inc similarity index 100% rename from programs/network/airc/trunk/eth.inc rename to programs/network_old/airc/trunk/eth.inc diff --git a/programs/network/airc/trunk/fdo.inc b/programs/network_old/airc/trunk/fdo.inc similarity index 100% rename from programs/network/airc/trunk/fdo.inc rename to programs/network_old/airc/trunk/fdo.inc diff --git a/programs/network/arpstat/trunk/arpstat.asm b/programs/network_old/arpstat/trunk/arpstat.asm similarity index 100% rename from programs/network/arpstat/trunk/arpstat.asm rename to programs/network_old/arpstat/trunk/arpstat.asm diff --git a/programs/network/arpstat/trunk/build_en.bat b/programs/network_old/arpstat/trunk/build_en.bat similarity index 100% rename from programs/network/arpstat/trunk/build_en.bat rename to programs/network_old/arpstat/trunk/build_en.bat diff --git a/programs/network/arpstat/trunk/build_ru.bat b/programs/network_old/arpstat/trunk/build_ru.bat similarity index 100% rename from programs/network/arpstat/trunk/build_ru.bat rename to programs/network_old/arpstat/trunk/build_ru.bat diff --git a/programs/network/browser/browser.asm b/programs/network_old/browser/browser.asm similarity index 100% rename from programs/network/browser/browser.asm rename to programs/network_old/browser/browser.asm diff --git a/programs/network/browser/build.bat b/programs/network_old/browser/build.bat similarity index 100% rename from programs/network/browser/build.bat rename to programs/network_old/browser/build.bat diff --git a/programs/network/browser/build.sh b/programs/network_old/browser/build.sh similarity index 100% rename from programs/network/browser/build.sh rename to programs/network_old/browser/build.sh diff --git a/programs/network/chess/trunk/build_en.bat b/programs/network_old/chess/trunk/build_en.bat similarity index 100% rename from programs/network/chess/trunk/build_en.bat rename to programs/network_old/chess/trunk/build_en.bat diff --git a/programs/network/chess/trunk/build_ru.bat b/programs/network_old/chess/trunk/build_ru.bat similarity index 100% rename from programs/network/chess/trunk/build_ru.bat rename to programs/network_old/chess/trunk/build_ru.bat diff --git a/programs/network/chess/trunk/chess.asm b/programs/network_old/chess/trunk/chess.asm similarity index 100% rename from programs/network/chess/trunk/chess.asm rename to programs/network_old/chess/trunk/chess.asm diff --git a/programs/network/chess/trunk/chess.bmp b/programs/network_old/chess/trunk/chess.bmp similarity index 100% rename from programs/network/chess/trunk/chess.bmp rename to programs/network_old/chess/trunk/chess.bmp diff --git a/programs/network/dhcp/trunk/build_en.bat b/programs/network_old/dhcp/trunk/build_en.bat similarity index 100% rename from programs/network/dhcp/trunk/build_en.bat rename to programs/network_old/dhcp/trunk/build_en.bat diff --git a/programs/network/dhcp/trunk/build_ru.bat b/programs/network_old/dhcp/trunk/build_ru.bat similarity index 100% rename from programs/network/dhcp/trunk/build_ru.bat rename to programs/network_old/dhcp/trunk/build_ru.bat diff --git a/programs/network/dhcp/trunk/dhcp.asm b/programs/network_old/dhcp/trunk/dhcp.asm similarity index 100% rename from programs/network/dhcp/trunk/dhcp.asm rename to programs/network_old/dhcp/trunk/dhcp.asm diff --git a/programs/network/dnsr/trunk/build_en.bat b/programs/network_old/dnsr/trunk/build_en.bat similarity index 100% rename from programs/network/dnsr/trunk/build_en.bat rename to programs/network_old/dnsr/trunk/build_en.bat diff --git a/programs/network/dnsr/trunk/build_ru.bat b/programs/network_old/dnsr/trunk/build_ru.bat similarity index 100% rename from programs/network/dnsr/trunk/build_ru.bat rename to programs/network_old/dnsr/trunk/build_ru.bat diff --git a/programs/network/dnsr/trunk/dnsr.asm b/programs/network_old/dnsr/trunk/dnsr.asm similarity index 100% rename from programs/network/dnsr/trunk/dnsr.asm rename to programs/network_old/dnsr/trunk/dnsr.asm diff --git a/programs/network/downloader/trunk/build.bat b/programs/network_old/downloader/trunk/build.bat similarity index 100% rename from programs/network/downloader/trunk/build.bat rename to programs/network_old/downloader/trunk/build.bat diff --git a/programs/network/downloader/trunk/build.sh b/programs/network_old/downloader/trunk/build.sh similarity index 100% rename from programs/network/downloader/trunk/build.sh rename to programs/network_old/downloader/trunk/build.sh diff --git a/programs/network/downloader/trunk/downloader.asm b/programs/network_old/downloader/trunk/downloader.asm similarity index 100% rename from programs/network/downloader/trunk/downloader.asm rename to programs/network_old/downloader/trunk/downloader.asm diff --git a/programs/network/ethstat/trunk/build_en.bat b/programs/network_old/ethstat/trunk/build_en.bat similarity index 100% rename from programs/network/ethstat/trunk/build_en.bat rename to programs/network_old/ethstat/trunk/build_en.bat diff --git a/programs/network/ethstat/trunk/build_ru.bat b/programs/network_old/ethstat/trunk/build_ru.bat similarity index 100% rename from programs/network/ethstat/trunk/build_ru.bat rename to programs/network_old/ethstat/trunk/build_ru.bat diff --git a/programs/network/ethstat/trunk/ethstat.asm b/programs/network_old/ethstat/trunk/ethstat.asm similarity index 100% rename from programs/network/ethstat/trunk/ethstat.asm rename to programs/network_old/ethstat/trunk/ethstat.asm diff --git a/programs/network/ftps/trunk/FTPS.ASM b/programs/network_old/ftps/trunk/FTPS.ASM similarity index 100% rename from programs/network/ftps/trunk/FTPS.ASM rename to programs/network_old/ftps/trunk/FTPS.ASM diff --git a/programs/network/ftps/trunk/build.bat b/programs/network_old/ftps/trunk/build.bat similarity index 100% rename from programs/network/ftps/trunk/build.bat rename to programs/network_old/ftps/trunk/build.bat diff --git a/programs/network/https/trunk/build_en.bat b/programs/network_old/https/trunk/build_en.bat similarity index 100% rename from programs/network/https/trunk/build_en.bat rename to programs/network_old/https/trunk/build_en.bat diff --git a/programs/network/https/trunk/build_ru.bat b/programs/network_old/https/trunk/build_ru.bat similarity index 100% rename from programs/network/https/trunk/build_ru.bat rename to programs/network_old/https/trunk/build_ru.bat diff --git a/programs/network/https/trunk/https.asm b/programs/network_old/https/trunk/https.asm similarity index 100% rename from programs/network/https/trunk/https.asm rename to programs/network_old/https/trunk/https.asm diff --git a/programs/network/icq/trunk/2000.inc b/programs/network_old/icq/trunk/2000.inc similarity index 100% rename from programs/network/icq/trunk/2000.inc rename to programs/network_old/icq/trunk/2000.inc diff --git a/programs/network/icq/trunk/README.TXT b/programs/network_old/icq/trunk/README.TXT similarity index 100% rename from programs/network/icq/trunk/README.TXT rename to programs/network_old/icq/trunk/README.TXT diff --git a/programs/network/icq/trunk/SSI_INFO.txt b/programs/network_old/icq/trunk/SSI_INFO.txt similarity index 100% rename from programs/network/icq/trunk/SSI_INFO.txt rename to programs/network_old/icq/trunk/SSI_INFO.txt diff --git a/programs/network/icq/trunk/STDCALL.INC b/programs/network_old/icq/trunk/STDCALL.INC similarity index 100% rename from programs/network/icq/trunk/STDCALL.INC rename to programs/network_old/icq/trunk/STDCALL.INC diff --git a/programs/network/icq/trunk/build_en.bat b/programs/network_old/icq/trunk/build_en.bat similarity index 100% rename from programs/network/icq/trunk/build_en.bat rename to programs/network_old/icq/trunk/build_en.bat diff --git a/programs/network/icq/trunk/build_ru.bat b/programs/network_old/icq/trunk/build_ru.bat similarity index 100% rename from programs/network/icq/trunk/build_ru.bat rename to programs/network_old/icq/trunk/build_ru.bat diff --git a/programs/network/icq/trunk/cmdipc.inc b/programs/network_old/icq/trunk/cmdipc.inc similarity index 100% rename from programs/network/icq/trunk/cmdipc.inc rename to programs/network_old/icq/trunk/cmdipc.inc diff --git a/programs/network/icq/trunk/comp.inc b/programs/network_old/icq/trunk/comp.inc similarity index 100% rename from programs/network/icq/trunk/comp.inc rename to programs/network_old/icq/trunk/comp.inc diff --git a/programs/network/icq/trunk/comp_data.inc b/programs/network_old/icq/trunk/comp_data.inc similarity index 100% rename from programs/network/icq/trunk/comp_data.inc rename to programs/network_old/icq/trunk/comp_data.inc diff --git a/programs/network_old/icq/trunk/config.inc b/programs/network_old/icq/trunk/config.inc new file mode 100644 index 0000000000..dc70bf9760 --- /dev/null +++ b/programs/network_old/icq/trunk/config.inc @@ -0,0 +1 @@ +__CPU_type fix p5 diff --git a/programs/network/icq/trunk/dialogs1.inc b/programs/network_old/icq/trunk/dialogs1.inc similarity index 100% rename from programs/network/icq/trunk/dialogs1.inc rename to programs/network_old/icq/trunk/dialogs1.inc diff --git a/programs/network/icq/trunk/dos2win.inc b/programs/network_old/icq/trunk/dos2win.inc similarity index 100% rename from programs/network/icq/trunk/dos2win.inc rename to programs/network_old/icq/trunk/dos2win.inc diff --git a/programs/network/icq/trunk/editbox.inc b/programs/network_old/icq/trunk/editbox.inc similarity index 100% rename from programs/network/icq/trunk/editbox.inc rename to programs/network_old/icq/trunk/editbox.inc diff --git a/programs/network/icq/trunk/editbox.mac b/programs/network_old/icq/trunk/editbox.mac similarity index 100% rename from programs/network/icq/trunk/editbox.mac rename to programs/network_old/icq/trunk/editbox.mac diff --git a/programs/network/icq/trunk/icons.inc b/programs/network_old/icq/trunk/icons.inc similarity index 100% rename from programs/network/icq/trunk/icons.inc rename to programs/network_old/icq/trunk/icons.inc diff --git a/programs/network/icq/trunk/ki.asm b/programs/network_old/icq/trunk/ki.asm similarity index 100% rename from programs/network/icq/trunk/ki.asm rename to programs/network_old/icq/trunk/ki.asm diff --git a/programs/network/icq/trunk/ki.cfg b/programs/network_old/icq/trunk/ki.cfg similarity index 100% rename from programs/network/icq/trunk/ki.cfg rename to programs/network_old/icq/trunk/ki.cfg diff --git a/programs/network/icq/trunk/lang.inc b/programs/network_old/icq/trunk/lang.inc similarity index 100% rename from programs/network/icq/trunk/lang.inc rename to programs/network_old/icq/trunk/lang.inc diff --git a/programs/network/icq/trunk/macros.inc b/programs/network_old/icq/trunk/macros.inc similarity index 100% rename from programs/network/icq/trunk/macros.inc rename to programs/network_old/icq/trunk/macros.inc diff --git a/programs/network/icq/trunk/parser.inc b/programs/network_old/icq/trunk/parser.inc similarity index 100% rename from programs/network/icq/trunk/parser.inc rename to programs/network_old/icq/trunk/parser.inc diff --git a/programs/network/icq/trunk/parser_data.inc b/programs/network_old/icq/trunk/parser_data.inc similarity index 100% rename from programs/network/icq/trunk/parser_data.inc rename to programs/network_old/icq/trunk/parser_data.inc diff --git a/programs/network_old/icq/trunk/proc32.inc b/programs/network_old/icq/trunk/proc32.inc new file mode 100644 index 0000000000..aa3ffc9702 --- /dev/null +++ b/programs/network_old/icq/trunk/proc32.inc @@ -0,0 +1,270 @@ + +; Macroinstructions for defining and calling procedures + +macro stdcall proc,[arg] ; directly call STDCALL procedure + { common + if ~ arg eq + reverse + pushd arg + common + end if + call proc } + +macro invoke proc,[arg] ; indirectly call STDCALL procedure + { common + if ~ arg eq + reverse + pushd arg + common + end if + call [proc] } + +macro ccall proc,[arg] ; directly call CDECL procedure + { common + size@ccall = 0 + if ~ arg eq + reverse + pushd arg + size@ccall = size@ccall+4 + common + end if + call proc + if size@ccall + add esp,size@ccall + end if } + +macro cinvoke proc,[arg] ; indirectly call CDECL procedure + { common + size@ccall = 0 + if ~ arg eq + reverse + pushd arg + size@ccall = size@ccall+4 + common + end if + call [proc] + if size@ccall + add esp,size@ccall + end if } + +macro proc [args] ; define procedure + { common + match name params, args> + \{ define@proc name, \{ prologue name,flag,parmbytes,localbytes,reglist \} + macro locals + \{ virtual at ebp-localbytes+current + macro label def \\{ match . type,def> \\\{ deflocal@proc .,label, + \\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \} + macro finish@proc \{ localbytes = (((current-1) shr 2)+1) shl 2 + end if \} } + +macro defargs@proc [arg] + { common + if ~ arg eq + forward + local ..arg,current@arg + match argname:type, arg + \{ current@arg equ argname + label ..arg type + argname equ ..arg + if dqword eq type + dd ?,?,?,? + else if tbyte eq type + dd ?,?,? + else if qword eq type | pword eq type + dd ?,? + else + dd ? + end if \} + match =current@arg,current@arg + \{ current@arg equ arg + arg equ ..arg + ..arg dd ? \} + common + args@proc equ current@arg + forward + restore current@arg + common + end if } + +macro deflocal@proc name,def,[val] + { common + match vars, all@vars \{ all@vars equ all@vars, \} + all@vars equ all@vars name + forward + local ..var,..tmp + match =label,def \{ ..tmp equ \} + match tmp,..tmp \{ ..var def val \} + match ,..tmp \{ label ..var val \} + match =?, val \{ ..tmp equ \} + match any =dup (=?), val \{ ..tmp equ \} + match tmp : value, ..tmp : val + \{ tmp: end virtual + initlocal@proc ..var,def value + virtual at tmp\} + common + match first rest, ..var, \{ name equ first \} } + +macro initlocal@proc name,def + { virtual at name + def + size@initlocal = $ - name + end virtual + position@initlocal = 0 + while size@initlocal > position@initlocal + virtual at name + def + if size@initlocal - position@initlocal < 2 + current@initlocal = 1 + load byte@initlocal byte from name+position@initlocal + else if size@initlocal - position@initlocal < 4 + current@initlocal = 2 + load word@initlocal word from name+position@initlocal + else + current@initlocal = 4 + load dword@initlocal dword from name+position@initlocal + end if + end virtual + if current@initlocal = 1 + mov byte [name+position@initlocal],byte@initlocal + else if current@initlocal = 2 + mov word [name+position@initlocal],word@initlocal + else + mov dword [name+position@initlocal],dword@initlocal + end if + position@initlocal = position@initlocal + current@initlocal + end while } + +macro endp + { purge ret,locals,endl + finish@proc + purge finish@proc + restore regs@proc + match all,args@proc \{ restore all \} + restore args@proc + match all,all@vars \{ restore all \} } + +macro local [var] + { common + locals + forward done@local equ + match varname[count]:vartype, var + \{ match =BYTE, vartype \\{ varname rb count + restore done@local \\} + match =WORD, vartype \\{ varname rw count + restore done@local \\} + match =DWORD, vartype \\{ varname rd count + restore done@local \\} + match =PWORD, vartype \\{ varname rp count + restore done@local \\} + match =QWORD, vartype \\{ varname rq count + restore done@local \\} + match =TBYTE, vartype \\{ varname rt count + restore done@local \\} + match =DQWORD, vartype \\{ label varname dqword + rq count+count + restore done@local \\} + match , done@local \\{ virtual + varname vartype + end virtual + rb count*sizeof.\#vartype + restore done@local \\} \} + match :varname:vartype, done@local:var + \{ match =BYTE, vartype \\{ varname db ? + restore done@local \\} + match =WORD, vartype \\{ varname dw ? + restore done@local \\} + match =DWORD, vartype \\{ varname dd ? + restore done@local \\} + match =PWORD, vartype \\{ varname dp ? + restore done@local \\} + match =QWORD, vartype \\{ varname dq ? + restore done@local \\} + match =TBYTE, vartype \\{ varname dt ? + restore done@local \\} + match =DQWORD, vartype \\{ label varname dqword + dq ?,? + restore done@local \\} + match , done@local \\{ varname vartype + restore done@local \\} \} + match ,done@local + \{ var + restore done@local \} + common + endl } diff --git a/programs/network/icq/trunk/ssi.inc b/programs/network_old/icq/trunk/ssi.inc similarity index 100% rename from programs/network/icq/trunk/ssi.inc rename to programs/network_old/icq/trunk/ssi.inc diff --git a/programs/network/icq/trunk/ssi_data.inc b/programs/network_old/icq/trunk/ssi_data.inc similarity index 100% rename from programs/network/icq/trunk/ssi_data.inc rename to programs/network_old/icq/trunk/ssi_data.inc diff --git a/programs/network/icq/trunk/st_red.bmp b/programs/network_old/icq/trunk/st_red.bmp similarity index 100% rename from programs/network/icq/trunk/st_red.bmp rename to programs/network_old/icq/trunk/st_red.bmp diff --git a/programs/network/icq/trunk/struct.inc b/programs/network_old/icq/trunk/struct.inc similarity index 100% rename from programs/network/icq/trunk/struct.inc rename to programs/network_old/icq/trunk/struct.inc diff --git a/programs/network/ipc/trunk/build_en.bat b/programs/network_old/ipc/trunk/build_en.bat similarity index 100% rename from programs/network/ipc/trunk/build_en.bat rename to programs/network_old/ipc/trunk/build_en.bat diff --git a/programs/network/ipc/trunk/build_ru.bat b/programs/network_old/ipc/trunk/build_ru.bat similarity index 100% rename from programs/network/ipc/trunk/build_ru.bat rename to programs/network_old/ipc/trunk/build_ru.bat diff --git a/programs/network/ipc/trunk/ipc.asm b/programs/network_old/ipc/trunk/ipc.asm similarity index 100% rename from programs/network/ipc/trunk/ipc.asm rename to programs/network_old/ipc/trunk/ipc.asm diff --git a/programs/network/local/trunk/build_en.bat b/programs/network_old/local/trunk/build_en.bat similarity index 100% rename from programs/network/local/trunk/build_en.bat rename to programs/network_old/local/trunk/build_en.bat diff --git a/programs/network/local/trunk/build_ru.bat b/programs/network_old/local/trunk/build_ru.bat similarity index 100% rename from programs/network/local/trunk/build_ru.bat rename to programs/network_old/local/trunk/build_ru.bat diff --git a/programs/network/local/trunk/local.asm b/programs/network_old/local/trunk/local.asm similarity index 100% rename from programs/network/local/trunk/local.asm rename to programs/network_old/local/trunk/local.asm diff --git a/programs/network/mp3s/trunk/build_en.bat b/programs/network_old/mp3s/trunk/build_en.bat similarity index 100% rename from programs/network/mp3s/trunk/build_en.bat rename to programs/network_old/mp3s/trunk/build_en.bat diff --git a/programs/network/mp3s/trunk/build_ru.bat b/programs/network_old/mp3s/trunk/build_ru.bat similarity index 100% rename from programs/network/mp3s/trunk/build_ru.bat rename to programs/network_old/mp3s/trunk/build_ru.bat diff --git a/programs/network/mp3s/trunk/mp3s.asm b/programs/network_old/mp3s/trunk/mp3s.asm similarity index 100% rename from programs/network/mp3s/trunk/mp3s.asm rename to programs/network_old/mp3s/trunk/mp3s.asm diff --git a/programs/network/netsendc/trunk/build_en.bat b/programs/network_old/netsendc/trunk/build_en.bat similarity index 100% rename from programs/network/netsendc/trunk/build_en.bat rename to programs/network_old/netsendc/trunk/build_en.bat diff --git a/programs/network/netsendc/trunk/build_ru.bat b/programs/network_old/netsendc/trunk/build_ru.bat similarity index 100% rename from programs/network/netsendc/trunk/build_ru.bat rename to programs/network_old/netsendc/trunk/build_ru.bat diff --git a/programs/network/netsendc/trunk/netsendc.asm b/programs/network_old/netsendc/trunk/netsendc.asm similarity index 100% rename from programs/network/netsendc/trunk/netsendc.asm rename to programs/network_old/netsendc/trunk/netsendc.asm diff --git a/programs/network/netsends/trunk/build_en.bat b/programs/network_old/netsends/trunk/build_en.bat similarity index 100% rename from programs/network/netsends/trunk/build_en.bat rename to programs/network_old/netsends/trunk/build_en.bat diff --git a/programs/network/netsends/trunk/build_ru.bat b/programs/network_old/netsends/trunk/build_ru.bat similarity index 100% rename from programs/network/netsends/trunk/build_ru.bat rename to programs/network_old/netsends/trunk/build_ru.bat diff --git a/programs/network/netsends/trunk/netsends.asm b/programs/network_old/netsends/trunk/netsends.asm similarity index 100% rename from programs/network/netsends/trunk/netsends.asm rename to programs/network_old/netsends/trunk/netsends.asm diff --git a/programs/network/nntpc/trunk/build_en.bat b/programs/network_old/nntpc/trunk/build_en.bat similarity index 100% rename from programs/network/nntpc/trunk/build_en.bat rename to programs/network_old/nntpc/trunk/build_en.bat diff --git a/programs/network/nntpc/trunk/build_ru.bat b/programs/network_old/nntpc/trunk/build_ru.bat similarity index 100% rename from programs/network/nntpc/trunk/build_ru.bat rename to programs/network_old/nntpc/trunk/build_ru.bat diff --git a/programs/network/nntpc/trunk/nntpc.asm b/programs/network_old/nntpc/trunk/nntpc.asm similarity index 100% rename from programs/network/nntpc/trunk/nntpc.asm rename to programs/network_old/nntpc/trunk/nntpc.asm diff --git a/programs/network/popc/trunk/build_en.bat b/programs/network_old/popc/trunk/build_en.bat similarity index 100% rename from programs/network/popc/trunk/build_en.bat rename to programs/network_old/popc/trunk/build_en.bat diff --git a/programs/network/popc/trunk/build_ru.bat b/programs/network_old/popc/trunk/build_ru.bat similarity index 100% rename from programs/network/popc/trunk/build_ru.bat rename to programs/network_old/popc/trunk/build_ru.bat diff --git a/programs/network/popc/trunk/popc.asm b/programs/network_old/popc/trunk/popc.asm similarity index 100% rename from programs/network/popc/trunk/popc.asm rename to programs/network_old/popc/trunk/popc.asm diff --git a/programs/network/ppp/trunk/build_en.bat b/programs/network_old/ppp/trunk/build_en.bat similarity index 100% rename from programs/network/ppp/trunk/build_en.bat rename to programs/network_old/ppp/trunk/build_en.bat diff --git a/programs/network/ppp/trunk/build_ru.bat b/programs/network_old/ppp/trunk/build_ru.bat similarity index 100% rename from programs/network/ppp/trunk/build_ru.bat rename to programs/network_old/ppp/trunk/build_ru.bat diff --git a/programs/network/ppp/trunk/chat.inc b/programs/network_old/ppp/trunk/chat.inc similarity index 100% rename from programs/network/ppp/trunk/chat.inc rename to programs/network_old/ppp/trunk/chat.inc diff --git a/programs/network/ppp/trunk/ppp.asm b/programs/network_old/ppp/trunk/ppp.asm similarity index 100% rename from programs/network/ppp/trunk/ppp.asm rename to programs/network_old/ppp/trunk/ppp.asm diff --git a/programs/network/rccc/trunk/build_en.bat b/programs/network_old/rccc/trunk/build_en.bat similarity index 100% rename from programs/network/rccc/trunk/build_en.bat rename to programs/network_old/rccc/trunk/build_en.bat diff --git a/programs/network/rccc/trunk/build_ru.bat b/programs/network_old/rccc/trunk/build_ru.bat similarity index 100% rename from programs/network/rccc/trunk/build_ru.bat rename to programs/network_old/rccc/trunk/build_ru.bat diff --git a/programs/network/rccc/trunk/rccc.asm b/programs/network_old/rccc/trunk/rccc.asm similarity index 100% rename from programs/network/rccc/trunk/rccc.asm rename to programs/network_old/rccc/trunk/rccc.asm diff --git a/programs/network/rccs/trunk/build_en.bat b/programs/network_old/rccs/trunk/build_en.bat similarity index 100% rename from programs/network/rccs/trunk/build_en.bat rename to programs/network_old/rccs/trunk/build_en.bat diff --git a/programs/network/rccs/trunk/build_ru.bat b/programs/network_old/rccs/trunk/build_ru.bat similarity index 100% rename from programs/network/rccs/trunk/build_ru.bat rename to programs/network_old/rccs/trunk/build_ru.bat diff --git a/programs/network/rccs/trunk/rccs.asm b/programs/network_old/rccs/trunk/rccs.asm similarity index 100% rename from programs/network/rccs/trunk/rccs.asm rename to programs/network_old/rccs/trunk/rccs.asm diff --git a/programs/network/remote/trunk/build_en.bat b/programs/network_old/remote/trunk/build_en.bat similarity index 100% rename from programs/network/remote/trunk/build_en.bat rename to programs/network_old/remote/trunk/build_en.bat diff --git a/programs/network/remote/trunk/build_ru.bat b/programs/network_old/remote/trunk/build_ru.bat similarity index 100% rename from programs/network/remote/trunk/build_ru.bat rename to programs/network_old/remote/trunk/build_ru.bat diff --git a/programs/network/remote/trunk/remote.asm b/programs/network_old/remote/trunk/remote.asm similarity index 100% rename from programs/network/remote/trunk/remote.asm rename to programs/network_old/remote/trunk/remote.asm diff --git a/programs/network/smtps/trunk/build_en.bat b/programs/network_old/smtps/trunk/build_en.bat similarity index 100% rename from programs/network/smtps/trunk/build_en.bat rename to programs/network_old/smtps/trunk/build_en.bat diff --git a/programs/network/smtps/trunk/build_ru.bat b/programs/network_old/smtps/trunk/build_ru.bat similarity index 100% rename from programs/network/smtps/trunk/build_ru.bat rename to programs/network_old/smtps/trunk/build_ru.bat diff --git a/programs/network/smtps/trunk/smtps.asm b/programs/network_old/smtps/trunk/smtps.asm similarity index 100% rename from programs/network/smtps/trunk/smtps.asm rename to programs/network_old/smtps/trunk/smtps.asm diff --git a/programs/network/stackcfg/trunk/build_en.bat b/programs/network_old/stackcfg/trunk/build_en.bat similarity index 100% rename from programs/network/stackcfg/trunk/build_en.bat rename to programs/network_old/stackcfg/trunk/build_en.bat diff --git a/programs/network/stackcfg/trunk/build_ru.bat b/programs/network_old/stackcfg/trunk/build_ru.bat similarity index 100% rename from programs/network/stackcfg/trunk/build_ru.bat rename to programs/network_old/stackcfg/trunk/build_ru.bat diff --git a/programs/network/stackcfg/trunk/readme.txt b/programs/network_old/stackcfg/trunk/readme.txt similarity index 100% rename from programs/network/stackcfg/trunk/readme.txt rename to programs/network_old/stackcfg/trunk/readme.txt diff --git a/programs/network/stackcfg/trunk/stackcfg.asm b/programs/network_old/stackcfg/trunk/stackcfg.asm similarity index 100% rename from programs/network/stackcfg/trunk/stackcfg.asm rename to programs/network_old/stackcfg/trunk/stackcfg.asm diff --git a/programs/network/telnet/trunk/build_en.bat b/programs/network_old/telnet/trunk/build_en.bat similarity index 100% rename from programs/network/telnet/trunk/build_en.bat rename to programs/network_old/telnet/trunk/build_en.bat diff --git a/programs/network/telnet/trunk/build_ru.bat b/programs/network_old/telnet/trunk/build_ru.bat similarity index 100% rename from programs/network/telnet/trunk/build_ru.bat rename to programs/network_old/telnet/trunk/build_ru.bat diff --git a/programs/network/telnet/trunk/telnet.asm b/programs/network_old/telnet/trunk/telnet.asm similarity index 100% rename from programs/network/telnet/trunk/telnet.asm rename to programs/network_old/telnet/trunk/telnet.asm diff --git a/programs/network/terminal/trunk/build_en.bat b/programs/network_old/terminal/trunk/build_en.bat similarity index 100% rename from programs/network/terminal/trunk/build_en.bat rename to programs/network_old/terminal/trunk/build_en.bat diff --git a/programs/network/terminal/trunk/build_ru.bat b/programs/network_old/terminal/trunk/build_ru.bat similarity index 100% rename from programs/network/terminal/trunk/build_ru.bat rename to programs/network_old/terminal/trunk/build_ru.bat diff --git a/programs/network/terminal/trunk/terminal.asm b/programs/network_old/terminal/trunk/terminal.asm similarity index 100% rename from programs/network/terminal/trunk/terminal.asm rename to programs/network_old/terminal/trunk/terminal.asm diff --git a/programs/network/tftpa/trunk/build_en.bat b/programs/network_old/tftpa/trunk/build_en.bat similarity index 100% rename from programs/network/tftpa/trunk/build_en.bat rename to programs/network_old/tftpa/trunk/build_en.bat diff --git a/programs/network/tftpa/trunk/build_ru.bat b/programs/network_old/tftpa/trunk/build_ru.bat similarity index 100% rename from programs/network/tftpa/trunk/build_ru.bat rename to programs/network_old/tftpa/trunk/build_ru.bat diff --git a/programs/network/tftpa/trunk/tftpa.asm b/programs/network_old/tftpa/trunk/tftpa.asm similarity index 100% rename from programs/network/tftpa/trunk/tftpa.asm rename to programs/network_old/tftpa/trunk/tftpa.asm diff --git a/programs/network/tftpc/trunk/build_en.bat b/programs/network_old/tftpc/trunk/build_en.bat similarity index 100% rename from programs/network/tftpc/trunk/build_en.bat rename to programs/network_old/tftpc/trunk/build_en.bat diff --git a/programs/network/tftpc/trunk/build_ru.bat b/programs/network_old/tftpc/trunk/build_ru.bat similarity index 100% rename from programs/network/tftpc/trunk/build_ru.bat rename to programs/network_old/tftpc/trunk/build_ru.bat diff --git a/programs/network/tftpc/trunk/tftpc.asm b/programs/network_old/tftpc/trunk/tftpc.asm similarity index 100% rename from programs/network/tftpc/trunk/tftpc.asm rename to programs/network_old/tftpc/trunk/tftpc.asm diff --git a/programs/network/ym/trunk/build_en.bat b/programs/network_old/ym/trunk/build_en.bat similarity index 100% rename from programs/network/ym/trunk/build_en.bat rename to programs/network_old/ym/trunk/build_en.bat diff --git a/programs/network/ym/trunk/build_ru.bat b/programs/network_old/ym/trunk/build_ru.bat similarity index 100% rename from programs/network/ym/trunk/build_ru.bat rename to programs/network_old/ym/trunk/build_ru.bat diff --git a/programs/network/ym/trunk/ym.asm b/programs/network_old/ym/trunk/ym.asm similarity index 100% rename from programs/network/ym/trunk/ym.asm rename to programs/network_old/ym/trunk/ym.asm diff --git a/programs/network/zeroconf/trunk/ETH.INC b/programs/network_old/zeroconf/trunk/ETH.INC similarity index 100% rename from programs/network/zeroconf/trunk/ETH.INC rename to programs/network_old/zeroconf/trunk/ETH.INC diff --git a/programs/network/zeroconf/trunk/build.bat b/programs/network_old/zeroconf/trunk/build.bat similarity index 100% rename from programs/network/zeroconf/trunk/build.bat rename to programs/network_old/zeroconf/trunk/build.bat diff --git a/programs/network_old/zeroconf/trunk/debug-fdo.inc b/programs/network_old/zeroconf/trunk/debug-fdo.inc new file mode 100644 index 0000000000..40b2cb00e4 --- /dev/null +++ b/programs/network_old/zeroconf/trunk/debug-fdo.inc @@ -0,0 +1,422 @@ +; +; Formatted Debug Output (FDO) +; Copyright (c) 2005-2006, mike.dld +; Created: 2005-01-29, Changed: 2006-11-10 +; +; For questions and bug reports, mail to mike.dld@gmail.com +; +; Available format specifiers are: %s, %d, %u, %x (with partial width support) +; + +; to be defined: +; __DEBUG__ equ 1 +; __DEBUG_LEVEL__ equ 5 + +macro debug_func name { + if used name + name@of@func equ name +} + +macro debug_beginf { + align 4 + name@of@func: +} + +debug_endf fix end if + +macro DEBUGS _sign,[_str] { + common + local tp + tp equ 0 + match _arg:_num,_str \{ + DEBUGS_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _str \{ + DEBUGS_N _sign,,_arg + \} +} + +macro DEBUGS_N _sign,_num,[_str] { + common + pushf + pushad + local ..str,..label,is_str + is_str = 0 + forward + if _str eqtype '' + is_str = 1 + end if + common + if is_str = 1 + jmp ..label + ..str db _str,0 + ..label: + add esp,4*8+4 + mov edx,..str + sub esp,4*8+4 + else + mov edx,_str + end if + if ~_num eq + if _num eqtype eax + if _num in + mov esi,_num + else if ~_num eq esi + movzx esi,_num + end if + else if _num eqtype 0 + mov esi,_num + else + local tp + tp equ 0 + match [_arg],_num \{ + mov esi,dword[_arg] + tp equ 1 + \} + match =0 =dword[_arg],tp _num \{ + mov esi,dword[_arg] + tp equ 1 + \} + match =0 =word[_arg],tp _num \{ + movzx esi,word[_arg] + tp equ 1 + \} + match =0 =byte[_arg],tp _num \{ + movzx esi,byte[_arg] + tp equ 1 + \} + match =0,tp \{ + 'Error: specified string width is incorrect' + \} + end if + else + mov esi,0x7FFFFFFF + end if + call fdo_debug_outstr + popad + popf +} + +macro DEBUGD _sign,_dec { + local tp + tp equ 0 + match _arg:_num,_dec \{ + DEBUGD_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _dec \{ + DEBUGD_N _sign,,_arg + \} +} + +macro DEBUGD_N _sign,_num,_dec { + pushf + pushad + if (~_num eq) + if (_dec eqtype eax | _dec eqtype 0) + 'Error: precision allowed only for in-memory variables' + end if + if (~_num in <1,2,4>) + if _sign + 'Error: 1, 2 and 4 are only allowed for precision in %d' + else + 'Error: 1, 2 and 4 are only allowed for precision in %u' + end if + end if + end if + if _dec eqtype eax + if _dec in + mov eax,_dec + else if ~_dec eq eax + if _sign = 1 + movsx eax,_dec + else + movzx eax,_dec + end if + end if + else if _dec eqtype 0 + mov eax,_dec + else + add esp,4*8+4 + if _num eq + mov eax,dword _dec + else if _num = 1 + if _sign = 1 + movsx eax,byte _dec + else + movzx eax,byte _dec + end if + else if _num = 2 + if _sign = 1 + movsx eax,word _dec + else + movzx eax,word _dec + end if + else + mov eax,dword _dec + end if + sub esp,4*8+4 + end if + mov cl,_sign + call fdo_debug_outdec + popad + popf +} + +macro DEBUGH _sign,_hex { + local tp + tp equ 0 + match _arg:_num,_hex \{ + DEBUGH_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _hex \{ + DEBUGH_N _sign,,_arg + \} +} + +macro DEBUGH_N _sign,_num,_hex { + pushf + pushad + if (~_num eq) & (~_num in <1,2,3,4,5,6,7,8>) + 'Error: 1..8 are only allowed for precision in %x' + end if + if _hex eqtype eax + if _hex in + if ~_hex eq eax + mov eax,_hex + end if + else if _hex in + if ~_hex eq ax + movzx eax,_hex + end if + shl eax,16 + if (_num eq) + mov edx,4 + end if + else if _hex in + if ~_hex eq al + movzx eax,_hex + end if + shl eax,24 + if (_num eq) + mov edx,2 + end if + end if + else if _hex eqtype 0 + mov eax,_hex + else + add esp,4*8+4 + mov eax,dword _hex + sub esp,4*8+4 + end if + if ~_num eq + mov edx,_num + else + mov edx,8 + end if + call fdo_debug_outhex + popad + popf +} + +;----------------------------------------------------------------------------- + +debug_func fdo_debug_outchar +debug_beginf + pushad + mov cl,al + mov ebx,1 + mov eax,63 + mcall + popad + ret +debug_endf + +debug_func fdo_debug_outstr +debug_beginf + mov eax,63 + mov ebx,1 + .l1: dec esi + js .l2 + mov cl,[edx] + or cl,cl + jz .l2 + mcall + inc edx + jmp .l1 + .l2: ret +debug_endf + +debug_func fdo_debug_outdec +debug_beginf + or cl,cl + jz @f + or eax,eax + jns @f + neg eax + push eax + mov al,'-' + call fdo_debug_outchar + pop eax + @@: push 10 + pop ecx + push -'0' + .l1: xor edx,edx + div ecx + push edx + test eax,eax + jnz .l1 + .l2: pop eax + add al,'0' + jz .l3 + call fdo_debug_outchar + jmp .l2 + .l3: ret +debug_endf + +debug_func fdo_debug_outhex + __fdo_hexdigits db '0123456789ABCDEF' +debug_beginf + mov cl,dl + neg cl + add cl,8 + shl cl,2 + rol eax,cl + .l1: rol eax,4 + push eax + and eax,0x0000000F + mov al,[__fdo_hexdigits+eax] + call fdo_debug_outchar + pop eax + dec edx + jnz .l1 + ret +debug_endf + +;----------------------------------------------------------------------------- + +macro DEBUGF _level,_format,[_arg] { + common + if __DEBUG__ = 1 & _level >= __DEBUG_LEVEL__ + local ..f1,f2,a1,a2,c1,c2,c3,..lbl + _debug_str_ equ __debug_str_ # a1 + a1 = 0 + c2 = 0 + c3 = 0 + f2 = 0 + repeat ..lbl-..f1 + virtual at 0 + db _format,0,0 + load c1 word from %-1 + end virtual + if c1 = '%s' + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER S,a1,0,_arg + else if c1 = '%x' + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER H,a1,0,_arg + else if c1 = '%d' | c1 = '%u' + local c4 + if c1 = '%d' + c4 = 1 + else + c4 = 0 + end if + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER D,a1,c4,_arg + else if c1 = '\n' + c3 = c3 + 1 + end if + end repeat + virtual at 0 + db _format,0,0 + load c1 from f2-c2 + end virtual + if (c1<>0)&(f2<>..lbl-..f1-1) + DEBUGS 0,_debug_str_+f2-c2 + end if + virtual at 0 + ..f1 db _format,0 + ..lbl: + __debug_strings equ __debug_strings,_debug_str_,<_format>,..lbl-..f1-1-c2-c3 + end virtual + end if +} + +macro __include_debug_strings dummy,[_id,_fmt,_len] { + common + local c1,a1,a2 + forward + if defined _len & ~_len eq + _id: + a1 = 0 + a2 = 0 + repeat _len + virtual at 0 + db _fmt,0,0 + load c1 word from %+a2-1 + end virtual + if (c1='%s')|(c1='%x')|(c1='%d')|(c1='%u') + db 0 + a2 = a2 + 1 + else if (c1='\n') + dw $0A0D + a1 = a1 + 1 + a2 = a2 + 1 + else + db c1 and 0x0FF + end if + end repeat + db 0 + end if +} + +macro DEBUGF_HELPER _letter,_num,_sign,[_arg] { + common + local num + num = 0 + forward + if num = _num + DEBUG#_letter _sign,_arg + end if + num = num+1 + common + _num = _num+1 +} + +macro include_debug_strings { + if __DEBUG__ = 1 + match dbg_str,__debug_strings \{ + __include_debug_strings dbg_str + \} + end if +} diff --git a/programs/network_old/zeroconf/trunk/dhcp.inc b/programs/network_old/zeroconf/trunk/dhcp.inc new file mode 100644 index 0000000000..afe6c8fbaf --- /dev/null +++ b/programs/network_old/zeroconf/trunk/dhcp.inc @@ -0,0 +1,263 @@ +;Name Number Length Meaning + +dhcp_pad_option equ 0 ; 0 None +dhcp_end_option equ 255 ; 0 None +dhcp_subnet_mask equ 1 ; 4 Subnet Mask Value +dhcp_time_offset equ 2 ; 4 Time Offset in Seconds from UTC +dhcp_router equ 3 ; N4 Router addresses +dhcp_time_server equ 4 ; N4 Timeserver addresses +dhcp_name_server equ 5 ; N4 IEN-116 Server addresses +dhcp_domain_server equ 6 ; N4 DNS Server addresses +dhcp_log_server equ 7 ; N4 Logging Server addresses +dhcp_quotes_server equ 8 ; N4 Quotes Server addresses +dhcp_lpr_server equ 9 ; N4 Printer Server addresses +dhcp_impress_server equ 10 ; N4 Impress Server addresses +dhcp_rlp_server equ 11 ; N4 N RLP Server addresses +dhcp_hostname equ 12 ; N Hostname string +dhcp_boot_file_size equ 13 ; 2 Size of boot file in 512-octet blocks +dhcp_merit_dump_file equ 14 ; N Client to dump and name the file to dump it to +dhcp_domain_name equ 15 ; N The DNS domain name of the client +dhcp_swap_server equ 16 ; 4 Swap Server address +dhcp_root_path equ 17 ; N Path name for root disk +dhcp_extension_file equ 18 ; N Path name for more BOOTP info + +;IP Layer Parameters per Host + +dhcp_forward equ 19 ; 1 Enable/Disable IP Forwarding +dhcp_srcrte equ 20 ; 1 Enable/Disable Non-Local Source Routing +dhcp_policy equ 21 ; N8 Non-Local Source Routing Policy Filters +dhcp_mag_dg_assembly equ 22 ; 2 Max Datagram Reassembly Size +dhcp_default_ip_tll equ 23 ; 1 Default IP Time to Live +dhcp_mtu_timeout equ 24 ; 4 Path MTU Aging Timeout +dhcp_mtu_plateau equ 25 ; N2 Path MTU Plateau Table + +;IP Layer Parameters per Interface + +dhcp_mtu_interface equ 26 ; 2 Interface MTU Size +dhcp_mtu_subnet equ 27 ; 1 All Subnets are Local +dhcp_broadcast_address equ 28 ; 4 Broadcast Address +dhcp_mask_discovery equ 29 ; 1 Perform Mask Discovery +dhcp_mask_supplier equ 30 ; 1 Provide Mask to Others +dhcp_router_discovery equ 31 ; 1 Perform Router Discovery +dhcp_router_request equ 32 ; 4 Router Solicitation Address +dhcp_static_route equ 33 ; N8 Static Routing Table + +;Link Layer Parameters per Interface + +dhcp_trailers equ 34 ; 1 Trailer Encapsulation +dhcp_arp_timeout equ 35 ; 4 ARP Cache Timeout +dhcp_ethernet equ 36 ; 1 Ethernet Encapsulation + +;TCP Parameters + +dhcp_default_tcp_tll equ 37 ; 1 Default TCP Time to Live +dhcp_keepalive_time equ 38 ; 4 TCP Keepalive Interval +dhcp_keepalive_data equ 39 ; 1 TCP Keepalive Garbage + +;Application and Service Parameters + +dhcp_nis_domain equ 40 ; N NIS Domain Name +dhcp_nis_servers equ 41 ; N4 NIS Server Addresses +dhcp_ntp_servers equ 42 ; N4 NTP Server Addresses +dhcp_vendor_specific equ 43 ; N Vendor Specific Information +dhcp_netbios_name_srv equ 44 ; N4 NETBIOS Name Servers +dhcp_netbios_dist_srv equ 45 ; N4 NETBIOS Datagram Distribution +dhcp_netbios_node_type equ 46 ; 1 NETBIOS Node Type +dhcp_netbios_scope equ 47 ; N NETBIOS Scope +dhcp_x_window_font equ 48 ; N4 X Window Font Server +dhcp_x_window_manager equ 49 ; N4 X Window Display Manager +dhcp_nis_domain_name equ 64 ; N NIS+ v3 Client Domain Name +dhcp_nis_server_addr equ 65 ; N4 NIS+ v3 Server Addresses +dhcp_home_agent_addrs equ 68 ; N4 Mobile IP Home Agent Addresses +dhcp_smtp_server equ 69 ; N4 Simple Mail Server Addresses +dhcp_pop3_server equ 70 ; N4 Post Office Server Addresses +dhcp_nntp_server equ 71 ; N4 Network News Server Addresses +dhcp_www_server equ 72 ; N4 WWW Server Addresses +dhcp_finger_server equ 73 ; N4 Finger Server Addresses +dhcp_irc_server equ 74 ; N4 Chat Server Addresses +dhcp_streettalk_server equ 75 ; N4 StreetTalk Server Addresses +dhcp_stda_server equ 76 ; N4 ST Directory Assist. Addresses + +;DHCP Extensions + +dhcp_address_request equ 50 ; 4 Requested IP Address +dhcp_address_time equ 51 ; 4 IP Address Lease Time +dhcp_option_overload equ 52 ; 1 Overload "sname" or "file" +dhcp_msg_type equ 53 ; 1 DHCP Message Type +dhcp_dhcp_server_id equ 54 ; 4 DHCP Server Identification +dhcp_parameter_list equ 55 ; N Parameter Request List +dhcp_dhcp_message equ 56 ; N DHCP Error Message +dhcp_dhcp_max_msg_size equ 57 ; 2 DHCP Maximum Message Size +dhcp_renewal_time equ 58 ; 4 DHCP Renewal (T1) Time +dhcp_rebinding_time equ 59 ; 4 DHCP Rebinding (T2) Time +dhcp_class_id equ 60 ; N Vendor Class Identifier +dhcp_client_id equ 61 ; N Client Identifier +dhcp_server_name equ 66 ; N TFTP Server Name +dhcp_bootfile_name equ 67 ; N Boot File Name + +;Newer extensions + +dhcp_netware_ip_domain equ 62 ; N Netware/IP Domain Name +dhcp_netware_ip_option equ 63 ; N Netware/IP sub Options +dhcp_user_class equ 77 ; N User Class Information +dhcp_directory_agent equ 78 ; N directory agent information +dhcp_service_scope equ 79 ; N service location agent scope +dhcp_rapid_commit equ 80 ; 0 Rapid Commit +dhcp_client_fqdn equ 81 ; N Fully Qualified Domain Name +dhcp_relay_agent_info equ 82 ; N Relay Agent Information, RFC 3046 +dhcp_isns equ 83 ; N Internet Storage Name Service +; 84 REMOVED/Unassigned +dhcp_nds_servers equ 85 ; N Novell Directory Services +dhcp_nds_tree_name equ 86 ; N Novell Directory Services +dhcp_nds_conext equ 87 ; N Novell Directory Services +dhcp_bcmcs equ 88 ; Controller Domain Name list +dhcp_bcmcs equ 89 ; Controller IPv4 address option +dhcp_authentication equ 90 ; N Authentication +; 91 REMOVED/Unassigned +; 92 REMOVED/Unassigned +dhcp_client_system equ 93 ; N Client System Architecture +dhcp_client_ndi equ 94 ; N Client Network Device Interface +dhcp_ldap equ 95 ; N Lightweight Directory Access Protocol +; 96 REMOVED/Unassigned +dhcp_uuid_guid equ 97 ; N UUID/GUID-based Client Identifier +dchp_user_auth equ 98 ; N Open Group's User Authentication +; 99 REMOVED/Unassigned +; 100 REMOVED/Unassigned +; 101 REMOVED/Unassigned +; 102 REMOVED/Unassigned +; 103 REMOVED/Unassigned +; 104 REMOVED/Unassigned +; 105 REMOVED/Unassigned +; 106 REMOVED/Unassigned +; 107 REMOVED/Unassigned +; 108 REMOVED/Unassigned +; 109 REMOVED/Unassigned +; 110 REMOVED/Unassigned +; 111 REMOVED/Unassigned +dhcp_netinfo_address equ 112 ; N NetInfo Parent Server Address +dhcp_netinfo_tag equ 113 ; N NetInfo Parent Server Tag +dhcp_url equ 114 ; N URL +; 115 REMOVED/Unassigned +dhcp_auto_config equ 116 ; N DHCP Auto-Configuration +dhcp_ns_search equ 117 ; N Name Service Search +dhcp_subnet_selection equ 118 ; 4 Subnet Selection Option +dhcp_domain_search equ 119 ; N DNS domain search list +dhcp_sip_servers equ 120 ; N SIP Servers DHCP Option +dhcp_cl_static_route equ 121 ; N Classless Static Route Option +dhcp_ccc equ 122 ; N CableLabs Client Configuration +dhcp_geoconf equ 123 ; 16 GeoConf Option +dhcp_v_i_vendor_class equ 124 ; Vendor-Identifying Vendor Class +dhcp_v_i_vendor_spec equ 125 ; Vendor-Identifying Vendor-Specific +; 126 REMOVED/Unassigned +; 127 REMOVED/Unassigned +dhcp_pxe equ 128 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) +dhcp_etherboot_sign equ 128 ; Etherboot signature. 6 bytes: E4:45:74:68:00:00 +dhcp_docsis equ 128 ; DOCSIS "full security" server IP address +dhcp_tftp_server_ip equ 128 ; TFTP Server IP address (for IP Phone software load) +dhcp_pxe equ 129 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) +dhcp_kernel_options equ 129 ; Kernel options. Variable length string +dhcp_call_server_ip equ 129 ; Call Server IP address +dhcp_pxe equ 130 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) +dhcp_ethernet_interface equ 130 ; Ethernet interface. Variable length string. +dhcp_siscrimination equ 130 ; Discrimination string (to identify vendor) +dhcp_pxe equ 131 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) +dhcp_remote_stat_server equ 131 ; Remote statistics server IP address +dhcp_pxe equ 132 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) +dhcp_802.1p equ 132 ; 802.1P VLAN ID +dhcp_pxe equ 133 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) +dhcp_802.1q equ 133 ; 802.1Q L2 Priority +dhcp_pxe equ 134 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) +dhcp_diffserv equ 134 ; Diffserv Code Point +dhcp_pxe equ 135 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) +dhcp_http_proxy_psa equ 135 ; HTTP Proxy for phone-specific applications +; 136 REMOVED/Unassigned +; 137 REMOVED/Unassigned +; 138 REMOVED/Unassigned +; 139 REMOVED/Unassigned +; 140 REMOVED/Unassigned +; 141 REMOVED/Unassigned +; 142 REMOVED/Unassigned +; 143 REMOVED/Unassigned +; 144 REMOVED/Unassigned +; 145 REMOVED/Unassigned +; 146 REMOVED/Unassigned +; 147 REMOVED/Unassigned +; 148 REMOVED/Unassigned +; 149 REMOVED/Unassigned +dhcp_tftp_server_addr equ 150 ; TFTP server address (Tentatively Assigned - 23 June 2005) +dhcp_etherboot equ 150 ; Etherboot +dhcp_grub_conf_path equ 150 ; GRUB configuration path name +; 151 REMOVED/Unassigned +; 152 REMOVED/Unassigned +; 153 REMOVED/Unassigned +; 154 REMOVED/Unassigned +; 155 REMOVED/Unassigned +; 156 REMOVED/Unassigned +; 157 REMOVED/Unassigned +; 158 REMOVED/Unassigned +; 159 REMOVED/Unassigned +; 160 REMOVED/Unassigned +; 161 REMOVED/Unassigned +; 162 REMOVED/Unassigned +; 163 REMOVED/Unassigned +; 164 REMOVED/Unassigned +; 165 REMOVED/Unassigned +; 166 REMOVED/Unassigned +; 167 REMOVED/Unassigned +; 168 REMOVED/Unassigned +; 169 REMOVED/Unassigned +; 170 REMOVED/Unassigned +; 171 REMOVED/Unassigned +; 172 REMOVED/Unassigned +; 173 REMOVED/Unassigned +; 174 REMOVED/Unassigned +dhcp_etherboot equ 175 ; Etherboot (Tentatively Assigned - 23 June 2005) +dhcp_ip_telephone equ 176 ; IP Telephone (Tentatively Assigned - 23 June 2005) +dhcp_etherboot equ 177 ; Etherboot (Tentatively Assigned - 23 June 2005) +dhcp_packetcable equ 177 ; PacketCable and CableHome (replaced by 122) +; 178 REMOVED/Unassigned +; 179 REMOVED/Unassigned +; 180 REMOVED/Unassigned +; 181 REMOVED/Unassigned +; 182 REMOVED/Unassigned +; 183 REMOVED/Unassigned +; 184 REMOVED/Unassigned +; 185 REMOVED/Unassigned +; 186 REMOVED/Unassigned +; 187 REMOVED/Unassigned +; 188 REMOVED/Unassigned +; 189 REMOVED/Unassigned +; 190 REMOVED/Unassigned +; 191 REMOVED/Unassigned +; 192 REMOVED/Unassigned +; 193 REMOVED/Unassigned +; 194 REMOVED/Unassigned +; 195 REMOVED/Unassigned +; 196 REMOVED/Unassigned +; 197 REMOVED/Unassigned +; 198 REMOVED/Unassigned +; 199 REMOVED/Unassigned +; 200 REMOVED/Unassigned +; 201 REMOVED/Unassigned +; 202 REMOVED/Unassigned +; 203 REMOVED/Unassigned +; 204 REMOVED/Unassigned +; 205 REMOVED/Unassigned +; 206 REMOVED/Unassigned +; 207 REMOVED/Unassigned +dhcp_pxelinux.magic equ 208 ; pxelinux.magic (string) = F1:00:74:7E (241.0.116.126) (Tentatively Assigned - 23 June 2005) +dhcp_pxelinux.conffile equ 209 ; pxelinux.configfile (text) (Tentatively Assigned - 23 June 2005) +dhcp_pxelinux.path equ 210 ; pxelinux.pathprefix (text) (Tentatively Assigned - 23 June 2005) +dhcp_pxelinux.reboot equ 211 ; pxelinux.reboottime (unsigned integer 32 bits) (Tentatively Assigned - 23 June 2005) +; 212 REMOVED/Unassigned +; 213 REMOVED/Unassigned +; 214 REMOVED/Unassigned +; 215 REMOVED/Unassigned +; 216 REMOVED/Unassigned +; 217 REMOVED/Unassigned +; 218 REMOVED/Unassigned +; 219 REMOVED/Unassigned +dhcp_subnet_aloc equ 220 ; Subnet Allocation Option (Tentatively Assigned - 23 June 2005) +dhcp_virtual_subnet equ 221 ; Virtual Subnet Selection Option (Tentatively Assigned - 23 June 2005) +; 222 REMOVED/Unassigned +; 223 REMOVED/Unassigned diff --git a/programs/network/zeroconf/trunk/zeroconf.asm b/programs/network_old/zeroconf/trunk/zeroconf.asm similarity index 100% rename from programs/network/zeroconf/trunk/zeroconf.asm rename to programs/network_old/zeroconf/trunk/zeroconf.asm diff --git a/programs/network/zeroconf/trunk/zeroconf.ini b/programs/network_old/zeroconf/trunk/zeroconf.ini similarity index 100% rename from programs/network/zeroconf/trunk/zeroconf.ini rename to programs/network_old/zeroconf/trunk/zeroconf.ini