Added advisory locks. ftdi_get_list now returns list of FTDI devices. Added some requests. Added chip type identification in AddDevice. Changed linkedlist's procs' names. Added linkedlist_isvalid

git-svn-id: svn://kolibrios.org@4997 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
gtament 2014-07-16 17:40:12 +00:00
parent a440af1ed3
commit 81fda06eb0
2 changed files with 275 additions and 52 deletions

View File

@ -1,9 +1,14 @@
head dd 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
node equ ftdi_context ;; ;;
node.next equ ftdi_context.next_context ;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;;
linkedlist: ;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.add: head dd 0
size dd 0
linkedlist_add:
push ebx push ebx
mov ebx, [head] mov ebx, [head]
mov [head], eax mov [head], eax
@ -11,7 +16,7 @@ linkedlist:
pop ebx pop ebx
ret ret
.delete: linkedlist_delete:
push ebx ecx push ebx ecx
mov ebx, eax ; eax - pointer to node for delete mov ebx, eax ; eax - pointer to node for delete
cmp eax, [head] cmp eax, [head]
@ -29,8 +34,7 @@ linkedlist:
mov ecx, [eax+node.next] mov ecx, [eax+node.next]
mov [ebx+node.next], ecx mov [ebx+node.next], ecx
jmp @f jmp @f
.unlink_head: .unlink_head:
mov ebx, [eax+node.next] mov ebx, [eax+node.next]
mov [head], ebx mov [head], ebx
@ -40,8 +44,26 @@ linkedlist:
.invalid_pointer: .invalid_pointer:
pop ecx ebx pop ecx ebx
ret ret
linkedlist_isvalid:
push ebx ecx
xor ecx, ecx
mov ebx, [head]
.next_check:
cmp eax, ebx
jz .valid_pointer
mov ebx, [ebx + node.next]
test ebx, ebx
jz .invalid_pointer
jmp .next_check
.invalid_pointer:
inc ecx
.valid_pointer:
mov eax, ecx
pop ecx ebx
ret
.gethead: linkedlist_gethead:
mov eax, [head] mov eax, [head]
ret ret

View File

