Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [rom/] [w5100_sockalloc.asm] - Blame information for rev 384

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 24 winston
;The MIT License
2
;
3
;Copyright (c) 2008 Dylan Smith
4
;
5
;Permission is hereby granted, free of charge, to any person obtaining a copy
6
;of this software and associated documentation files (the "Software"), to deal
7
;in the Software without restriction, including without limitation the rights
8
;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
;copies of the Software, and to permit persons to whom the Software is
10
;furnished to do so, subject to the following conditions:
11
;
12
;The above copyright notice and this permission notice shall be included in
13
;all copies or substantial portions of the Software.
14
;
15
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
;THE SOFTWARE.
22 384 winston
.include        "w5100_defs.inc"
23
.include        "sysvars.inc"
24
.include        "sockdefs.inc"
25 24 winston
 
26
; Socket allocation routines. In this file:
27
; F_socket
28
; F_accept
29
; F_close
30
;
31
; These routines open hardware sockets and map them to a file descriptor,
32
; and clean up when all work is done. They are the equivalent of the
33
; BSD socket library function calls socket() and close(). C implementations
34
; should wrap these in the appropriate socket()/close() functions.
35
; The file descriptor is actually the low order of the fd <-> socket
36
; map address. C wrappers might need to map this further into a list
37
; of file descriptors.
38
;
39
; F_socket:
40
; Finds a free hardware socket and allocates it to a file descriptor.
41
; The full BSD routine is int socket(int family, int type, int proto)
42
; but this function will always be specific to AF_INET sockets, so
43
; only the type parameter is used. This should be SOCK_STREAM, SOCK_DGRAM
44
; or SOCK_RAW.
45
;
46
; Parameters: C = int type
47
; Returns: file descriptor in A
48
;
49
; Preserves: BC
50 384 winston
.text
51
.globl F_socket
52
F_socket:
53 142 winston
        ld a, (v_pga)           ; save page A
54
        ld (v_buf_pga), a
55 110 winston
        ld a, REGPAGE
56 24 winston
        call F_setpageA
57
 
58
        ; Find a free socket. HL will contain the pointer to the socket
59
        ; register.
60
        call F_hwallocsock      ; carry is set when no hw sockets left.
61 384 winston
        jr nc, .foundsock1
62
.nosockets1:
63 267 winston
        ld a, ESNFILE           ; no more hardware sockets, sorry
64 142 winston
        jp J_leavesockfn
65 384 winston
.foundsock1:
66 24 winston
        ld de, v_fd1hwsock      ; (de) = fd map first entry
67
        ex de, hl
68 384 winston
.findfd1:
69 24 winston
        bit 7, (hl)             ; is bit 7 (not allocated) set?
70 384 winston
        jr nz, .allocfd1
71 24 winston
        inc l                   ; next fd
72 384 winston
        jr .findfd1
73
.allocfd1:
74 24 winston
        ld (hl), d              ; associate the hw socket with the fd
75
        ex de, hl
76
        call F_hwopensock       ; h = msb of socket register
77 384 winston
        jr nc, .sockopen1       ; if carry not set, socket was opened
78 24 winston
        ld a, EBUGGERED         ; TODO: better return code
79 142 winston
        jp J_leavesockfn
80 24 winston
 
81 384 winston
.sockopen1:
82 24 winston
        ld a, e                 ; a = file descriptor
83 142 winston
        jp J_leavesockfn
84 24 winston
 
85
;-------------------------------------------------------------------------
86
; F_sockclose:
87
; Close an open socket and free its file descriptor. The BSD socket
88
; library equivalent is: int close(int fd)
89
;
90
; Parameters: A = file descriptor
91
;
92
; Carry flag is set if an error occurs reopening a virtual socket.
93 384 winston
.globl F_sockclose
94
F_sockclose:
95 42 winston
        push af
96 142 winston
        ld a, (v_pga)           ; save page A
97
        ld (v_buf_pga), a
98 110 winston
        ld a, REGPAGE
99 24 winston
        call F_setpageA
100 42 winston
        pop af
101 24 winston
 
102
        ld h, v_fd1hwsock / 256 ; high order of file descriptor map
103
        ld l, a                 ; (hl) = file descriptor map
