forked from KolibriOS/kolibrios
eee894983a
git-svn-id: svn://kolibrios.org@7552 a494cfbc-eb01-0410-851d-a64ba20cac60
1036 lines
35 KiB
NASM
1036 lines
35 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
;; ;;
|
|
;; FTDI chips driver for KolibriOS ;;
|
|
;; ;;
|
|
;; Written by gtament@gmail.com ;;
|
|
;; ;;
|
|
;; GNU GENERAL PUBLIC LICENSE ;;
|
|
;; Version 2, June 1991 ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
format PE DLL native 0.05
|
|
entry START
|
|
|
|
DEBUG = 1
|
|
|
|
__DEBUG__ = 1
|
|
__DEBUG_LEVEL__ = 1
|
|
|
|
node equ ftdi_context
|
|
node.next equ ftdi_context.next_context
|
|
|
|
include '../../proc32.inc'
|
|
include '../../peimport.inc'
|
|
include '../../fdo.inc'
|
|
include '../../struct.inc'
|
|
|
|
; USB constants
|
|
DEVICE_DESCR_TYPE = 1
|
|
CONFIG_DESCR_TYPE = 2
|
|
STRING_DESCR_TYPE = 3
|
|
INTERFACE_DESCR_TYPE = 4
|
|
ENDPOINT_DESCR_TYPE = 5
|
|
DEVICE_QUALIFIER_DESCR_TYPE = 6
|
|
|
|
CONTROL_PIPE = 0
|
|
ISOCHRONOUS_PIPE = 1
|
|
BULK_PIPE = 2
|
|
INTERRUPT_PIPE = 3
|
|
|
|
; USB HID constants
|
|
HID_DESCR_TYPE = 21h
|
|
REPORT_DESCR_TYPE = 22h
|
|
PHYSICAL_DESCR_TYPE = 23h
|
|
|
|
; LibUSB constatnts
|
|
LIBUSB_REQUEST_TYPE_STANDARD = (0x00 shl 5)
|
|
LIBUSB_REQUEST_TYPE_CLASS = (0x01 shl 5)
|
|
LIBUSB_REQUEST_TYPE_VENDOR = (0x02 shl 5)
|
|
LIBUSB_REQUEST_TYPE_RESERVED = (0x03 shl 5)
|
|
|
|
LIBUSB_RECIPIENT_DEVICE = 0x00
|
|
LIBUSB_RECIPIENT_INTERFACE = 0x01
|
|
LIBUSB_RECIPIENT_ENDPOINT = 0x02
|
|
LIBUSB_RECIPIENT_OTHER = 0x03
|
|
|
|
LIBUSB_ENDPOINT_IN = 0x80
|
|
LIBUSB_ENDPOINT_OUT = 0x00
|
|
|
|
; FTDI Constants
|
|
FTDI_DEVICE_OUT_REQTYPE = (LIBUSB_REQUEST_TYPE_VENDOR or LIBUSB_RECIPIENT_DEVICE or LIBUSB_ENDPOINT_OUT)
|
|
FTDI_DEVICE_IN_REQTYPE = (LIBUSB_REQUEST_TYPE_VENDOR or LIBUSB_RECIPIENT_DEVICE or LIBUSB_ENDPOINT_IN)
|
|
|
|
; Requests
|
|
;Definitions for flow control
|
|
SIO_RESET =0 ;Reset the port
|
|
SIO_MODEM_CTRL =1 ;Set the modem control register
|
|
SIO_SET_FLOW_CTRL =2 ;Set flow control register
|
|
SIO_SET_BAUD_RATE =3 ;Set baud rate
|
|
SIO_SET_DATA =4 ;Set the data characteristics of the port
|
|
|
|
SIO_RESET_REQUEST =SIO_RESET
|
|
SIO_SET_BAUDRATE_REQUEST =SIO_SET_BAUD_RATE
|
|
SIO_SET_DATA_REQUEST =SIO_SET_DATA
|
|
SIO_SET_FLOW_CTRL_REQUEST =SIO_SET_FLOW_CTRL
|
|
SIO_SET_MODEM_CTRL_REQUEST =SIO_MODEM_CTRL
|
|
SIO_POLL_MODEM_STATUS_REQUEST=0x05
|
|
SIO_SET_EVENT_CHAR_REQUEST =0x06
|
|
SIO_SET_ERROR_CHAR_REQUEST =0x07
|
|
SIO_SET_LATENCY_TIMER_REQUEST=0x09
|
|
SIO_GET_LATENCY_TIMER_REQUEST=0x0A
|
|
SIO_SET_BITMODE_REQUEST =0x0B
|
|
SIO_READ_PINS_REQUEST =0x0C
|
|
SIO_READ_EEPROM_REQUEST =0x90
|
|
SIO_WRITE_EEPROM_REQUEST =0x91
|
|
SIO_ERASE_EEPROM_REQUEST =0x92
|
|
|
|
|
|
SIO_RESET_SIO=0
|
|
SIO_RESET_PURGE_RX=1
|
|
SIO_RESET_PURGE_TX=2
|
|
|
|
SIO_DISABLE_FLOW_CTRL=0x0
|
|
SIO_RTS_CTS_HS =(0x1 shl 8)
|
|
SIO_DTR_DSR_HS =(0x2 shl 8)
|
|
SIO_XON_XOFF_HS=(0x4 shl 8)
|
|
|
|
SIO_SET_DTR_MASK=0x1
|
|
SIO_SET_DTR_HIGH=( 1 or ( SIO_SET_DTR_MASK shl 8))
|
|
SIO_SET_DTR_LOW =( 0 or ( SIO_SET_DTR_MASK shl 8))
|
|
SIO_SET_RTS_MASK=0x2
|
|
SIO_SET_RTS_HIGH=( 2 or ( SIO_SET_RTS_MASK shl 8 ))
|
|
SIO_SET_RTS_LOW =( 0 or ( SIO_SET_RTS_MASK shl 8 ))
|
|
|
|
SIO_RTS_CTS_HS =(0x1 shl 8)
|
|
|
|
;FTDI chip type
|
|
TYPE_AM=0
|
|
TYPE_BM=1
|
|
TYPE_2232C=2
|
|
TYPE_R=3
|
|
TYPE_2232H=4
|
|
TYPE_4232H=5
|
|
TYPE_232H=6
|
|
TYPE_230X=7
|
|
|
|
;strings
|
|
my_driver db 'usbother',0
|
|
nomemory_msg db 'K : no memory',13,10,0
|
|
|
|
; Structures
|
|
struct ftdi_context
|
|
chipType db ?
|
|
baudrate dd ?
|
|
bitbangEnabled db ?
|
|
readBufChunkSize dd ?
|
|
writeBufChunkSize dd ?
|
|
readBufPtr dd ?
|
|
writeBufPtr dd ?
|
|
readBufSize dd ?
|
|
writeBufSize dd ?
|
|
maxPacketSize dd ?
|
|
interface dd ?
|
|
index dd ?
|
|
inEP dd ?
|
|
outEP dd ?
|
|
nullP dd ?
|
|
lockPID dd ?
|
|
next_context dd ?
|
|
ends
|
|
|
|
struct IOCTL
|
|
handle dd ?
|
|
io_code dd ?
|
|
input dd ?
|
|
inp_size dd ?
|
|
output dd ?
|
|
out_size dd ?
|
|
ends
|
|
|
|
struct usb_descr
|
|
bLength db ?
|
|
bDescriptorType db ?
|
|
bcdUSB dw ?
|
|
bDeviceClass db ?
|
|
bDeviceSubClass db ?
|
|
bDeviceProtocol db ?
|
|
bMaxPacketSize0 db ?
|
|
idVendor dw ?
|
|
idProduct dw ?
|
|
bcdDevice dw ?
|
|
iManufacturer db ?
|
|
iProduct db ?
|
|
iSerialNumber db ?
|
|
bNumConfigurations db ?
|
|
ends
|
|
|
|
struct conf_packet
|
|
bmRequestType db ?
|
|
bRequest db ?
|
|
wValue dw ?
|
|
wIndex dw ?
|
|
wLength dw ?
|
|
ends
|
|
|
|
section '.flat' code readable executable
|
|
; The start procedure.
|
|
proc START c, .reason:DWORD, .cmdline:DWORD
|
|
|
|
xor eax, eax ; initialize return value
|
|
cmp [.reason], 1 ; compare the argument
|
|
jnz .nothing
|
|
invoke RegUSBDriver, my_driver, service_proc, usb_functions
|
|
|
|
.nothing:
|
|
ret
|
|
endp
|
|
|
|
|
|
proc AddDevice stdcall uses ebx esi edi, .config_pipe:DWORD, .config_descr:DWORD, .interface:DWORD
|
|
|
|
invoke USBGetParam, [.config_pipe], 0
|
|
mov edx, eax
|
|
DEBUGF 2,'K : Detected device vendor: 0x%x\n', [eax+usb_descr.idVendor]
|
|
cmp word[eax+usb_descr.idVendor], 0x0403
|
|
jnz .notftdi
|
|
mov eax, sizeof.ftdi_context
|
|
invoke Kmalloc
|
|
test eax, eax
|
|
jnz @f
|
|
mov esi, nomemory_msg
|
|
invoke SysMsgBoardStr
|
|
jmp .nothing
|
|
@@:
|
|
DEBUGF 2,'K : Adding struct to list 0x%x\n', eax
|
|
call linkedlist_add
|
|
|
|
mov ebx, [.config_pipe]
|
|
mov [eax + ftdi_context.nullP], ebx
|
|
mov [eax + ftdi_context.index], 0
|
|
mov [eax + ftdi_context.lockPID], 0
|
|
mov [eax + ftdi_context.maxPacketSize], 64
|
|
mov [eax + ftdi_context.readBufChunkSize], 64
|
|
mov [eax + ftdi_context.writeBufChunkSize], 64
|
|
|
|
mov [eax + ftdi_context.chipType], TYPE_R
|
|
jmp .slow
|
|
|
|
mov cx, [edx+usb_descr.bcdDevice]
|
|
DEBUGF 2, 'K : Chip type 0x%x\n', ecx
|
|
cmp cx, 0x400
|
|
jnz @f
|
|
mov [eax + ftdi_context.chipType], TYPE_BM
|
|
jmp .slow
|
|
@@:
|
|
cmp cx, 0x200
|
|
jnz @f
|
|
mov [eax + ftdi_context.chipType], TYPE_AM
|
|
jmp .slow
|
|
@@:
|
|
cmp cx, 0x500
|
|
jnz @f
|
|
mov [eax + ftdi_context.chipType], TYPE_2232C
|
|
jmp .slow
|
|
@@:
|
|
cmp cx, 0x600
|
|
jnz @f
|
|
mov [eax + ftdi_context.chipType], TYPE_R
|
|
jmp .slow
|
|
@@:
|
|
cmp cx, 0x700
|
|
jnz @f
|
|
mov [eax + ftdi_context.chipType], TYPE_2232H
|
|
jmp .fast
|
|
@@:
|
|
cmp cx, 0x900
|
|
jnz @f
|
|
mov [eax + ftdi_context.chipType], TYPE_232H
|
|
jmp .fast
|
|
@@:
|
|
cmp cx, 0x1000
|
|
jnz .slow
|
|
mov [eax + ftdi_context.chipType], TYPE_230X
|
|
jmp .fast
|
|
|
|
.fast:
|
|
add [eax + ftdi_context.maxPacketSize], 512-64
|
|
.slow:
|
|
mov ebx, eax
|
|
invoke USBOpenPipe, [.config_pipe], 0x81, \
|
|
[ebx + ftdi_context.maxPacketSize], BULK_PIPE, 0
|
|
test eax, eax
|
|
jz .nothing
|
|
mov [ebx + ftdi_context.outEP], eax
|
|
invoke USBOpenPipe, [.config_pipe], 0x02, \
|
|
[ebx + ftdi_context.maxPacketSize], BULK_PIPE, 0
|
|
test eax, eax
|
|
jz .nothing
|
|
mov [ebx + ftdi_context.inEP], eax
|
|
mov eax, ebx
|
|
ret
|
|
|
|
.notftdi:
|
|
DEBUGF 1,'K : Skipping not FTDI device\n'
|
|
.nothing:
|
|
xor eax, eax
|
|
ret
|
|
endp
|
|
|
|
|
|
handle equ IOCTL.handle
|
|
io_code equ IOCTL.io_code
|
|
input equ IOCTL.input
|
|
inp_size equ IOCTL.inp_size
|
|
output equ IOCTL.output
|
|
out_size equ IOCTL.out_size
|
|
|
|
proc service_proc stdcall uses ebx esi edi, ioctl:DWORD
|
|
locals
|
|
ConfPacket rb 10
|
|
EventData rd 3
|
|
endl
|
|
mov edi, [ioctl]
|
|
mov eax, [edi+io_code]
|
|
DEBUGF 1,'K : FTDI got the request: %d\n', eax
|
|
test eax, eax ;0
|
|
jz .version
|
|
dec eax ;1
|
|
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 dword[esi], 0
|
|
jz .error
|
|
cmp ecx, [esi]
|
|
jz .pid_ok
|
|
mov esi, [edi+output]
|
|
mov dword[esi], 'LCKD'
|
|
jmp .endswitch
|
|
|
|
.pid_ok:
|
|
dec eax
|
|
jz .ftdi_get_wchunksize ;4
|
|
dec eax
|
|
jz .ftdi_get_rchunksize ;5
|
|
|
|
mov edi, [edi+input]
|
|
|
|
dec eax
|
|
jz .ftdi_set_rchunksize ;6
|
|
dec eax
|
|
jz .ftdi_set_wchunksize ;7
|
|
|
|
push eax edi
|
|
mov ecx, 0x80000000
|
|
cmp eax, 8-7
|
|
je .bulkevent
|
|
cmp eax, 9-7
|
|
je .bulkevent
|
|
xor ecx, ecx
|
|
.bulkevent:
|
|
xor esi, esi
|
|
invoke CreateEvent
|
|
mov [EventData], eax
|
|
mov [EventData+4], edx
|
|
pop edi eax
|
|
|
|
dec eax ;8
|
|
jz .ftdi_write_data
|
|
dec eax ;9
|
|
jz .ftdi_read_data
|
|
dec eax ;10
|
|
jz .ftdi_set_baudrate
|
|
dec eax ;11
|
|
jz .ftdi_set_bitmode
|
|
dec eax ;12
|
|
jz .ftdi_setrtshigh
|
|
dec eax ;13
|
|
jz .ftdi_setrtslow
|
|
dec eax ;14
|
|
jz .ftdi_setdtrhigh
|
|
dec eax ;15
|
|
jz .ftdi_setdtrlow
|
|
dec eax ;16
|
|
jz .ftdi_usb_reset
|
|
dec eax ;17
|
|
jz .ftdi_setflowctrl
|
|
dec eax ;18
|
|
jz .ftdi_set_event_char
|
|
dec eax ;19
|
|
jz .ftdi_set_error_char
|
|
dec eax ;20
|
|
jz .ftdi_set_latency_timer
|
|
dec eax ;21
|
|
jz .ftdi_get_latency_timer
|
|
dec eax ;22
|
|
jz .ftdi_read_pins
|
|
dec eax ;23
|
|
jz .ftdi_poll_modem_status
|
|
dec eax ;24
|
|
jz .ftdi_set_line_property
|
|
dec eax ;25
|
|
jz .ftdi_purge_rx_buf
|
|
dec eax ;26
|
|
jz .ftdi_purge_tx_buf
|
|
jmp .error
|
|
|
|
.version:
|
|
jmp .endswitch
|
|
.error:
|
|
DEBUGF 1, 'K : FTDI error occured! %d\n', eax
|
|
;mov esi, [edi+output]
|
|
;mov [esi], dword 'ERR0'
|
|
;or [esi], eax
|
|
ret
|
|
.endswitch:
|
|
xor eax, eax
|
|
ret
|
|
|
|
.eventdestroy:
|
|
;---Dirty hack begin
|
|
test eax, eax
|
|
jz @f
|
|
mov eax, dword[ConfPacket]
|
|
invoke Kfree
|
|
@@:
|
|
;---Dirty hack end
|
|
mov eax, [EventData]
|
|
mov ebx, [EventData+4]
|
|
invoke DestroyEvent
|
|
jmp .endswitch
|
|
|
|
.ftdi_out_control_transfer_withinp:
|
|
mov dx, word[edi+8]
|
|
mov word[ConfPacket+2], dx
|
|
.ftdi_out_control_transfer_noinp:
|
|
mov ebx, [edi+4]
|
|
mov cx, word[ebx + ftdi_context.index]
|
|
mov word[ConfPacket+4], cx
|
|
xor cx, cx
|
|
mov word[ConfPacket+6], cx
|
|
.own_index:
|
|
mov ebx, [edi+4]
|
|
DEBUGF 2,'K : ConfPacket 0x%x 0x%x\n', [ConfPacket], [ConfPacket+4]
|
|
lea esi, [ConfPacket]
|
|
lea edi, [EventData]
|
|
invoke USBControlTransferAsync, [ebx + ftdi_context.nullP], esi, 0,\
|
|
0, control_callback, edi, 0
|
|
test eax, eax
|
|
jz .error
|
|
mov eax, [EventData]
|
|
mov ebx, [EventData+4]
|
|
invoke WaitEvent
|
|
mov eax, [EventData+8]
|
|
test eax, eax
|
|
jz .endswitch
|
|
jmp .error
|
|
|
|
.ftdi_setrtshigh:
|
|
DEBUGF 2,'K : FTDI Setting RTS pin HIGH PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
|
|
+ (SIO_SET_RTS_HIGH shl 16)
|
|
jmp .ftdi_out_control_transfer_noinp
|
|
|
|
.ftdi_setrtslow:
|
|
DEBUGF 2,'K : FTDI Setting RTS pin LOW PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
|
|
+ (SIO_SET_RTS_LOW shl 16)
|
|
jmp .ftdi_out_control_transfer_noinp
|
|
|
|
.ftdi_setdtrhigh:
|
|
DEBUGF 2,'K : FTDI Setting DTR pin HIGH PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
|
|
+ (SIO_SET_DTR_HIGH shl 16)
|
|
jmp .ftdi_out_control_transfer_noinp
|
|
|
|
.ftdi_setdtrlow:
|
|
DEBUGF 2,'K : FTDI Setting DTR pin LOW PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
|
|
+ (SIO_SET_DTR_LOW shl 16)
|
|
jmp .ftdi_out_control_transfer_noinp
|
|
|
|
.ftdi_usb_reset:
|
|
DEBUGF 2,'K : FTDI Reseting PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_RESET_REQUEST shl 8) \
|
|
+ (SIO_RESET_SIO shl 16)
|
|
jmp .ftdi_out_control_transfer_noinp
|
|
|
|
.ftdi_purge_rx_buf:
|
|
DEBUGF 2, 'K : FTDI Purge TX buffer PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_RESET_REQUEST shl 8) \
|
|
+ (SIO_RESET_PURGE_RX shl 16)
|
|
jmp .ftdi_out_control_transfer_noinp
|
|
|
|
.ftdi_purge_tx_buf:
|
|
DEBUGF 2, 'K : FTDI Purge RX buffer PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_RESET_REQUEST shl 8) \
|
|
+ (SIO_RESET_PURGE_TX shl 16)
|
|
jmp .ftdi_out_control_transfer_noinp
|
|
|
|
.ftdi_set_bitmode:
|
|
DEBUGF 2, 'K : FTDI Set bitmode 0x%x, bitmask 0x%x %d PID: %d Dev handler 0x0x%x\n', \
|
|
[edi+8]:2,[edi+10]:2,[edi],[edi+4]
|
|
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_BITMODE_REQUEST shl 8)
|
|
jmp .ftdi_out_control_transfer_withinp
|
|
|
|
.ftdi_set_line_property:
|
|
DEBUGF 2, 'K : FTDI Set line property 0x%x PID: %d Dev handler 0x0x%x\n', \
|
|
[edi+8]:4,[edi],[edi+4]
|
|
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_DATA_REQUEST shl 8)
|
|
jmp .ftdi_out_control_transfer_withinp
|
|
|
|
.ftdi_set_latency_timer:
|
|
DEBUGF 2, 'K : FTDI Set latency %d PID: %d Dev handler 0x0x%x\n', \
|
|
[edi+8],[edi],[edi+4]
|
|
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_LATENCY_TIMER_REQUEST shl 8)
|
|
jmp .ftdi_out_control_transfer_withinp
|
|
|
|
.ftdi_set_event_char:
|
|
DEBUGF 2, 'K : FTDI Set event char %c PID: %d Dev handler 0x0x%x\n', \
|
|
[edi+8],[edi],[edi+4]
|
|
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_EVENT_CHAR_REQUEST shl 8)
|
|
jmp .ftdi_out_control_transfer_withinp
|
|
|
|
.ftdi_set_error_char:
|
|
DEBUGF 2, 'K : FTDI Set error char %c PID: %d Dev handler 0x0x%x\n', \
|
|
[edi+8],[edi],[edi+4]
|
|
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_ERROR_CHAR_REQUEST shl 8)
|
|
jmp .ftdi_out_control_transfer_withinp
|
|
|
|
.ftdi_setflowctrl:
|
|
DEBUGF 2, 'K : FTDI Set flow control PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_FLOW_CTRL_REQUEST shl 8) + (0 shl 16)
|
|
mov ebx, [edi+4]
|
|
mov cx, word[edi+8]
|
|
or ecx, [ebx + ftdi_context.index]
|
|
mov word[ConfPacket+4], cx
|
|
xor cx, cx
|
|
mov word[ConfPacket+6], cx
|
|
jmp .own_index
|
|
|
|
.ftdi_read_pins:
|
|
DEBUGF 2, 'K : FTDI Read pins PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov ebx, [edi+4]
|
|
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 edi, [EventData]
|
|
mov ecx, esi
|
|
add ecx, 8
|
|
mov word[ConfPacket+8], 0
|
|
invoke USBControlTransferAsync, [ebx + ftdi_context.nullP], esi, ecx, \
|
|
1, control_callback, edi, 0
|
|
mov eax, [EventData]
|
|
mov ebx, [EventData+4]
|
|
invoke WaitEvent
|
|
xor ebx, ebx
|
|
mov bx, word[ConfPacket+8]
|
|
mov ecx, [ioctl]
|
|
mov ecx, [ecx+output]
|
|
mov [ecx], ebx
|
|
mov eax, [EventData+8]
|
|
test eax, eax
|
|
jz .endswitch
|
|
jmp .error
|
|
|
|
.ftdi_set_wchunksize:
|
|
DEBUGF 2, 'K : FTDI Set write chunksize %d bytes PID: %d Dev handler 0x0x%x\n', \
|
|
[edi+8], [edi], [edi+4]
|
|
mov ebx, [edi+4]
|
|
mov ecx, [edi+8]
|
|
cmp [ebx + ftdi_context.maxPacketSize], ecx
|
|
jg .error
|
|
mov [ebx + ftdi_context.writeBufChunkSize], ecx
|
|
jmp .endswitch
|
|
|
|
.ftdi_get_wchunksize:
|
|
DEBUGF 2, 'K : FTDI Get write chunksize PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov esi, [edi+output]
|
|
mov edi, [edi+input]
|
|
mov ebx, [edi+4]
|
|
mov ecx, [ebx + ftdi_context.writeBufChunkSize]
|
|
mov [esi], ecx
|
|
jmp .endswitch
|
|
|
|
.ftdi_set_rchunksize:
|
|
DEBUGF 2, 'K : FTDI Set read chunksize %d bytes PID: %d Dev handler 0x0x%x\n', \
|
|
[edi+8], [edi], [edi+4]
|
|
mov ebx, [edi+4]
|
|
mov ecx, [edi+8]
|
|
cmp [ebx + ftdi_context.maxPacketSize], ecx
|
|
jg .error
|
|
mov [ebx + ftdi_context.readBufChunkSize], ecx
|
|
jmp .endswitch
|
|
|
|
.ftdi_get_rchunksize:
|
|
DEBUGF 2, 'K : FTDI Get read chunksize PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
mov esi, [edi+output]
|
|
mov edi, [edi+input]
|
|
mov ebx, [edi+4]
|
|
mov ecx, [ebx + ftdi_context.readBufChunkSize]
|
|
mov [esi], ecx
|
|
jmp .endswitch
|
|
|
|
.ftdi_write_data:
|
|
DEBUGF 2, 'K : FTDI Write %d bytes PID: %d Dev handler 0x%x\n', [edi+8],\
|
|
[edi], [edi+4]
|
|
mov esi, edi
|
|
add esi, 12
|
|
mov ebx, [edi+4]
|
|
;---Dirty hack begin
|
|
mov eax, [edi+8]
|
|
invoke Kmalloc
|
|
test eax, eax
|
|
jnz @f
|
|
mov esi, nomemory_msg
|
|
invoke SysMsgBoardStr
|
|
jmp .eventdestroy
|
|
@@:
|
|
mov dword[ConfPacket], eax
|
|
mov ecx, [edi+8]
|
|
push edi
|
|
mov edi, eax
|
|
rep movsb
|
|
pop edi
|
|
mov esi, dword[ConfPacket]
|
|
;---Dirty hack end
|
|
xor ecx, ecx ; ecx - offset
|
|
.write_loop:
|
|
mov edx, [edi+8] ; edx - write_size
|
|
sub edx, ecx
|
|
cmp edx, [ebx + ftdi_context.writeBufChunkSize]
|
|
jle .lessthanchunk_write
|
|
mov edx, [ebx + ftdi_context.writeBufChunkSize]
|
|
.lessthanchunk_write:
|
|
add esi, ecx
|
|
lea eax, [EventData]
|
|
push ecx ebx esi edi
|
|
invoke USBNormalTransferAsync, [ebx + ftdi_context.inEP], esi, edx, \
|
|
bulk_callback, eax, 1
|
|
mov eax, [EventData]
|
|
mov ebx, [EventData+4]
|
|
invoke WaitEvent
|
|
pop edi esi ebx ecx
|
|
cmp [EventData+8], -1
|
|
jz .error
|
|
add ecx, [EventData+8]
|
|
cmp ecx, [edi+8]
|
|
jge .eventdestroy
|
|
jmp .write_loop
|
|
|
|
.ftdi_read_data:
|
|
DEBUGF 2, 'K : FTDI Read %d bytes PID: %d Dev handler 0x%x\n', [edi+8],\
|
|
[edi], [edi+4]
|
|
mov edi, [ioctl]
|
|
mov esi, [edi+input]
|
|
mov edi, [edi+output]
|
|
mov ebx, [esi+4]
|
|
;---Dirty hack begin
|
|
mov eax, [esi+8]
|
|
invoke Kmalloc
|
|
test eax, eax
|
|
jnz @f
|
|
mov esi, nomemory_msg
|
|
invoke SysMsgBoardStr
|
|
jmp .eventdestroy
|
|
@@:
|
|
mov edi, eax
|
|
; push edi eax
|
|
; mov ecx, [esi+8]
|
|
; xor eax, eax
|
|
; rep stosb
|
|
; pop eax edi
|
|
mov dword[ConfPacket], eax ; Store in ConfPacket ptr to allocated memory
|
|
;---Dirty hack end
|
|
xor ecx, ecx
|
|
.read_loop:
|
|
mov edx, [esi+8]
|
|
cmp ecx, edx
|
|
jge .read_end;jge .eventdestroy ;part of Dirty hack
|
|
sub edx, ecx
|
|
cmp edx, [ebx + ftdi_context.readBufChunkSize]
|
|
jl .lessthanchunk_read
|
|
mov edx, [ebx + ftdi_context.readBufChunkSize]
|
|
.lessthanchunk_read:
|
|
lea eax, [EventData]
|
|
add edi, ecx
|
|
push esi edi ecx ebx
|
|
invoke USBNormalTransferAsync, [ebx + ftdi_context.outEP], edi, edx, \
|
|
bulk_callback, eax, 1
|
|
mov eax, [EventData]
|
|
mov ebx, [EventData+4]
|
|
invoke WaitEvent
|
|
pop ebx ecx edi esi
|
|
cmp [EventData+8], -1
|
|
jz .error
|
|
add ecx, [EventData+8]
|
|
jmp .read_loop
|
|
;---Dirty hack begin
|
|
.read_end:
|
|
mov esi, dword[ConfPacket]
|
|
mov edi, [ioctl]
|
|
mov ecx, [edi+input]
|
|
mov ecx, [ecx+8]
|
|
mov edi, [edi+output]
|
|
rep movsb
|
|
jmp .eventdestroy
|
|
;---Dirty hack end
|
|
|
|
.ftdi_poll_modem_status:
|
|
DEBUGF 2, 'K : FTDI Poll modem status PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
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]
|
|
invoke USBControlTransferAsync, [ebx + ftdi_context.nullP], esi, ecx, \
|
|
2, control_callback, edi, 0
|
|
mov eax, [EventData]
|
|
mov ebx, [EventData+4]
|
|
invoke WaitEvent
|
|
mov ax, word[ecx]
|
|
xchg ah, al
|
|
and ah, 0xFF
|
|
mov word[ecx], ax
|
|
jmp .endswitch
|
|
|
|
.ftdi_get_latency_timer:
|
|
DEBUGF 2, 'K : FTDI Get latency timer PID: %d Dev handler 0x0x%x\n', [edi],\
|
|
[edi+4]
|
|
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]
|
|
invoke USBControlTransferAsync, [ebx + ftdi_context.nullP], esi, ecx, \
|
|
2, control_callback, edi, 0
|
|
mov eax, [EventData]
|
|
mov ebx, [EventData+4]
|
|
invoke WaitEvent
|
|
jmp .endswitch
|
|
|
|
.ftdi_get_list:
|
|
DEBUGF 2, 'K : FTDI devices list request\n'
|
|
mov edi, [edi+output]
|
|
xor ecx, ecx
|
|
call linkedlist_gethead
|
|
test eax, eax
|
|
jz .emptylist
|
|
push edi
|
|
add edi, 4
|
|
.nextdev:
|
|
inc ecx
|
|
cmp [eax + ftdi_context.lockPID], 0
|
|
jnz .dev_is_locked
|
|
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
|
|
pop edi
|
|
.emptylist:
|
|
mov [edi], ecx
|
|
jmp .endswitch
|
|
|
|
.ftdi_lock:
|
|
DEBUGF 2, 'K : FTDI Lock PID: %d Dev handler 0x0x%x\n', [edi], [edi+4]
|
|
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:
|
|
DEBUGF 2, 'K : FTDI Unlock PID: %d Dev handler 0x0x%x\n', [edi], [edi+4]
|
|
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
|
|
|
|
H_CLK = 120000000
|
|
C_CLK = 48000000
|
|
.ftdi_set_baudrate:
|
|
DEBUGF 2, 'K : FTDI Set baudrate to %d PID: %d Dev handle: 0x%x\n',\
|
|
[edi+8], [edi], [edi+4]
|
|
mov ebx, [edi+4]
|
|
cmp [ebx + ftdi_context.chipType], TYPE_2232H
|
|
jl .c_clk
|
|
imul eax, [edi+8], 10
|
|
cmp eax, H_CLK / 0x3FFF
|
|
jle .c_clk
|
|
.h_clk:
|
|
cmp dword[edi+8], H_CLK/10
|
|
jl .h_nextbaud1
|
|
xor edx, edx
|
|
mov ecx, H_CLK/10
|
|
jmp .calcend
|
|
|
|
.c_clk:
|
|
cmp dword[edi+8], C_CLK/16
|
|
jl .c_nextbaud1
|
|
xor edx, edx
|
|
mov ecx, C_CLK/16
|
|
jmp .calcend
|
|
|
|
.h_nextbaud1:
|
|
cmp dword[edi+8], H_CLK/(10 + 10/2)
|
|
jl .h_nextbaud2
|
|
mov edx, 1
|
|
mov ecx, H_CLK/(10 + 10/2)
|
|
jmp .calcend
|
|
|
|
.c_nextbaud1:
|
|
cmp dword[edi+8], C_CLK/(16 + 16/2)
|
|
jl .c_nextbaud2
|
|
mov edx, 1
|
|
mov ecx, C_CLK/(16 + 16/2)
|
|
jmp .calcend
|
|
|
|
.h_nextbaud2:
|
|
cmp dword[edi+8], H_CLK/(2*10)
|
|
jl .h_nextbaud3
|
|
mov edx, 2
|
|
mov ecx, H_CLK/(2*10)
|
|
jmp .calcend
|
|
|
|
.c_nextbaud2:
|
|
cmp dword[edi+8], C_CLK/(2*16)
|
|
jl .c_nextbaud3
|
|
mov edx, 2
|
|
mov ecx, C_CLK/(2*16)
|
|
jmp .calcend
|
|
|
|
.h_nextbaud3:
|
|
mov eax, H_CLK*16/10 ; eax - best_divisor
|
|
xor edx, edx
|
|
div dword[edi+8] ; [edi+8] - baudrate
|
|
push eax
|
|
and eax, 1
|
|
pop eax
|
|
shr eax, 1
|
|
jz .h_rounddowndiv ; jump by result of and eax, 1
|
|
inc eax
|
|
.h_rounddowndiv:
|
|
cmp eax, 0x20000
|
|
jle .h_best_divok
|
|
mov eax, 0x1FFFF
|
|
.h_best_divok:
|
|
mov ecx, eax
|
|
mov eax, H_CLK*16/10
|
|
xor edx, edx
|
|
div ecx
|
|
xchg ecx, eax ; ecx - best_baud
|
|
push ecx
|
|
and ecx, 1
|
|
pop ecx
|
|
shr ecx, 1
|
|
jz .rounddownbaud
|
|
inc ecx
|
|
jmp .rounddownbaud
|
|
|
|
.c_nextbaud3:
|
|
mov eax, C_CLK ; eax - best_divisor
|
|
xor edx, edx
|
|
div dword[edi+8] ; [edi+8] - baudrate
|
|
push eax
|
|
and eax, 1
|
|
pop eax
|
|
shr eax, 1
|
|
jnz .c_rounddowndiv ; jump by result of and eax, 1
|
|
inc eax
|
|
.c_rounddowndiv:
|
|
cmp eax, 0x20000
|
|
jle .c_best_divok
|
|
mov eax, 0x1FFFF
|
|
.c_best_divok:
|
|
mov ecx, eax
|
|
mov eax, C_CLK
|
|
xor edx, edx
|
|
div ecx
|
|
xchg ecx, eax ; ecx - best_baud
|
|
push ecx
|
|
and ecx, 1
|
|
pop ecx
|
|
shr ecx, 1
|
|
jnz .rounddownbaud
|
|
inc ecx
|
|
|
|
.rounddownbaud:
|
|
mov edx, eax ; edx - encoded_divisor
|
|
shr edx, 3
|
|
and eax, 0x7
|
|
push 7 6 5 1 4 2 3 0
|
|
mov eax, [esp+eax*4]
|
|
shl eax, 14
|
|
or edx, eax
|
|
add esp, 32
|
|
|
|
.calcend:
|
|
mov eax, edx ; eax - *value
|
|
mov ecx, edx ; ecx - *index
|
|
and eax, 0xFFFF
|
|
cmp [ebx + ftdi_context.chipType], TYPE_2232H
|
|
jge .foxyindex
|
|
shr ecx, 16
|
|
jmp .preparepacket
|
|
.foxyindex:
|
|
shr ecx, 8
|
|
and ecx, 0xFF00
|
|
or ecx, [ebx + ftdi_context.index]
|
|
|
|
.preparepacket:
|
|
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
|
|
+ (SIO_SET_BAUDRATE_REQUEST shl 8)
|
|
mov word[ConfPacket+2], ax
|
|
mov word[ConfPacket+4], cx
|
|
mov word[ConfPacket+6], 0
|
|
jmp .own_index
|
|
|
|
endp
|
|
restore handle
|
|
restore io_code
|
|
restore input
|
|
restore inp_size
|
|
restore output
|
|
restore out_size
|
|
|
|
|
|
proc control_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, [.status]
|
|
mov [ecx+8], edx
|
|
xor esi, esi
|
|
xor edx, edx
|
|
invoke RaiseEvent
|
|
ret
|
|
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]
|
|
cmp [.status], 0
|
|
jz .normal
|
|
cmp [.status], 9
|
|
jne .error
|
|
.normal:
|
|
mov edx, [.length]
|
|
mov [ecx+8], edx
|
|
jmp .ok
|
|
.error:
|
|
mov [ecx+8], dword -1
|
|
.ok:
|
|
xor esi, esi
|
|
xor edx, edx
|
|
invoke RaiseEvent
|
|
ret
|
|
endp
|
|
|
|
proc DeviceDisconnected stdcall uses ebx esi edi, .device_data:DWORD
|
|
|
|
DEBUGF 1, 'K : FTDI deleting device data 0x%x\n', [.device_data]
|
|
mov eax, [.device_data]
|
|
call linkedlist_unlink
|
|
invoke Kfree
|
|
ret
|
|
endp
|
|
|
|
include 'linkedlist.inc'
|
|
|
|
align 4
|
|
|
|
; Structure with callback functions.
|
|
usb_functions:
|
|
dd 12
|
|
dd AddDevice
|
|
dd DeviceDisconnected
|
|
|
|
data fixups
|
|
end data
|
|
|
|
;for DEBUGF macro
|
|
include_debug_strings |