Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [rom/] [w5100_sockalloc.asm] - Diff between revs 371 and 384

Show entire file | Details | Blame | View Log

Rev 371 Rev 384
Line 17... Line 17...
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;THE SOFTWARE.
;THE SOFTWARE.
 
.include        "w5100_defs.inc"
 
.include        "sysvars.inc"
 
.include        "sockdefs.inc"
 
 
; Socket allocation routines. In this file:
; Socket allocation routines. In this file:
; F_socket
; F_socket
; F_accept
; F_accept
; F_close
; F_close
Line 43... Line 45...
;
;
; Parameters: C = int type
; Parameters: C = int type
; Returns: file descriptor in A
; Returns: file descriptor in A
;
;
; Preserves: BC
; Preserves: BC
F_socket
.text
 
.globl F_socket
 
F_socket:
        ld a, (v_pga)           ; save page A
        ld a, (v_pga)           ; save page A
        ld (v_buf_pga), a
        ld (v_buf_pga), a
        ld a, REGPAGE
        ld a, REGPAGE
        call F_setpageA
        call F_setpageA
 
 
        ; Find a free socket. HL will contain the pointer to the socket
        ; Find a free socket. HL will contain the pointer to the socket
        ; register.
        ; register.
        call F_hwallocsock      ; carry is set when no hw sockets left.
        call F_hwallocsock      ; carry is set when no hw sockets left.
        jr nc, .foundsock
        jr nc, .foundsock1
.nosockets
.nosockets1:
        ld a, ESNFILE           ; no more hardware sockets, sorry
        ld a, ESNFILE           ; no more hardware sockets, sorry
        jp J_leavesockfn
        jp J_leavesockfn
.foundsock
.foundsock1:
        ld de, v_fd1hwsock      ; (de) = fd map first entry
        ld de, v_fd1hwsock      ; (de) = fd map first entry
        ex de, hl
        ex de, hl
.findfd
.findfd1:
        bit 7, (hl)             ; is bit 7 (not allocated) set?
        bit 7, (hl)             ; is bit 7 (not allocated) set?
        jr nz, .allocfd
        jr nz, .allocfd1
        inc l                   ; next fd
        inc l                   ; next fd
        jr .findfd
        jr .findfd1
.allocfd
.allocfd1:
        ld (hl), d              ; associate the hw socket with the fd
        ld (hl), d              ; associate the hw socket with the fd
        ex de, hl
        ex de, hl
        call F_hwopensock       ; h = msb of socket register
        call F_hwopensock       ; h = msb of socket register
        jr nc, .sockopen        ; if carry not set, socket was opened
        jr nc, .sockopen1       ; if carry not set, socket was opened
        ld a, EBUGGERED         ; TODO: better return code
        ld a, EBUGGERED         ; TODO: better return code
        jp J_leavesockfn
        jp J_leavesockfn
 
 
.sockopen
.sockopen1:
        ld a, e                 ; a = file descriptor
        ld a, e                 ; a = file descriptor
        jp J_leavesockfn
        jp J_leavesockfn
 
 
;-------------------------------------------------------------------------
;-------------------------------------------------------------------------
; F_sockclose:
; F_sockclose:
Line 84... Line 88...
; library equivalent is: int close(int fd)
; library equivalent is: int close(int fd)
;
;
; Parameters: A = file descriptor
; Parameters: A = file descriptor
;
;
; Carry flag is set if an error occurs reopening a virtual socket.
; Carry flag is set if an error occurs reopening a virtual socket.
F_sockclose
.globl F_sockclose
 
F_sockclose:
        push af
        push af
        ld a, (v_pga)           ; save page A
        ld a, (v_pga)           ; save page A
        ld (v_buf_pga), a
        ld (v_buf_pga), a
        ld a, REGPAGE
        ld a, REGPAGE
        call F_setpageA
        call F_setpageA
