Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pdaudiocf_irq.c
Go to the documentation of this file.
1 /*
2  * Driver for Sound Core PDAudioCF soundcard
3  *
4  * Copyright (c) 2003 by Jaroslav Kysela <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 #include <sound/core.h>
22 #include "pdaudiocf.h"
23 #include <sound/initval.h>
24 #include <asm/irq_regs.h>
25 
26 /*
27  *
28  */
30 {
31  struct snd_pdacf *chip = dev;
32  unsigned short stat;
33 
37  return IRQ_HANDLED; /* IRQ_NONE here? */
38 
39  stat = inw(chip->port + PDAUDIOCF_REG_ISR);
40  if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
41  if (stat & PDAUDIOCF_IRQOVR) /* should never happen */
42  snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
43  if (chip->pcm_substream)
44  tasklet_schedule(&chip->tq);
45  if (!(stat & PDAUDIOCF_IRQAKM))
46  stat |= PDAUDIOCF_IRQAKM; /* check rate */
47  }
48  if (get_irq_regs() != NULL)
50  return IRQ_HANDLED;
51 }
52 
53 static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
54 {
55  while (size-- > 0) {
56  *dst++ = inw(rdp_port) ^ xor;
57  inw(rdp_port);
58  }
59 }
60 
61 static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
62 {
63  register u16 val1, val2;
64 
65  while (size-- > 0) {
66  val1 = inw(rdp_port);
67  val2 = inw(rdp_port);
68  inw(rdp_port);
69  *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
70  }
71 }
72 
73 static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
74 {
75  while (size-- > 0) {
76  *dst++ = inw(rdp_port) ^ xor;
77  *dst++ = inw(rdp_port) ^ xor;
78  }
79 }
80 
81 static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
82 {
83  register u16 val1, val2, val3;
84 
85  while (size-- > 0) {
86  val1 = inw(rdp_port);
87  val2 = inw(rdp_port);
88  val3 = inw(rdp_port);
89  *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
90  *dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
91  }
92 }
93 
94 static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
95 {
96  while (size-- > 0) {
97  *dst++ = swab16(inw(rdp_port) ^ xor);
98  inw(rdp_port);
99  }
100 }
101 
102 static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
103 {
104  register u16 val1, val2;
105 
106  while (size-- > 0) {
107  val1 = inw(rdp_port);
108  val2 = inw(rdp_port);
109  inw(rdp_port);
110  *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
111  }
112 }
113 
114 static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
115 {
116  while (size-- > 0) {
117  *dst++ = swab16(inw(rdp_port) ^ xor);
118  *dst++ = swab16(inw(rdp_port) ^ xor);
119  }
120 }
121 
122 static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
123 {
124  register u16 val1, val2, val3;
125 
126  while (size-- > 0) {
127  val1 = inw(rdp_port);
128  val2 = inw(rdp_port);
129  val3 = inw(rdp_port);
130  *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
131  *dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);
132  }
133 }
134 
135 static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
136 {
137  register u16 val1, val2;
138  register u32 xval1;
139 
140  while (size-- > 0) {
141  val1 = inw(rdp_port);
142  val2 = inw(rdp_port);
143  inw(rdp_port);
144  xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
145  *dst++ = (u8)(xval1 >> 8);
146  *dst++ = (u8)(xval1 >> 16);
147  *dst++ = (u8)(xval1 >> 24);
148  }
149 }
150 
151 static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
152 {
153  register u16 val1, val2;
154  register u32 xval1;
155 
156  while (size-- > 0) {
157  val1 = inw(rdp_port);
158  val2 = inw(rdp_port);
159  inw(rdp_port);
160  xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
161  *dst++ = (u8)(xval1 >> 24);
162  *dst++ = (u8)(xval1 >> 16);
163  *dst++ = (u8)(xval1 >> 8);
164  }
165 }
166 
167 static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
168 {
169  register u16 val1, val2, val3;
170  register u32 xval1, xval2;
171 
172  while (size-- > 0) {
173  val1 = inw(rdp_port);
174  val2 = inw(rdp_port);
175  val3 = inw(rdp_port);
176  xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
177  xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
178  *dst++ = (u8)(xval1 >> 8);
179  *dst++ = (u8)(xval1 >> 16);
180  *dst++ = (u8)(xval1 >> 24);
181  *dst++ = (u8)(xval2 >> 8);
182  *dst++ = (u8)(xval2 >> 16);
183  *dst++ = (u8)(xval2 >> 24);
184  }
185 }
186 
187 static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
188 {
189  register u16 val1, val2, val3;
190  register u32 xval1, xval2;
191 
192  while (size-- > 0) {
193  val1 = inw(rdp_port);
194  val2 = inw(rdp_port);
195  val3 = inw(rdp_port);
196  xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
197  xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
198  *dst++ = (u8)(xval1 >> 24);
199  *dst++ = (u8)(xval1 >> 16);
200  *dst++ = (u8)(xval1 >> 8);
201  *dst++ = (u8)(xval2 >> 24);
202  *dst++ = (u8)(xval2 >> 16);
203  *dst++ = (u8)(xval2 >> 8);
204  }
205 }
206 
207 static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off)
208 {
209  unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
210  unsigned int xor = chip->pcm_xor;
211 
212  if (chip->pcm_sample == 3) {
213  if (chip->pcm_little) {
214  if (chip->pcm_channels == 1) {
215  pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
216  } else {
217  pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
218  }
219  } else {
220  if (chip->pcm_channels == 1) {
221  pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
222  } else {
223  pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
224  }
225  }
226  return;
227  }
228  if (chip->pcm_swab == 0) {
229  if (chip->pcm_channels == 1) {
230  if (chip->pcm_frame == 2) {
231  pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);
232  } else {
233  pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);
234  }
235  } else {
236  if (chip->pcm_frame == 2) {
237  pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
238  } else {
239  pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
240  }
241  }
242  } else {
243  if (chip->pcm_channels == 1) {
244  if (chip->pcm_frame == 2) {
245  pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);
246  } else {
247  pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);
248  }
249  } else {
250  if (chip->pcm_frame == 2) {
251  pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
252  } else {
253  pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
254  }
255  }
256  }
257 }
258 
259 void pdacf_tasklet(unsigned long private_data)
260 {
261  struct snd_pdacf *chip = (struct snd_pdacf *) private_data;
262  int size, off, cont, rdp, wdp;
263 
265  return;
266 
267  if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
268  return;
269 
270  rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
271  wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
272  /* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
273  size = wdp - rdp;
274  if (size < 0)
275  size += 0x10000;
276  if (size == 0)
277  size = 0x10000;
278  size /= chip->pcm_frame;
279  if (size > 64)
280  size -= 32;
281 
282 #if 0
283  chip->pcm_hwptr += size;
284  chip->pcm_hwptr %= chip->pcm_size;
285  chip->pcm_tdone += size;
286  if (chip->pcm_frame == 2) {
287  unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
288  while (size-- > 0) {
289  inw(rdp_port);
290  inw(rdp_port);
291  }
292  } else {
293  unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
294  while (size-- > 0) {
295  inw(rdp_port);
296  inw(rdp_port);
297  inw(rdp_port);
298  }
299  }
300 #else
301  off = chip->pcm_hwptr + chip->pcm_tdone;
302  off %= chip->pcm_size;
303  chip->pcm_tdone += size;
304  while (size > 0) {
305  cont = chip->pcm_size - off;
306  if (cont > size)
307  cont = size;
308  pdacf_transfer(chip, cont, off);
309  off += cont;
310  off %= chip->pcm_size;
311  size -= cont;
312  }
313 #endif
314  spin_lock(&chip->reg_lock);
315  while (chip->pcm_tdone >= chip->pcm_period) {
316  chip->pcm_hwptr += chip->pcm_period;
317  chip->pcm_hwptr %= chip->pcm_size;
318  chip->pcm_tdone -= chip->pcm_period;
319  spin_unlock(&chip->reg_lock);
321  spin_lock(&chip->reg_lock);
322  }
323  spin_unlock(&chip->reg_lock);
324  /* printk(KERN_DEBUG "TASKLET: end\n"); */
325 }