Rev 4418 | Rev 4850 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4418 | Rev 4547 | ||
---|---|---|---|
Line 11... | Line 11... | ||
11 | popad |
11 | popad |
12 | else |
12 | else |
13 | stdcall arg |
13 | stdcall arg |
14 | end if |
14 | end if |
15 | } |
15 | } |
- | 16 | if USB_STDCALL_VERIFY |
|
- | 17 | STDCALL_VERIFY_EXTRA = 20h |
|
- | 18 | else |
|
- | 19 | STDCALL_VERIFY_EXTRA = 0 |
|
- | 20 | end if |
|
Line 16... | Line 21... | ||
16 | 21 | ||
17 | ; Initialization of usb_static_ep structure, |
22 | ; Initialization of usb_static_ep structure, |
18 | ; called from controller-specific initialization; edi -> usb_static_ep |
23 | ; called from controller-specific initialization; edi -> usb_static_ep |
19 | proc usb_init_static_endpoint |
24 | proc usb_init_static_endpoint |
Line 236... | Line 241... | ||
236 | @@: |
241 | @@: |
237 | push edx |
242 | push edx |
238 | call mutex_lock |
243 | call mutex_lock |
239 | push ecx |
244 | push ecx |
240 | ; 3b. Let the controller-specific code do its job. |
245 | ; 3b. Let the controller-specific code do its job. |
- | 246 | test [ebx+usb_pipe.Flags], USB_FLAG_DISABLED |
|
- | 247 | jnz @f |
|
- | 248 | mov eax, [esi+usb_controller.HardwareFunc] |
|
- | 249 | call [eax+usb_hardware_func.DisablePipe] |
|
- | 250 | @@: |
|
241 | mov eax, [esi+usb_controller.HardwareFunc] |
251 | mov eax, [esi+usb_controller.HardwareFunc] |
242 | call [eax+usb_hardware_func.UnlinkPipe] |
252 | call [eax+usb_hardware_func.UnlinkPipe] |
- | 253 | mov edx, [ebx+usb_pipe.NextVirt] |
|
- | 254 | mov eax, [ebx+usb_pipe.PrevVirt] |
|
- | 255 | mov [edx+usb_pipe.PrevVirt], eax |
|
- | 256 | mov [eax+usb_pipe.NextVirt], edx |
|
243 | ; 3c. Release the corresponding lock. |
257 | ; 3c. Release the corresponding lock. |
244 | pop ecx |
258 | pop ecx |
245 | call mutex_unlock |
259 | call mutex_unlock |
246 | ; 4. Put the pipe into wait queue. |
260 | ; 4. Put the pipe into wait queue. |
247 | pop edx |
261 | pop edx |
Line 260... | Line 274... | ||
260 | call mutex_unlock |
274 | call mutex_unlock |
261 | xor eax, eax |
275 | xor eax, eax |
262 | ret |
276 | ret |
263 | endp |
277 | endp |
Line -... | Line 278... | ||
- | 278 | ||
- | 279 | ; This procedure is called when all transfers are aborted |
|
- | 280 | ; either due to call to usb_abort_pipe or due to pipe closing. |
|
- | 281 | ; It notifies all callbacks and frees all transfer descriptors. |
|
- | 282 | ; ebx -> usb_pipe, esi -> usb_controller, edi -> usb_hardware_func |
|
- | 283 | ; three stack parameters: status code for callback functions |
|
- | 284 | ; and descriptors where to start and stop. |
|
- | 285 | proc usb_pipe_aborted |
|
- | 286 | virtual at esp |
|
- | 287 | dd ? ; return address |
|
- | 288 | .status dd ? ; USB_STATUS_CLOSED or USB_STATUS_CANCELLED |
|
- | 289 | .first_td dd ? |
|
- | 290 | .last_td dd ? |
|
- | 291 | end virtual |
|
- | 292 | ; Loop over all transfers, calling the driver with the given status |
|
- | 293 | ; and freeing all descriptors except the last one. |
|
- | 294 | .loop: |
|
- | 295 | mov edx, [.first_td] |
|
- | 296 | cmp edx, [.last_td] |
|
- | 297 | jz .done |
|
- | 298 | mov ecx, [edx+usb_gtd.Callback] |
|
- | 299 | test ecx, ecx |
|
- | 300 | jz .no_callback |
|
- | 301 | stdcall_verify ecx, ebx, [.status+12+STDCALL_VERIFY_EXTRA], \ |
|
- | 302 | [edx+usb_gtd.Buffer], 0, [edx+usb_gtd.UserData] |
|
- | 303 | mov edx, [.first_td] |
|
- | 304 | .no_callback: |
|
- | 305 | mov eax, [edx+usb_gtd.NextVirt] |
|
- | 306 | mov [.first_td], eax |
|
- | 307 | stdcall [edi+usb_hardware_func.FreeTD], edx |
|
- | 308 | jmp .loop |
|
- | 309 | .done: |
|
- | 310 | ret 12 |
|
- | 311 | endp |
|
264 | 312 | ||
265 | ; This procedure is called when a pipe with USB_FLAG_CLOSED is removed from the |
313 | ; This procedure is called when a pipe with USB_FLAG_CLOSED is removed from the |
266 | ; corresponding wait list. It means that the hardware has fully forgot about it. |
314 | ; corresponding wait list. It means that the hardware has fully forgot about it. |
267 | ; ebx -> usb_pipe, esi -> usb_controller |
315 | ; ebx -> usb_pipe, esi -> usb_controller |
268 | proc usb_pipe_closed |
316 | proc usb_pipe_closed |
269 | push edi |
317 | push edi |
270 | mov edi, [esi+usb_controller.HardwareFunc] |
318 | mov edi, [esi+usb_controller.HardwareFunc] |
271 | ; 1. Loop over all transfers, calling the driver with USB_STATUS_CLOSED |
319 | ; 1. Notify all registered callbacks with status USB_STATUS_CLOSED, if any, |
- | 320 | ; and free all transfer descriptors, including the last one. |
|
- | 321 | lea ecx, [ebx+usb_pipe.Lock] |
|
272 | ; and freeing all descriptors. |
322 | call mutex_lock |
273 | mov edx, [ebx+usb_pipe.LastTD] |
323 | mov edx, [ebx+usb_pipe.LastTD] |
274 | test edx, edx |
324 | test edx, edx |
275 | jz .no_transfer |
325 | jz .no_transfer |
276 | mov edx, [edx+usb_gtd.NextVirt] |
- | |
277 | .transfer_loop: |
- | |
278 | cmp edx, [ebx+usb_pipe.LastTD] |
- | |
279 | jz .transfer_done |
- | |
280 | mov ecx, [edx+usb_gtd.Callback] |
- | |
281 | test ecx, ecx |
- | |
282 | jz .no_callback |
326 | mov eax, [edx+usb_gtd.NextVirt] |
283 | push edx |
- | |
284 | stdcall_verify ecx, ebx, USB_STATUS_CLOSED, \ |
- | |
285 | [edx+usb_gtd.Buffer], 0, [edx+usb_gtd.UserData] |
327 | push edx |
286 | pop edx |
328 | push eax |
287 | .no_callback: |
329 | call mutex_unlock |
288 | push [edx+usb_gtd.NextVirt] |
330 | push USB_STATUS_CLOSED |
289 | stdcall [edi+usb_hardware_func.FreeTD], edx |
331 | call usb_pipe_aborted |
290 | pop edx |
332 | ; It is safe to free LastTD here: |
291 | jmp .transfer_loop |
- | |
292 | .transfer_done: |
333 | ; usb_*_transfer_async do not enqueue new transfers if USB_FLAG_CLOSED is set. |
- | 334 | stdcall [edi+usb_hardware_func.FreeTD], [ebx+usb_pipe.LastTD] |
|
293 | stdcall [edi+usb_hardware_func.FreeTD], edx |
335 | jmp @f |
- | 336 | .no_transfer: |
|
- | 337 | call mutex_unlock |
|
294 | .no_transfer: |
338 | @@: |
295 | ; 2. Decrement number of pipes for the device. |
339 | ; 2. Decrement number of pipes for the device. |
296 | ; If this pipe is the last pipe, go to 5. |
340 | ; If this pipe is the last pipe, go to 5. |
297 | mov ecx, [ebx+usb_pipe.DeviceData] |
341 | mov ecx, [ebx+usb_pipe.DeviceData] |
298 | call mutex_lock |
342 | call mutex_lock |
Line 340... | Line 384... | ||
340 | @@: |
384 | @@: |
341 | add ecx, sizeof.usb_interface_data |
385 | add ecx, sizeof.usb_interface_data |
342 | dec eax |
386 | dec eax |
343 | jnz .notify_loop |
387 | jnz .notify_loop |
344 | .notify_done: |
388 | .notify_done: |
- | 389 | ; 6. Kill the timer, if active. |
|
- | 390 | ; (Usually not; possible if device is disconnected |
|
- | 391 | ; while processing SET_ADDRESS request). |
|
- | 392 | mov eax, [ebx+usb_pipe.DeviceData] |
|
- | 393 | cmp [eax+usb_device_data.Timer], 0 |
|
- | 394 | jz @f |
|
- | 395 | stdcall cancel_timer_hs, [eax+usb_device_data.Timer] |
|
- | 396 | mov [eax+usb_device_data.Timer], 0 |
|
- | 397 | @@: |
|
345 | ; 6. Bus address, if assigned, can now be reused. |
398 | ; 7. Bus address, if assigned, can now be reused. |
346 | call [edi+usb_hardware_func.GetDeviceAddress] |
399 | call [edi+usb_hardware_func.GetDeviceAddress] |
347 | test eax, eax |
400 | test eax, eax |
348 | jz @f |
401 | jz @f |
349 | bts [esi+usb_controller.ExistingAddresses], eax |
402 | bts [esi+usb_controller.ExistingAddresses], eax |
350 | @@: |
403 | @@: |
351 | dbgstr 'USB device disconnected' |
404 | dbgstr 'USB device disconnected' |
352 | ; 7. All drivers have returned from disconnect callback, |
405 | ; 8. All drivers have returned from disconnect callback, |
353 | ; so all drivers should not use any device-related pipes. |
406 | ; so all drivers should not use any device-related pipes. |
354 | ; Free the remaining pipes. |
407 | ; Free the remaining pipes. |
355 | mov eax, [ebx+usb_pipe.DeviceData] |
408 | mov eax, [ebx+usb_pipe.DeviceData] |
356 | add eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling |
409 | add eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling |
357 | push eax |
410 | push eax |
Line 364... | Line 417... | ||
364 | pop eax |
417 | pop eax |
365 | jmp .free_loop |
418 | jmp .free_loop |
366 | .free_done: |
419 | .free_done: |
367 | stdcall [edi+usb_hardware_func.FreePipe], ebx |
420 | stdcall [edi+usb_hardware_func.FreePipe], ebx |
368 | pop eax |
421 | pop eax |
369 | ; 8. Free the usb_device_data structure. |
422 | ; 9. Free the usb_device_data structure. |
370 | sub eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling |
423 | sub eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling |
371 | call free |
424 | call free |
372 | ; 9. Return. |
425 | ; 10. Return. |
373 | .nothing: |
426 | .nothing: |
374 | pop edi |
427 | pop edi |
375 | ret |
428 | ret |
376 | endp |
429 | endp |
Line -... | Line 430... | ||
- | 430 | ||
- | 431 | ; This procedure is called when a pipe with USB_FLAG_DISABLED is removed from the |
|
- | 432 | ; corresponding wait list. It means that the hardware has fully forgot about it. |
|
- | 433 | ; ebx -> usb_pipe, esi -> usb_controller |
|
- | 434 | proc usb_pipe_disabled |
|
- | 435 | push edi |
|
- | 436 | mov edi, [esi+usb_controller.HardwareFunc] |
|
- | 437 | ; 1. Acquire pipe lock. |
|
- | 438 | lea ecx, [ebx+usb_pipe.Lock] |
|
- | 439 | call mutex_lock |
|
- | 440 | ; 2. Clear USB_FLAG_DISABLED in pipe state. |
|
- | 441 | and [ebx+usb_pipe.Flags], not USB_FLAG_DISABLED |
|
- | 442 | ; 3. Sanity check: ignore uninitialized pipes. |
|
- | 443 | cmp [ebx+usb_pipe.LastTD], 0 |
|
- | 444 | jz .no_transfer |
|
- | 445 | ; 4. Acquire the first and last to-be-cancelled transfer descriptor, |
|
- | 446 | ; save them in stack for the step 6, |
|
- | 447 | ; ask the controller driver to enable the pipe for hardware, |
|
- | 448 | ; removing transfers between first and last to-be-cancelled descriptors. |
|
- | 449 | lea ecx, [esi+usb_controller.ControlLock] |
|
- | 450 | cmp [ebx+usb_pipe.Type], BULK_PIPE |
|
- | 451 | jb @f ; control pipe |
|
- | 452 | lea ecx, [esi+usb_controller.BulkLock] |
|
- | 453 | jz @f ; bulk pipe |
|
- | 454 | lea ecx, [esi+usb_controller.PeriodicLock] |
|
- | 455 | @@: |
|
- | 456 | call mutex_lock |
|
- | 457 | mov eax, [ebx+usb_pipe.BaseList] |
|
- | 458 | mov edx, [eax+usb_pipe.NextVirt] |
|
- | 459 | mov [ebx+usb_pipe.NextVirt], edx |
|
- | 460 | mov [ebx+usb_pipe.PrevVirt], eax |
|
- | 461 | mov [edx+usb_pipe.PrevVirt], ebx |
|
- | 462 | mov [eax+usb_pipe.NextVirt], ebx |
|
- | 463 | mov eax, [ebx+usb_pipe.LastTD] |
|
- | 464 | mov edx, [eax+usb_gtd.NextVirt] |
|
- | 465 | mov [eax+usb_gtd.NextVirt], eax |
|
- | 466 | mov [eax+usb_gtd.PrevVirt], eax |
|
- | 467 | push eax |
|
- | 468 | push edx |
|
- | 469 | push ecx |
|
- | 470 | call [edi+usb_hardware_func.EnablePipe] |
|
- | 471 | pop ecx |
|
- | 472 | call mutex_unlock |
|
- | 473 | ; 5. Release pipe lock acquired at step 1. |
|
- | 474 | ; Callbacks called at step 6 can insert new transfers, |
|
- | 475 | ; so we cannot call usb_pipe_aborted while holding pipe lock. |
|
- | 476 | lea ecx, [ebx+usb_pipe.Lock] |
|
- | 477 | call mutex_unlock |
|
- | 478 | ; 6. Notify all registered callbacks with status USB_STATUS_CANCELLED, if any. |
|
- | 479 | ; Two arguments describing transfers range were pushed at step 4. |
|
- | 480 | push USB_STATUS_CANCELLED |
|
- | 481 | call usb_pipe_aborted |
|
- | 482 | pop edi |
|
- | 483 | ret |
|
- | 484 | .no_transfer: |
|
- | 485 | call mutex_unlock |
|
- | 486 | pop edi |
|
- | 487 | ret |
|
- | 488 | endp |
|
377 | 489 | ||
378 | ; Part of API for drivers, see documentation for USBNormalTransferAsync. |
490 | ; Part of API for drivers, see documentation for USBNormalTransferAsync. |
379 | proc usb_normal_transfer_async stdcall uses ebx edi,\ |
491 | proc usb_normal_transfer_async stdcall uses ebx edi,\ |
380 | pipe:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword |
492 | pipe:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword |
381 | ; 1. Sanity check: callback must be nonzero. |
493 | ; 1. Sanity check: callback must be nonzero. |
Line 506... | Line 618... | ||
506 | .return0: |
618 | .return0: |
507 | xor eax, eax |
619 | xor eax, eax |
508 | ret |
620 | ret |
509 | endp |
621 | endp |
Line -... | Line 622... | ||
- | 622 | ||
- | 623 | ; Part of API for drivers, see documentation for USBAbortPipe. |
|
- | 624 | proc usb_abort_pipe |
|
- | 625 | push ebx esi ; save used registers to be stdcall |
|
- | 626 | virtual at esp |
|
- | 627 | rd 2 ; saved registers |
|
- | 628 | dd ? ; return address |
|
- | 629 | .pipe dd ? |
|
- | 630 | end virtual |
|
- | 631 | mov ebx, [.pipe] |
|
- | 632 | ; 1. Acquire pipe lock. |
|
- | 633 | lea ecx, [ebx+usb_pipe.Lock] |
|
- | 634 | call mutex_lock |
|
- | 635 | ; 2. If the pipe is already closed or abort is in progress, |
|
- | 636 | ; just release pipe lock and return. |
|
- | 637 | test [ebx+usb_pipe.Flags], USB_FLAG_CLOSED + USB_FLAG_DISABLED |
|
- | 638 | jnz .nothing |
|
- | 639 | ; 3. Mark the pipe as aborting. |
|
- | 640 | or [ebx+usb_pipe.Flags], USB_FLAG_DISABLED |
|
- | 641 | ; 4. We cannot do anything except adding new transfers concurrently with hardware. |
|
- | 642 | ; Ask the controller driver to (temporarily) remove the pipe from hardware queue. |
|
- | 643 | mov esi, [ebx+usb_pipe.Controller] |
|
- | 644 | ; 4a. Acquire queue lock. |
|
- | 645 | lea ecx, [esi+usb_controller.ControlLock] |
|
- | 646 | cmp [ebx+usb_pipe.Type], BULK_PIPE |
|
- | 647 | jb @f ; control pipe |
|
- | 648 | lea ecx, [esi+usb_controller.BulkLock] |
|
- | 649 | jz @f ; bulk pipe |
|
- | 650 | lea ecx, [esi+usb_controller.PeriodicLock] |
|
- | 651 | @@: |
|
- | 652 | call mutex_lock |
|
- | 653 | push ecx |
|
- | 654 | ; 4b. Call the driver. |
|
- | 655 | mov eax, [esi+usb_controller.HardwareFunc] |
|
- | 656 | call [eax+usb_hardware_func.DisablePipe] |
|
- | 657 | ; 4c. Remove the pipe from software list. |
|
- | 658 | mov eax, [ebx+usb_pipe.NextVirt] |
|
- | 659 | mov edx, [ebx+usb_pipe.PrevVirt] |
|
- | 660 | mov [eax+usb_pipe.PrevVirt], edx |
|
- | 661 | mov [edx+usb_pipe.NextVirt], eax |
|
- | 662 | ; 4c. Register the pipe in corresponding wait list. |
|
- | 663 | test [ebx+usb_pipe.Type], 1 |
|
- | 664 | jz .control_bulk |
|
- | 665 | call usb_subscribe_periodic |
|
- | 666 | jmp @f |
|
- | 667 | .control_bulk: |
|
- | 668 | call usb_subscribe_control |
|
- | 669 | @@: |
|
- | 670 | ; 4d. Release queue lock. |
|
- | 671 | pop ecx |
|
- | 672 | call mutex_unlock |
|
- | 673 | ; 4e. Notify the USB thread about new work. |
|
- | 674 | push ebx esi edi |
|
- | 675 | call usb_wakeup |
|
- | 676 | pop edi esi ebx |
|
- | 677 | ; That's all for now. To be continued in usb_pipe_disabled. |
|
- | 678 | ; 5. Release pipe lock acquired at step 1 and return. |
|
- | 679 | .nothing: |
|
- | 680 | lea ecx, [ebx+usb_pipe.Lock] |
|
- | 681 | call mutex_unlock |
|
- | 682 | pop esi ebx |
|
- | 683 | ret 4 |
|
- | 684 | endp |
|
510 | 685 | ||
511 | ; Part of API for drivers, see documentation for USBGetParam. |
686 | ; Part of API for drivers, see documentation for USBGetParam. |
512 | proc usb_get_param |
687 | proc usb_get_param |
513 | virtual at esp |
688 | virtual at esp |
514 | dd ? ; return address |
689 | dd ? ; return address |