104
        ld a, (hl)              ; get possible MSB of socket register ptr
105
        bit 6, a                ; is this a virtual socket or not even open?
106
        ld (hl), FD_CLOSED      ; unmap the file descriptor
107 142 winston
        jp nz, J_leavesockfn    ; virtual socket, no hardware sock to close
108 24 winston
 
109
        ld h, a                 ; h = MSB of socket register pointer
110 51 winston
        ld l, Sn_MR % 256       ; check for non-stream socket
111
        ld a, (hl)
112
        and S_MR_TCP            ; if it's not TCP jump forward
113 384 winston
        jr z, .close2           ; straight to closing the hardware resource
114 51 winston
 
115 79 winston
        ld l, Sn_SR % 256       ; check the status register
116
        ld a, (hl)
117
        cp S_SR_SOCK_INIT       ; nothing has been done yet
118 384 winston
        jr z, .close2           ; so skip disconnect part.
119 79 winston
 
120 84 winston
        cp S_SR_SOCK_LISTEN     ; still nothing has been done
121 384 winston
        jr z, .close2           ; so skip disconnect part.
122 84 winston
 
123 24 winston
        ld l, Sn_CR % 256       ; (hl) = socket's command register
124
        ld (hl), S_CR_DISCON    ; disconnect remote host
125
        ld l, Sn_IR % 256       ; (hl) = interrupt register
126 384 winston
.waitfordiscon2:
127 24 winston
        ld a, (hl)
128
        and S_IR_DISCON
129 384 winston
        jr z, .waitfordiscon2
130 24 winston
        ld (hl), S_IR_DISCON    ; reset interrupt register
131 384 winston
.close2:
132 24 winston
        ld l, Sn_CR % 256       ; (hl) = command register
133
        ld (hl), S_CR_CLOSE     ; close the socket.
134
        ex de, hl               ; store socket register pointer in DE
135
 
136
        ; Check for virtual sockets. A virtual socket is allocated when
137
        ; we are listening, and ran out of hardware sockets but needed
138
        ; to keep an open fd for the listen()/accept() routine. We now
139
        ; definitely have at least one free socket going, so we can give
140
        ; it to the first fd that we find that's in need of one.
141
        ld hl, v_fd1hwsock
142
        ld b, MAX_FDS
143 384 winston
.vsearch2:
144 24 winston
        bit 6, (hl)             ; virtual bit set?
145 384 winston
        jr nz, .realloc2                ; reallocate the hardware socket to this fd
146 24 winston
        inc l                   ; check the next fd
147 384 winston
        djnz .vsearch2
148 142 winston
        jp J_leavesockfn        ; nothing more to do - function complete.
149 24 winston
 
150
        ; To reallocate a hardware socket to a file descriptor that's
151
        ; gone virtual, it must be opened.
152 384 winston
.realloc2:
153 87 winston
        ; The hardware needs a delay before a socket is re-opened.
154
        ; TODO: write to Wiznet and see if there's a better way of doing this.
155
        ld b, 255
156 384 winston
.waitloop2:
157
        djnz .waitloop2
158 87 winston
 
159 24 winston
        ex de, hl               ; socket register pointer back to HL
160 86 winston
        ld a, (v_virtualmr)     ; get socket type for the socket we're doing
161
        ld c, a                 ; socket type in C
162 24 winston
        call F_hwopensock       ; open socket pointed to by (hl)
163 142 winston
        jp c, J_leavesockfn     ; an error has occurred if carry is set.
164 86 winston
        ex de, hl               ; fd address now in hl, sock register in de
165
        push hl                 ; save fd
166
        ld hl, v_virtualport    ; v_virtualport is in network byte order
167
        ld e, Sn_PORT0 % 256    ; de = port register
168
        ldi
169
        ldi
170
        ex de, hl               ; sock in hl, de=don't care
171
        ld l, Sn_CR % 256       ; get command register
172
        ld (hl), S_CR_LISTEN    ; listen
173
        ld l, Sn_SR % 256       ; get status register
174
        ld a, (hl)
175
        cp S_SR_SOCK_LISTEN     ; should be listening
176
        ex de, hl               ; move sock register addr to de
