]>
Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
2 | /* |
3 | * ISA DMA support functions | |
c1017a4c | 4 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
1da177e4 LT |
5 | */ |
6 | ||
7 | /* | |
8 | * Defining following add some delay. Maybe this helps for some broken | |
9 | * ISA DMA controllers. | |
10 | */ | |
11 | ||
12 | #undef HAVE_REALLY_SLOW_DMA_CONTROLLER | |
13 | ||
d81a6d71 | 14 | #include <linux/export.h> |
1da177e4 LT |
15 | #include <sound/core.h> |
16 | #include <asm/dma.h> | |
17 | ||
18 | /** | |
19 | * snd_dma_program - program an ISA DMA transfer | |
20 | * @dma: the dma number | |
21 | * @addr: the physical address of the buffer | |
22 | * @size: the DMA transfer size | |
23 | * @mode: the DMA transfer mode, DMA_MODE_XXX | |
24 | * | |
25 | * Programs an ISA DMA transfer for the given buffer. | |
26 | */ | |
27 | void snd_dma_program(unsigned long dma, | |
28 | unsigned long addr, unsigned int size, | |
29 | unsigned short mode) | |
30 | { | |
31 | unsigned long flags; | |
32 | ||
33 | flags = claim_dma_lock(); | |
34 | disable_dma(dma); | |
35 | clear_dma_ff(dma); | |
36 | set_dma_mode(dma, mode); | |
37 | set_dma_addr(dma, addr); | |
38 | set_dma_count(dma, size); | |
39 | if (!(mode & DMA_MODE_NO_ENABLE)) | |
40 | enable_dma(dma); | |
41 | release_dma_lock(flags); | |
42 | } | |
c0d3fb39 TI |
43 | EXPORT_SYMBOL(snd_dma_program); |
44 | ||
1da177e4 LT |
45 | /** |
46 | * snd_dma_disable - stop the ISA DMA transfer | |
47 | * @dma: the dma number | |
48 | * | |
49 | * Stops the ISA DMA transfer. | |
50 | */ | |
51 | void snd_dma_disable(unsigned long dma) | |
52 | { | |
53 | unsigned long flags; | |
54 | ||
55 | flags = claim_dma_lock(); | |
56 | clear_dma_ff(dma); | |
57 | disable_dma(dma); | |
58 | release_dma_lock(flags); | |
59 | } | |
c0d3fb39 TI |
60 | EXPORT_SYMBOL(snd_dma_disable); |
61 | ||
1da177e4 LT |
62 | /** |
63 | * snd_dma_pointer - return the current pointer to DMA transfer buffer in bytes | |
64 | * @dma: the dma number | |
65 | * @size: the dma transfer size | |
66 | * | |
eb7c06e8 | 67 | * Return: The current pointer in DMA transfer buffer in bytes. |
1da177e4 LT |
68 | */ |
69 | unsigned int snd_dma_pointer(unsigned long dma, unsigned int size) | |
70 | { | |
71 | unsigned long flags; | |
8066e51a | 72 | unsigned int result, result1; |
1da177e4 LT |
73 | |
74 | flags = claim_dma_lock(); | |
75 | clear_dma_ff(dma); | |
76 | if (!isa_dma_bridge_buggy) | |
77 | disable_dma(dma); | |
78 | result = get_dma_residue(dma); | |
8066e51a KH |
79 | /* |
80 | * HACK - read the counter again and choose higher value in order to | |
81 | * avoid reading during counter lower byte roll over if the | |
82 | * isa_dma_bridge_buggy is set. | |
83 | */ | |
84 | result1 = get_dma_residue(dma); | |
1da177e4 LT |
85 | if (!isa_dma_bridge_buggy) |
86 | enable_dma(dma); | |
87 | release_dma_lock(flags); | |
8066e51a KH |
88 | if (unlikely(result < result1)) |
89 | result = result1; | |
1da177e4 LT |
90 | #ifdef CONFIG_SND_DEBUG |
91 | if (result > size) | |
f2f9307a | 92 | pr_err("ALSA: pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size); |
1da177e4 LT |
93 | #endif |
94 | if (result >= size || result == 0) | |
95 | return 0; | |
96 | else | |
97 | return size - result; | |
98 | } | |
c0d3fb39 | 99 | EXPORT_SYMBOL(snd_dma_pointer); |
c2b94954 TI |
100 | |
101 | struct snd_dma_data { | |
102 | int dma; | |
103 | }; | |
104 | ||
105 | static void __snd_release_dma(struct device *dev, void *data) | |
106 | { | |
107 | struct snd_dma_data *p = data; | |
108 | ||
109 | snd_dma_disable(p->dma); | |
110 | free_dma(p->dma); | |
111 | } | |
112 | ||
113 | /** | |
114 | * snd_devm_request_dma - the managed version of request_dma() | |
115 | * @dev: the device pointer | |
116 | * @dma: the dma number | |
117 | * @name: the name string of the requester | |
118 | * | |
119 | * Returns zero on success, or a negative error code. | |
120 | * The requested DMA will be automatically released at unbinding via devres. | |
121 | */ | |
122 | int snd_devm_request_dma(struct device *dev, int dma, const char *name) | |
123 | { | |
124 | struct snd_dma_data *p; | |
125 | ||
126 | if (request_dma(dma, name)) | |
127 | return -EBUSY; | |
128 | p = devres_alloc(__snd_release_dma, sizeof(*p), GFP_KERNEL); | |
129 | if (!p) { | |
130 | free_dma(dma); | |
131 | return -ENOMEM; | |
132 | } | |
133 | p->dma = dma; | |
134 | devres_add(dev, p); | |
135 | return 0; | |
136 | } | |
137 | EXPORT_SYMBOL_GPL(snd_devm_request_dma); |