Line 103... Line 108...
 
 
        ld h, a                 ; h = MSB of socket register pointer
        ld h, a                 ; h = MSB of socket register pointer
        ld l, Sn_MR % 256       ; check for non-stream socket
        ld l, Sn_MR % 256       ; check for non-stream socket
        ld a, (hl)
        ld a, (hl)
        and S_MR_TCP            ; if it's not TCP jump forward
        and S_MR_TCP            ; if it's not TCP jump forward
        jr z, .close            ; straight to closing the hardware resource
        jr z, .close2           ; straight to closing the hardware resource
 
 
        ld l, Sn_SR % 256       ; check the status register
        ld l, Sn_SR % 256       ; check the status register
        ld a, (hl)
        ld a, (hl)
        cp S_SR_SOCK_INIT       ; nothing has been done yet
        cp S_SR_SOCK_INIT       ; nothing has been done yet
        jr z, .close            ; so skip disconnect part.
        jr z, .close2           ; so skip disconnect part.
 
 
        cp S_SR_SOCK_LISTEN     ; still nothing has been done
        cp S_SR_SOCK_LISTEN     ; still nothing has been done
        jr z, .close            ; so skip disconnect part.
        jr z, .close2           ; so skip disconnect part.
 
 
        ld l, Sn_CR % 256       ; (hl) = socket's command register
        ld l, Sn_CR % 256       ; (hl) = socket's command register
        ld (hl), S_CR_DISCON    ; disconnect remote host
        ld (hl), S_CR_DISCON    ; disconnect remote host
        ld l, Sn_IR % 256       ; (hl) = interrupt register
        ld l, Sn_IR % 256       ; (hl) = interrupt register
.waitfordiscon
.waitfordiscon2:
        ld a, (hl)
        ld a, (hl)
        and S_IR_DISCON
        and S_IR_DISCON
        jr z, .waitfordiscon
        jr z, .waitfordiscon2
        ld (hl), S_IR_DISCON    ; reset interrupt register
        ld (hl), S_IR_DISCON    ; reset interrupt register
.close
.close2:
        ld l, Sn_CR % 256       ; (hl) = command register
        ld l, Sn_CR % 256       ; (hl) = command register
        ld (hl), S_CR_CLOSE     ; close the socket.
        ld (hl), S_CR_CLOSE     ; close the socket.
        ex de, hl               ; store socket register pointer in DE
        ex de, hl               ; store socket register pointer in DE
 
 
        ; Check for virtual sockets. A virtual socket is allocated when
        ; Check for virtual sockets. A virtual socket is allocated when
Line 133... Line 138...
        ; to keep an open fd for the listen()/accept() routine. We now
        ; to keep an open fd for the listen()/accept() routine. We now
        ; definitely have at least one free socket going, so we can give
        ; definitely have at least one free socket going, so we can give
        ; it to the first fd that we find that's in need of one.
        ; it to the first fd that we find that's in need of one.
        ld hl, v_fd1hwsock
        ld hl, v_fd1hwsock
        ld b, MAX_FDS
        ld b, MAX_FDS
.vsearch
.vsearch2:
        bit 6, (hl)             ; virtual bit set?
        bit 6, (hl)             ; virtual bit set?
        jr nz, .realloc         ; reallocate the hardware socket to this fd
        jr nz, .realloc2                ; reallocate the hardware socket to this fd
        inc l                   ; check the next fd
        inc l                   ; check the next fd
        djnz .vsearch
        djnz .vsearch2
        jp J_leavesockfn        ; nothing more to do - function complete.
        jp J_leavesockfn        ; nothing more to do - function complete.
 
 
        ; To reallocate a hardware socket to a file descriptor that's
        ; To reallocate a hardware socket to a file descriptor that's
        ; gone virtual, it must be opened.
        ; gone virtual, it must be opened.
.realloc
.realloc2:
        ; The hardware needs a delay before a socket is re-opened.
        ; The hardware needs a delay before a socket is re-opened.
        ; TODO: write to Wiznet and see if there's a better way of doing this.
        ; TODO: write to Wiznet and see if there's a better way of doing this.
        ld b, 255
        ld b, 255
.waitloop
.waitloop2:
        djnz .waitloop
        djnz .waitloop2
 
 
        ex de, hl               ; socket register pointer back to HL
        ex de, hl               ; socket register pointer back to HL
        ld a, (v_virtualmr)     ; get socket type for the socket we're doing
        ld a, (v_virtualmr)     ; get socket type for the socket we're doing
        ld c, a                 ; socket type in C
        ld c, a                 ; socket type in C
        call F_hwopensock       ; open socket pointed to by (hl)
        call F_hwopensock       ; open socket pointed to by (hl)
