]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - sound/oss/harmony.c
fix file specification in comments
[mirror_ubuntu-zesty-kernel.git] / sound / oss / harmony.c
CommitLineData
1da177e4 1/*
f30c2269 2 sound/oss/harmony.c
1da177e4
LT
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
18TODO:
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
148struct 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
168struct 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
196static struct harmony_dev harmony;
197
198
199/*
200 * Dynamic sound buffer allocation and DMA memory
201 */
202
203struct 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
214static 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
223static 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
246static 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
266static 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
274static 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
289static 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
297static void harmony_set_rate(u8 data_rate)
298{
299 harmony.sample_rate = data_rate;
300 harmony_update_control();
301}
302
303static 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
327static void harmony_set_format(u8 data_format)
328{
329 harmony.data_format = data_format;
330 harmony_update_control();
331}
332
333static void harmony_set_stereo(u8 stereo_select)
334{
335 harmony.stereo_select = stereo_select;
336 harmony_update_control();
337}
338
339static void harmony_disable_interrupts(void)
340{
341 harmony_wait_CNTL();
342 gsc_writel(0, &harmony.hpa->dstatus);
343}
344
345static 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
360static 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
377static 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
407static 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
421static 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
487static 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);
540out:
541 return ret;
542}
543#undef four_bytes_to_u32
544
545
546static 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
617static 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
639static 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
775static 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
845static 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
856static 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
891static 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
907static 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
943static 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
994static 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
1010static 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
1037static 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
1049static 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
1075static 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
1157static 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
1165static 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
1173static 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
1186static 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
1198static 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 */
1219static int __devinit
1220harmony_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 */
49efdd46 1239 harmony.hpa = (struct harmony_hpa *)dev->hpa.start;
1da177e4
LT
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",
49efdd46 1253 id, rev, dev->hpa.start, harmony.dev->irq);
1da177e4
LT
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
1280out_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
1290static 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
1298MODULE_DEVICE_TABLE(parisc, harmony_tbl);
1299
1300static struct parisc_driver harmony_driver = {
1301 .name = "Lasi Harmony",
1302 .id_table = harmony_tbl,
1303 .probe = harmony_driver_probe,
1304};
1305
1306static int __init init_harmony(void)
1307{
1308 return register_parisc_driver(&harmony_driver);
1309}
1310
1311static 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
1324MODULE_AUTHOR("Alex DeVries <alex@onefishtwo.ca>");
1325MODULE_DESCRIPTION("Harmony sound driver");
1326MODULE_LICENSE("GPL");
1327
1328module_init(init_harmony);
1329module_exit(cleanup_harmony);
1330