diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/oss/harmony.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/oss/harmony.c')
-rw-r--r-- | sound/oss/harmony.c | 1330 |
1 files changed, 1330 insertions, 0 deletions
diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c new file mode 100644 index 000000000000..bee9d344cd26 --- /dev/null +++ b/sound/oss/harmony.c | |||
@@ -0,0 +1,1330 @@ | |||
1 | /* | ||
2 | drivers/sound/harmony.c | ||
3 | |||
4 | This is a sound driver for ASP's and Lasi's Harmony sound chip | ||
5 | and is unlikely to be used for anything other than on a HP PA-RISC. | ||
6 | |||
7 | Harmony is found in HP 712s, 715/new and many other GSC based machines. | ||
8 | On older 715 machines you'll find the technically identical chip | ||
9 | called 'Vivace'. Both Harmony and Vicace are supported by this driver. | ||
10 | |||
11 | Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex@onefishtwo.ca> | ||
12 | Copyright 2000-2003 (c) Helge Deller <deller@gmx.de> | ||
13 | Copyright 2001 (c) Matthieu Delahaye <delahaym@esiee.fr> | ||
14 | Copyright 2001 (c) Jean-Christophe Vaugeois <vaugeoij@esiee.fr> | ||
15 | Copyright 2004 (c) Stuart Brady <sdbrady@ntlworld.com> | ||
16 | |||
17 | |||
18 | TODO: | ||
19 | - fix SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls to | ||
20 | return the real values | ||
21 | - add private ioctl for selecting line- or microphone input | ||
22 | (only one of them is available at the same time) | ||
23 | - add module parameters | ||
24 | - implement mmap functionality | ||
25 | - implement gain meter ? | ||
26 | - ... | ||
27 | */ | ||
28 | |||
29 | #include <linux/delay.h> | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/ioport.h> | ||
34 | #include <linux/types.h> | ||
35 | #include <linux/mm.h> | ||
36 | #include <linux/pci.h> | ||
37 | |||
38 | #include <asm/parisc-device.h> | ||
39 | #include <asm/io.h> | ||
40 | |||
41 | #include "sound_config.h" | ||
42 | |||
43 | |||
44 | #define PFX "harmony: " | ||
45 | #define HARMONY_VERSION "V0.9a" | ||
46 | |||
47 | #undef DEBUG | ||
48 | #ifdef DEBUG | ||
49 | # define DPRINTK printk | ||
50 | #else | ||
51 | # define DPRINTK(x,...) | ||
52 | #endif | ||
53 | |||
54 | |||
55 | #define MAX_BUFS 10 /* maximum number of rotating buffers */ | ||
56 | #define HARMONY_BUF_SIZE 4096 /* needs to be a multiple of PAGE_SIZE (4096)! */ | ||
57 | |||
58 | #define CNTL_C 0x80000000 | ||
59 | #define CNTL_ST 0x00000020 | ||
60 | #define CNTL_44100 0x00000015 /* HARMONY_SR_44KHZ */ | ||
61 | #define CNTL_8000 0x00000008 /* HARMONY_SR_8KHZ */ | ||
62 | |||
63 | #define GAINCTL_HE 0x08000000 | ||
64 | #define GAINCTL_LE 0x04000000 | ||
65 | #define GAINCTL_SE 0x02000000 | ||
66 | |||
67 | #define DSTATUS_PN 0x00000200 | ||
68 | #define DSTATUS_RN 0x00000002 | ||
69 | |||
70 | #define DSTATUS_IE 0x80000000 | ||
71 | |||
72 | #define HARMONY_DF_16BIT_LINEAR 0 | ||
73 | #define HARMONY_DF_8BIT_ULAW 1 | ||
74 | #define HARMONY_DF_8BIT_ALAW 2 | ||
75 | |||
76 | #define HARMONY_SS_MONO 0 | ||
77 | #define HARMONY_SS_STEREO 1 | ||
78 | |||
79 | #define HARMONY_SR_8KHZ 0x08 | ||
80 | #define HARMONY_SR_16KHZ 0x09 | ||
81 | #define HARMONY_SR_27KHZ 0x0A | ||
82 | #define HARMONY_SR_32KHZ 0x0B | ||
83 | #define HARMONY_SR_48KHZ 0x0E | ||
84 | #define HARMONY_SR_9KHZ 0x0F | ||
85 | #define HARMONY_SR_5KHZ 0x10 | ||
86 | #define HARMONY_SR_11KHZ 0x11 | ||
87 | #define HARMONY_SR_18KHZ 0x12 | ||
88 | #define HARMONY_SR_22KHZ 0x13 | ||
89 | #define HARMONY_SR_37KHZ 0x14 | ||
90 | #define HARMONY_SR_44KHZ 0x15 | ||
91 | #define HARMONY_SR_33KHZ 0x16 | ||
92 | #define HARMONY_SR_6KHZ 0x17 | ||
93 | |||
94 | /* | ||
95 | * Some magics numbers used to auto-detect file formats | ||
96 | */ | ||
97 | |||
98 | #define HARMONY_MAGIC_8B_ULAW 1 | ||
99 | #define HARMONY_MAGIC_8B_ALAW 27 | ||
100 | #define HARMONY_MAGIC_16B_LINEAR 3 | ||
101 | #define HARMONY_MAGIC_MONO 1 | ||
102 | #define HARMONY_MAGIC_STEREO 2 | ||
103 | |||
104 | /* | ||
105 | * Channels Positions in mixer register | ||
106 | */ | ||
107 | |||
108 | #define GAIN_HE_SHIFT 27 | ||
109 | #define GAIN_HE_MASK ( 1 << GAIN_HE_SHIFT) | ||
110 | #define GAIN_LE_SHIFT 26 | ||
111 | #define GAIN_LE_MASK ( 1 << GAIN_LE_SHIFT) | ||
112 | #define GAIN_SE_SHIFT 25 | ||
113 | #define GAIN_SE_MASK ( 1 << GAIN_SE_SHIFT) | ||
114 | #define GAIN_IS_SHIFT 24 | ||
115 | #define GAIN_IS_MASK ( 1 << GAIN_IS_SHIFT) | ||
116 | #define GAIN_MA_SHIFT 20 | ||
117 | #define GAIN_MA_MASK ( 0x0f << GAIN_MA_SHIFT) | ||
118 | #define GAIN_LI_SHIFT 16 | ||
119 | #define GAIN_LI_MASK ( 0x0f << GAIN_LI_SHIFT) | ||
120 | #define GAIN_RI_SHIFT 12 | ||
121 | #define GAIN_RI_MASK ( 0x0f << GAIN_RI_SHIFT) | ||
122 | #define GAIN_LO_SHIFT 6 | ||
123 | #define GAIN_LO_MASK ( 0x3f << GAIN_LO_SHIFT) | ||
124 | #define GAIN_RO_SHIFT 0 | ||
125 | #define GAIN_RO_MASK ( 0x3f << GAIN_RO_SHIFT) | ||
126 | |||
127 | |||
128 | #define MAX_OUTPUT_LEVEL (GAIN_RO_MASK >> GAIN_RO_SHIFT) | ||
129 | #define MAX_INPUT_LEVEL (GAIN_RI_MASK >> GAIN_RI_SHIFT) | ||
130 | #define MAX_MONITOR_LEVEL (GAIN_MA_MASK >> GAIN_MA_SHIFT) | ||
131 | |||
132 | #define MIXER_INTERNAL SOUND_MIXER_LINE1 | ||
133 | #define MIXER_LINEOUT SOUND_MIXER_LINE2 | ||
134 | #define MIXER_HEADPHONES SOUND_MIXER_LINE3 | ||
135 | |||
136 | #define MASK_INTERNAL SOUND_MASK_LINE1 | ||
137 | #define MASK_LINEOUT SOUND_MASK_LINE2 | ||
138 | #define MASK_HEADPHONES SOUND_MASK_LINE3 | ||
139 | |||
140 | /* | ||
141 | * Channels Mask in mixer register | ||
142 | */ | ||
143 | |||
144 | #define GAIN_TOTAL_SILENCE 0x00F00FFF | ||
145 | #define GAIN_DEFAULT 0x0FF00000 | ||
146 | |||
147 | |||
148 | struct harmony_hpa { | ||
149 | u8 unused000; | ||
150 | u8 id; | ||
151 | u8 teleshare_id; | ||
152 | u8 unused003; | ||
153 | u32 reset; | ||
154 | u32 cntl; | ||
155 | u32 gainctl; | ||
156 | u32 pnxtadd; | ||
157 | u32 pcuradd; | ||
158 | u32 rnxtadd; | ||
159 | u32 rcuradd; | ||
160 | u32 dstatus; | ||
161 | u32 ov; | ||
162 | u32 pio; | ||
163 | u32 unused02c; | ||
164 | u32 unused030[3]; | ||
165 | u32 diag; | ||
166 | }; | ||
167 | |||
168 | struct harmony_dev { | ||
169 | struct harmony_hpa *hpa; | ||
170 | struct parisc_device *dev; | ||
171 | u32 current_gain; | ||
172 | u32 dac_rate; /* 8000 ... 48000 (Hz) */ | ||
173 | u8 data_format; /* HARMONY_DF_xx_BIT_xxx */ | ||
174 | u8 sample_rate; /* HARMONY_SR_xx_KHZ */ | ||
175 | u8 stereo_select; /* HARMONY_SS_MONO or HARMONY_SS_STEREO */ | ||
176 | int format_initialized :1; | ||
177 | int suspended_playing :1; | ||
178 | int suspended_recording :1; | ||
179 | |||
180 | int blocked_playing :1; | ||
181 | int blocked_recording :1; | ||
182 | int audio_open :1; | ||
183 | int mixer_open :1; | ||
184 | |||
185 | wait_queue_head_t wq_play, wq_record; | ||
186 | int first_filled_play; /* first buffer containing data (next to play) */ | ||
187 | int nb_filled_play; | ||
188 | int play_offset; | ||
189 | int first_filled_record; | ||
190 | int nb_filled_record; | ||
191 | |||
192 | int dsp_unit, mixer_unit; | ||
193 | }; | ||
194 | |||
195 | |||
196 | static struct harmony_dev harmony; | ||
197 | |||
198 | |||
199 | /* | ||
200 | * Dynamic sound buffer allocation and DMA memory | ||
201 | */ | ||
202 | |||
203 | struct harmony_buffer { | ||
204 | unsigned char *addr; | ||
205 | dma_addr_t dma_handle; | ||
206 | int dma_coherent; /* Zero if dma_alloc_coherent() fails */ | ||
207 | unsigned int len; | ||
208 | }; | ||
209 | |||
210 | /* | ||
211 | * Harmony memory buffers | ||
212 | */ | ||
213 | |||
214 | static struct harmony_buffer played_buf, recorded_buf, silent, graveyard; | ||
215 | |||
216 | |||
217 | #define CHECK_WBACK_INV_OFFSET(b,offset,len) \ | ||
218 | do { if (!b.dma_coherent) \ | ||
219 | dma_cache_wback_inv((unsigned long)b.addr+offset,len); \ | ||
220 | } while (0) | ||
221 | |||
222 | |||
223 | static int __init harmony_alloc_buffer(struct harmony_buffer *b, | ||
224 | unsigned int buffer_count) | ||
225 | { | ||
226 | b->len = buffer_count * HARMONY_BUF_SIZE; | ||
227 | b->addr = dma_alloc_coherent(&harmony.dev->dev, | ||
228 | b->len, &b->dma_handle, GFP_KERNEL|GFP_DMA); | ||
229 | if (b->addr && b->dma_handle) { | ||
230 | b->dma_coherent = 1; | ||
231 | DPRINTK(KERN_INFO PFX "coherent memory: 0x%lx, played_buf: 0x%lx\n", | ||
232 | (unsigned long)b->dma_handle, (unsigned long)b->addr); | ||
233 | } else { | ||
234 | b->dma_coherent = 0; | ||
235 | /* kmalloc()ed memory will HPMC on ccio machines ! */ | ||
236 | b->addr = kmalloc(b->len, GFP_KERNEL); | ||
237 | if (!b->addr) { | ||
238 | printk(KERN_ERR PFX "couldn't allocate memory\n"); | ||
239 | return -EBUSY; | ||
240 | } | ||
241 | b->dma_handle = __pa(b->addr); | ||
242 | } | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static void __exit harmony_free_buffer(struct harmony_buffer *b) | ||
247 | { | ||
248 | if (!b->addr) | ||
249 | return; | ||
250 | |||
251 | if (b->dma_coherent) | ||
252 | dma_free_coherent(&harmony.dev->dev, | ||
253 | b->len, b->addr, b->dma_handle); | ||
254 | else | ||
255 | kfree(b->addr); | ||
256 | |||
257 | memset(b, 0, sizeof(*b)); | ||
258 | } | ||
259 | |||
260 | |||
261 | |||
262 | /* | ||
263 | * Low-Level sound-chip programming | ||
264 | */ | ||
265 | |||
266 | static void __inline__ harmony_wait_CNTL(void) | ||
267 | { | ||
268 | /* Wait until we're out of control mode */ | ||
269 | while (gsc_readl(&harmony.hpa->cntl) & CNTL_C) | ||
270 | /* wait */ ; | ||
271 | } | ||
272 | |||
273 | |||
274 | static void harmony_update_control(void) | ||
275 | { | ||
276 | u32 default_cntl; | ||
277 | |||
278 | /* Set CNTL */ | ||
279 | default_cntl = (CNTL_C | /* The C bit */ | ||
280 | (harmony.data_format << 6) | /* Set the data format */ | ||
281 | (harmony.stereo_select << 5) | /* Stereo select */ | ||
282 | (harmony.sample_rate)); /* Set sample rate */ | ||
283 | harmony.format_initialized = 1; | ||
284 | |||
285 | /* initialize CNTL */ | ||
286 | gsc_writel(default_cntl, &harmony.hpa->cntl); | ||
287 | } | ||
288 | |||
289 | static void harmony_set_control(u8 data_format, u8 sample_rate, u8 stereo_select) | ||
290 | { | ||
291 | harmony.sample_rate = sample_rate; | ||
292 | harmony.data_format = data_format; | ||
293 | harmony.stereo_select = stereo_select; | ||
294 | harmony_update_control(); | ||
295 | } | ||
296 | |||
297 | static void harmony_set_rate(u8 data_rate) | ||
298 | { | ||
299 | harmony.sample_rate = data_rate; | ||
300 | harmony_update_control(); | ||
301 | } | ||
302 | |||
303 | static int harmony_detect_rate(int *freq) | ||
304 | { | ||
305 | int newrate; | ||
306 | switch (*freq) { | ||
307 | case 8000: newrate = HARMONY_SR_8KHZ; break; | ||
308 | case 16000: newrate = HARMONY_SR_16KHZ; break; | ||
309 | case 27428: newrate = HARMONY_SR_27KHZ; break; | ||
310 | case 32000: newrate = HARMONY_SR_32KHZ; break; | ||
311 | case 48000: newrate = HARMONY_SR_48KHZ; break; | ||
312 | case 9600: newrate = HARMONY_SR_9KHZ; break; | ||
313 | case 5512: newrate = HARMONY_SR_5KHZ; break; | ||
314 | case 11025: newrate = HARMONY_SR_11KHZ; break; | ||
315 | case 18900: newrate = HARMONY_SR_18KHZ; break; | ||
316 | case 22050: newrate = HARMONY_SR_22KHZ; break; | ||
317 | case 37800: newrate = HARMONY_SR_37KHZ; break; | ||
318 | case 44100: newrate = HARMONY_SR_44KHZ; break; | ||
319 | case 33075: newrate = HARMONY_SR_33KHZ; break; | ||
320 | case 6615: newrate = HARMONY_SR_6KHZ; break; | ||
321 | default: newrate = HARMONY_SR_8KHZ; | ||
322 | *freq = 8000; break; | ||
323 | } | ||
324 | return newrate; | ||
325 | } | ||
326 | |||
327 | static void harmony_set_format(u8 data_format) | ||
328 | { | ||
329 | harmony.data_format = data_format; | ||
330 | harmony_update_control(); | ||
331 | } | ||
332 | |||
333 | static void harmony_set_stereo(u8 stereo_select) | ||
334 | { | ||
335 | harmony.stereo_select = stereo_select; | ||
336 | harmony_update_control(); | ||
337 | } | ||
338 | |||
339 | static void harmony_disable_interrupts(void) | ||
340 | { | ||
341 | harmony_wait_CNTL(); | ||
342 | gsc_writel(0, &harmony.hpa->dstatus); | ||
343 | } | ||
344 | |||
345 | static void harmony_enable_interrupts(void) | ||
346 | { | ||
347 | harmony_wait_CNTL(); | ||
348 | gsc_writel(DSTATUS_IE, &harmony.hpa->dstatus); | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * harmony_silence() | ||
353 | * | ||
354 | * This subroutine fills in a buffer starting at location start and | ||
355 | * silences for length bytes. This references the current | ||
356 | * configuration of the audio format. | ||
357 | * | ||
358 | */ | ||
359 | |||
360 | static void harmony_silence(struct harmony_buffer *buffer, int start, int length) | ||
361 | { | ||
362 | u8 silence_char; | ||
363 | |||
364 | /* Despite what you hear, silence is different in | ||
365 | different audio formats. */ | ||
366 | switch (harmony.data_format) { | ||
367 | case HARMONY_DF_8BIT_ULAW: silence_char = 0x55; break; | ||
368 | case HARMONY_DF_8BIT_ALAW: silence_char = 0xff; break; | ||
369 | case HARMONY_DF_16BIT_LINEAR: /* fall through */ | ||
370 | default: silence_char = 0; | ||
371 | } | ||
372 | |||
373 | memset(buffer->addr+start, silence_char, length); | ||
374 | } | ||
375 | |||
376 | |||
377 | static int harmony_audio_open(struct inode *inode, struct file *file) | ||
378 | { | ||
379 | if (harmony.audio_open) | ||
380 | return -EBUSY; | ||
381 | |||
382 | harmony.audio_open = 1; | ||
383 | harmony.suspended_playing = harmony.suspended_recording = 1; | ||
384 | harmony.blocked_playing = harmony.blocked_recording = 0; | ||
385 | harmony.first_filled_play = harmony.first_filled_record = 0; | ||
386 | harmony.nb_filled_play = harmony.nb_filled_record = 0; | ||
387 | harmony.play_offset = 0; | ||
388 | init_waitqueue_head(&harmony.wq_play); | ||
389 | init_waitqueue_head(&harmony.wq_record); | ||
390 | |||
391 | /* Start off in a balanced mode. */ | ||
392 | harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO); | ||
393 | harmony_update_control(); | ||
394 | harmony.format_initialized = 0; | ||
395 | |||
396 | /* Clear out all the buffers and flush to cache */ | ||
397 | harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); | ||
398 | CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Release (close) the audio device. | ||
405 | */ | ||
406 | |||
407 | static int harmony_audio_release(struct inode *inode, struct file *file) | ||
408 | { | ||
409 | if (!harmony.audio_open) | ||
410 | return -EBUSY; | ||
411 | |||
412 | harmony.audio_open = 0; | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * Read recorded data off the audio device. | ||
419 | */ | ||
420 | |||
421 | static ssize_t harmony_audio_read(struct file *file, | ||
422 | char *buffer, | ||
423 | size_t size_count, | ||
424 | loff_t *ppos) | ||
425 | { | ||
426 | int total_count = (int) size_count; | ||
427 | int count = 0; | ||
428 | int buf_to_read; | ||
429 | |||
430 | while (count<total_count) { | ||
431 | /* Wait until we're out of control mode */ | ||
432 | harmony_wait_CNTL(); | ||
433 | |||
434 | /* Figure out which buffer to fill in */ | ||
435 | if (harmony.nb_filled_record <= 2) { | ||
436 | harmony.blocked_recording = 1; | ||
437 | if (harmony.suspended_recording) { | ||
438 | harmony.suspended_recording = 0; | ||
439 | harmony_enable_interrupts(); | ||
440 | } | ||
441 | |||
442 | interruptible_sleep_on(&harmony.wq_record); | ||
443 | harmony.blocked_recording = 0; | ||
444 | } | ||
445 | |||
446 | if (harmony.nb_filled_record < 2) | ||
447 | return -EBUSY; | ||
448 | |||
449 | buf_to_read = harmony.first_filled_record; | ||
450 | |||
451 | /* Copy the page to an aligned buffer */ | ||
452 | if (copy_to_user(buffer+count, recorded_buf.addr + | ||
453 | (HARMONY_BUF_SIZE*buf_to_read), | ||
454 | HARMONY_BUF_SIZE)) { | ||
455 | count = -EFAULT; | ||
456 | break; | ||
457 | } | ||
458 | |||
459 | harmony.nb_filled_record--; | ||
460 | harmony.first_filled_record++; | ||
461 | harmony.first_filled_record %= MAX_BUFS; | ||
462 | |||
463 | count += HARMONY_BUF_SIZE; | ||
464 | } | ||
465 | return count; | ||
466 | } | ||
467 | |||
468 | |||
469 | |||
470 | |||
471 | /* | ||
472 | * Here is the place where we try to recognize file format. | ||
473 | * Sun/NeXT .au files begin with the string .snd | ||
474 | * At offset 12 is specified the encoding. | ||
475 | * At offset 16 is specified speed rate | ||
476 | * At Offset 20 is specified the numbers of voices | ||
477 | */ | ||
478 | |||
479 | #define four_bytes_to_u32(start) (file_header[start] << 24)|\ | ||
480 | (file_header[start+1] << 16)|\ | ||
481 | (file_header[start+2] << 8)|\ | ||
482 | (file_header[start+3]); | ||
483 | |||
484 | #define test_rate(tested,real_value,harmony_value) if ((tested)<=(real_value))\ | ||
485 | |||
486 | |||
487 | static int harmony_format_auto_detect(const char *buffer, int block_size) | ||
488 | { | ||
489 | u8 file_header[24]; | ||
490 | u32 start_string; | ||
491 | int ret = 0; | ||
492 | |||
493 | if (block_size>24) { | ||
494 | if (copy_from_user(file_header, buffer, sizeof(file_header))) | ||
495 | ret = -EFAULT; | ||
496 | |||
497 | start_string = four_bytes_to_u32(0); | ||
498 | |||
499 | if ((file_header[4]==0) && (start_string==0x2E736E64)) { | ||
500 | u32 format; | ||
501 | u32 nb_voices; | ||
502 | u32 speed; | ||
503 | |||
504 | format = four_bytes_to_u32(12); | ||
505 | nb_voices = four_bytes_to_u32(20); | ||
506 | speed = four_bytes_to_u32(16); | ||
507 | |||
508 | switch (format) { | ||
509 | case HARMONY_MAGIC_8B_ULAW: | ||
510 | harmony.data_format = HARMONY_DF_8BIT_ULAW; | ||
511 | break; | ||
512 | case HARMONY_MAGIC_8B_ALAW: | ||
513 | harmony.data_format = HARMONY_DF_8BIT_ALAW; | ||
514 | break; | ||
515 | case HARMONY_MAGIC_16B_LINEAR: | ||
516 | harmony.data_format = HARMONY_DF_16BIT_LINEAR; | ||
517 | break; | ||
518 | default: | ||
519 | harmony_set_control(HARMONY_DF_16BIT_LINEAR, | ||
520 | HARMONY_SR_44KHZ, HARMONY_SS_STEREO); | ||
521 | goto out; | ||
522 | } | ||
523 | switch (nb_voices) { | ||
524 | case HARMONY_MAGIC_MONO: | ||
525 | harmony.stereo_select = HARMONY_SS_MONO; | ||
526 | break; | ||
527 | case HARMONY_MAGIC_STEREO: | ||
528 | harmony.stereo_select = HARMONY_SS_STEREO; | ||
529 | break; | ||
530 | default: | ||
531 | harmony.stereo_select = HARMONY_SS_MONO; | ||
532 | break; | ||
533 | } | ||
534 | harmony_set_rate(harmony_detect_rate(&speed)); | ||
535 | harmony.dac_rate = speed; | ||
536 | goto out; | ||
537 | } | ||
538 | } | ||
539 | harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO); | ||
540 | out: | ||
541 | return ret; | ||
542 | } | ||
543 | #undef four_bytes_to_u32 | ||
544 | |||
545 | |||
546 | static ssize_t harmony_audio_write(struct file *file, | ||
547 | const char *buffer, | ||
548 | size_t size_count, | ||
549 | loff_t *ppos) | ||
550 | { | ||
551 | int total_count = (int) size_count; | ||
552 | int count = 0; | ||
553 | int frame_size; | ||
554 | int buf_to_fill; | ||
555 | int fresh_buffer; | ||
556 | |||
557 | if (!harmony.format_initialized) { | ||
558 | if (harmony_format_auto_detect(buffer, total_count)) | ||
559 | return -EFAULT; | ||
560 | } | ||
561 | |||
562 | while (count<total_count) { | ||
563 | /* Wait until we're out of control mode */ | ||
564 | harmony_wait_CNTL(); | ||
565 | |||
566 | /* Figure out which buffer to fill in */ | ||
567 | if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) { | ||
568 | harmony.blocked_playing = 1; | ||
569 | interruptible_sleep_on(&harmony.wq_play); | ||
570 | harmony.blocked_playing = 0; | ||
571 | } | ||
572 | if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) | ||
573 | return -EBUSY; | ||
574 | |||
575 | |||
576 | buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play); | ||
577 | if (harmony.play_offset) { | ||
578 | buf_to_fill--; | ||
579 | buf_to_fill += MAX_BUFS; | ||
580 | } | ||
581 | buf_to_fill %= MAX_BUFS; | ||
582 | |||
583 | fresh_buffer = (harmony.play_offset == 0); | ||
584 | |||
585 | /* Figure out the size of the frame */ | ||
586 | if ((total_count-count) >= HARMONY_BUF_SIZE - harmony.play_offset) { | ||
587 | frame_size = HARMONY_BUF_SIZE - harmony.play_offset; | ||
588 | } else { | ||
589 | frame_size = total_count - count; | ||
590 | /* Clear out the buffer, since there we'll only be | ||
591 | overlaying part of the old buffer with the new one */ | ||
592 | harmony_silence(&played_buf, | ||
593 | HARMONY_BUF_SIZE*buf_to_fill+frame_size+harmony.play_offset, | ||
594 | HARMONY_BUF_SIZE-frame_size-harmony.play_offset); | ||
595 | } | ||
596 | |||
597 | /* Copy the page to an aligned buffer */ | ||
598 | if (copy_from_user(played_buf.addr +(HARMONY_BUF_SIZE*buf_to_fill) + harmony.play_offset, | ||
599 | buffer+count, frame_size)) | ||
600 | return -EFAULT; | ||
601 | CHECK_WBACK_INV_OFFSET(played_buf, (HARMONY_BUF_SIZE*buf_to_fill + harmony.play_offset), | ||
602 | frame_size); | ||
603 | |||
604 | if (fresh_buffer) | ||
605 | harmony.nb_filled_play++; | ||
606 | |||
607 | count += frame_size; | ||
608 | harmony.play_offset += frame_size; | ||
609 | harmony.play_offset %= HARMONY_BUF_SIZE; | ||
610 | if (harmony.suspended_playing && (harmony.nb_filled_play>=4)) | ||
611 | harmony_enable_interrupts(); | ||
612 | } | ||
613 | |||
614 | return count; | ||
615 | } | ||
616 | |||
617 | static unsigned int harmony_audio_poll(struct file *file, | ||
618 | struct poll_table_struct *wait) | ||
619 | { | ||
620 | unsigned int mask = 0; | ||
621 | |||
622 | if (file->f_mode & FMODE_READ) { | ||
623 | if (!harmony.suspended_recording) | ||
624 | poll_wait(file, &harmony.wq_record, wait); | ||
625 | if (harmony.nb_filled_record) | ||
626 | mask |= POLLIN | POLLRDNORM; | ||
627 | } | ||
628 | |||
629 | if (file->f_mode & FMODE_WRITE) { | ||
630 | if (!harmony.suspended_playing) | ||
631 | poll_wait(file, &harmony.wq_play, wait); | ||
632 | if (harmony.nb_filled_play) | ||
633 | mask |= POLLOUT | POLLWRNORM; | ||
634 | } | ||
635 | |||
636 | return mask; | ||
637 | } | ||
638 | |||
639 | static int harmony_audio_ioctl(struct inode *inode, | ||
640 | struct file *file, | ||
641 | unsigned int cmd, | ||
642 | unsigned long arg) | ||
643 | { | ||
644 | int ival, new_format; | ||
645 | int frag_size, frag_buf; | ||
646 | struct audio_buf_info info; | ||
647 | |||
648 | switch (cmd) { | ||
649 | case OSS_GETVERSION: | ||
650 | return put_user(SOUND_VERSION, (int *) arg); | ||
651 | |||
652 | case SNDCTL_DSP_GETCAPS: | ||
653 | ival = DSP_CAP_DUPLEX; | ||
654 | return put_user(ival, (int *) arg); | ||
655 | |||
656 | case SNDCTL_DSP_GETFMTS: | ||
657 | ival = (AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW ); | ||
658 | return put_user(ival, (int *) arg); | ||
659 | |||
660 | case SNDCTL_DSP_SETFMT: | ||
661 | if (get_user(ival, (int *) arg)) | ||
662 | return -EFAULT; | ||
663 | if (ival != AFMT_QUERY) { | ||
664 | switch (ival) { | ||
665 | case AFMT_MU_LAW: new_format = HARMONY_DF_8BIT_ULAW; break; | ||
666 | case AFMT_A_LAW: new_format = HARMONY_DF_8BIT_ALAW; break; | ||
667 | case AFMT_S16_BE: new_format = HARMONY_DF_16BIT_LINEAR; break; | ||
668 | default: { | ||
669 | DPRINTK(KERN_WARNING PFX | ||
670 | "unsupported sound format 0x%04x requested.\n", | ||
671 | ival); | ||
672 | ival = AFMT_S16_BE; | ||
673 | return put_user(ival, (int *) arg); | ||
674 | } | ||
675 | } | ||
676 | harmony_set_format(new_format); | ||
677 | return 0; | ||
678 | } else { | ||
679 | switch (harmony.data_format) { | ||
680 | case HARMONY_DF_8BIT_ULAW: ival = AFMT_MU_LAW; break; | ||
681 | case HARMONY_DF_8BIT_ALAW: ival = AFMT_A_LAW; break; | ||
682 | case HARMONY_DF_16BIT_LINEAR: ival = AFMT_U16_BE; break; | ||
683 | default: ival = 0; | ||
684 | } | ||
685 | return put_user(ival, (int *) arg); | ||
686 | } | ||
687 | |||
688 | case SOUND_PCM_READ_RATE: | ||
689 | ival = harmony.dac_rate; | ||
690 | return put_user(ival, (int *) arg); | ||
691 | |||
692 | case SNDCTL_DSP_SPEED: | ||
693 | if (get_user(ival, (int *) arg)) | ||
694 | return -EFAULT; | ||
695 | harmony_set_rate(harmony_detect_rate(&ival)); | ||
696 | harmony.dac_rate = ival; | ||
697 | return put_user(ival, (int*) arg); | ||
698 | |||
699 | case SNDCTL_DSP_STEREO: | ||
700 | if (get_user(ival, (int *) arg)) | ||
701 | return -EFAULT; | ||
702 | if (ival != 0 && ival != 1) | ||
703 | return -EINVAL; | ||
704 | harmony_set_stereo(ival); | ||
705 | return 0; | ||
706 | |||
707 | case SNDCTL_DSP_CHANNELS: | ||
708 | if (get_user(ival, (int *) arg)) | ||
709 | return -EFAULT; | ||
710 | if (ival != 1 && ival != 2) { | ||
711 | ival = harmony.stereo_select == HARMONY_SS_MONO ? 1 : 2; | ||
712 | return put_user(ival, (int *) arg); | ||
713 | } | ||
714 | harmony_set_stereo(ival-1); | ||
715 | return 0; | ||
716 | |||
717 | case SNDCTL_DSP_GETBLKSIZE: | ||
718 | ival = HARMONY_BUF_SIZE; | ||
719 | return put_user(ival, (int *) arg); | ||
720 | |||
721 | case SNDCTL_DSP_NONBLOCK: | ||
722 | file->f_flags |= O_NONBLOCK; | ||
723 | return 0; | ||
724 | |||
725 | case SNDCTL_DSP_RESET: | ||
726 | if (!harmony.suspended_recording) { | ||
727 | /* TODO: stop_recording() */ | ||
728 | } | ||
729 | return 0; | ||
730 | |||
731 | case SNDCTL_DSP_SETFRAGMENT: | ||
732 | if (get_user(ival, (int *)arg)) | ||
733 | return -EFAULT; | ||
734 | frag_size = ival & 0xffff; | ||
735 | frag_buf = (ival>>16) & 0xffff; | ||
736 | /* TODO: We use hardcoded fragment sizes and numbers for now */ | ||
737 | frag_size = 12; /* 4096 == 2^12 */ | ||
738 | frag_buf = MAX_BUFS; | ||
739 | ival = (frag_buf << 16) + frag_size; | ||
740 | return put_user(ival, (int *) arg); | ||
741 | |||
742 | case SNDCTL_DSP_GETOSPACE: | ||
743 | if (!(file->f_mode & FMODE_WRITE)) | ||
744 | return -EINVAL; | ||
745 | info.fragstotal = MAX_BUFS; | ||
746 | info.fragments = MAX_BUFS - harmony.nb_filled_play; | ||
747 | info.fragsize = HARMONY_BUF_SIZE; | ||
748 | info.bytes = info.fragments * info.fragsize; | ||
749 | return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0; | ||
750 | |||
751 | case SNDCTL_DSP_GETISPACE: | ||
752 | if (!(file->f_mode & FMODE_READ)) | ||
753 | return -EINVAL; | ||
754 | info.fragstotal = MAX_BUFS; | ||
755 | info.fragments = /*MAX_BUFS-*/ harmony.nb_filled_record; | ||
756 | info.fragsize = HARMONY_BUF_SIZE; | ||
757 | info.bytes = info.fragments * info.fragsize; | ||
758 | return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0; | ||
759 | |||
760 | case SNDCTL_DSP_SYNC: | ||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | return -EINVAL; | ||
765 | } | ||
766 | |||
767 | |||
768 | /* | ||
769 | * harmony_interrupt() | ||
770 | * | ||
771 | * harmony interruption service routine | ||
772 | * | ||
773 | */ | ||
774 | |||
775 | static irqreturn_t harmony_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
776 | { | ||
777 | u32 dstatus; | ||
778 | struct harmony_hpa *hpa; | ||
779 | |||
780 | /* Setup the hpa */ | ||
781 | hpa = ((struct harmony_dev *)dev)->hpa; | ||
782 | harmony_wait_CNTL(); | ||
783 | |||
784 | /* Read dstatus and pcuradd (the current address) */ | ||
785 | dstatus = gsc_readl(&hpa->dstatus); | ||
786 | |||
787 | /* Turn off interrupts */ | ||
788 | harmony_disable_interrupts(); | ||
789 | |||
790 | /* Check if this is a request to get the next play buffer */ | ||
791 | if (dstatus & DSTATUS_PN) { | ||
792 | if (!harmony.nb_filled_play) { | ||
793 | harmony.suspended_playing = 1; | ||
794 | gsc_writel((unsigned long)silent.dma_handle, &hpa->pnxtadd); | ||
795 | |||
796 | if (!harmony.suspended_recording) | ||
797 | harmony_enable_interrupts(); | ||
798 | } else { | ||
799 | harmony.suspended_playing = 0; | ||
800 | gsc_writel((unsigned long)played_buf.dma_handle + | ||
801 | (HARMONY_BUF_SIZE*harmony.first_filled_play), | ||
802 | &hpa->pnxtadd); | ||
803 | harmony.first_filled_play++; | ||
804 | harmony.first_filled_play %= MAX_BUFS; | ||
805 | harmony.nb_filled_play--; | ||
806 | |||
807 | harmony_enable_interrupts(); | ||
808 | } | ||
809 | |||
810 | if (harmony.blocked_playing) | ||
811 | wake_up_interruptible(&harmony.wq_play); | ||
812 | } | ||
813 | |||
814 | /* Check if we're being asked to fill in a recording buffer */ | ||
815 | if (dstatus & DSTATUS_RN) { | ||
816 | if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording) | ||
817 | { | ||
818 | harmony.nb_filled_record = 0; | ||
819 | harmony.first_filled_record = 0; | ||
820 | harmony.suspended_recording = 1; | ||
821 | gsc_writel((unsigned long)graveyard.dma_handle, &hpa->rnxtadd); | ||
822 | if (!harmony.suspended_playing) | ||
823 | harmony_enable_interrupts(); | ||
824 | } else { | ||
825 | int buf_to_fill; | ||
826 | buf_to_fill = (harmony.first_filled_record+harmony.nb_filled_record) % MAX_BUFS; | ||
827 | CHECK_WBACK_INV_OFFSET(recorded_buf, HARMONY_BUF_SIZE*buf_to_fill, HARMONY_BUF_SIZE); | ||
828 | gsc_writel((unsigned long)recorded_buf.dma_handle + | ||
829 | HARMONY_BUF_SIZE*buf_to_fill, | ||
830 | &hpa->rnxtadd); | ||
831 | harmony.nb_filled_record++; | ||
832 | harmony_enable_interrupts(); | ||
833 | } | ||
834 | |||
835 | if (harmony.blocked_recording && harmony.nb_filled_record>3) | ||
836 | wake_up_interruptible(&harmony.wq_record); | ||
837 | } | ||
838 | return IRQ_HANDLED; | ||
839 | } | ||
840 | |||
841 | /* | ||
842 | * Sound playing functions | ||
843 | */ | ||
844 | |||
845 | static struct file_operations harmony_audio_fops = { | ||
846 | .owner = THIS_MODULE, | ||
847 | .llseek = no_llseek, | ||
848 | .read = harmony_audio_read, | ||
849 | .write = harmony_audio_write, | ||
850 | .poll = harmony_audio_poll, | ||
851 | .ioctl = harmony_audio_ioctl, | ||
852 | .open = harmony_audio_open, | ||
853 | .release = harmony_audio_release, | ||
854 | }; | ||
855 | |||
856 | static int harmony_audio_init(void) | ||
857 | { | ||
858 | /* Request that IRQ */ | ||
859 | if (request_irq(harmony.dev->irq, harmony_interrupt, 0 ,"harmony", &harmony)) { | ||
860 | printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony.dev->irq); | ||
861 | return -EFAULT; | ||
862 | } | ||
863 | |||
864 | harmony.dsp_unit = register_sound_dsp(&harmony_audio_fops, -1); | ||
865 | if (harmony.dsp_unit < 0) { | ||
866 | printk(KERN_ERR PFX "Error registering dsp\n"); | ||
867 | free_irq(harmony.dev->irq, &harmony); | ||
868 | return -EFAULT; | ||
869 | } | ||
870 | |||
871 | /* Clear the buffers so you don't end up with crap in the buffers. */ | ||
872 | harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); | ||
873 | |||
874 | /* Make sure this makes it to cache */ | ||
875 | CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); | ||
876 | |||
877 | /* Clear out the silent buffer and flush to cache */ | ||
878 | harmony_silence(&silent, 0, HARMONY_BUF_SIZE); | ||
879 | CHECK_WBACK_INV_OFFSET(silent, 0, HARMONY_BUF_SIZE); | ||
880 | |||
881 | harmony.audio_open = 0; | ||
882 | |||
883 | return 0; | ||
884 | } | ||
885 | |||
886 | |||
887 | /* | ||
888 | * mixer functions | ||
889 | */ | ||
890 | |||
891 | static void harmony_mixer_set_gain(void) | ||
892 | { | ||
893 | harmony_wait_CNTL(); | ||
894 | gsc_writel(harmony.current_gain, &harmony.hpa->gainctl); | ||
895 | } | ||
896 | |||
897 | /* | ||
898 | * Read gain of selected channel. | ||
899 | * The OSS rate is from 0 (silent) to 100 -> need some conversions | ||
900 | * | ||
901 | * The harmony gain are attenuation for output and monitor gain. | ||
902 | * is amplifaction for input gain | ||
903 | */ | ||
904 | #define to_harmony_level(level,max) ((level)*max/100) | ||
905 | #define to_oss_level(level,max) ((level)*100/max) | ||
906 | |||
907 | static int harmony_mixer_get_level(int channel) | ||
908 | { | ||
909 | int left_level; | ||
910 | int right_level; | ||
911 | |||
912 | switch (channel) { | ||
913 | case SOUND_MIXER_VOLUME: | ||
914 | left_level = (harmony.current_gain & GAIN_LO_MASK) >> GAIN_LO_SHIFT; | ||
915 | right_level = (harmony.current_gain & GAIN_RO_MASK) >> GAIN_RO_SHIFT; | ||
916 | left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL); | ||
917 | right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL); | ||
918 | return (right_level << 8)+left_level; | ||
919 | |||
920 | case SOUND_MIXER_IGAIN: | ||
921 | left_level = (harmony.current_gain & GAIN_LI_MASK) >> GAIN_LI_SHIFT; | ||
922 | right_level= (harmony.current_gain & GAIN_RI_MASK) >> GAIN_RI_SHIFT; | ||
923 | left_level = to_oss_level(left_level, MAX_INPUT_LEVEL); | ||
924 | right_level= to_oss_level(right_level, MAX_INPUT_LEVEL); | ||
925 | return (right_level << 8)+left_level; | ||
926 | |||
927 | case SOUND_MIXER_MONITOR: | ||
928 | left_level = (harmony.current_gain & GAIN_MA_MASK) >> GAIN_MA_SHIFT; | ||
929 | left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL); | ||
930 | return (left_level << 8)+left_level; | ||
931 | } | ||
932 | return -EINVAL; | ||
933 | } | ||
934 | |||
935 | |||
936 | |||
937 | /* | ||
938 | * Some conversions for the same reasons. | ||
939 | * We give back the new real value(s) due to | ||
940 | * the rescale. | ||
941 | */ | ||
942 | |||
943 | static int harmony_mixer_set_level(int channel, int value) | ||
944 | { | ||
945 | int left_level; | ||
946 | int right_level; | ||
947 | int new_left_level; | ||
948 | int new_right_level; | ||
949 | |||
950 | right_level = (value & 0x0000ff00) >> 8; | ||
951 | left_level = value & 0x000000ff; | ||
952 | if (right_level > 100) right_level = 100; | ||
953 | if (left_level > 100) left_level = 100; | ||
954 | |||
955 | switch (channel) { | ||
956 | case SOUND_MIXER_VOLUME: | ||
957 | right_level = to_harmony_level(100-right_level, MAX_OUTPUT_LEVEL); | ||
958 | left_level = to_harmony_level(100-left_level, MAX_OUTPUT_LEVEL); | ||
959 | new_right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL); | ||
960 | new_left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL); | ||
961 | harmony.current_gain = (harmony.current_gain & ~(GAIN_LO_MASK | GAIN_RO_MASK)) | ||
962 | | (left_level << GAIN_LO_SHIFT) | (right_level << GAIN_RO_SHIFT); | ||
963 | harmony_mixer_set_gain(); | ||
964 | return (new_right_level << 8) + new_left_level; | ||
965 | |||
966 | case SOUND_MIXER_IGAIN: | ||
967 | right_level = to_harmony_level(right_level, MAX_INPUT_LEVEL); | ||
968 | left_level = to_harmony_level(left_level, MAX_INPUT_LEVEL); | ||
969 | new_right_level = to_oss_level(right_level, MAX_INPUT_LEVEL); | ||
970 | new_left_level = to_oss_level(left_level, MAX_INPUT_LEVEL); | ||
971 | harmony.current_gain = (harmony.current_gain & ~(GAIN_LI_MASK | GAIN_RI_MASK)) | ||
972 | | (left_level << GAIN_LI_SHIFT) | (right_level << GAIN_RI_SHIFT); | ||
973 | harmony_mixer_set_gain(); | ||
974 | return (new_right_level << 8) + new_left_level; | ||
975 | |||
976 | case SOUND_MIXER_MONITOR: | ||
977 | left_level = to_harmony_level(100-left_level, MAX_MONITOR_LEVEL); | ||
978 | new_left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL); | ||
979 | harmony.current_gain = (harmony.current_gain & ~GAIN_MA_MASK) | (left_level << GAIN_MA_SHIFT); | ||
980 | harmony_mixer_set_gain(); | ||
981 | return (new_left_level << 8) + new_left_level; | ||
982 | } | ||
983 | |||
984 | return -EINVAL; | ||
985 | } | ||
986 | |||
987 | #undef to_harmony_level | ||
988 | #undef to_oss_level | ||
989 | |||
990 | /* | ||
991 | * Return the selected input device (mic or line) | ||
992 | */ | ||
993 | |||
994 | static int harmony_mixer_get_recmask(void) | ||
995 | { | ||
996 | int current_input_line; | ||
997 | |||
998 | current_input_line = (harmony.current_gain & GAIN_IS_MASK) | ||
999 | >> GAIN_IS_SHIFT; | ||
1000 | if (current_input_line) | ||
1001 | return SOUND_MASK_MIC; | ||
1002 | |||
1003 | return SOUND_MASK_LINE; | ||
1004 | } | ||
1005 | |||
1006 | /* | ||
1007 | * Set the input (only one at time, arbitrary priority to line in) | ||
1008 | */ | ||
1009 | |||
1010 | static int harmony_mixer_set_recmask(int recmask) | ||
1011 | { | ||
1012 | int new_input_line; | ||
1013 | int new_input_mask; | ||
1014 | int current_input_line; | ||
1015 | |||
1016 | current_input_line = (harmony.current_gain & GAIN_IS_MASK) | ||
1017 | >> GAIN_IS_SHIFT; | ||
1018 | if ((current_input_line && ((recmask & SOUND_MASK_LINE) || !(recmask & SOUND_MASK_MIC))) || | ||
1019 | (!current_input_line && ((recmask & SOUND_MASK_LINE) && !(recmask & SOUND_MASK_MIC)))) { | ||
1020 | new_input_line = 0; | ||
1021 | new_input_mask = SOUND_MASK_LINE; | ||
1022 | } else { | ||
1023 | new_input_line = 1; | ||
1024 | new_input_mask = SOUND_MASK_MIC; | ||
1025 | } | ||
1026 | harmony.current_gain = ((harmony.current_gain & ~GAIN_IS_MASK) | | ||
1027 | (new_input_line << GAIN_IS_SHIFT )); | ||
1028 | harmony_mixer_set_gain(); | ||
1029 | return new_input_mask; | ||
1030 | } | ||
1031 | |||
1032 | |||
1033 | /* | ||
1034 | * give the active outlines | ||
1035 | */ | ||
1036 | |||
1037 | static int harmony_mixer_get_outmask(void) | ||
1038 | { | ||
1039 | int outmask = 0; | ||
1040 | |||
1041 | if (harmony.current_gain & GAIN_SE_MASK) outmask |= MASK_INTERNAL; | ||
1042 | if (harmony.current_gain & GAIN_LE_MASK) outmask |= MASK_LINEOUT; | ||
1043 | if (harmony.current_gain & GAIN_HE_MASK) outmask |= MASK_HEADPHONES; | ||
1044 | |||
1045 | return outmask; | ||
1046 | } | ||
1047 | |||
1048 | |||
1049 | static int harmony_mixer_set_outmask(int outmask) | ||
1050 | { | ||
1051 | if (outmask & MASK_INTERNAL) | ||
1052 | harmony.current_gain |= GAIN_SE_MASK; | ||
1053 | else | ||
1054 | harmony.current_gain &= ~GAIN_SE_MASK; | ||
1055 | |||
1056 | if (outmask & MASK_LINEOUT) | ||
1057 | harmony.current_gain |= GAIN_LE_MASK; | ||
1058 | else | ||
1059 | harmony.current_gain &= ~GAIN_LE_MASK; | ||
1060 | |||
1061 | if (outmask & MASK_HEADPHONES) | ||
1062 | harmony.current_gain |= GAIN_HE_MASK; | ||
1063 | else | ||
1064 | harmony.current_gain &= ~GAIN_HE_MASK; | ||
1065 | |||
1066 | harmony_mixer_set_gain(); | ||
1067 | |||
1068 | return (outmask & (MASK_INTERNAL | MASK_LINEOUT | MASK_HEADPHONES)); | ||
1069 | } | ||
1070 | |||
1071 | /* | ||
1072 | * This code is inspired from sb_mixer.c | ||
1073 | */ | ||
1074 | |||
1075 | static int harmony_mixer_ioctl(struct inode * inode, struct file * file, | ||
1076 | unsigned int cmd, unsigned long arg) | ||
1077 | { | ||
1078 | int val; | ||
1079 | int ret; | ||
1080 | |||
1081 | if (cmd == SOUND_MIXER_INFO) { | ||
1082 | mixer_info info; | ||
1083 | memset(&info, 0, sizeof(info)); | ||
1084 | strncpy(info.id, "harmony", sizeof(info.id)-1); | ||
1085 | strncpy(info.name, "Harmony audio", sizeof(info.name)-1); | ||
1086 | info.modify_counter = 1; /* ? */ | ||
1087 | if (copy_to_user((void *)arg, &info, sizeof(info))) | ||
1088 | return -EFAULT; | ||
1089 | return 0; | ||
1090 | } | ||
1091 | |||
1092 | if (cmd == OSS_GETVERSION) | ||
1093 | return put_user(SOUND_VERSION, (int *)arg); | ||
1094 | |||
1095 | /* read */ | ||
1096 | val = 0; | ||
1097 | if (_SIOC_DIR(cmd) & _SIOC_WRITE) | ||
1098 | if (get_user(val, (int *)arg)) | ||
1099 | return -EFAULT; | ||
1100 | |||
1101 | switch (cmd) { | ||
1102 | case MIXER_READ(SOUND_MIXER_CAPS): | ||
1103 | ret = SOUND_CAP_EXCL_INPUT; | ||
1104 | break; | ||
1105 | case MIXER_READ(SOUND_MIXER_STEREODEVS): | ||
1106 | ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN; | ||
1107 | break; | ||
1108 | |||
1109 | case MIXER_READ(SOUND_MIXER_RECMASK): | ||
1110 | ret = SOUND_MASK_MIC | SOUND_MASK_LINE; | ||
1111 | break; | ||
1112 | case MIXER_READ(SOUND_MIXER_DEVMASK): | ||
1113 | ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN | | ||
1114 | SOUND_MASK_MONITOR; | ||
1115 | break; | ||
1116 | case MIXER_READ(SOUND_MIXER_OUTMASK): | ||
1117 | ret = MASK_INTERNAL | MASK_LINEOUT | | ||
1118 | MASK_HEADPHONES; | ||
1119 | break; | ||
1120 | |||
1121 | case MIXER_WRITE(SOUND_MIXER_RECSRC): | ||
1122 | ret = harmony_mixer_set_recmask(val); | ||
1123 | break; | ||
1124 | case MIXER_READ(SOUND_MIXER_RECSRC): | ||
1125 | ret = harmony_mixer_get_recmask(); | ||
1126 | break; | ||
1127 | |||
1128 | case MIXER_WRITE(SOUND_MIXER_OUTSRC): | ||
1129 | ret = harmony_mixer_set_outmask(val); | ||
1130 | break; | ||
1131 | case MIXER_READ(SOUND_MIXER_OUTSRC): | ||
1132 | ret = harmony_mixer_get_outmask(); | ||
1133 | break; | ||
1134 | |||
1135 | case MIXER_WRITE(SOUND_MIXER_VOLUME): | ||
1136 | case MIXER_WRITE(SOUND_MIXER_IGAIN): | ||
1137 | case MIXER_WRITE(SOUND_MIXER_MONITOR): | ||
1138 | ret = harmony_mixer_set_level(cmd & 0xff, val); | ||
1139 | break; | ||
1140 | |||
1141 | case MIXER_READ(SOUND_MIXER_VOLUME): | ||
1142 | case MIXER_READ(SOUND_MIXER_IGAIN): | ||
1143 | case MIXER_READ(SOUND_MIXER_MONITOR): | ||
1144 | ret = harmony_mixer_get_level(cmd & 0xff); | ||
1145 | break; | ||
1146 | |||
1147 | default: | ||
1148 | return -EINVAL; | ||
1149 | } | ||
1150 | |||
1151 | if (put_user(ret, (int *)arg)) | ||
1152 | return -EFAULT; | ||
1153 | return 0; | ||
1154 | } | ||
1155 | |||
1156 | |||
1157 | static int harmony_mixer_open(struct inode *inode, struct file *file) | ||
1158 | { | ||
1159 | if (harmony.mixer_open) | ||
1160 | return -EBUSY; | ||
1161 | harmony.mixer_open = 1; | ||
1162 | return 0; | ||
1163 | } | ||
1164 | |||
1165 | static int harmony_mixer_release(struct inode *inode, struct file *file) | ||
1166 | { | ||
1167 | if (!harmony.mixer_open) | ||
1168 | return -EBUSY; | ||
1169 | harmony.mixer_open = 0; | ||
1170 | return 0; | ||
1171 | } | ||
1172 | |||
1173 | static struct file_operations harmony_mixer_fops = { | ||
1174 | .owner = THIS_MODULE, | ||
1175 | .llseek = no_llseek, | ||
1176 | .open = harmony_mixer_open, | ||
1177 | .release = harmony_mixer_release, | ||
1178 | .ioctl = harmony_mixer_ioctl, | ||
1179 | }; | ||
1180 | |||
1181 | |||
1182 | /* | ||
1183 | * Mute all the output and reset Harmony. | ||
1184 | */ | ||
1185 | |||
1186 | static void __init harmony_mixer_reset(void) | ||
1187 | { | ||
1188 | harmony.current_gain = GAIN_TOTAL_SILENCE; | ||
1189 | harmony_mixer_set_gain(); | ||
1190 | harmony_wait_CNTL(); | ||
1191 | gsc_writel(1, &harmony.hpa->reset); | ||
1192 | mdelay(50); /* wait 50 ms */ | ||
1193 | gsc_writel(0, &harmony.hpa->reset); | ||
1194 | harmony.current_gain = GAIN_DEFAULT; | ||
1195 | harmony_mixer_set_gain(); | ||
1196 | } | ||
1197 | |||
1198 | static int __init harmony_mixer_init(void) | ||
1199 | { | ||
1200 | /* Register the device file operations */ | ||
1201 | harmony.mixer_unit = register_sound_mixer(&harmony_mixer_fops, -1); | ||
1202 | if (harmony.mixer_unit < 0) { | ||
1203 | printk(KERN_WARNING PFX "Error Registering Mixer Driver\n"); | ||
1204 | return -EFAULT; | ||
1205 | } | ||
1206 | |||
1207 | harmony_mixer_reset(); | ||
1208 | harmony.mixer_open = 0; | ||
1209 | |||
1210 | return 0; | ||
1211 | } | ||
1212 | |||
1213 | |||
1214 | |||
1215 | /* | ||
1216 | * This is the callback that's called by the inventory hardware code | ||
1217 | * if it finds a match to the registered driver. | ||
1218 | */ | ||
1219 | static int __devinit | ||
1220 | harmony_driver_probe(struct parisc_device *dev) | ||
1221 | { | ||
1222 | u8 id; | ||
1223 | u8 rev; | ||
1224 | u32 cntl; | ||
1225 | int ret; | ||
1226 | |||
1227 | if (harmony.hpa) { | ||
1228 | /* We only support one Harmony at this time */ | ||
1229 | printk(KERN_ERR PFX "driver already registered\n"); | ||
1230 | return -EBUSY; | ||
1231 | } | ||
1232 | |||
1233 | if (!dev->irq) { | ||
1234 | printk(KERN_ERR PFX "no irq found\n"); | ||
1235 | return -ENODEV; | ||
1236 | } | ||
1237 | |||
1238 | /* Set the HPA of harmony */ | ||
1239 | harmony.hpa = (struct harmony_hpa *)dev->hpa; | ||
1240 | harmony.dev = dev; | ||
1241 | |||
1242 | /* Grab the ID and revision from the device */ | ||
1243 | id = gsc_readb(&harmony.hpa->id); | ||
1244 | if ((id | 1) != 0x15) { | ||
1245 | printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", id); | ||
1246 | return -EBUSY; | ||
1247 | } | ||
1248 | cntl = gsc_readl(&harmony.hpa->cntl); | ||
1249 | rev = (cntl>>20) & 0xff; | ||
1250 | |||
1251 | printk(KERN_INFO "Lasi Harmony Audio driver " HARMONY_VERSION ", " | ||
1252 | "h/w id %i, rev. %i at 0x%lx, IRQ %i\n", | ||
1253 | id, rev, dev->hpa, harmony.dev->irq); | ||
1254 | |||
1255 | /* Make sure the control bit isn't set, although I don't think it | ||
1256 | ever is. */ | ||
1257 | if (cntl & CNTL_C) { | ||
1258 | printk(KERN_WARNING PFX "CNTL busy\n"); | ||
1259 | harmony.hpa = 0; | ||
1260 | return -EBUSY; | ||
1261 | } | ||
1262 | |||
1263 | /* Initialize the memory buffers */ | ||
1264 | if (harmony_alloc_buffer(&played_buf, MAX_BUFS) || | ||
1265 | harmony_alloc_buffer(&recorded_buf, MAX_BUFS) || | ||
1266 | harmony_alloc_buffer(&graveyard, 1) || | ||
1267 | harmony_alloc_buffer(&silent, 1)) { | ||
1268 | ret = -EBUSY; | ||
1269 | goto out_err; | ||
1270 | } | ||
1271 | |||
1272 | /* Initialize /dev/mixer and /dev/audio */ | ||
1273 | if ((ret=harmony_mixer_init())) | ||
1274 | goto out_err; | ||
1275 | if ((ret=harmony_audio_init())) | ||
1276 | goto out_err; | ||
1277 | |||
1278 | return 0; | ||
1279 | |||
1280 | out_err: | ||
1281 | harmony.hpa = 0; | ||
1282 | harmony_free_buffer(&played_buf); | ||
1283 | harmony_free_buffer(&recorded_buf); | ||
1284 | harmony_free_buffer(&graveyard); | ||
1285 | harmony_free_buffer(&silent); | ||
1286 | return ret; | ||
1287 | } | ||
1288 | |||
1289 | |||
1290 | static struct parisc_device_id harmony_tbl[] = { | ||
1291 | /* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, Bushmaster/Flounder */ | ||
1292 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */ | ||
1293 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */ | ||
1294 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */ | ||
1295 | { 0, } | ||
1296 | }; | ||
1297 | |||
1298 | MODULE_DEVICE_TABLE(parisc, harmony_tbl); | ||
1299 | |||
1300 | static struct parisc_driver harmony_driver = { | ||
1301 | .name = "Lasi Harmony", | ||
1302 | .id_table = harmony_tbl, | ||
1303 | .probe = harmony_driver_probe, | ||
1304 | }; | ||
1305 | |||
1306 | static int __init init_harmony(void) | ||
1307 | { | ||
1308 | return register_parisc_driver(&harmony_driver); | ||
1309 | } | ||
1310 | |||
1311 | static void __exit cleanup_harmony(void) | ||
1312 | { | ||
1313 | free_irq(harmony.dev->irq, &harmony); | ||
1314 | unregister_sound_mixer(harmony.mixer_unit); | ||
1315 | unregister_sound_dsp(harmony.dsp_unit); | ||
1316 | harmony_free_buffer(&played_buf); | ||
1317 | harmony_free_buffer(&recorded_buf); | ||
1318 | harmony_free_buffer(&graveyard); | ||
1319 | harmony_free_buffer(&silent); | ||
1320 | unregister_parisc_driver(&harmony_driver); | ||
1321 | } | ||
1322 | |||
1323 | |||
1324 | MODULE_AUTHOR("Alex DeVries <alex@onefishtwo.ca>"); | ||
1325 | MODULE_DESCRIPTION("Harmony sound driver"); | ||
1326 | MODULE_LICENSE("GPL"); | ||
1327 | |||
1328 | module_init(init_harmony); | ||
1329 | module_exit(cleanup_harmony); | ||
1330 | |||