Initial commit
This commit is contained in:
3 files changed
+459
No files matched your search
@@ -0,0 +1,47 @@
|
|||||||
|
# usbcdc driver for KolibriOS
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- [Fasm](https://flatassembler.net/) 1.7x
|
||||||
|
- [Tup](https://gittup.org/tup/) build system (optional)
|
||||||
|
- KolibriOS commit `#5593d344cd` or newer
|
||||||
|
- [usbdrv](https://t.me/kolibri_os/122988)
|
||||||
|
|
||||||
|
## Build instructions
|
||||||
|
|
||||||
|
1. Clone the KolibriOS repository:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://git.kolibrios.org/KolibriOS/kolibrios.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Clone this repository into kolibrios/drivers/usb/usbcdc:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd kolibrios/drivers/usb
|
||||||
|
git clone https://git.kolibrios.org/b00bl1k/usbcdc.git
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Build using either method:
|
||||||
|
|
||||||
|
With Tup (recommended):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
tup init
|
||||||
|
tup
|
||||||
|
```
|
||||||
|
|
||||||
|
Or directly with FASM:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fasm kterm.asm
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Add usbcdc into usbdrv.dat
|
||||||
|
|
||||||
|
Add `usbcdc` to usbdrv.asm and build:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
INIT_USBDRV_FILE
|
||||||
|
+ ADD_CLASS 'usbcdc', 0x0a, 0x00, X
|
||||||
|
```
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||||
|
ROOT = "../../.."
|
||||||
|
tup.rule("usbcdc.asm", "fasm %f %o " .. tup.getconfig("PESTRIP_CMD") .. tup.getconfig("KPACK_CMD"), "%B.sys")
|
||||||
+409
@@ -0,0 +1,409 @@
|
|||||||
|
format PE DLL native 0.05
|
||||||
|
entry START
|
||||||
|
|
||||||
|
include '../../struct.inc'
|
||||||
|
|
||||||
|
L_DBG = 1
|
||||||
|
L_ERR = 2
|
||||||
|
|
||||||
|
__DEBUG__ = 1
|
||||||
|
__DEBUG_LEVEL__ = L_DBG
|
||||||
|
|
||||||
|
USB_IFACE_CDCACM = 0x0202
|
||||||
|
USB_IFACE_CDCDATA = 0x000A
|
||||||
|
|
||||||
|
; USBPSTN1.2 Table 19
|
||||||
|
SET_COMM_FEATURE = 02h
|
||||||
|
GET_COMM_FEATURE = 03h
|
||||||
|
CLEAR_COMM_FEATURE = 04h
|
||||||
|
SET_AUX_LINE_STATE = 10h
|
||||||
|
SET_HOOK_STATE = 11h
|
||||||
|
PULSE_SETUP = 12h
|
||||||
|
SEND_PULSE = 13h
|
||||||
|
SET_PULSE_TIME = 14h
|
||||||
|
RING_AUX_JACK = 15h
|
||||||
|
SET_LINE_CODING = 20h
|
||||||
|
GET_LINE_CODING = 21h
|
||||||
|
SET_CONTROL_LINE_STATE = 22h
|
||||||
|
SEND_BREAK = 23h
|
||||||
|
SET_RINGER_PARMS = 30h
|
||||||
|
GET_RINGER_PARMS = 31h
|
||||||
|
SET_OPERATION_PARMS = 32h
|
||||||
|
GET_OPERATION_PARMS = 33h
|
||||||
|
SET_LINE_PARMS = 34h
|
||||||
|
GET_LINE_PARMS = 35h
|
||||||
|
DIAL_DIGITS = 36h
|
||||||
|
|
||||||
|
; USBPSTN1.2 Table 17
|
||||||
|
LINE_CODING_CHAR_FORMAT_1BIT = 0
|
||||||
|
LINE_CODING_CHAR_FORMAT_1_5BITS = 1
|
||||||
|
LINE_CODING_CHAR_FORMAT_2BITS = 2
|
||||||
|
|
||||||
|
LINE_CONFIG_PARITY_NONE = 0
|
||||||
|
LINE_CONFIG_PARITY_ODD = 1
|
||||||
|
LINE_CONFIG_PARITY_EVEN = 2
|
||||||
|
LINE_CONFIG_PARITY_MARK = 3
|
||||||
|
LINE_CONFIG_PARITY_SPACE = 4
|
||||||
|
|
||||||
|
; USBPSTN1.2 Table 17
|
||||||
|
struct LINE_CODING
|
||||||
|
dwDTERate dd ?
|
||||||
|
bCharFormat db ?
|
||||||
|
bParityType db ?
|
||||||
|
bDataBits db ?
|
||||||
|
ends
|
||||||
|
|
||||||
|
struct CDC_DEVICE
|
||||||
|
conf_pipe dd ?
|
||||||
|
|
||||||
|
in_ep db ?
|
||||||
|
out_ep db ?
|
||||||
|
in_data_sz dw ?
|
||||||
|
out_data_sz dw ?
|
||||||
|
|
||||||
|
in_pipe dd ?
|
||||||
|
out_pipe dd ?
|
||||||
|
|
||||||
|
port_handle dd ?
|
||||||
|
rx_timer dd ?
|
||||||
|
tx_buf dd ?
|
||||||
|
tx_buf_lock dd ?
|
||||||
|
rx_buf dd ?
|
||||||
|
rx_buf_lock dd ?
|
||||||
|
conf_buf dd ?, ?, ?, ?
|
||||||
|
inp_buf dd ?, ?, ?
|
||||||
|
ends
|
||||||
|
|
||||||
|
section '.flat' readable writable executable
|
||||||
|
|
||||||
|
include '../../proc32.inc'
|
||||||
|
include '../../fdo.inc'
|
||||||
|
include '../../macros.inc'
|
||||||
|
include '../../peimport.inc'
|
||||||
|
include '../../serial/common.inc'
|
||||||
|
include '../../../kernel/trunk/bus/usb/protocol.inc'
|
||||||
|
include '../../../kernel/trunk/bus/usb/common.inc'
|
||||||
|
|
||||||
|
proc START c, .reason:dword, .cmdline:dword
|
||||||
|
cmp [.reason], DRV_ENTRY
|
||||||
|
jne .fail
|
||||||
|
invoke GetService, drv_serial_name
|
||||||
|
test eax, eax
|
||||||
|
jnz @f
|
||||||
|
DEBUGF L_ERR, "usbcdc: couldn't load serial driver"
|
||||||
|
jmp .fail
|
||||||
|
@@:
|
||||||
|
mov [serial_drv_entry], eax
|
||||||
|
DEBUGF L_DBG, "usbcdc: loaded serial driver %x\n", eax
|
||||||
|
invoke RegUSBDriver, drv_usbcdc_name, service_proc, usb_functions
|
||||||
|
ret
|
||||||
|
.fail:
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc service_proc stdcall, .ioctl:dword
|
||||||
|
or eax, -1
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc usb_add_device stdcall uses ebx edi, .config_pipe:dword, \
|
||||||
|
.config_descr:dword, .interface:dword
|
||||||
|
; bInterfaceClass and bInterfaceSubClass must match to CDCDATA
|
||||||
|
mov ebx, [.interface]
|
||||||
|
cmp word [ebx + usb_interface_descr.bInterfaceClass], USB_IFACE_CDCDATA
|
||||||
|
jne .fail
|
||||||
|
; probably a valid interface, so alloc memory to store further information
|
||||||
|
mov eax, sizeof.CDC_DEVICE
|
||||||
|
invoke Kmalloc
|
||||||
|
test eax, eax
|
||||||
|
jz .fail
|
||||||
|
mov edi, eax
|
||||||
|
; two data endpoints must be present
|
||||||
|
movzx ecx, [ebx + usb_interface_descr.bNumEndpoints]
|
||||||
|
cmp ecx, 2
|
||||||
|
jne .fail_and_free
|
||||||
|
; jump to the end of the interface descriptor
|
||||||
|
movzx eax, [ebx + usb_interface_descr.bLength]
|
||||||
|
add ebx, eax
|
||||||
|
.lookup:
|
||||||
|
; validate endpoint descriptor
|
||||||
|
cmp [ebx + usb_endpoint_descr.bLength], sizeof.usb_endpoint_descr
|
||||||
|
jb .fail_and_free
|
||||||
|
cmp [ebx + usb_endpoint_descr.bDescriptorType], USB_ENDPOINT_DESCR
|
||||||
|
jne .fail_and_free
|
||||||
|
cmp [ebx + usb_endpoint_descr.bmAttributes], 2 ; bulk data
|
||||||
|
jne .fail_and_free
|
||||||
|
mov al, [ebx + usb_endpoint_descr.bEndpointAddress]
|
||||||
|
test al, 0x80
|
||||||
|
jnz .inp
|
||||||
|
; save OUT endpoint num and max packet size
|
||||||
|
mov [edi + CDC_DEVICE.out_ep], al
|
||||||
|
mov ax, [ebx + usb_endpoint_descr.wMaxPacketSize]
|
||||||
|
mov [edi + CDC_DEVICE.out_data_sz], ax
|
||||||
|
jmp .next_ep
|
||||||
|
.inp:
|
||||||
|
; save IN endpoint num and max packet size
|
||||||
|
mov [edi + CDC_DEVICE.in_ep], al
|
||||||
|
mov ax, [ebx + usb_endpoint_descr.wMaxPacketSize]
|
||||||
|
mov [edi + CDC_DEVICE.in_data_sz], ax
|
||||||
|
.next_ep:
|
||||||
|
movzx eax, [ebx + usb_endpoint_descr.bLength]
|
||||||
|
add ebx, eax
|
||||||
|
loop .lookup
|
||||||
|
DEBUGF L_DBG, "usbcdc: found endpoints: %x (%x) %x (%x)\n", \
|
||||||
|
[edi + CDC_DEVICE.in_ep]:2, \
|
||||||
|
[edi + CDC_DEVICE.in_data_sz]:4, \
|
||||||
|
[edi + CDC_DEVICE.out_ep]:2, \
|
||||||
|
[edi + CDC_DEVICE.out_data_sz]:4
|
||||||
|
; initialize fields
|
||||||
|
mov eax, [.config_pipe]
|
||||||
|
mov [edi + CDC_DEVICE.conf_pipe], eax
|
||||||
|
and [edi + CDC_DEVICE.tx_buf], 0
|
||||||
|
and [edi + CDC_DEVICE.tx_buf_lock], 0
|
||||||
|
and [edi + CDC_DEVICE.rx_buf], 0
|
||||||
|
and [edi + CDC_DEVICE.rx_buf_lock], 0
|
||||||
|
; open input pipe
|
||||||
|
movzx ecx, [edi + CDC_DEVICE.in_ep]
|
||||||
|
movzx edx, [edi + CDC_DEVICE.in_data_sz]
|
||||||
|
invoke USBOpenPipe, [.config_pipe], ecx, edx, BULK_PIPE, 0
|
||||||
|
test eax, eax
|
||||||
|
jz .fail_and_free
|
||||||
|
mov [edi + CDC_DEVICE.in_pipe], eax
|
||||||
|
; open output pipe
|
||||||
|
movzx ecx, [edi + CDC_DEVICE.out_ep]
|
||||||
|
movzx edx, [edi + CDC_DEVICE.out_data_sz]
|
||||||
|
invoke USBOpenPipe, [.config_pipe], ecx, edx, BULK_PIPE, 0
|
||||||
|
test eax, eax
|
||||||
|
jz .fail_and_free
|
||||||
|
mov [edi + CDC_DEVICE.out_pipe], eax
|
||||||
|
; TODO interrupt pipe?
|
||||||
|
mov eax, [serial_drv_entry]
|
||||||
|
test eax, eax
|
||||||
|
jz @f
|
||||||
|
; register new serial port
|
||||||
|
stdcall serial_add_port, serial_drv, edi
|
||||||
|
DEBUGF L_DBG, "usbcdc: add serial port with result %x\n", eax
|
||||||
|
@@:
|
||||||
|
mov [edi + CDC_DEVICE.port_handle], eax
|
||||||
|
mov eax, edi
|
||||||
|
ret
|
||||||
|
.fail_and_free:
|
||||||
|
mov eax, edi
|
||||||
|
invoke Kfree
|
||||||
|
.fail:
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc usb_device_disconnected stdcall, .port:dword
|
||||||
|
mov edx, [.port]
|
||||||
|
stdcall serial_remove_port, [edx + CDC_DEVICE.port_handle]
|
||||||
|
mov eax, edx
|
||||||
|
invoke Kfree
|
||||||
|
DEBUGF L_DBG, "usbcdc: disconnected\n"
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc got_input stdcall, .pipe:dword, .status:dword, .buffer:dword, \
|
||||||
|
.length:dword, .calldata:dword
|
||||||
|
DEBUGF L_DBG, "usbcdc: got_input status 0x%x length 0x%x\n", [.status], [.length]
|
||||||
|
cmp [.length], 2
|
||||||
|
jb @f
|
||||||
|
mov eax, [.buffer]
|
||||||
|
DEBUGF L_DBG, "usbcdc: got_input: %x %x\n", [eax]:2, [eax + 1]:2
|
||||||
|
@@:
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc serial_startup stdcall uses ebx, .port:dword, .conf:dword
|
||||||
|
DEBUGF L_DBG, "usbcdc: startup %x %x\n", [.port], [.conf]
|
||||||
|
stdcall serial_reconf, [.port], [.conf]
|
||||||
|
test eax, eax
|
||||||
|
jz @f
|
||||||
|
DEBUGF L_ERR, "usbcdc: uart reconf error %x\n", eax
|
||||||
|
jmp .exit
|
||||||
|
@@:
|
||||||
|
mov ebx, [.port]
|
||||||
|
invoke TimerHS, 2, 2, serial_rx, ebx
|
||||||
|
test eax, eax
|
||||||
|
jnz @f
|
||||||
|
DEBUGF L_ERR, "usbcdc: timer creation error\n"
|
||||||
|
or eax, -1
|
||||||
|
jmp .exit
|
||||||
|
@@:
|
||||||
|
mov [ebx + CDC_DEVICE.rx_timer], eax
|
||||||
|
xor eax, eax
|
||||||
|
.exit:
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc serial_shutdown stdcall uses ebx, .port:dword
|
||||||
|
DEBUGF L_DBG, "usbcdc: shutdown %x\n", [.port]
|
||||||
|
mov ebx, [.port]
|
||||||
|
cmp [ebx + CDC_DEVICE.rx_timer], 0
|
||||||
|
jz @f
|
||||||
|
invoke CancelTimerHS, [ebx + CDC_DEVICE.rx_timer]
|
||||||
|
DEBUGF L_DBG, "usbcdc: cancel timer %x\n", eax
|
||||||
|
@@:
|
||||||
|
; TODO dealloc [CDC_DEVICE.tx_buf]
|
||||||
|
; TODO dealloc [CDC_DEVICE.rx_buf]
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc control_complete stdcall, .pipe:dword, .status:dword, .buffer:dword, \
|
||||||
|
.length:dword, .calldata:dword
|
||||||
|
mov eax, [.status]
|
||||||
|
test eax, eax
|
||||||
|
jz @f
|
||||||
|
DEBUGF L_ERR, "usbcdc: control_complete err %x\n", eax
|
||||||
|
@@:
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
BAUDRATE = 9600 ; TODO
|
||||||
|
proc serial_reconf stdcall uses ebx edi esi, .port:dword, .conf:dword
|
||||||
|
mov ebx, [.port]
|
||||||
|
lea edi, [ebx + CDC_DEVICE.conf_buf]
|
||||||
|
mov dword [edi], 0x21 or (SET_LINE_CODING shl 8)
|
||||||
|
mov dword [edi + 4], 7 shl 16
|
||||||
|
mov esi, edi
|
||||||
|
add esi, 8
|
||||||
|
mov dword [esi], BAUDRATE
|
||||||
|
mov dword [esi + 4], LINE_CODING_CHAR_FORMAT_1BIT \
|
||||||
|
or (LINE_CONFIG_PARITY_NONE shl 8) \
|
||||||
|
or (8 shl 16)
|
||||||
|
invoke USBControlTransferAsync, [ebx + CDC_DEVICE.conf_pipe], edi, esi, \
|
||||||
|
7, control_complete, ebx, 0
|
||||||
|
test eax, eax
|
||||||
|
jz .exit
|
||||||
|
xor eax, eax
|
||||||
|
.exit:
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc bulk_out_complete stdcall uses ebx edi esi, .pipe:dword, .status:dword, \
|
||||||
|
.buffer:dword, .length:dword, .calldata:dword
|
||||||
|
mov eax, [.status]
|
||||||
|
test eax, eax
|
||||||
|
jz @f
|
||||||
|
DEBUGF L_ERR, "usbcdc: bulk out error %x\n", eax
|
||||||
|
@@:
|
||||||
|
mov ebx, [.calldata]
|
||||||
|
btr dword [ebx + CDC_DEVICE.tx_buf_lock], 0
|
||||||
|
stdcall serial_tx, ebx
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc serial_tx stdcall uses ebx esi, .port:dword
|
||||||
|
xor eax, eax
|
||||||
|
mov ebx, [.port]
|
||||||
|
bts dword [ebx + CDC_DEVICE.tx_buf_lock], 0
|
||||||
|
jc .exit
|
||||||
|
|
||||||
|
mov esi, [ebx + CDC_DEVICE.tx_buf]
|
||||||
|
test esi, esi
|
||||||
|
jnz .read
|
||||||
|
; allocate buffer for bulk_in transfer if not yet
|
||||||
|
mov eax, [ebx + CDC_DEVICE.out_data_sz]
|
||||||
|
invoke Kmalloc
|
||||||
|
test eax, eax
|
||||||
|
jz .error
|
||||||
|
mov [ebx + CDC_DEVICE.tx_buf], eax
|
||||||
|
mov esi, eax
|
||||||
|
|
||||||
|
.read:
|
||||||
|
stdcall serial_handle_event, [ebx + CDC_DEVICE.port_handle], \
|
||||||
|
SERIAL_EVT_TXE, TX_SIZE, esi
|
||||||
|
test eax, eax
|
||||||
|
jz .unlock
|
||||||
|
invoke USBNormalTransferAsync, [ebx + CDC_DEVICE.out_pipe], esi, eax, \
|
||||||
|
bulk_out_complete, ebx, 0
|
||||||
|
test eax, eax
|
||||||
|
jz .error
|
||||||
|
xor eax, eax
|
||||||
|
jmp .exit
|
||||||
|
|
||||||
|
.error:
|
||||||
|
or eax, -1
|
||||||
|
.unlock:
|
||||||
|
btr dword [ebx + CDC_DEVICE.tx_buf_lock], 0
|
||||||
|
.exit:
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc bulk_in_complete stdcall uses ebx edi esi, .pipe:dword, .status:dword, \
|
||||||
|
.buffer:dword, .length:dword, .calldata:dword
|
||||||
|
mov eax, [.status]
|
||||||
|
mov ebx, [.calldata]
|
||||||
|
test eax, eax
|
||||||
|
jz @f
|
||||||
|
DEBUGF L_ERR, "usbcdc: bulk in error %x\n", eax
|
||||||
|
jmp .exit
|
||||||
|
@@:
|
||||||
|
mov ecx, [.length]
|
||||||
|
test ecx, ecx
|
||||||
|
jz .exit
|
||||||
|
mov esi, [.buffer]
|
||||||
|
stdcall serial_handle_event, [ebx + CDC_DEVICE.port_handle], \
|
||||||
|
SERIAL_EVT_RXNE, ecx, esi
|
||||||
|
.exit:
|
||||||
|
btr dword [ebx + CDC_DEVICE.rx_buf_lock], 0
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc serial_rx stdcall uses ebx esi, .port:dword
|
||||||
|
xor eax, eax
|
||||||
|
mov ebx, [.port]
|
||||||
|
bts dword [ebx + CDC_DEVICE.rx_buf_lock], 0
|
||||||
|
jc .exit
|
||||||
|
|
||||||
|
mov esi, [ebx + CDC_DEVICE.rx_buf]
|
||||||
|
test esi, esi
|
||||||
|
jnz .read
|
||||||
|
; allocate buffer for bulk_out transfer if not yet
|
||||||
|
mov eax, [ebx + CDC_DEVICE.in_data_sz]
|
||||||
|
invoke Kmalloc
|
||||||
|
test eax, eax
|
||||||
|
jz .error
|
||||||
|
mov [ebx + CDC_DEVICE.rx_buf], eax
|
||||||
|
mov esi, eax
|
||||||
|
|
||||||
|
.read:
|
||||||
|
invoke USBNormalTransferAsync, [ebx + CDC_DEVICE.in_pipe], esi, \
|
||||||
|
RX_SIZE, bulk_in_complete, ebx, 1
|
||||||
|
test eax, eax
|
||||||
|
jz .error
|
||||||
|
xor eax, eax
|
||||||
|
jmp .exit
|
||||||
|
.error:
|
||||||
|
btr dword [ebx + CDC_DEVICE.rx_buf_lock], 0
|
||||||
|
or eax, -1
|
||||||
|
.exit:
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
align 4
|
||||||
|
usb_functions:
|
||||||
|
dd usb_functions_end - usb_functions
|
||||||
|
dd usb_add_device
|
||||||
|
dd usb_device_disconnected
|
||||||
|
usb_functions_end:
|
||||||
|
|
||||||
|
serial_drv:
|
||||||
|
dd serial_drv_end - serial_drv
|
||||||
|
dd serial_startup
|
||||||
|
dd serial_shutdown
|
||||||
|
dd serial_reconf
|
||||||
|
dd serial_tx
|
||||||
|
serial_drv_end:
|
||||||
|
|
||||||
|
drv_usbcdc_name db 'usbcdc', 0
|
||||||
|
drv_serial_name db 'SERIAL', 0
|
||||||
|
serial_drv_entry dd 0
|
||||||
|
include_debug_strings
|
||||||
|
|
||||||
|
align 4
|
||||||
|
data fixups
|
||||||
|
end data
|
||||||
Reference in new issue
Block a user