@ -5,15 +5,16 @@
;; ;; ;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; standard driver stuff
format MS COFF format MS COFF
DEBUG = 1 DEBUG = 1
; this is for DEBUGF macro from 'fdo.inc'
__DEBUG__ = 1 __DEBUG__ = 1
__DEBUG_LEVEL__ = 1 __DEBUG_LEVEL__ = 1
node equ ftdi_context
node.next equ ftdi_context.next_context
include '../../proc32.inc' include '../../proc32.inc'
include '../../imports.inc' include '../../imports.inc'
include '../../fdo.inc' include '../../fdo.inc'
@ -130,6 +131,7 @@ index dd ?
inEP dd ? inEP dd ?
outEP dd ? outEP dd ?
nullP dd ? nullP dd ?
lockPID dd ?
next_context dd ? next_context dd ?
ends ends
@ -181,9 +183,10 @@ proc START stdcall, .reason:DWORD
endp endp
proc AddDevice stdcall uses ebx, .config_pipe:DWORD, .config_descr:DWORD, .interface:DWORD proc AddDevice stdcall uses ebx esi, .config_pipe:DWORD, .config_descr:DWORD, .interface:DWORD
stdcall USBGetParam, [.config_pipe], 0 stdcall USBGetParam, [.config_pipe], 0
mov edx, eax
DEBUGF 1,'K : Device detected Vendor: %x\n', [eax+usb_descr.idVendor] DEBUGF 1,'K : Device detected Vendor: %x\n', [eax+usb_descr.idVendor]
cmp word[eax+usb_descr.idVendor], 0x0403 cmp word[eax+usb_descr.idVendor], 0x0403
jnz .notftdi jnz .notftdi
@ -194,16 +197,45 @@ proc AddDevice stdcall uses ebx, .config_pipe:DWORD, .config_descr:DWORD, .inter
jnz @f jnz @f
mov esi, nomemory_msg mov esi, nomemory_msg
call SysMsgBoardStr call SysMsgBoardStr
xor eax, eax
jmp .nothing jmp .nothing
@@: @@:
DEBUGF 1,'K : Adding struct to list %x\n', eax DEBUGF 1,'K : Adding struct to list %x\n', eax
call linkedlist.add call linkedlist_add
mov ebx, [.config_pipe] mov ebx, [.config_pipe]
mov [eax + ftdi_context.nullP], ebx mov [eax + ftdi_context.nullP], ebx
mov [eax + ftdi_context.index], 0 mov [eax + ftdi_context.index], 0
mov [eax + ftdi_context.lockPID], 0
cmp [edx+usb_descr.bcdDevice], 0x400
jnz @f
mov [eax + ftdi_context.chipType], TYPE_BM
@@:
cmp [edx+usb_descr.bcdDevice], 0x200
jnz @f
mov [eax + ftdi_context.chipType], TYPE_AM
@@:
cmp [edx+usb_descr.bcdDevice], 0x500
jnz @f
mov [eax + ftdi_context.chipType], TYPE_2232C
@@:
cmp [edx+usb_descr.bcdDevice], 0x600
jnz @f
mov [eax + ftdi_context.chipType], TYPE_R
@@:
cmp [edx+usb_descr.bcdDevice], 0x700
jnz @f
mov [eax + ftdi_context.chipType], TYPE_2232H
@@:
cmp [edx+usb_descr.bcdDevice], 0x900
jnz @f
mov [eax + ftdi_context.chipType], TYPE_232H
@@:
cmp [edx+usb_descr.bcdDevice], 0x1000
jnz @f
mov [eax + ftdi_context.chipType], TYPE_BM
@@:
DEBUGF 1,'K : Open first pipe\n' DEBUGF 1,'K : Open first pipe\n'
mov ebx, eax mov ebx, eax
stdcall USBOpenPipe, [.config_pipe], 0x81, 0x40, BULK_PIPE, 0 stdcall USBOpenPipe, [.config_pipe], 0x81, 0x40, BULK_PIPE, 0
@ -211,11 +243,10 @@ proc AddDevice stdcall uses ebx, .config_pipe:DWORD, .config_descr:DWORD, .inter
DEBUGF 1,'K : Open second pipe\n' DEBUGF 1,'K : Open second pipe\n'
stdcall USBOpenPipe, [.config_pipe], 0x02, 0x40, BULK_PIPE, 0 stdcall USBOpenPipe, [.config_pipe], 0x02, 0x40, BULK_PIPE, 0
mov [ebx + ftdi_context.outEP], eax mov [ebx + ftdi_context.outEP], eax
.nothing:
ret
.notftdi: .notftdi:
DEBUGF 1,'K : Skipping not FTDI device\n' DEBUGF 1,'K : Skipping not FTDI device\n'
.nothing:
xor eax, eax xor eax, eax
ret ret
endp endp
@ -235,13 +266,35 @@ ConfPacket rb 8
EventData rd 2 EventData rd 2
endl endl
mov edi, [ioctl] mov edi, [ioctl]
mov eax, [edi + io_code] mov eax, [edi+io_code]
DEBUGF 1,'K : FTDI got the request: %d\n', eax DEBUGF 1,'K : FTDI got the request: %d\n', eax
test eax, eax ;0 test eax, eax ;0
jz .version jz .version
dec eax ;1 dec eax ;1
jz .ftdi_get_list jz .ftdi_get_list
push eax
mov esi, [edi+input]
mov eax, [esi+4]
call linkedlist_isvalid
test eax, eax
pop eax
jnz .endswitch
dec eax
jz .ftdi_lock ;2
dec eax
jz .ftdi_unlock ;3
mov ebx, [esi+4]
mov ecx, [ebx + ftdi_context.lockPID]
cmp ecx, [esi]
jz .pid_ok
mov esi, [edi+output]
mov dword[esi], 'LCKD'
jmp .endswitch
.pid_ok:
push eax edi push eax edi
xor ecx, ecx xor ecx, ecx
xor esi, esi xor esi, esi
@ -250,12 +303,42 @@ endl
mov [EventData+4], edx mov [EventData+4], edx
pop edi eax pop edi eax
dec eax ;2
jz .ftdi_set_bitmode
dec eax ;3
jz .ftdi_setrtshigh
dec eax ;4 dec eax ;4
jz .ftdi_setrtslow jz .ftdi_set_bitmode
dec eax ;5
jz .ftdi_setrtshigh
dec eax ;6
jz .ftdi_setrtslow
dec eax
jz .ftdi_setdtrhigh
dec eax
jz .ftdi_setdtrlow
dec eax
jz .ftdi_usb_reset
dec eax
jz .ftdi_setflowctrl
dec eax
jz .ftdi_set_event_char
dec eax
jz .ftdi_set_error_char
dec eax
jz .ftdi_set_latency_timer
dec eax
jz .ftdi_get_latency_timer
dec eax
jz .ftdi_read_pins
dec eax
jz .ftdi_poll_modem_status
dec eax
jz .ftdi_write_data
dec eax
jz .ftdi_set_baudrate
dec eax
jz .ftdi_set_line_property
dec eax
jz .ftdi_purge_rx_buf
dec eax
jz .ftdi_purge_tx_buf
.version: .version:
.endswitch: .endswitch:
@ -269,7 +352,7 @@ endl
xor cx, cx xor cx, cx
mov word[ConfPacket+6], cx mov word[ConfPacket+6], cx
.own_index: .own_index:
mov ebx, [edi] mov ebx, [edi+4]
DEBUGF 1,'K : ConfPacket %x %x\n', [ConfPacket], [ConfPacket+4] DEBUGF 1,'K : ConfPacket %x %x\n', [ConfPacket], [ConfPacket+4]
lea esi, [ConfPacket] lea esi, [ConfPacket]
lea edi, [EventData] lea edi, [EventData]
@ -284,7 +367,7 @@ endl
DEBUGF 1,'K : FTDI Seting bitmode\n' DEBUGF 1,'K : FTDI Seting bitmode\n'
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_BITMODE_REQUEST shl 8) mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_BITMODE_REQUEST shl 8)
mov edi, [edi+input] mov edi, [edi+input]
mov dx, word[edi+4] mov dx, word[edi+8]
mov word[ConfPacket+2], dx mov word[ConfPacket+2], dx
jmp .ftdi_out_control_transfer jmp .ftdi_out_control_transfer
@ -328,46 +411,46 @@ C_CLK = 48000000
mov ebx, [edi] mov ebx, [edi]
cmp [ebx + ftdi_context.chipType], TYPE_2232H cmp [ebx + ftdi_context.chipType], TYPE_2232H
jl .c_clk jl .c_clk
imul eax, [edi+4], 10 imul eax, [edi+8], 10
cmp eax, H_CLK / 0x3FFF cmp eax, H_CLK / 0x3FFF
jle .c_clk jle .c_clk
.h_clk: .h_clk:
cmp dword[edi+4], H_CLK/10 cmp dword[edi+8], H_CLK/10
jl .h_nextbaud1 jl .h_nextbaud1
xor edx, edx xor edx, edx
mov ecx, H_CLK/10 mov ecx, H_CLK/10
jmp .calcend jmp .calcend
.c_clk: .c_clk:
cmp dword[edi+4], C_CLK/10 cmp dword[edi+8], C_CLK/10
jl .c_nextbaud1 jl .c_nextbaud1
xor edx, edx xor edx, edx
mov ecx, C_CLK/10 mov ecx, C_CLK/10
jmp .calcend jmp .calcend
.h_nextbaud1: .h_nextbaud1:
cmp dword[edi+4], H_CLK/(10 + 10/2) cmp dword[edi+8], H_CLK/(10 + 10/2)
jl .h_nextbaud2 jl .h_nextbaud2
mov edx, 1 mov edx, 1
mov ecx, H_CLK/(10 + 10/2) mov ecx, H_CLK/(10 + 10/2)
jmp .calcend jmp .calcend
.c_nextbaud1: .c_nextbaud1:
cmp dword[edi+4], C_CLK/(10 + 10/2) cmp dword[edi+8], C_CLK/(10 + 10/2)
jl .c_nextbaud2 jl .c_nextbaud2
mov edx, 1 mov edx, 1
mov ecx, C_CLK/(10 + 10/2) mov ecx, C_CLK/(10 + 10/2)
jmp .calcend jmp .calcend
.h_nextbaud2: .h_nextbaud2:
cmp dword[edi+4], H_CLK/(2*10) cmp dword[edi+8], H_CLK/(2*10)
jl .h_nextbaud3 jl .h_nextbaud3
mov edx, 2 mov edx, 2
mov ecx, H_CLK/(2*10) mov ecx, H_CLK/(2*10)
jmp .calcend jmp .calcend
.c_nextbaud2: .c_nextbaud2:
cmp dword[edi+4], C_CLK/(2*10) cmp dword[edi+8], C_CLK/(2*10)
jl .c_nextbaud3 jl .c_nextbaud3
mov edx, 2 mov edx, 2
mov ecx, C_CLK/(2*10) mov ecx, C_CLK/(2*10)
@ -375,7 +458,7 @@ C_CLK = 48000000
.h_nextbaud3: .h_nextbaud3:
mov eax, H_CLK*16/10 ; eax - best_divisor mov eax, H_CLK*16/10 ; eax - best_divisor
div dword[edi+4] ; [edi+4] - baudrate div dword[edi+8] ; [edi+8] - baudrate
push eax push eax
and eax, 1 and eax, 1
pop eax pop eax
@ -401,7 +484,7 @@ C_CLK = 48000000
.c_nextbaud3: .c_nextbaud3:
mov eax, C_CLK*16/10 ; eax - best_divisor mov eax, C_CLK*16/10 ; eax - best_divisor
div dword[edi+4] ; [edi+4] - baudrate div dword[edi+8] ; [edi+8] - baudrate
push eax push eax
and eax, 1 and eax, 1
pop eax pop eax
@ -458,28 +541,28 @@ C_CLK = 48000000
.ftdi_set_line_property: .ftdi_set_line_property:
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_DATA_REQUEST shl 8) mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_DATA_REQUEST shl 8)
mov edi, [edi+input] mov edi, [edi+input]
mov dx, word[edi+4] mov dx, word[edi+8]
mov word[ConfPacket+2], dx mov word[ConfPacket+2], dx
jmp .ftdi_out_control_transfer jmp .ftdi_out_control_transfer
.ftdi_set_latency_timer: .ftdi_set_latency_timer:
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_LATENCY_TIMER_REQUEST shl 8) mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_LATENCY_TIMER_REQUEST shl 8)
mov edi, [edi+input] mov edi, [edi+input]
mov dx, word[edi+4] mov dx, word[edi+8]
mov word[ConfPacket+2], dx mov word[ConfPacket+2], dx
jmp .ftdi_out_control_transfer jmp .ftdi_out_control_transfer
.ftdi_set_event_char: .ftdi_set_event_char:
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_EVENT_CHAR_REQUEST shl 8) mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_EVENT_CHAR_REQUEST shl 8)
mov edi, [edi+input] mov edi, [edi+input]
mov dx, word[edi+4] mov dx, word[edi+8]
mov word[ConfPacket+2], dx mov word[ConfPacket+2], dx
jmp .ftdi_out_control_transfer jmp .ftdi_out_control_transfer
.ftdi_set_error_char: .ftdi_set_error_char:
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_ERROR_CHAR_REQUEST shl 8) mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_ERROR_CHAR_REQUEST shl 8)
mov edi, [edi+input] mov edi, [edi+input]
mov dx, word[edi+4] mov dx, word[edi+8]
mov word[ConfPacket+2], dx mov word[ConfPacket+2], dx
jmp .ftdi_out_control_transfer jmp .ftdi_out_control_transfer
@ -487,7 +570,7 @@ C_CLK = 48000000
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_FLOW_CTRL_REQUEST shl 8) + (0 shl 16) mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) + (SIO_SET_FLOW_CTRL_REQUEST shl 8) + (0 shl 16)
mov edi, [edi+input] mov edi, [edi+input]
mov ebx, [edi] mov ebx, [edi]
mov cx, word[edi+4] mov cx, word[edi+8]
or ecx, [ebx + ftdi_context.index] or ecx, [ebx + ftdi_context.index]
mov word[ConfPacket+4], cx mov word[ConfPacket+4], cx
xor cx, cx xor cx, cx
@ -496,10 +579,12 @@ C_CLK = 48000000
.ftdi_read_pins: .ftdi_read_pins:
DEBUGF 1,'K : FTDI Reading pins\n' DEBUGF 1,'K : FTDI Reading pins\n'
mov dword[ConfPacket], FTDI_DEVICE_IN_REQTYPE + (SIO_READ_PINS_REQUEST shl 8) + (0 shl 16)
mov dword[ConfPacket+4], 0x00000001
mov edi, [edi+input] mov edi, [edi+input]
mov ebx, [edi] mov ebx, [edi]
mov dword[ConfPacket], FTDI_DEVICE_IN_REQTYPE + (SIO_READ_PINS_REQUEST shl 8) + (0 shl 16)
mov ecx, [ebx + ftdi_context.index]
mov word[ConfPacket+4], cx
mov word[ConfPacket+6], 1
lea esi, [ConfPacket] lea esi, [ConfPacket]
lea edi, [EventData] lea edi, [EventData]
mov ecx, [ioctl] mov ecx, [ioctl]
@ -510,19 +595,118 @@ C_CLK = 48000000
mov ebx, [EventData+4] mov ebx, [EventData+4]
call WaitEvent call WaitEvent
jmp .endswitch jmp .endswitch
.ftdi_read_data:
;stdcall USBNormalTransferAsync, [ebx + ftdi_context.inEP], [ebx + ftdi_context.readBufPtr], [ebx + 1]
.ftdi_get_list: .ftdi_write_data:
call linkedlist.gethead mov edi, [edi+input]
mov ebx, [edi+4]
mov eax, [edi+8]
xor ecx, ecx ; ecx - offset
.dataleft:
mov edx, [ebx + ftdi_context.writeBufChunkSize] ; edx - write_size
push ecx
add ecx, edx
cmp ecx, [edi+8]
pop ecx
jle .morethanchunk
mov edx, [edi+8]
sub edx, ecx
.morethanchunk:
stdcall USBNormalTransferAsync, [ebx + ftdi_context.inEP], [edi+12+ecx], edx, bulk_callback, edx, 1
mov eax, [EventData]
mov ebx, [EventData+4]
call WaitEvent
add ecx, [EventData]
cmp ecx, [edi+8]
jl .dataleft
jmp .endswitch
.ftdi_poll_modem_status:
mov edi, [edi+input]
mov ebx, [edi+4]
mov dword[ConfPacket], FTDI_DEVICE_IN_REQTYPE + (SIO_POLL_MODEM_STATUS_REQUEST shl 8) + (0 shl 16)
mov ecx, [ebx + ftdi_context.index]
mov word[ConfPacket+4], cx
mov word[ConfPacket+6], 1
lea esi, [ConfPacket]
lea edi, [EventData]
mov ecx, [ioctl]
mov ecx, [ecx+output]
stdcall USBControlTransferAsync, [ebx + ftdi_context.nullP], esi, ecx, 2, control_callback, edi, 0
DEBUGF 1, 'K : Returned value is %d\n', eax
mov eax, [EventData]
mov ebx, [EventData+4]
call WaitEvent
mov ax, word[ecx]
xchg ah, al
and ah, 0xFF
mov word[ecx], ax
jmp .endswitch
.ftdi_get_latency_timer:
mov edi, [edi+input]
mov ebx, [edi+4]
mov dword[ConfPacket], FTDI_DEVICE_IN_REQTYPE + (SIO_GET_LATENCY_TIMER_REQUEST shl 8) + (0 shl 16)
mov ecx, [ebx + ftdi_context.index]
mov word[ConfPacket+4], cx
mov word[ConfPacket+6], 1
lea esi, [ConfPacket]
lea edi, [EventData]
mov ecx, [ioctl]
mov ecx, [ecx+output]
stdcall USBControlTransferAsync, [ebx + ftdi_context.nullP], esi, ecx, 2, control_callback, edi, 0
DEBUGF 1, 'K : Returned value is %d\n', eax
mov eax, [EventData]
mov ebx, [EventData+4]
call WaitEvent
jmp .endswitch
.ftdi_get_list:
call linkedlist_gethead
mov edi, [edi+output] mov edi, [edi+output]
mov [edi], eax .nextdev:
DEBUGF 1, 'K : FTDI Device pointer %x\n', [edi] cmp [eax + ftdi_context.lockPID], 0
mov eax, 4 jnz .dev_is_locked
mov [edi+out_size], eax mov dword[edi], 'NLKD'
jmp .nextfields
.dev_is_locked:
mov dword[edi], 'LCKD'
.nextfields:
mov bl, [eax + ftdi_context.chipType]
mov [edi+4], ebx
mov [edi+8], eax
add edi, 12
mov eax, [eax + ftdi_context.next_context]
test eax, eax
jnz .nextdev
jmp .endswitch jmp .endswitch
.ftdi_lock:
mov esi, [edi+input]
mov ebx, [esi+4]
mov eax, [ebx + ftdi_context.lockPID]
test eax, eax
jnz .lockedby
mov eax, [esi]
mov [ebx + ftdi_context.lockPID], eax
.lockedby:
mov edi, [edi+output]
mov [edi], eax
jmp .endswitch
.ftdi_unlock:
mov esi, [edi+input]
mov edi, [edi+output]
mov ebx, [esi+4]
mov eax, [ebx + ftdi_context.lockPID]
cmp eax, [esi]
jnz .unlockimp
mov [ebx + ftdi_context.lockPID], 0
mov dword[edi], 0
jmp .endswitch
.unlockimp:
mov [edi], eax
jmp .endswitch
endp endp
restore handle restore handle
restore io_code restore io_code
@ -539,18 +723,35 @@ proc control_callback stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, .buf
mov ecx, [.calldata] mov ecx, [.calldata]
mov eax, [ecx] mov eax, [ecx]
mov ebx, [ecx+4] mov ebx, [ecx+4]
xor esi, esi
xor edx, edx xor edx, edx
call RaiseEvent call RaiseEvent
ret ret
endp endp
proc bulk_callback stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, .buffer:DWORD, .length:DWORD, .calldata:DWORD
DEBUGF 1, 'K : status is %d\n', [.status]
mov ecx, [.calldata]
mov eax, [ecx]
mov ebx, [ecx+4]
mov edx, [.length]
mov edx, [edx]
mov [ecx], edx
xor esi, esi
xor edx, edx
call RaiseEvent
ret
endp
proc DeviceDisconnected stdcall uses ebx esi edi, .device_data:DWORD proc DeviceDisconnected stdcall uses ebx esi edi, .device_data:DWORD
DEBUGF 1, 'K : FTDI deleting device data\n' DEBUGF 1, 'K : FTDI deleting device data\n'
mov eax, [.device_data] mov eax, [.device_data]
call linkedlist.delete call linkedlist_delete
ret ret
endp endp