177
        pop hl                  ; retrieve fd
178 384 winston
        jr nz, .reallocerr2
179 24 winston
        ld (hl), d              ; store socket register ptr MSB in fd map
180 142 winston
        jp J_leavesockfn
181 384 winston
.reallocerr2:
182 86 winston
        ld a, EBUGGERED
183
        scf
184 142 winston
        jp J_leavesockfn
185 24 winston
 
186
;--------------------------------------------------------------------------
187
; F_accept: Accept a connection on a socket that is listening.
188
;
189
; First, the connection is accepted by poking the hardware registers.
190
; Then a new fd is allocated, and the hardware socket is associated with
191
; the new fd. Then, a new listening socket is opened - and if we've not
192
; run out of hardware sockets it is associated with the original fd.
193
; If we've run out of hardware sockets, the original fd is marked
194
; virtual (so that a new socket can get allocated when one gets closed).
195
;
196
; Parameters: A = file descriptor to perform an accept on.
197
; Returns: A = file descriptor of accepted connection
198
;
199
; On error carry is set and A contains the error number.
200 384 winston
.globl F_accept
201
F_accept:
202 24 winston
        push af                 ; save the fd
203 142 winston
        ld a, (v_pga)           ; save page A
204
        ld (v_buf_pga), a
205 110 winston
        ld a, REGPAGE
206 24 winston
        call F_setpageA
207
        pop af
208
 
209
        ld h, v_fd1hwsock / 256 ; MSB of fd map address
210
        ld l, a                 ; (hl) = fd map for this fd
211
        ld d, (hl)              ; d = MSB of socket register address
212
        ex de, hl               ; h = MSB of socket register address
213
        ld l, Sn_SR % 256       ; (hl) = socket's SR
214 384 winston
.waitforestablished3:
215 24 winston
        ld a, (hl)
216 309 winston
        cp S_SR_SOCK_CLOSE_WAIT ; a really short connection can mean we
217 384 winston
        jr z, .continue3                ; are in CLOSE_WAIT before we ever got
218 309 winston
        cp S_SR_SOCK_ESTABLISHED ; an opportunity to accept...
219 384 winston
        jr nz, .waitforestablished3
220
.continue3:
221 24 winston
        ld l, Sn_IR % 256       ; clear the interrupt flag for this socket
222
        ld (hl), S_IR_CON
223
 
224
        ; Now allocate a new fd for the accepted connection.
225
        ld b, h                 ; save socket register pointer MSB
226
        ld hl, v_fd1hwsock
227 384 winston
.findfd3:
228 24 winston
        bit 7, (hl)             ; is bit 7 (not allocated) set?
229 384 winston
        jr nz, .allocfd3
230 24 winston
        inc l                   ; next fd
231 384 winston
        jr .findfd3
232
.allocfd3:
233 24 winston
        ld (hl), b              ; associate new fd with accepted socket
234
        push hl                 ; save address of new fd
235
        ld h, b                 ; point hl at accepted socket to get type
236
        ld l, Sn_MR % 256       ; (hl) = socket's MR
237
        ld c, (hl)              ; save MR in c
238
        call F_hwallocsock      ; try to open a new hardware socket
239 384 winston
        jr c, .virtualize3      ; no sockets left, so virtualize the fd
240 24 winston
        call F_hwopensock       ; (hl) points at new registers, try to open
241 384 winston
        jr c, .virtualize3      ; failed
242 24 winston
        ex de, hl               ; get original fd address into hl
243
        ld (hl), d              ; save the new listening socket's MSB in fd map
244
        ld h, b                 ; get MSB of original socket
245
        ld l, Sn_PORT0 % 256    ; (hl) = port register of accepted hw socket
246
        ld e, l                 ; (de) = port register of new hw socket
247
        ldi                     ; copy port across to bind new hw socket
248
        ldi
249 42 winston
        ex de, hl               ; new socket pointed to by hl
250
        ld l, Sn_CR % 256       ; hl = command register ptr
251
        ld (hl), S_CR_LISTEN    ; tell new socket to listen
252
        ld l, Sn_SR % 256       ; hl = status register ptr
253
        ld a, (hl)
254
        cp S_SR_SOCK_LISTEN     ; check for listening state