Line 168... Line 173...
        ld l, Sn_SR % 256       ; get status register
        ld l, Sn_SR % 256       ; get status register
        ld a, (hl)
        ld a, (hl)
        cp S_SR_SOCK_LISTEN     ; should be listening
        cp S_SR_SOCK_LISTEN     ; should be listening
        ex de, hl               ; move sock register addr to de
        ex de, hl               ; move sock register addr to de
        pop hl                  ; retrieve fd
        pop hl                  ; retrieve fd
        jr nz, .reallocerr
        jr nz, .reallocerr2
        ld (hl), d              ; store socket register ptr MSB in fd map
        ld (hl), d              ; store socket register ptr MSB in fd map
        jp J_leavesockfn
        jp J_leavesockfn
.reallocerr
.reallocerr2:
        ld a, EBUGGERED
        ld a, EBUGGERED
        scf
        scf
        jp J_leavesockfn
        jp J_leavesockfn
 
 
;--------------------------------------------------------------------------
;--------------------------------------------------------------------------
Line 190... Line 195...
;
;
; Parameters: A = file descriptor to perform an accept on.
; Parameters: A = file descriptor to perform an accept on.
; Returns: A = file descriptor of accepted connection
; Returns: A = file descriptor of accepted connection
;
;
; On error carry is set and A contains the error number.
; On error carry is set and A contains the error number.
F_accept
.globl F_accept
 
F_accept:
        push af                 ; save the fd
        push af                 ; save the fd
        ld a, (v_pga)           ; save page A
        ld a, (v_pga)           ; save page A
        ld (v_buf_pga), a
        ld (v_buf_pga), a
        ld a, REGPAGE
        ld a, REGPAGE
        call F_setpageA
        call F_setpageA
Line 203... Line 209...
        ld h, v_fd1hwsock / 256 ; MSB of fd map address
        ld h, v_fd1hwsock / 256 ; MSB of fd map address
        ld l, a                 ; (hl) = fd map for this fd
        ld l, a                 ; (hl) = fd map for this fd
        ld d, (hl)              ; d = MSB of socket register address
        ld d, (hl)              ; d = MSB of socket register address
        ex de, hl               ; h = MSB of socket register address
        ex de, hl               ; h = MSB of socket register address
        ld l, Sn_SR % 256       ; (hl) = socket's SR
        ld l, Sn_SR % 256       ; (hl) = socket's SR
.waitforestablished
.waitforestablished3:
        ld a, (hl)
        ld a, (hl)
        cp S_SR_SOCK_CLOSE_WAIT ; a really short connection can mean we
        cp S_SR_SOCK_CLOSE_WAIT ; a really short connection can mean we
        jr z, .continue         ; are in CLOSE_WAIT before we ever got
        jr z, .continue3                ; are in CLOSE_WAIT before we ever got
        cp S_SR_SOCK_ESTABLISHED ; an opportunity to accept...
        cp S_SR_SOCK_ESTABLISHED ; an opportunity to accept...
        jr nz, .waitforestablished
        jr nz, .waitforestablished3
.continue
.continue3:
        ld l, Sn_IR % 256       ; clear the interrupt flag for this socket
        ld l, Sn_IR % 256       ; clear the interrupt flag for this socket
        ld (hl), S_IR_CON
        ld (hl), S_IR_CON
 
 
        ; Now allocate a new fd for the accepted connection.
        ; Now allocate a new fd for the accepted connection.
        ld b, h                 ; save socket register pointer MSB
        ld b, h                 ; save socket register pointer MSB
        ld hl, v_fd1hwsock
        ld hl, v_fd1hwsock
.findfd
.findfd3:
        bit 7, (hl)             ; is bit 7 (not allocated) set?
        bit 7, (hl)             ; is bit 7 (not allocated) set?
        jr nz, .allocfd
        jr nz, .allocfd3
        inc l                   ; next fd
        inc l                   ; next fd
        jr .findfd
        jr .findfd3
