dma.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #include "u.h"
  2. #include "lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. typedef struct DMAport DMAport;
  7. typedef struct DMA DMA;
  8. typedef struct DMAxfer DMAxfer;
  9. enum
  10. {
  11. /*
  12. * the byte registers for DMA0 are all one byte apart
  13. */
  14. Dma0= 0x00,
  15. Dma0status= Dma0+0x8, /* status port */
  16. Dma0reset= Dma0+0xD, /* reset port */
  17. /*
  18. * the byte registers for DMA1 are all two bytes apart (why?)
  19. */
  20. Dma1= 0xC0,
  21. Dma1status= Dma1+2*0x8, /* status port */
  22. Dma1reset= Dma1+2*0xD, /* reset port */
  23. };
  24. /*
  25. * state of a dma transfer
  26. */
  27. struct DMAxfer
  28. {
  29. ulong bpa; /* bounce buffer physical address */
  30. void* bva; /* bounce buffer virtual address */
  31. void* va; /* virtual address destination/src */
  32. long len; /* bytes to be transferred */
  33. int isread;
  34. };
  35. /*
  36. * the dma controllers. the first half of this structure specifies
  37. * the I/O ports used by the DMA controllers.
  38. */
  39. struct DMAport
  40. {
  41. uchar addr[4]; /* current address (4 channels) */
  42. uchar count[4]; /* current count (4 channels) */
  43. uchar page[4]; /* page registers (4 channels) */
  44. uchar cmd; /* command status register */
  45. uchar req; /* request registers */
  46. uchar sbm; /* single bit mask register */
  47. uchar mode; /* mode register */
  48. uchar cbp; /* clear byte pointer */
  49. uchar mc; /* master clear */
  50. uchar cmask; /* clear mask register */
  51. uchar wam; /* write all mask register bit */
  52. };
  53. struct DMA
  54. {
  55. DMAport;
  56. int shift;
  57. Lock;
  58. DMAxfer x[4];
  59. };
  60. DMA dma[2] = {
  61. { 0x00, 0x02, 0x04, 0x06,
  62. 0x01, 0x03, 0x05, 0x07,
  63. 0x87, 0x83, 0x81, 0x82,
  64. 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
  65. 0 },
  66. { 0xc0, 0xc4, 0xc8, 0xcc,
  67. 0xc2, 0xc6, 0xca, 0xce,
  68. 0x8f, 0x8b, 0x89, 0x8a,
  69. 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
  70. 1 },
  71. };
  72. /*
  73. * DMA must be in the first 16MB. This gets called early by the
  74. * initialisation routines of any devices which require DMA to ensure
  75. * the allocated bounce buffers are below the 16MB limit.
  76. */
  77. void
  78. dmainit(int chan)
  79. {
  80. DMA *dp;
  81. DMAxfer *xp;
  82. ulong v;
  83. static int once;
  84. if(once == 0){
  85. // if(ioalloc(0x00, 0x10, 0, "dma") < 0
  86. // || ioalloc(0x80, 0x10, 0, "dma") < 0
  87. // || ioalloc(0xd0, 0x10, 0, "dma") < 0)
  88. // panic("dmainit");
  89. outb(dma[0].mc, 0);
  90. outb(dma[1].mc, 0);
  91. outb(dma[0].cmask, 0);
  92. outb(dma[1].cmask, 0);
  93. outb(dma[1].mode, 0xC0);
  94. once = 1;
  95. }
  96. dp = &dma[(chan>>2)&1];
  97. chan = chan & 3;
  98. xp = &dp->x[chan];
  99. if(xp->bva != nil)
  100. return;
  101. v = (ulong)xalloc(BY2PG+BY2PG);
  102. if(v == 0 || PADDR(v) >= 16*MB){
  103. print("dmainit: chan %d: 0x%luX out of range\n", chan, v);
  104. xfree((void*)v);
  105. v = 0;
  106. }
  107. xp->bva = (void*)ROUND(v, BY2PG);
  108. xp->bpa = PADDR(xp->bva);
  109. xp->len = 0;
  110. xp->isread = 0;
  111. }
  112. /*
  113. * setup a dma transfer. if the destination is not in kernel
  114. * memory, allocate a page for the transfer.
  115. *
  116. * we assume BIOS has set up the command register before we
  117. * are booted.
  118. *
  119. * return the updated transfer length (we can't transfer across 64k
  120. * boundaries)
  121. */
  122. long
  123. dmasetup(int chan, void *va, long len, int isread)
  124. {
  125. DMA *dp;
  126. ulong pa;
  127. uchar mode;
  128. DMAxfer *xp;
  129. dp = &dma[(chan>>2)&1];
  130. chan = chan & 3;
  131. xp = &dp->x[chan];
  132. /*
  133. * if this isn't kernel memory or crossing 64k boundary or above 16 meg
  134. * use the allocated low memory page.
  135. */
  136. pa = PADDR(va);
  137. if((((ulong)va)&0xF0000000) != KZERO
  138. || (pa&0xFFFF0000) != ((pa+len)&0xFFFF0000)
  139. || pa > 16*MB) {
  140. if(xp->bva == nil)
  141. return -1;
  142. if(len > BY2PG)
  143. len = BY2PG;
  144. if(!isread)
  145. memmove(xp->bva, va, len);
  146. xp->va = va;
  147. xp->len = len;
  148. xp->isread = isread;
  149. pa = xp->bpa;
  150. }
  151. else
  152. xp->len = 0;
  153. /*
  154. * this setup must be atomic
  155. */
  156. ilock(dp);
  157. mode = (isread ? 0x44 : 0x48) | chan;
  158. outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */
  159. outb(dp->page[chan], pa>>16);
  160. outb(dp->cbp, 0); /* set count & address to their first byte */
  161. outb(dp->addr[chan], pa>>dp->shift); /* set address */
  162. outb(dp->addr[chan], pa>>(8+dp->shift));
  163. outb(dp->count[chan], (len>>dp->shift)-1); /* set count */
  164. outb(dp->count[chan], ((len>>dp->shift)-1)>>8);
  165. outb(dp->sbm, chan); /* enable the channel */
  166. iunlock(dp);
  167. return len;
  168. }
  169. int
  170. dmadone(int chan)
  171. {
  172. DMA *dp;
  173. dp = &dma[(chan>>2)&1];
  174. chan = chan & 3;
  175. return inb(dp->cmd) & (1<<chan);
  176. }
  177. /*
  178. * this must be called after a dma has been completed.
  179. *
  180. * if a page has been allocated for the dma,
  181. * copy the data into the actual destination
  182. * and free the page.
  183. */
  184. void
  185. dmaend(int chan)
  186. {
  187. DMA *dp;
  188. DMAxfer *xp;
  189. dp = &dma[(chan>>2)&1];
  190. chan = chan & 3;
  191. /*
  192. * disable the channel
  193. */
  194. ilock(dp);
  195. outb(dp->sbm, 4|chan);
  196. iunlock(dp);
  197. xp = &dp->x[chan];
  198. if(xp->len == 0 || !xp->isread)
  199. return;
  200. /*
  201. * copy out of temporary page
  202. */
  203. memmove(xp->va, xp->bva, xp->len);
  204. xp->len = 0;
  205. }
  206. /*
  207. int
  208. dmacount(int chan)
  209. {
  210. int retval;
  211. DMA *dp;
  212. dp = &dma[(chan>>2)&1];
  213. outb(dp->cbp, 0);
  214. retval = inb(dp->count[chan]);
  215. retval |= inb(dp->count[chan]) << 8;
  216. return((retval<<dp->shift)+1);
  217. }
  218. */