255 384 winston
        jr nz, .listenfail3
256 24 winston
        pop hl                  ; get fd back to return to caller
257
        ld a, l                 ; set fd number in A
258 142 winston
        jp J_leavesockfn
259 384 winston
.listenfail3:
260 42 winston
        ld a, EBUGGERED         ; set error code and return with carry set
261
        scf
262 142 winston
        jp J_leavesockfn
263 24 winston
 
264 384 winston
.virtualize3:
265 24 winston
        ex de, hl               ; get original fd address
266
        ld (hl), FD_VIRTUAL     ; mark as virtual
267 86 winston
        ld h, b                 ; get MSB of socket register into H for HL
268
        ld l, Sn_MR % 256       ; mode register
269
        ld de, v_virtualmr      ; point de at MR storage
270
        ldi                     ; save MR
271
        ld l, Sn_PORT0 % 256    ; port number
272
        ldi                     ; save in network byte order in v_virtualport
273
        ldi
274
        pop hl                  ; get fd back
275 24 winston
        ld a, l                 ; new fd number in A
276 142 winston
        jp J_leavesockfn
277 24 winston
 
278
;--------------------------------------------------------------------------
279
; Find a free hardware socket. Carry flag is set if no free sockets.
280
; An internal function.
281
; No parameters.
282
; On return (hl) = status register of available hardware socket.
283 384 winston
.globl F_hwallocsock
284
F_hwallocsock:
285 24 winston
        ; Find a free socket.
286
        ld hl, Sn_SR            ; hl points at the first socket register
287 384 winston
.sockloop4:
288 24 winston
        ld a, (hl)              ; get status register value
289
        cp S_SR_SOCK_CLOSED     ; a closed socket?
290 384 winston
        jr z, .foundsock4       ; yes, allocate it
291 24 winston
        inc h                   ; next socket register
292
        ld a, h                 ; check whether hardware sockets are
293
        cp Sn_MAX               ; exhausted
294 384 winston
        jr nz, .sockloop4       ; and check the next if not.
295 24 winston
        scf                     ; out of sockets - set C
296 384 winston
.foundsock4:
297 24 winston
        ret
298
 
299
; Open a hardware socket. Carry flag is set if no free sockets.
300
; An internal function.
301
; Parameters: C = socket type (SOCK_STREAM, SOCK_DGRAM, SOCK_RAW etc)
302
;             HL = pointer to socket register area
303 384 winston
.globl F_hwopensock
304
F_hwopensock:
305 90 winston
        ld a, SOCK_STREAM       ; for SOCK_STREAM ensure delayed ACK is off
306
        cp c
307 384 winston
        jr nz, .continue5
308 90 winston
        set 5, c                ; set 'use no delayed ACK'
309 384 winston
.continue5:
310 42 winston
        ld l, Sn_IR % 256       ; (hl) = interrupt register
311
        ld (hl), 0x1F           ; clear all interrupt flags
312 24 winston
        ld l, Sn_MR % 256       ; (hl) = socket mode register
313
        ld (hl), c              ; set type of socket
314
        ld l, Sn_CR % 256       ; (hl) = command register
315
        ld (hl), S_CR_OPEN      ; hardware command: open socket
316
        ld l, Sn_SR % 256       ; (hl) = status register
317 46 winston
        ld a, SOCK_DGRAM        ; is this a UDP socket?
318
        cp c
319 384 winston
        jr z, .checkudpstat5    ; do status check for UDP socket.
320 46 winston
        ld a, (hl)              ; TCP socket (SOCK_STREAM)
321 24 winston
        cp S_SR_SOCK_INIT       ; did it initialize ok?
322
        ret z
323
 
324
        ; Bad things happened. Clean up and return an error.
325 384 winston
.failed5:
326 24 winston
        ld l, Sn_CR % 256       ; (hl) = command register so...
327
        ld (hl), S_CR_CLOSE     ; clean up.
328
        scf
329
        ret
330 384 winston
.checkudpstat5:
331 46 winston
        ld a, (hl)
332
        cp S_SR_SOCK_UDP        ; Successfully initialized?
333
        ret z
334 384 winston
        jr .failed5
335 86 winston