]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 |