UsbTdAllocator.Mod 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. (**
  2. * UsbTdAllocator
  3. *
  4. * This module provides common TD allocation code for UsbOhci and UsbUhci.
  5. * In those USB 1.0 controllers, all data structures are 16-byte aligned and their size
  6. * is less than or equal to 16 bytes.
  7. *)
  8. MODULE UsbTdAllocator; (** AUTHOR "Timothée Martiel"; PURPOSE "Common TD allocation code for UsbUhci and UsbOhci"; *)
  9. CONST
  10. (** Size of each individual buffer. Must be a multiple of BlockSize * 32. *)
  11. TdBufferSize = 4096;
  12. (** Size of an allocation block. *)
  13. BlockSize = 16;
  14. BitmaskSize = TdBufferSize DIV (BlockSize * 32);
  15. TYPE
  16. TdBuffer = POINTER TO RECORD
  17. buffer: ARRAY TdBufferSize OF CHAR;
  18. used: ARRAY BitmaskSize OF SET;
  19. next: TdBuffer;
  20. END;
  21. Allocator * = OBJECT
  22. VAR
  23. buffers: TdBuffer;
  24. PROCEDURE Allocate * (): ADDRESS;
  25. VAR
  26. buf: TdBuffer;
  27. count, tdIn, tdOut: LONGINT;
  28. (** Allocate a new TD buffer and mark as used the last 32-byte block before a 4kB page boundary. *)
  29. PROCEDURE AllocateBuffer;
  30. VAR
  31. buf: TdBuffer;
  32. count: LONGINT;
  33. BEGIN
  34. (* No buffer found: allocate a new one *)
  35. NEW(buf);
  36. buf.next := buffers;
  37. buffers := buf;
  38. count := 0;
  39. END AllocateBuffer;
  40. BEGIN
  41. (* Find a buffer with enough room. *)
  42. buf := buffers;
  43. LOOP
  44. IF buf = NIL THEN
  45. AllocateBuffer;
  46. buf := buffers;
  47. ASSERT(buf # NIL)
  48. END;
  49. count := 0;
  50. tdOut := 0;
  51. FOR tdOut := 0 TO BitmaskSize - 1 DO
  52. FOR tdIn := 0 TO 31 DO
  53. IF ~(tdIn IN buf.used[tdOut]) THEN
  54. INCL(buf.used[tdOut], tdIn);
  55. RETURN ADDRESSOF(buf.buffer[(tdOut * 32 + tdIn) * BlockSize])
  56. END
  57. END
  58. END;
  59. buf := buf.next
  60. END;
  61. (* We should not get to this point *)
  62. ASSERT(buf # NIL);
  63. END Allocate;
  64. PROCEDURE Free * (td: ADDRESS(*; size: LONGINT*));
  65. VAR
  66. buf: TdBuffer;
  67. adr: ADDRESS;
  68. slot, tdIn, tdOut: LONGINT;
  69. BEGIN
  70. (*ASSERT(size MOD BlockSize = 0);*)
  71. buf := buffers;
  72. LOOP
  73. IF buf = NIL THEN EXIT END;
  74. adr := ADDRESSOF(buf.buffer[0]);
  75. IF (adr <= td) & (td <= adr + TdBufferSize) THEN EXIT END;
  76. buf := buf.next
  77. END;
  78. ASSERT(buf # NIL); (* Not a TD *)
  79. slot := (td - adr) DIV BlockSize;
  80. tdOut := slot DIV 32;
  81. tdIn := slot MOD 32;
  82. (*FOR i := 0 TO (size DIV BlockSize) - 1 DO
  83. IF tdIn + i < 32 THEN*)
  84. ASSERT(tdIn (*+ i*) IN buf.used[tdOut]);
  85. EXCL(buf.used[tdOut], tdIn (*+ i*))
  86. (*ELSE
  87. ASSERT(tdIn + i - 32 IN buf.used[tdOut + 1]);
  88. EXCL(buf.used[tdOut + 1], tdIn + i - 32)
  89. END
  90. END;*)
  91. END Free;
  92. END Allocator;
  93. END UsbTdAllocator.