.allocfd
.allocfd3:
        ld (hl), b              ; associate new fd with accepted socket
        ld (hl), b              ; associate new fd with accepted socket
        push hl                 ; save address of new fd
        push hl                 ; save address of new fd
        ld h, b                 ; point hl at accepted socket to get type
        ld h, b                 ; point hl at accepted socket to get type
        ld l, Sn_MR % 256       ; (hl) = socket's MR
        ld l, Sn_MR % 256       ; (hl) = socket's MR
        ld c, (hl)              ; save MR in c
        ld c, (hl)              ; save MR in c
        call F_hwallocsock      ; try to open a new hardware socket
        call F_hwallocsock      ; try to open a new hardware socket
        jr c, .virtualize       ; no sockets left, so virtualize the fd
        jr c, .virtualize3      ; no sockets left, so virtualize the fd
        call F_hwopensock       ; (hl) points at new registers, try to open
        call F_hwopensock       ; (hl) points at new registers, try to open
        jr c, .virtualize       ; failed
        jr c, .virtualize3      ; failed
        ex de, hl               ; get original fd address into hl
        ex de, hl               ; get original fd address into hl
        ld (hl), d              ; save the new listening socket's MSB in fd map
        ld (hl), d              ; save the new listening socket's MSB in fd map
        ld h, b                 ; get MSB of original socket
        ld h, b                 ; get MSB of original socket
        ld l, Sn_PORT0 % 256    ; (hl) = port register of accepted hw socket
        ld l, Sn_PORT0 % 256    ; (hl) = port register of accepted hw socket
        ld e, l                 ; (de) = port register of new hw socket
        ld e, l                 ; (de) = port register of new hw socket
Line 244... Line 250...
        ld l, Sn_CR % 256       ; hl = command register ptr
        ld l, Sn_CR % 256       ; hl = command register ptr
        ld (hl), S_CR_LISTEN    ; tell new socket to listen
        ld (hl), S_CR_LISTEN    ; tell new socket to listen
        ld l, Sn_SR % 256       ; hl = status register ptr
        ld l, Sn_SR % 256       ; hl = status register ptr
        ld a, (hl)
        ld a, (hl)
        cp S_SR_SOCK_LISTEN     ; check for listening state
        cp S_SR_SOCK_LISTEN     ; check for listening state
        jr nz, .listenfail
        jr nz, .listenfail3
        pop hl                  ; get fd back to return to caller
        pop hl                  ; get fd back to return to caller
        ld a, l                 ; set fd number in A
        ld a, l                 ; set fd number in A
        jp J_leavesockfn
        jp J_leavesockfn
.listenfail
.listenfail3:
        ld a, EBUGGERED         ; set error code and return with carry set
        ld a, EBUGGERED         ; set error code and return with carry set
        scf
        scf
        jp J_leavesockfn
        jp J_leavesockfn
 
 
.virtualize
.virtualize3:
        ex de, hl               ; get original fd address
        ex de, hl               ; get original fd address
        ld (hl), FD_VIRTUAL     ; mark as virtual
        ld (hl), FD_VIRTUAL     ; mark as virtual
        ld h, b                 ; get MSB of socket register into H for HL
        ld h, b                 ; get MSB of socket register into H for HL
        ld l, Sn_MR % 256       ; mode register
        ld l, Sn_MR % 256       ; mode register
        ld de, v_virtualmr      ; point de at MR storage
        ld de, v_virtualmr      ; point de at MR storage
Line 272... Line 278...
;--------------------------------------------------------------------------
;--------------------------------------------------------------------------
; Find a free hardware socket. Carry flag is set if no free sockets.
; Find a free hardware socket. Carry flag is set if no free sockets.
; An internal function.
; An internal function.
; No parameters.
; No parameters.
; On return (hl) = status register of available hardware socket.
; On return (hl) = status register of available hardware socket.
F_hwallocsock
.globl F_hwallocsock
 
F_hwallocsock:
        ; Find a free socket.
        ; Find a free socket.
        ld hl, Sn_SR            ; hl points at the first socket register
        ld hl, Sn_SR            ; hl points at the first socket register
