/kernel/trunk/bus/pci/pci32.inc |
---|
694,7 → 694,8 |
mov [ecx+PCIDEV.fd], edi |
mov [eax+PCIDEV.bk], edi |
mov eax, dword [.devfn] |
mov word [edi+PCIDEV.devfn], ax |
mov dword [edi+PCIDEV.devfn], eax |
mov dword [edi+PCIDEV.owner], 0 |
mov bh, al |
mov al, 2 |
mov bl, 8 |
/kernel/trunk/bus/usb/ohci.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/bus/usb/scheduler.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/bus/usb/ehci.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/bus/usb/uhci.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/bus/usb/hccommon.inc |
---|
1,238 → 1,33 |
; USB Host Controller support code: hardware-independent part, |
; common for all controller types. |
; ============================================================================= |
; ================================= Constants ================================= |
; ============================================================================= |
; USB device must have at least 100ms of stable power before initializing can |
; proceed; one timer tick is 10ms, so enforce delay in 10 ticks |
USB_CONNECT_DELAY = 10 |
; USB requires at least 10 ms for reset signalling. Normally, this is one timer |
; tick. However, it is possible that we start reset signalling in the end of |
; interval between timer ticks and then we test time in the start of the next |
; interval; in this case, the delta between [timer_ticks] is 1, but the real |
; time passed is significantly less than 10 ms. To avoid this, we add an extra |
; tick; this guarantees that at least 10 ms have passed. |
USB_RESET_TIME = 2 |
; USB requires at least 10 ms of reset recovery, a delay between reset |
; signalling and any commands to device. Add an extra tick for the same reasons |
; as with the previous constant. |
USB_RESET_RECOVERY_TIME = 2 |
iglobal |
; USB HC support: some functions interesting only for *HCI-drivers. |
align 4 |
usb_hc_func: |
dd usb_process_gtd |
dd usb_init_static_endpoint |
dd usb_wakeup_if_needed |
dd usb_subscribe_control |
dd usb_subscription_done |
dd usb_allocate_common |
dd usb_free_common |
dd usb_td_to_virt |
dd usb_init_transfer |
dd usb_undo_tds |
dd usb_test_pending_port |
dd usb_get_tt |
dd usb_get_tt_think_time |
dd usb_new_device |
dd usb_disconnect_stage2 |
dd usb_process_wait_lists |
dd usb_unlink_td |
dd usb_is_final_packet |
dd usb_find_ehci_companion |
endg |
; ============================================================================= |
; ================================ Structures ================================= |
; ============================================================================= |
; Controller descriptor. |
; This structure represents the common (controller-independent) part |
; of a controller for the USB code. The corresponding controller-dependent |
; part *hci_controller is located immediately before usb_controller. |
struct usb_controller |
; Two following fields organize all controllers in the global linked list. |
Next dd ? |
Prev dd ? |
HardwareFunc dd ? |
; Pointer to usb_hardware_func structure with controller-specific functions. |
NumPorts dd ? |
; Number of ports in the root hub. |
SetAddressBuffer rb 8 |
; Buffer for USB control command SET_ADDRESS. |
ExistingAddresses rd 128/32 |
; Bitmask for 128 bits; bit i is cleared <=> address i is free for allocating |
; for new devices. Bit 0 is always set. |
; |
; The hardware is allowed to cache some data from hardware structures. |
; Regular operations are designed considering this, |
; but sometimes it is required to wait for synchronization of hardware cache |
; with modified structures in memory. |
; The code keeps two queues of pipes waiting for synchronization, |
; one for asynchronous (bulk/control) pipes, one for periodic pipes, hardware |
; cache is invalidated under different conditions for those types. |
; Both queues are organized in the same way, as single-linked lists. |
; There are three special positions: the head of list (new pipes are added |
; here), the first pipe to be synchronized at the current iteration, |
; the tail of list (all pipes starting from here are synchronized). |
WaitPipeListAsync dd ? |
WaitPipeListPeriodic dd ? |
; List heads. |
WaitPipeRequestAsync dd ? |
WaitPipeRequestPeriodic dd ? |
; Pending request to hardware to refresh cache for items from WaitPipeList*. |
; (Pointers to some items in WaitPipeList* or NULLs). |
ReadyPipeHeadAsync dd ? |
ReadyPipeHeadPeriodic dd ? |
; Items of RemovingList* which were released by hardware and are ready |
; for further processing. |
; (Pointers to some items in WaitPipeList* or NULLs). |
NewConnected dd ? |
; bit mask of recently connected ports of the root hub, |
; bit set = a device was recently connected to the corresponding port; |
; after USB_CONNECT_DELAY ticks of stable status these ports are moved to |
; PendingPorts |
NewDisconnected dd ? |
; bit mask of disconnected ports of the root hub, |
; bit set = a device in the corresponding port was disconnected, |
; disconnect processing is required. |
PendingPorts dd ? |
; bit mask of ports which are ready to be initialized |
ControlLock MUTEX ? |
; mutex which guards all operations with control queue |
BulkLock MUTEX ? |
; mutex which guards all operations with bulk queue |
PeriodicLock MUTEX ? |
; mutex which guards all operations with periodic queues |
WaitSpinlock: |
; spinlock guarding WaitPipeRequest/ReadyPipeHead (but not WaitPipeList) |
StartWaitFrame dd ? |
; USB frame number when WaitPipeRequest* was registered. |
ResettingHub dd ? |
; Pointer to usb_hub responsible for the currently resetting port, if any. |
; NULL for the root hub. |
ResettingPort db ? |
; Port that is currently resetting, 0-based. |
ResettingSpeed db ? |
; Speed of currently resetting device. |
ResettingStatus db ? |
; Status of port reset. 0 = no port is resetting, -1 = reset failed, |
; 1 = reset in progress, 2 = reset recovery in progress. |
rb 1 ; alignment |
ResetTime dd ? |
; Time when reset signalling or reset recovery has been started. |
ConnectedTime rd 16 |
; Time, in timer ticks, when the port i has signalled the connect event. |
; Valid only if bit i in NewConnected is set. |
DevicesByPort rd 16 |
; Pointer to usb_pipe for zero endpoint (which serves as device handle) |
; for each port. |
ends |
; Interface-specific data. Several interfaces of one device can operate |
; independently, each is controlled by some driver and is identified by |
; some driver-specific data passed as is to the driver. |
struct usb_interface_data |
DriverData dd ? |
; Passed as is to the driver. |
DriverFunc dd ? |
; Pointer to USBSRV structure for the driver. |
ends |
; Device-specific data. |
struct usb_device_data |
PipeListLock MUTEX |
; Lock guarding OpenedPipeList. Must be the first item of the structure, |
; the code passes pointer to usb_device_data as is to mutex_lock/unlock. |
OpenedPipeList rd 2 |
; List of all opened pipes for the device. |
; Used when the device is disconnected, so all pipes should be closed. |
ClosedPipeList rd 2 |
; List of all closed, but still valid pipes for the device. |
; A pipe closed with USBClosePipe is just deallocated, |
; but a pipe closed due to disconnect must remain valid until driver-provided |
; disconnect handler returns; this list links all such pipes to deallocate them |
; after disconnect processing. |
NumPipes dd ? |
; Number of not-yet-closed pipes. |
Hub dd ? |
; NULL if connected to the root hub, pointer to usb_hub otherwise. |
TTHub dd ? |
; Pointer to usb_hub for (the) hub with Transaction Translator for the device, |
; NULL if the device operates in the same speed as the controller. |
Port db ? |
; Port on the hub, zero-based. |
TTPort db ? |
; Port on the TTHub, zero-based. |
DeviceDescrSize db ? |
; Size of device descriptor. |
Speed db ? |
; Device speed, one of USB_SPEED_*. |
NumInterfaces dd ? |
; Number of interfaces. |
ConfigDataSize dd ? |
; Total size of data associated with the configuration descriptor |
; (including the configuration descriptor itself). |
Interfaces dd ? |
; Offset from the beginning of this structure to Interfaces field. |
; Variable-length fields: |
; DeviceDescriptor: |
; device descriptor starts here |
; ConfigDescriptor = DeviceDescriptor + DeviceDescrSize |
; configuration descriptor with all associated data |
; Interfaces = ALIGN_UP(ConfigDescriptor + ConfigDataSize, 4) |
; array of NumInterfaces elements of type usb_interface_data |
ends |
usb_device_data.DeviceDescriptor = sizeof.usb_device_data |
; Description of controller-specific data and functions. |
struct usb_hardware_func |
ID dd ? ; '*HCI' |
DataSize dd ? ; sizeof(*hci_controller) |
Init dd ? |
; Initialize controller-specific part of controller data. |
; in: eax -> *hci_controller to initialize, [ebp-4] = (bus shl 8) + devfn |
; out: eax = 0 <=> failed, otherwise eax -> usb_controller |
ProcessDeferred dd ? |
; Called regularly from the main loop of USB thread |
; (either due to timeout from a previous call, or due to explicit wakeup). |
; in: esi -> usb_controller |
; out: eax = maximum timeout for next call (-1 = infinity) |
SetDeviceAddress dd ? |
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address |
GetDeviceAddress dd ? |
; in: esi -> usb_controller, ebx -> usb_pipe |
; out: eax = address |
PortDisable dd ? |
; Disable the given port in the root hub. |
; in: esi -> usb_controller, ecx = port (zero-based) |
InitiateReset dd ? |
; Start reset signalling on the given port. |
; in: esi -> usb_controller, ecx = port (zero-based) |
SetEndpointPacketSize dd ? |
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size |
AllocPipe dd ? |
; out: eax = pointer to allocated usb_pipe |
FreePipe dd ? |
; void stdcall with one argument = pointer to previously allocated usb_pipe |
InitPipe dd ? |
; in: edi -> usb_pipe for target, ecx -> usb_pipe for config pipe, |
; esi -> usb_controller, eax -> usb_gtd for the first TD, |
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type |
UnlinkPipe dd ? |
; esi -> usb_controller, ebx -> usb_pipe |
AllocTD dd ? |
; out: eax = pointer to allocated usb_gtd |
FreeTD dd ? |
; void stdcall with one argument = pointer to previously allocated usb_gtd |
AllocTransfer dd ? |
; Allocate and initialize one stage of a transfer. |
; ebx -> usb_pipe, other parameters are passed through the stack: |
; buffer,size = data to transfer |
; flags = same as in usb_open_pipe: |
; bit 0 = allow short transfer, other bits reserved |
; td = pointer to the current end-of-queue descriptor |
; direction = |
; 0000b for normal transfers, |
; 1000b for control SETUP transfer, |
; 1101b for control OUT transfer, |
; 1110b for control IN transfer |
; returns eax = pointer to the new end-of-queue descriptor |
; (not included in the queue itself) or 0 on error |
InsertTransfer dd ? |
; Activate previously initialized transfer (maybe with multiple stages). |
; esi -> usb_controller, ebx -> usb_pipe, |
; [esp+4] -> first usb_gtd for the transfer, |
; ecx -> last descriptor for the transfer |
NewDevice dd ? |
; Initiate configuration of a new device (create pseudo-pipe describing that |
; device and call usb_new_device). |
; esi -> usb_controller, eax = speed (one of USB_SPEED_* constants). |
ends |
; ============================================================================= |
; =================================== Code ==================================== |
; ============================================================================= |
; Initializes one controller, called by usb_init for every controller. |
; edi -> usb_hardware_func, eax -> PCIDEV structure for the device. |
; eax -> PCIDEV structure for the device. |
proc usb_init_controller |
push ebp |
mov ebp, esp |
240,6 → 35,10 |
; make [ebp-4] = (bus shl 8) + devfn, used by controller-specific Init funcs. |
push dword [eax+PCIDEV.devfn] |
push eax |
mov edi, [eax+PCIDEV.owner] |
test edi, edi |
jz .nothing |
mov edi, [edi+USBSRV.usb_func] |
; 2. Allocate *hci_controller + usb_controller. |
mov ebx, [edi+usb_hardware_func.DataSize] |
add ebx, sizeof.usb_controller |
264,6 → 63,8 |
mov [edi+usb_controller.ResettingPort-sizeof.usb_controller], al ; no resetting port |
dec eax ; don't allocate zero address |
mov [edi+usb_controller.ExistingAddresses-sizeof.usb_controller], eax |
mov eax, [ebp-4] |
mov [edi+usb_controller.PCICoordinates-sizeof.usb_controller], eax |
lea ecx, [edi+usb_controller.PeriodicLock-sizeof.usb_controller] |
call mutex_init |
add ecx, usb_controller.ControlLock - usb_controller.PeriodicLock |
474,3 → 275,48 |
.nothing: |
ret |
endp |
; Called from USB1 controller-specific initialization. |
; Finds EHCI companion controller for given USB1 controller. |
; in: bl = PCI device:function for USB1 controller, bh = PCI bus |
; out: eax -> usb_controller for EHCI companion |
proc usb_find_ehci_companion |
; 1. Loop over all registered controllers. |
mov eax, usb_controllers_list |
.next: |
mov eax, [eax+usb_controller.Next] |
cmp eax, usb_controllers_list |
jz .notfound |
; 2. For every controller, check the type, ignore everything that is not EHCI. |
mov edx, [eax+usb_controller.HardwareFunc] |
cmp [edx+usb_hardware_func.ID], 'EHCI' |
jnz .next |
; 3. For EHCI controller, compare PCI coordinates with input data: |
; bus and device must be the same, function can be different. |
mov edx, [eax+usb_controller.PCICoordinates] |
xor edx, ebx |
cmp dx, 8 |
jae .next |
ret |
.notfound: |
xor eax, eax |
ret |
endp |
; Find Transaction Translator hub and port for the given device. |
; in: edx = parent hub for the device, ecx = port for the device |
; out: edx = TT hub for the device, ecx = TT port for the device. |
proc usb_get_tt |
; If the parent hub is high-speed, it is TT for the device. |
; Otherwise, the parent hub itself is behind TT, and the device |
; has the same TT hub+port as the parent hub. |
mov eax, [edx+usb_hub.ConfigPipe] |
mov eax, [eax+usb_pipe.DeviceData] |
cmp [eax+usb_device_data.Speed], USB_SPEED_HS |
jz @f |
movzx ecx, [eax+usb_device_data.TTPort] |
mov edx, [eax+usb_device_data.TTHub] |
@@: |
mov edx, [edx+usb_hub.ConfigPipe] |
ret |
endp |
/kernel/trunk/bus/usb/hub.inc |
---|
1262,3 → 1262,14 |
.nothing: |
retn 4 |
endp |
; Helper function for USB2 scheduler. |
; in: eax -> usb_hub |
; out: ecx = TT think time for the hub in FS-bytes |
proc usb_get_tt_think_time |
movzx ecx, [eax+usb_hub.HubCharacteristics] |
shr ecx, 5 |
and ecx, 3 |
inc ecx |
ret |
endp |
/kernel/trunk/bus/usb/init.inc |
---|
29,19 → 29,20 |
; ProcessDeferred and sleeps until this moment is reached or the thread |
; is awakened by IRQ handler. |
iglobal |
uhci_service_name: |
db 'UHCI',0 |
ohci_service_name: |
db 'OHCI',0 |
ehci_service_name: |
db 'EHCI',0 |
endg |
; Initializes the USB subsystem. |
proc usb_init |
; 1. Initialize all locks. |
mov ecx, usb_controllers_list_mutex |
call mutex_init |
mov ecx, usb1_ep_mutex |
call mutex_init |
mov ecx, usb_gtd_mutex |
call mutex_init |
mov ecx, ehci_ep_mutex |
call mutex_init |
mov ecx, ehci_gtd_mutex |
call mutex_init |
; 2. Kick off BIOS from all USB controllers, calling the corresponding function |
; *hci_kickoff_bios. Also count USB controllers for the next step. |
; Note: USB1 companion(s) must go before the corresponding EHCI controller, |
59,19 → 60,34 |
jz .done_kickoff |
cmp word [esi+PCIDEV.class+1], 0x0C03 |
jnz .kickoff |
mov eax, uhci_kickoff_bios |
mov ebx, uhci_service_name |
cmp byte [esi+PCIDEV.class], 0x00 |
jz .do_kickoff |
mov eax, ohci_kickoff_bios |
mov ebx, ohci_service_name |
cmp byte [esi+PCIDEV.class], 0x10 |
jz .do_kickoff |
mov eax, ehci_kickoff_bios |
mov ebx, ehci_service_name |
cmp byte [esi+PCIDEV.class], 0x20 |
jnz .kickoff |
.do_kickoff: |
inc dword [esp] |
call eax |
push ebx esi |
stdcall get_service, ebx |
pop esi ebx |
test eax, eax |
jz .driver_fail |
mov edx, [eax+USBSRV.usb_func] |
cmp [edx+usb_hardware_func.Version], USBHC_VERSION |
jnz .driver_invalid |
mov [esi+PCIDEV.owner], eax |
call [edx+usb_hardware_func.BeforeInit] |
jmp .kickoff |
.driver_fail: |
DEBUGF 1,'K : failed to load driver %s\n',ebx |
jmp .kickoff |
.driver_invalid: |
DEBUGF 1,'K : driver %s has wrong version\n',ebx |
jmp .kickoff |
.done_kickoff: |
pop eax |
; 3. If no controllers were found, exit. |
97,7 → 113,6 |
jz .done_ehci |
cmp [eax+PCIDEV.class], 0x0C0320 |
jnz .scan_ehci |
mov edi, ehci_hardware_func |
call usb_init_controller |
jmp .scan_ehci |
.done_ehci: |
108,10 → 123,8 |
mov eax, [eax+PCIDEV.fd] |
cmp eax, pcidev_list |
jz .done_usb1 |
mov edi, uhci_hardware_func |
cmp [eax+PCIDEV.class], 0x0C0300 |
jz @f |
mov edi, ohci_hardware_func |
cmp [eax+PCIDEV.class], 0x0C0310 |
jnz .scan_usb1 |
@@: |
238,11 → 251,8 |
endg |
include "memory.inc" |
include "common.inc" |
include "hccommon.inc" |
include "pipe.inc" |
include "ohci.inc" |
include "uhci.inc" |
include "ehci.inc" |
include "protocol.inc" |
include "hub.inc" |
include "scheduler.inc" |
/kernel/trunk/bus/usb/memory.inc |
---|
12,77 → 12,6 |
; Data for one pool: dd pointer to the first page, MUTEX lock. |
uglobal |
; Structures in UHCI and OHCI have equal sizes. |
; Thus, functions and data for allocating/freeing can be shared; |
; we keep them here rather than in controller-specific files. |
align 4 |
; Data for UHCI and OHCI endpoints pool. |
usb1_ep_first_page dd ? |
usb1_ep_mutex MUTEX |
; Data for UHCI and OHCI general transfer descriptors pool. |
usb_gtd_first_page dd ? |
usb_gtd_mutex MUTEX |
endg |
; sanity check: structures in UHCI and OHCI should be the same for allocation |
if (sizeof.ohci_pipe = sizeof.uhci_pipe) |
; Allocates one endpoint structure for UHCI/OHCI. |
; Returns pointer to software part (usb_pipe) in eax. |
proc usb1_allocate_endpoint |
push ebx |
mov ebx, usb1_ep_mutex |
stdcall usb_allocate_common, (sizeof.ohci_pipe + sizeof.usb_pipe + 0Fh) and not 0Fh |
test eax, eax |
jz @f |
add eax, sizeof.ohci_pipe |
@@: |
pop ebx |
ret |
endp |
; Free one endpoint structure for UHCI/OHCI. |
; Stdcall with one argument, pointer to software part (usb_pipe). |
proc usb1_free_endpoint |
sub dword [esp+4], sizeof.ohci_pipe |
jmp usb_free_common |
endp |
else |
; sanity check continued |
.err allocate_endpoint/free_endpoint must be different for OHCI and UHCI |
end if |
; sanity check: structures in UHCI and OHCI should be the same for allocation |
if (sizeof.ohci_gtd = sizeof.uhci_gtd) |
; Allocates one general transfer descriptor structure for UHCI/OHCI. |
; Returns pointer to software part (usb_gtd) in eax. |
proc usb1_allocate_general_td |
push ebx |
mov ebx, usb_gtd_mutex |
stdcall usb_allocate_common, (sizeof.ohci_gtd + sizeof.usb_gtd + 0Fh) and not 0Fh |
test eax, eax |
jz @f |
add eax, sizeof.ohci_gtd |
@@: |
pop ebx |
ret |
endp |
; Free one general transfer descriptor structure for UHCI/OHCI. |
; Stdcall with one argument, pointer to software part (usb_gtd). |
proc usb1_free_general_td |
sub dword [esp+4], sizeof.ohci_gtd |
jmp usb_free_common |
endp |
else |
; sanity check continued |
.err allocate_general_td/free_general_td must be different for OHCI and UHCI |
end if |
; Allocator for fixed-size blocks: allocate a block. |
; [ebx-4] = pointer to the first page, ebx = pointer to MUTEX structure. |
proc usb_allocate_common |
187,12 → 116,12 |
ret 4 |
endp |
; Helper procedure for OHCI: translate physical address in ecx |
; Helper procedure: translate physical address in ecx |
; of some transfer descriptor to linear address. |
; in: eax = address of first page |
proc usb_td_to_virt |
; Traverse all pages used for transfer descriptors, looking for the one |
; with physical address as in ecx. |
mov eax, [usb_gtd_first_page] |
@@: |
test eax, eax |
jz .zero |
/kernel/trunk/bus/usb/pipe.inc |
---|
1,195 → 1,5 |
; Functions for USB pipe manipulation: opening/closing, sending data etc. |
; |
; ============================================================================= |
; ================================= Constants ================================= |
; ============================================================================= |
; USB pipe types |
CONTROL_PIPE = 0 |
ISOCHRONOUS_PIPE = 1 |
BULK_PIPE = 2 |
INTERRUPT_PIPE = 3 |
; Status codes for transfer callbacks. |
; Taken from OHCI as most verbose controller in this sense. |
USB_STATUS_OK = 0 ; no error |
USB_STATUS_CRC = 1 ; CRC error |
USB_STATUS_BITSTUFF = 2 ; bit stuffing violation |
USB_STATUS_TOGGLE = 3 ; data toggle mismatch |
USB_STATUS_STALL = 4 ; device returned STALL |
USB_STATUS_NORESPONSE = 5 ; device not responding |
USB_STATUS_PIDCHECK = 6 ; invalid PID check bits |
USB_STATUS_WRONGPID = 7 ; unexpected PID value |
USB_STATUS_OVERRUN = 8 ; too many data from endpoint |
USB_STATUS_UNDERRUN = 9 ; too few data from endpoint |
USB_STATUS_BUFOVERRUN = 12 ; overflow of internal controller buffer |
USB_STATUS_BUFUNDERRUN = 13 ; underflow of internal controller buffer |
USB_STATUS_CLOSED = 16 ; pipe closed |
; either explicitly with USBClosePipe |
; or implicitly due to device disconnect |
; flags for usb_pipe.Flags |
USB_FLAG_CLOSED = 1 ; pipe is closed, no new transfers |
; pipe is closed, return error instead of submitting any new transfer |
USB_FLAG_CAN_FREE = 2 |
; pipe is closed via explicit call to USBClosePipe, so it can be freed without |
; any driver notification; if this flag is not set, then the pipe is closed due |
; to device disconnect, so it must remain valid until return from disconnect |
; callback provided by the driver |
USB_FLAG_EXTRA_WAIT = 4 |
; The pipe was in wait list, while another event occured; |
; when the first wait will be done, reinsert the pipe to wait list |
USB_FLAG_CLOSED_BIT = 0 ; USB_FLAG_CLOSED = 1 shl USB_FLAG_CLOSED_BIT |
; ============================================================================= |
; ================================ Structures ================================= |
; ============================================================================= |
; Pipe descriptor. |
; * An USB pipe is described by two structures, for hardware and for software. |
; * This is the software part. The hardware part is defined in a driver |
; of the corresponding controller. |
; * The hardware part is located immediately before usb_pipe, |
; both are allocated at once by controller-specific code |
; (it knows the total length, which depends on the hardware part). |
struct usb_pipe |
Controller dd ? |
; Pointer to usb_controller structure corresponding to this pipe. |
; Must be the first dword after hardware part, see *hci_new_device. |
; |
; Every endpoint is included into one of processing lists: |
; * Bulk list contains all Bulk endpoints. |
; * Control list contains all Control endpoints. |
; * Several Periodic lists serve Interrupt endpoints with different interval. |
; - There are N=2^n "leaf" periodic lists for N ms interval, one is processed |
; in the frames 0,N,2N,..., another is processed in the frames |
; 1,1+N,1+2N,... and so on. The hardware starts processing of periodic |
; endpoints in every frame from the list identified by lower n bits of the |
; frame number; the addresses of these N lists are written to the |
; controller data area during the initialization. |
; - We assume that n=5, N=32 to simplify the code and compact the data. |
; OHCI works in this way. UHCI and EHCI actually have n=10, N=1024, |
; but this is an overkill for interrupt endpoints; the large value of N is |
; useful only for isochronous transfers in UHCI and EHCI. UHCI/EHCI code |
; initializes "leaf" lists k,k+32,k+64,...,k+(1024-32) to the same value, |
; giving essentially N=32. |
; This restriction means that the actual maximum interval of polling any |
; interrupt endpoint is 32ms, which seems to be a reasonable value. |
; - Similarly, there are 16 lists for 16-ms interval, 8 lists for 8-ms |
; interval and so on. Finally, there is one list for 1ms interval. Their |
; addresses are not directly known to the controller. |
; - The hardware serves endpoints following a physical link from the hardware |
; part. |
; - The hardware links are organized as follows. If the list item is not the |
; last, it's hardware link points to the next item. The hardware link of |
; the last item points to the first item of the "next" list. |
; - The "next" list for k-th and (k+M)-th periodic lists for interval 2M ms |
; is the k-th periodic list for interval M ms, M >= 1. In this scheme, |
; if two "previous" lists are served in the frames k,k+2M,k+4M,... |
; and k+M,k+3M,k+5M,... correspondingly, the "next" list is served in |
; the frames k,k+M,k+2M,k+3M,k+4M,k+5M,..., which is exactly what we want. |
; - The links between Periodic, Control, Bulk lists and the processing of |
; Isochronous endpoints are controller-specific. |
; * The head of every processing list is a static entry which does not |
; correspond to any real pipe. It is described by usb_static_ep |
; structure, not usb_pipe. For OHCI and UHCI, sizeof.usb_static_ep plus |
; sizeof hardware part is 20h, the total number of lists is |
; 32+16+8+4+2+1+1+1 = 65, so all these structures fit in one page, |
; leaving space for other data. This is another reason for 32ms limit. |
; * Static endpoint descriptors are kept in *hci_controller structure. |
; * All items in every processing list, including the static head, are |
; organized in a double-linked list using .NextVirt and .PrevVirt fields. |
; * [[item.NextVirt].PrevVirt] = [[item.PrevVirt].NextVirt] for all items. |
NextVirt dd ? |
; Next endpoint in the processing list. |
; See also PrevVirt field and the description before NextVirt field. |
PrevVirt dd ? |
; Previous endpoint in the processing list. |
; See also NextVirt field and the description before NextVirt field. |
; |
; Every pipe has the associated transfer queue, that is, the double-linked |
; list of Transfer Descriptors aka TD. For Control, Bulk and Interrupt |
; endpoints this list consists of usb_gtd structures |
; (GTD = General Transfer Descriptors), for Isochronous endpoints |
; this list consists of usb_itd structures, which are not developed yet. |
; The pipe needs to know only the last TD; the first TD can be |
; obtained as [[pipe.LastTD].NextVirt]. |
LastTD dd ? |
; Last TD in the transfer queue. |
; |
; All opened pipes corresponding to the same physical device are organized in |
; the double-linked list using .NextSibling and .PrevSibling fields. |
; The head of this list is kept in usb_device_data structure (OpenedPipeList). |
; This list is used when the device is disconnected and all pipes for the |
; device should be closed. |
; Also, all pipes closed due to disconnect must remain valid at least until |
; driver-provided disconnect function returns; all should-be-freed-but-not-now |
; pipes for one device are organized in another double-linked list with |
; the head in usb_device_data.ClosedPipeList; this list uses the same link |
; fields, one pipe can never be in both lists. |
NextSibling dd ? |
; Next pipe for the physical device. |
PrevSibling dd ? |
; Previous pipe for the physical device. |
; |
; When hardware part of pipe is changed, some time is needed before further |
; actions so that hardware reacts on this change. During that time, |
; all changed pipes are organized in single-linked list with the head |
; usb_controller.WaitPipeList* and link field NextWait. |
; Currently there are two possible reasons to change: |
; change of address/packet size in initial configuration, |
; close of the pipe. They are distinguished by USB_FLAG_CLOSED. |
NextWait dd ? |
Lock MUTEX |
; Mutex that guards operations with transfer queue for this pipe. |
Type db ? |
; Type of pipe, one of {CONTROL,ISOCHRONOUS,BULK,INTERRUPT}_PIPE. |
Flags db ? |
; Combination of flags, USB_FLAG_*. |
rb 2 ; dword alignment |
DeviceData dd ? |
; Pointer to usb_device_data, common for all pipes for one device. |
ends |
; This structure describes the static head of every list of pipes. |
struct usb_static_ep |
; software fields |
Bandwidth dd ? |
; valid only for interrupt/isochronous USB1 lists |
; The offsets of the following two fields must be the same in this structure |
; and in usb_pipe. |
NextVirt dd ? |
PrevVirt dd ? |
ends |
; This structure represents one transfer descriptor |
; ('g' stands for "general" as opposed to isochronous usb_itd). |
; Note that one transfer can have several descriptors: |
; a control transfer has three stages. |
; Additionally, every controller has a limit on transfer length with |
; one descriptor (packet size for UHCI, 1K for OHCI, 4K for EHCI), |
; large transfers must be split into individual packets according to that limit. |
struct usb_gtd |
Callback dd ? |
; Zero for intermediate descriptors, pointer to callback function |
; for final descriptor. See the docs for description of the callback. |
UserData dd ? |
; Dword which is passed to Callback as is, not used by USB code itself. |
; Two following fields organize all descriptors for one pipe in |
; the linked list. |
NextVirt dd ? |
PrevVirt dd ? |
Pipe dd ? |
; Pointer to the parent usb_pipe. |
Buffer dd ? |
; Pointer to data for this descriptor. |
Length dd ? |
; Length of data for this descriptor. |
ends |
; ============================================================================= |
; =================================== Code ==================================== |
; ============================================================================= |
USB_STDCALL_VERIFY = 1 |
macro stdcall_verify [arg] |
{ |
216,7 → 26,7 |
proc usb_open_pipe stdcall uses ebx esi edi,\ |
config_pipe:dword, endpoint:dword, maxpacket:dword, type:dword, interval:dword |
locals |
tt_vars rd (ehci_select_tt_interrupt_list.local_vars_size + 3) / 4 |
tt_vars rd 24 ; should be enough for ehci_select_tt_interrupt_list |
targetsmask dd ? ; S-Mask for USB2 |
bandwidth dd ? |
target dd ? |
810,6 → 620,27 |
ret |
endp |
; One part of transfer is completed, run the associated callback |
; or update total length in the next part of transfer. |
; in: ebx -> usb_gtd, ecx = status, edx = length |
proc usb_process_gtd |
; 1. Test whether it is the last descriptor in the transfer |
; <=> it has an associated callback. |
mov eax, [ebx+usb_gtd.Callback] |
test eax, eax |
jz .nocallback |
; 2. It has an associated callback; call it with corresponding parameters. |
stdcall_verify eax, [ebx+usb_gtd.Pipe], ecx, \ |
[ebx+usb_gtd.Buffer], edx, [ebx+usb_gtd.UserData] |
ret |
.nocallback: |
; 3. It is an intermediate descriptor. Add its length to the length |
; in the following descriptor. |
mov eax, [ebx+usb_gtd.NextVirt] |
add [eax+usb_gtd.Length], edx |
ret |
endp |
if USB_STDCALL_VERIFY |
proc verify_regs |
virtual at esp |
/kernel/trunk/bus/usb/protocol.inc |
---|
29,11 → 29,6 |
USB_OTHER_SPEED_CONFIG_DESCR = 7 |
USB_INTERFACE_POWER_DESCR = 8 |
; Possible speeds of USB devices |
USB_SPEED_FS = 0 ; full-speed |
USB_SPEED_LS = 1 ; low-speed |
USB_SPEED_HS = 2 ; high-speed |
; Compile-time setting. If set, the code will dump all descriptors as they are |
; read to the debug board. |
USB_DUMP_DESCRIPTORS = 1 |
370,7 → 365,7 |
; so setting the address could take some time until the cache is evicted. |
; Thus, the call is asynchronous; meet us in usb_after_set_address when it will |
; be safe to continue. |
dbgstr 'address set in device' |
; dbgstr 'address set in device' |
call [eax+usb_hardware_func.SetDeviceAddress] |
; 2b. If the port is in non-root hub, clear 'reset in progress' flag. |
; In any case, proceed to 4. |
409,7 → 404,7 |
; is cleared after request from usb_set_address_callback. |
; in: ebx -> usb_pipe |
proc usb_after_set_address |
dbgstr 'address set for controller' |
; dbgstr 'address set for controller' |
; Issue control transfer GET_DESCRIPTOR(DEVICE_DESCR) for first 8 bytes. |
; Remember, we still do not know the actual packet size; |
; 8-bytes-request is safe. |
/kernel/trunk/const.inc |
---|
509,6 → 509,8 |
class dd ? |
devfn db ? |
bus db ? |
rb 2 |
owner dd ? ; pointer to SRV or 0 |
ends |
; The following macro assume that we are on uniprocessor machine. |
/kernel/trunk/core/dll.inc |
---|
214,10 → 214,35 |
mov edx, [edx+SRV.fd] |
jmp @B |
.not_load: |
mov eax, [sz_name] |
; Try to load .dll driver first. If not, fallback to .obj. |
push edi |
sub esp, 36 |
mov edi, esp |
mov dword [edi], '/sys' |
mov dword [edi+4], '/dri' |
mov dword [edi+8], 'vers' |
mov byte [edi+12], '/' |
@@: |
mov dl, [eax] |
mov [edi+13], dl |
inc eax |
inc edi |
test dl, dl |
jnz @b |
mov dword [edi+12], '.sys' |
mov byte [edi+16], 0 |
mov edi, esp |
stdcall load_pe_driver, edi, 0 |
add esp, 36 |
pop edi |
test eax, eax |
jnz .nothing |
pop ebp |
jmp load_driver |
.ok: |
mov eax, edx |
.nothing: |
ret |
endp |
/kernel/trunk/core/exports.inc |
---|
45,6 → 45,7 |
map_io_mem, 'MapIoMem', \ ; stdcall |
map_page, 'MapPage', \ ; stdcall |
get_pg_addr, 'GetPgAddr', \ ; eax |
get_phys_addr, 'GetPhysAddr', \ ; eax |
map_space, 'MapSpace', \ |
release_pages, 'ReleasePages', \ |
\ |
113,6 → 114,7 |
usb_normal_transfer_async, 'USBNormalTransferAsync', \ |
usb_control_async, 'USBControlTransferAsync', \ |
usb_get_param, 'USBGetParam', \ |
usb_hc_func, 'USBHCFunc', \ |
\ |
NET_add_device, 'NetRegDev', \ |
NET_remove_device, 'NetUnRegDev', \ |
/kernel/trunk/core/memory.inc |
---|
1253,22 → 1253,7 |
cmp edx, OS_BASE |
jae .fail |
mov edi, edx |
stdcall load_PE, ecx |
mov esi, eax |
test eax, eax |
jz @F |
push edi |
push DRV_ENTRY |
call eax |
add esp, 8 |
test eax, eax |
jz @F |
mov [eax+SRV.entry], esi |
@@: |
stdcall load_pe_driver, ecx, edx |
mov [esp+32], eax |
ret |
.22: |
1348,7 → 1333,8 |
align 4 |
proc load_pe_driver stdcall, file:dword |
proc load_pe_driver stdcall, file:dword, cmdline:dword |
push esi |
stdcall load_PE, [file] |
test eax, eax |
1355,19 → 1341,24 |
jz .fail |
mov esi, eax |
stdcall eax, DRV_ENTRY |
push [cmdline] |
push DRV_ENTRY |
call eax |
pop ecx |
pop ecx |
test eax, eax |
jz .fail |
mov [eax+SRV.entry], esi |
pop esi |
ret |
.fail: |
xor eax, eax |
pop esi |
ret |
endp |
align 4 |
proc init_mtrr |
1415,9 → 1406,9 |
xor eax, eax |
xor edx, edx |
@@: |
inc ecx |
wrmsr |
inc ecx |
cmp ecx, 0x210 |
cmp ecx, 0x20F |
jb @b |
; enable MTRRs |
pop eax |
/kernel/trunk/core/peload.inc |
---|
85,13 → 85,12 |
mov ecx, eax |
add edi, DWORD PTR [edx+260] |
add ecx, 3 |
shr ecx, 2 |
rep movsd |
L4: |
mov ecx, DWORD PTR [edx+256] |
add ecx, 4095 |
and ecx, -4096 |
cmp ecx, eax |
jbe L6 |
sub ecx, eax |
178,6 → 177,10 |
mov ecx, DWORD PTR [eax-4] |
mov DWORD PTR [esp+48], edi |
mov edx, DWORD PTR [eax-20] |
test edx, edx |
jnz @f |
mov edx, ecx |
@@: |
mov DWORD PTR [esp+52], 0 |
add ecx, ebp |
add edx, ebp |