io.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * arch/parisc/lib/io.c
  3.  *
  4.  * Copyright (c) Matthew Wilcox 2001 for Hewlett-Packard
  5.  * Copyright (c) Randolph Chung 2001 <tausq@debian.org>
  6.  *
  7.  * IO accessing functions which shouldn't be inlined because they're too big
  8.  */
  9. #include <linux/kernel.h>
  10. #include <asm/io.h>
  11. /* Copies a block of memory to a device in an efficient manner.
  12.  * Assumes the device can cope with 32-bit transfers.  If it can't,
  13.  * don't use this function.
  14.  */
  15. void memcpy_toio(unsigned long dest, const void *src, int count)
  16. {
  17. if ((dest & 3) != ((unsigned long)src & 3))
  18. goto bytecopy;
  19. while (dest & 3) {
  20. writeb(*(char *)src, dest++);
  21. ((char *)src)++;
  22. count--;
  23. }
  24. while (count > 3) {
  25. __raw_writel(*(u32 *)src, dest);
  26. (unsigned long) src += 4;
  27. dest += 4;
  28. count -= 4;
  29. }
  30.  bytecopy:
  31. while (count--) {
  32. writeb(*(char *)src, dest++);
  33. ((char *)src)++;
  34. }
  35. }
  36. /*
  37. ** Copies a block of memory from a device in an efficient manner.
  38. ** Assumes the device can cope with 32-bit transfers.  If it can't,
  39. ** don't use this function.
  40. **
  41. ** CR16 counts on C3000 reading 256 bytes from Symbios 896 RAM:
  42. ** 27341/64    = 427 cyc per int
  43. ** 61311/128   = 478 cyc per short
  44. ** 122637/256  = 479 cyc per byte
  45. ** Ergo bus latencies dominant (not transfer size).
  46. **      Minimize total number of transfers at cost of CPU cycles.
  47. ** TODO: only look at src alignment and adjust the stores to dest.
  48. */
  49. void memcpy_fromio(void *dest, unsigned long src, int count)
  50. {
  51. /* first compare alignment of src/dst */ 
  52. if ( (((unsigned long)dest ^ src) & 1) || (count < 2) )
  53. goto bytecopy;
  54. if ( (((unsigned long)dest ^ src) & 2) || (count < 4) )
  55. goto shortcopy;
  56. /* Then check for misaligned start address */
  57. if (src & 1) {
  58. *(u8 *)dest = readb(src);
  59. ((u8 *)src)++;
  60. ((u8 *)dest)++;
  61. count--;
  62. if (count < 2) goto bytecopy;
  63. }
  64. if (src & 2) {
  65. *(u16 *)dest = __raw_readw(src);
  66. ((u16 *)src)++;
  67. ((u16 *)dest)++;
  68. count-=2;
  69. }
  70. while (count > 3) {
  71. *(u32 *)dest = __raw_readl(src);
  72. dest += 4;
  73. src += 4;
  74. count -= 4;
  75. }
  76.  shortcopy:
  77. while (count > 1) {
  78. *(u16 *)dest = __raw_readw(src);
  79. ((u16 *)src)++;
  80. ((u16 *)dest)++;
  81. count-=2;
  82. }
  83.  bytecopy:
  84. while (count--) {
  85. *(char *)dest = readb(src);
  86. ((char *)src)++;
  87. ((char *)dest)++;
  88. }
  89. }
  90. /* Sets a block of memory on a device to a given value.
  91.  * Assumes the device can cope with 32-bit transfers.  If it can't,
  92.  * don't use this function.
  93.  */
  94. void memset_io(unsigned long dest, char fill, int count)
  95. {
  96. u32 fill32 = (fill << 24) | (fill << 16) | (fill << 8) | fill;
  97. while (dest & 3) {
  98. writeb(fill, dest++);
  99. count--;
  100. }
  101. while (count > 3) {
  102. __raw_writel(fill32, dest);
  103. dest += 4;
  104. count -= 4;
  105. }
  106. while (count--) {
  107. writeb(fill, dest++);
  108. }
  109. }
  110. /*
  111.  * Read COUNT 8-bit bytes from port PORT into memory starting at
  112.  * SRC.
  113.  */
  114. void insb (unsigned long port, void *dst, unsigned long count)
  115. {
  116. while (((unsigned long)dst) & 0x3) {
  117. if (!count)
  118. return;
  119. count--;
  120. *(unsigned char *) dst = inb(port);
  121. ((unsigned char *) dst)++;
  122. }
  123. while (count >= 4) {
  124. unsigned int w;
  125. count -= 4;
  126. w = inb(port) << 24;
  127. w |= inb(port) << 16;
  128. w |= inb(port) << 8;
  129. w |= inb(port);
  130. *(unsigned int *) dst = w;
  131. ((unsigned int *) dst)++;
  132. }
  133. while (count) {
  134. --count;
  135. *(unsigned char *) dst = inb(port);
  136. ((unsigned char *) dst)++;
  137. }
  138. }
  139. /*
  140.  * Read COUNT 16-bit words from port PORT into memory starting at
  141.  * SRC.  SRC must be at least short aligned.  This is used by the
  142.  * IDE driver to read disk sectors.  Performance is important, but
  143.  * the interfaces seems to be slow: just using the inlined version
  144.  * of the inw() breaks things.
  145.  */
  146. void insw (unsigned long port, void *dst, unsigned long count)
  147. {
  148. unsigned int l = 0, l2;
  149. if (!count)
  150. return;
  151. switch (((unsigned long) dst) & 0x3)
  152. {
  153.  case 0x00: /* Buffer 32-bit aligned */
  154. while (count>=2) {
  155. count -= 2;
  156. l = cpu_to_le16(inw(port)) << 16;
  157. l |= cpu_to_le16(inw(port));
  158. *(unsigned int *) dst = l;
  159. ((unsigned int *) dst)++;
  160. }
  161. if (count) {
  162. *(unsigned short *) dst = cpu_to_le16(inw(port));
  163. }
  164. break;
  165.  case 0x02: /* Buffer 16-bit aligned */
  166. *(unsigned short *) dst = cpu_to_le16(inw(port));
  167. ((unsigned short *) dst)++;
  168. count--;
  169. while (count>=2) {
  170. count -= 2;
  171. l = cpu_to_le16(inw(port)) << 16;
  172. l |= cpu_to_le16(inw(port));
  173. *(unsigned int *) dst = l;
  174. ((unsigned int *) dst)++;
  175. }
  176. if (count) {
  177. *(unsigned short *) dst = cpu_to_le16(inw(port));
  178. }
  179. break;
  180.  case 0x01: /* Buffer 8-bit aligned */
  181.  case 0x03:
  182. /* I don't bother with 32bit transfers
  183.  * in this case, 16bit will have to do -- DE */
  184. --count;
  185. l = cpu_to_le16(inw(port));
  186. *(unsigned char *) dst = l >> 8;
  187. ((unsigned char *) dst)++;
  188. while (count--)
  189. {
  190. l2 = cpu_to_le16(inw(port));
  191. *(unsigned short *) dst = (l & 0xff) << 8 | (l2 >> 8);
  192. ((unsigned short *) dst)++;
  193. l = l2;
  194. }
  195. *(unsigned char *) dst = l & 0xff;
  196. break;
  197. }
  198. }
  199. /*
  200.  * Read COUNT 32-bit words from port PORT into memory starting at
  201.  * SRC. Now works with any alignment in SRC. Performance is important,
  202.  * but the interfaces seems to be slow: just using the inlined version
  203.  * of the inl() breaks things.
  204.  */
  205. void insl (unsigned long port, void *dst, unsigned long count)
  206. {
  207. unsigned int l = 0, l2;
  208. if (!count)
  209. return;
  210. switch (((unsigned long) dst) & 0x3)
  211. {
  212.  case 0x00: /* Buffer 32-bit aligned */
  213. while (count--)
  214. {
  215. *(unsigned int *) dst = cpu_to_le32(inl(port));
  216. ((unsigned int *) dst)++;
  217. }
  218. break;
  219.  case 0x02: /* Buffer 16-bit aligned */
  220. --count;
  221. l = cpu_to_le32(inl(port));
  222. *(unsigned short *) dst = l >> 16;
  223. ((unsigned short *) dst)++;
  224. while (count--)
  225. {
  226. l2 = cpu_to_le32(inl(port));
  227. *(unsigned int *) dst = (l & 0xffff) << 16 | (l2 >> 16);
  228. ((unsigned int *) dst)++;
  229. l = l2;
  230. }
  231. *(unsigned short *) dst = l & 0xffff;
  232. break;
  233.  case 0x01: /* Buffer 8-bit aligned */
  234. --count;
  235. l = cpu_to_le32(inl(port));
  236. *(unsigned char *) dst = l >> 24;
  237. ((unsigned char *) dst)++;
  238. *(unsigned short *) dst = (l >> 8) & 0xffff;
  239. ((unsigned short *) dst)++;
  240. while (count--)
  241. {
  242. l2 = cpu_to_le32(inl(port));
  243. *(unsigned int *) dst = (l & 0xff) << 24 | (l2 >> 8);
  244. ((unsigned int *) dst)++;
  245. l = l2;
  246. }
  247. *(unsigned char *) dst = l & 0xff;
  248. break;
  249.  case 0x03: /* Buffer 8-bit aligned */
  250. --count;
  251. l = cpu_to_le32(inl(port));
  252. *(unsigned char *) dst = l >> 24;
  253. ((unsigned char *) dst)++;
  254. while (count--)
  255. {
  256. l2 = cpu_to_le32(inl(port));
  257. *(unsigned int *) dst = (l & 0xffffff) << 8 | l2 >> 24;
  258. ((unsigned int *) dst)++;
  259. l = l2;
  260. }
  261. *(unsigned short *) dst = (l >> 8) & 0xffff;
  262. ((unsigned short *) dst)++;
  263. *(unsigned char *) dst = l & 0xff;
  264. break;
  265. }
  266. }
  267. /*
  268.  * Like insb but in the opposite direction.
  269.  * Don't worry as much about doing aligned memory transfers:
  270.  * doing byte reads the "slow" way isn't nearly as slow as
  271.  * doing byte writes the slow way (no r-m-w cycle).
  272.  */
  273. void outsb(unsigned long port, const void * src, unsigned long count)
  274. {
  275. while (count) {
  276. count--;
  277. outb(*(char *)src, port);
  278. ((char *) src)++;
  279. }
  280. }
  281. /*
  282.  * Like insw but in the opposite direction.  This is used by the IDE
  283.  * driver to write disk sectors.  Performance is important, but the
  284.  * interfaces seems to be slow: just using the inlined version of the
  285.  * outw() breaks things.
  286.  */
  287. void outsw (unsigned long port, const void *src, unsigned long count)
  288. {
  289. unsigned int l = 0, l2;
  290. if (!count)
  291. return;
  292. switch (((unsigned long) src) & 0x3)
  293. {
  294.  case 0x00: /* Buffer 32-bit aligned */
  295. while (count>=2) {
  296. count -= 2;
  297. l = *(unsigned int *) src;
  298. ((unsigned int *) src)++;
  299. outw(le16_to_cpu(l >> 16), port);
  300. outw(le16_to_cpu(l & 0xffff), port);
  301. }
  302. if (count) {
  303. outw(le16_to_cpu(*(unsigned short*)src), port);
  304. }
  305. break;
  306.  case 0x02: /* Buffer 16-bit aligned */
  307. outw(le16_to_cpu(*(unsigned short*)src), port);
  308. ((unsigned short *) src)++;
  309. count--;
  310. while (count>=2) {
  311. count -= 2;
  312. l = *(unsigned int *) src;
  313. ((unsigned int *) src)++;
  314. outw(le16_to_cpu(l >> 16), port);
  315. outw(le16_to_cpu(l & 0xffff), port);
  316. }
  317. if (count) {
  318. outw(le16_to_cpu(*(unsigned short*)src), port);
  319. }
  320. break;
  321.  case 0x01: /* Buffer 8-bit aligned */
  322. /* I don't bother with 32bit transfers
  323.  * in this case, 16bit will have to do -- DE */
  324. l  = *(unsigned char *) src << 8;
  325. ((unsigned char *) src)++;
  326. count--;
  327. while (count)
  328. {
  329. count--;
  330. l2 = *(unsigned short *) src;
  331. ((unsigned short *) src)++;
  332. outw(le16_to_cpu(l | l2 >> 8), port);
  333.         l = l2 << 8;
  334. }
  335. l2 = *(unsigned char *) src;
  336. outw (le16_to_cpu(l | l2>>8), port);
  337. break;
  338. }
  339. }
  340. /*
  341.  * Like insl but in the opposite direction.  This is used by the IDE
  342.  * driver to write disk sectors.  Works with any alignment in SRC.
  343.  *  Performance is important, but the interfaces seems to be slow:
  344.  * just using the inlined version of the outl() breaks things.
  345.  */
  346. void outsl (unsigned long port, const void *src, unsigned long count)
  347. {
  348. unsigned int l = 0, l2;
  349. if (!count)
  350. return;
  351. switch (((unsigned long) src) & 0x3)
  352. {
  353.  case 0x00: /* Buffer 32-bit aligned */
  354. while (count--)
  355. {
  356. outl(le32_to_cpu(*(unsigned int *) src), port);
  357. ((unsigned int *) src)++;
  358. }
  359. break;
  360.  case 0x02: /* Buffer 16-bit aligned */
  361. --count;
  362. l = *(unsigned short *) src;
  363. ((unsigned short *) src)++;
  364. while (count--)
  365. {
  366. l2 = *(unsigned int *) src;
  367. ((unsigned int *) src)++;
  368. outl (le32_to_cpu(l << 16 | l2 >> 16), port);
  369. l = l2;
  370. }
  371. l2 = *(unsigned short *) src;
  372. outl (le32_to_cpu(l << 16 | l2), port);
  373. break;
  374.  case 0x01: /* Buffer 8-bit aligned */
  375. --count;
  376. l  = *(unsigned char *) src << 24;
  377. ((unsigned char *) src)++;
  378. l |= *(unsigned short *) src << 8;
  379. ((unsigned short *) src)++;
  380. while (count--)
  381. {
  382. l2 = *(unsigned int *) src;
  383. ((unsigned int *) src)++;
  384. outl (le32_to_cpu(l | l2 >> 24), port);
  385. l = l2 << 8;
  386. }
  387. l2 = *(unsigned char *) src;
  388.       outl (le32_to_cpu(l | l2), port);
  389. break;
  390.  case 0x03: /* Buffer 8-bit aligned */
  391. --count;
  392. l  = *(unsigned char *) src << 24;
  393. ((unsigned char *) src)++;
  394. while (count--)
  395. {
  396. l2 = *(unsigned int *) src;
  397. ((unsigned int *) src)++;
  398. outl (le32_to_cpu(l | l2 >> 8), port);
  399. l = l2 << 24;
  400. }
  401. l2  = *(unsigned short *) src << 16;
  402. ((unsigned short *) src)++;
  403. l2 |= *(unsigned char *) src;
  404. outl (le32_to_cpu(l | l2), port);
  405. break;
  406. }
  407. }