.sockloop
.sockloop4:
        ld a, (hl)              ; get status register value
        ld a, (hl)              ; get status register value
        cp S_SR_SOCK_CLOSED     ; a closed socket?
        cp S_SR_SOCK_CLOSED     ; a closed socket?
        jr z, .foundsock        ; yes, allocate it
        jr z, .foundsock4       ; yes, allocate it
        inc h                   ; next socket register
        inc h                   ; next socket register
        ld a, h                 ; check whether hardware sockets are
        ld a, h                 ; check whether hardware sockets are
        cp Sn_MAX               ; exhausted
        cp Sn_MAX               ; exhausted
        jr nz, .sockloop        ; and check the next if not.
        jr nz, .sockloop4       ; and check the next if not.
        scf                     ; out of sockets - set C
        scf                     ; out of sockets - set C
.foundsock
.foundsock4:
        ret
        ret
 
 
; Open a hardware socket. Carry flag is set if no free sockets.
; Open a hardware socket. Carry flag is set if no free sockets.
; An internal function.
; An internal function.
; Parameters: C = socket type (SOCK_STREAM, SOCK_DGRAM, SOCK_RAW etc)
; Parameters: C = socket type (SOCK_STREAM, SOCK_DGRAM, SOCK_RAW etc)
;             HL = pointer to socket register area
;             HL = pointer to socket register area
F_hwopensock
.globl F_hwopensock
 
F_hwopensock:
        ld a, SOCK_STREAM       ; for SOCK_STREAM ensure delayed ACK is off
        ld a, SOCK_STREAM       ; for SOCK_STREAM ensure delayed ACK is off
        cp c
        cp c
        jr nz, .continue
        jr nz, .continue5
        set 5, c                ; set 'use no delayed ACK'
        set 5, c                ; set 'use no delayed ACK'
.continue
.continue5:
        ld l, Sn_IR % 256       ; (hl) = interrupt register
        ld l, Sn_IR % 256       ; (hl) = interrupt register
        ld (hl), 0x1F           ; clear all interrupt flags
        ld (hl), 0x1F           ; clear all interrupt flags
        ld l, Sn_MR % 256       ; (hl) = socket mode register
        ld l, Sn_MR % 256       ; (hl) = socket mode register
        ld (hl), c              ; set type of socket
        ld (hl), c              ; set type of socket
        ld l, Sn_CR % 256       ; (hl) = command register
        ld l, Sn_CR % 256       ; (hl) = command register
        ld (hl), S_CR_OPEN      ; hardware command: open socket
        ld (hl), S_CR_OPEN      ; hardware command: open socket
        ld l, Sn_SR % 256       ; (hl) = status register
        ld l, Sn_SR % 256       ; (hl) = status register
        ld a, SOCK_DGRAM        ; is this a UDP socket?
        ld a, SOCK_DGRAM        ; is this a UDP socket?
        cp c
        cp c
        jr z, .checkudpstat     ; do status check for UDP socket.
        jr z, .checkudpstat5    ; do status check for UDP socket.
        ld a, (hl)              ; TCP socket (SOCK_STREAM)
        ld a, (hl)              ; TCP socket (SOCK_STREAM)
        cp S_SR_SOCK_INIT       ; did it initialize ok?
        cp S_SR_SOCK_INIT       ; did it initialize ok?
        ret z
        ret z
 
 
        ; Bad things happened. Clean up and return an error.
        ; Bad things happened. Clean up and return an error.
.failed
.failed5:
        ld l, Sn_CR % 256       ; (hl) = command register so...
        ld l, Sn_CR % 256       ; (hl) = command register so...
        ld (hl), S_CR_CLOSE     ; clean up.
        ld (hl), S_CR_CLOSE     ; clean up.
        scf
        scf
        ret
        ret
.checkudpstat
.checkudpstat5:
        ld a, (hl)
        ld a, (hl)
        cp S_SR_SOCK_UDP        ; Successfully initialized?
        cp S_SR_SOCK_UDP        ; Successfully initialized?
        ret z
        ret z
        jr .failed
        jr .failed5