isadma.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * ISA DMA support functions
  4. * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  5. */
  6. /*
  7. * Defining following add some delay. Maybe this helps for some broken
  8. * ISA DMA controllers.
  9. */
  10. #undef HAVE_REALLY_SLOW_DMA_CONTROLLER
  11. #include <linux/export.h>
  12. #include <sound/core.h>
  13. #include <asm/dma.h>
  14. /**
  15. * snd_dma_program - program an ISA DMA transfer
  16. * @dma: the dma number
  17. * @addr: the physical address of the buffer
  18. * @size: the DMA transfer size
  19. * @mode: the DMA transfer mode, DMA_MODE_XXX
  20. *
  21. * Programs an ISA DMA transfer for the given buffer.
  22. */
  23. void snd_dma_program(unsigned long dma,
  24. unsigned long addr, unsigned int size,
  25. unsigned short mode)
  26. {
  27. unsigned long flags;
  28. flags = claim_dma_lock();
  29. disable_dma(dma);
  30. clear_dma_ff(dma);
  31. set_dma_mode(dma, mode);
  32. set_dma_addr(dma, addr);
  33. set_dma_count(dma, size);
  34. if (!(mode & DMA_MODE_NO_ENABLE))
  35. enable_dma(dma);
  36. release_dma_lock(flags);
  37. }
  38. EXPORT_SYMBOL(snd_dma_program);
  39. /**
  40. * snd_dma_disable - stop the ISA DMA transfer
  41. * @dma: the dma number
  42. *
  43. * Stops the ISA DMA transfer.
  44. */
  45. void snd_dma_disable(unsigned long dma)
  46. {
  47. unsigned long flags;
  48. flags = claim_dma_lock();
  49. clear_dma_ff(dma);
  50. disable_dma(dma);
  51. release_dma_lock(flags);
  52. }
  53. EXPORT_SYMBOL(snd_dma_disable);
  54. /**
  55. * snd_dma_pointer - return the current pointer to DMA transfer buffer in bytes
  56. * @dma: the dma number
  57. * @size: the dma transfer size
  58. *
  59. * Return: The current pointer in DMA transfer buffer in bytes.
  60. */
  61. unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
  62. {
  63. unsigned long flags;
  64. unsigned int result, result1;
  65. flags = claim_dma_lock();
  66. clear_dma_ff(dma);
  67. if (!isa_dma_bridge_buggy)
  68. disable_dma(dma);
  69. result = get_dma_residue(dma);
  70. /*
  71. * HACK - read the counter again and choose higher value in order to
  72. * avoid reading during counter lower byte roll over if the
  73. * isa_dma_bridge_buggy is set.
  74. */
  75. result1 = get_dma_residue(dma);
  76. if (!isa_dma_bridge_buggy)
  77. enable_dma(dma);
  78. release_dma_lock(flags);
  79. if (unlikely(result < result1))
  80. result = result1;
  81. #ifdef CONFIG_SND_DEBUG
  82. if (result > size)
  83. pr_err("ALSA: pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
  84. #endif
  85. if (result >= size || result == 0)
  86. return 0;
  87. else
  88. return size - result;
  89. }
  90. EXPORT_SYMBOL(snd_dma_pointer);