1/*
2	Copyright 1999, Be Incorporated.   All Rights Reserved.
3	This file may be used under the terms of the Be Sample Code License.
4*/
5#include <string.h>
6
7#include <ByteOrder.h>
8#include <MediaDefs.h>
9
10#include "cm_private.h"
11#include "sound.h"
12
13#include <KernelExport.h>
14
15extern int sprintf(char *, const char *, ...);
16
17
18extern void dump_card(cmedia_pci_dev * card);
19
20// Buffer header for audio server from BeOS R3 MediaDefs.h
21
22typedef struct audio_buffer_header {
23	int32		buffer_number;
24	int32		subscriber_count;
25	bigtime_t	time;
26	int32		reserved_1;
27	int32		reserved_2;
28	bigtime_t	sample_clock;
29} audio_buffer_header;
30
31#if !defined(OLDAPI)
32 #if DEBUG
33  #define OLDAPI(x) dprintf x
34 #else
35  #define OLDAPI(x)
36 #endif
37#endif
38
39#if DEBUG
40int32 int_cnt;
41int32 put_cnt;
42bigtime_t the_time;
43#endif
44
45#if 0
46/* early Intel kernels forgot to export these functions */
47#undef B_HOST_TO_LENDIAN_FLOAT
48#undef B_HOST_TO_BENDIAN_FLOAT
49#undef B_LENDIAN_TO_HOST_FLOAT
50#undef B_BENDIAN_TO_HOST_FLOAT
51
52static float
53_swap_float_(float x)
54{
55	uint32 temp1 = *(uint32*)&x;
56	uint32 temp2 = ((temp1>>24)|((temp1>>8)&0xff00)|((temp1<<8)&0xff0000)|
57					(temp1<<24));
58	return *(float *)&temp2;
59}
60
61#if B_HOST_IS_BENDIAN
62#define B_HOST_TO_LENDIAN_FLOAT(x) _swap_float_(x)
63#define B_HOST_TO_BENDIAN_FLOAT(x) ((float)(x))
64#define B_LENDIAN_TO_HOST_FLOAT(x) _swap_float_(x)
65#define B_BENDIAN_TO_HOST_FLOAT(x) ((float)(x))
66#else
67#define B_HOST_TO_LENDIAN_FLOAT(x) ((float)(x))
68#define B_HOST_TO_BENDIAN_FLOAT(x) _swap_float_(x)
69#define B_LENDIAN_TO_HOST_FLOAT(x) ((float)(x))
70#define B_BENDIAN_TO_HOST_FLOAT(x) _swap_float_(x)
71#endif
72
73#endif
74
75
76static status_t pcm_open(const char *name, uint32 flags, void **cookie);
77static status_t pcm_close(void *cookie);
78static status_t pcm_free(void *cookie);
79static status_t pcm_control(void *cookie, uint32 op, void *data, size_t len);
80static status_t pcm_read(void *cookie, off_t pos, void *data, size_t *len);
81static status_t pcm_write(void *cookie, off_t pos, const void *data, size_t *len);
82//static status_t pcm_writev(void *cookie, off_t pos, const iovec *vec, size_t count, size_t *len); /* */
83
84device_hooks pcm_hooks = {
85    &pcm_open,
86    &pcm_close,
87    &pcm_free,
88    &pcm_control,
89    &pcm_read,
90    &pcm_write,
91    NULL,			/* select */
92    NULL,			/* deselect */
93    NULL,			/* readv */
94	NULL	// &pcm_writev		/* writev */
95};
96
97static pcm_cfg default_pcm = {
98	44100.0,	/* sample rate */
99	2,			/* channels */
100	0x2,		/* format */
101#if B_HOST_IS_BENDIAN
102	1,			/* endian (big) */
103#else
104	0,			/* endian (little) */
105#endif
106	0,			/* header size */
107	PLAYBACK_BUF_SIZE,	/* these are currently hard-coded */
108	RECORD_BUF_SIZE		/* and cannot be changed without re-compile */
109};
110
111
112#if 0
113
114typedef struct {
115	uint8 control;
116	uint8 imask;
117	uint8 regs[0x2e];
118} chip_state;
119
120static void
121save_state(
122	pcm_dev * port,
123	chip_state * state)
124{
125	int ix;
126	state->control = get_direct(port->card, 0);
127	state->imask = get_direct(port->card, 1);
128	for (ix=0; ix<0x0e; ix++) {
129		if (ix != 0x28 && ix != 0x29 && ix != 0x1a && ix != 0x1b) {
130			state->regs[ix] = get_indirect(port->card, ix+0x30);
131		}
132	}
133}
134
135
136static void
137restore_state(
138	pcm_dev * port,
139	const chip_state * state)
140{
141	int ix;
142	set_direct(port->card, 0, state->control, 0xff);
143	for (ix=0; ix<0x0e; ix++) {
144		if (ix != 0x28 && ix != 0x29 && ix != 0x1a && ix != 0x1b) {
145			set_indirect(port->card, ix, state->regs[ix]+0x30, 0xff);
146		}
147	}
148	set_direct(port->card, 1, state->imask, 0xff);
149}
150
151
152static void
153reset_chip(
154	pcm_dev * port)
155{
156	set_direct(port->card, 0x1b, 0x40, 0x40);
157	snooze(2);
158	set_direct(port->card, 0x1b, 0x00, 0x40);
159}
160
161#endif
162
163
164static void
165stop_dma(
166	pcm_dev * port)
167{
168	set_direct(port->card, 0x24, 0x40, 0x40);	// mute wave stream
169	set_direct(port->card, 0x02, 0, 0x03);		// stop both ch0 and ch1
170
171	set_direct(port->card, 0x02, 0x0c, 0x0c);	// reset both ch0 and ch1
172	set_direct(port->card, 0x02, 0, 0x0c);
173	ddprintf(("cmedia_pci: DMA stopped\n"));
174}
175
176
177static void
178start_dma(
179	pcm_dev * port)
180{
181	int	sample_size = 1;
182
183	/* start out with a clean slate */
184
185	KTRACE();
186	ddprintf(("cmedia_pci: start_dma()\n"));
187	if (port->config.format == 0x11) {
188		memset((void*)port->card->low_mem, 0x80, port->config.play_buf_size +
189			port->config.rec_buf_size);
190	}
191	else {
192		memset((void *)port->card->low_mem, 0, port->config.play_buf_size +
193			port->config.rec_buf_size);
194	}
195
196	port->wr_cur = port->wr_2;
197	port->wr_silence = port->config.play_buf_size;
198	port->was_written = 0;
199	port->rd_cur = port->rd_2;
200	port->was_read = port->config.rec_buf_size/2; /* how much has been read */
201	port->wr_total = 0;
202	port->rd_total = 0;
203
204	/* we split the available low memory buffer in a small chunk */
205	/* for playback, and a large chunk for recording. Then we split */
206	/* each of those in half for double-buffering. While the DMA */
207	/* just runs the entire range of the buffer, wrapping around when */
208	/* done, the count register is set up to generate interrupt after */
209	/* each half of the buffer. Because of latency requirements, we */
210	/* will get 187 interrupts a second from playback, and 94 interrupts */
211	/* a second from recording, at 48 kHz sampling rate, when buffers */
212	/* are 2048 for playback and 4096 for record. */
213
214	ddprintf(("play_buf_size %lx   rec_buf_size %lx\n",
215		port->config.play_buf_size/2, port->config.rec_buf_size/2));
216
217	PCI_IO_WR(port->dma_c, ((uint32)port->card->low_phys+
218		port->config.play_buf_size)&0xff);
219	PCI_IO_WR(port->dma_c+1, (((uint32)port->card->low_phys+
220		port->config.play_buf_size)>>8)&0xff);
221	PCI_IO_WR(port->dma_c+2, (((uint32)port->card->low_phys+
222		port->config.play_buf_size)>>16)&0xff);
223	PCI_IO_WR(port->dma_c+3, 0);
224	/* if this is a 16 bit channel, divide transfer count in 2 */
225	if (port->config.format != 0x11)
226		sample_size *= 2;
227	/* if this is a stereo channel, divide transfer count in 2 */
228	if (port->config.channels == 2)
229		sample_size *= 2;
230	PCI_IO_WR(port->dma_c+4, (port->config.rec_buf_size/sample_size-1)&0xff);
231	PCI_IO_WR(port->dma_c+5, ((port->config.rec_buf_size/sample_size-1)>>8)&0xff);
232	PCI_IO_WR(port->dma_c+6, (port->rd_size/sample_size-1)&0xff);
233	PCI_IO_WR(port->dma_c+7, ((port->rd_size/sample_size-1)>>8)&0xff);
234
235	PCI_IO_WR(port->dma_a, ((uint32)port->card->low_phys)&0xff);
236	PCI_IO_WR(port->dma_a+1, ((uint32)port->card->low_phys>>8)&0xff);
237	PCI_IO_WR(port->dma_a+2, ((uint32)port->card->low_phys>>16)&0xff);
238	PCI_IO_WR(port->dma_a+3, 0);
239	PCI_IO_WR(port->dma_a+4, (port->config.play_buf_size/sample_size-1)&0xff);
240	PCI_IO_WR(port->dma_a+5, ((port->config.play_buf_size/sample_size-1)>>8)&0xff);
241	PCI_IO_WR(port->dma_a+6, (port->wr_size/sample_size-1)&0xff);
242	PCI_IO_WR(port->dma_a+7, ((port->wr_size/sample_size-1)>>8)&0xff);
243
244/* here, we should mute the PCM output to avoid clicking */
245
246	ddprintf(("cmedia_pci: DMA starts as %lx/%lx\n", port->config.format, port->open_mode));
247	set_direct(port->card, 0x24, 0x00, 0x40);
248
249/* enable ch0 as play, and ch1 as record */
250	set_direct(port->card, 0, 0x02, 0x03);
251	set_direct(port->card, 0x02, 0x03, 0x03);
252
253/* here, we should snooze for 16 samples' time, then un-mute the PCM output */
254	KTRACE();
255}
256
257
258static status_t
259configure_pcm(
260	pcm_dev * port,
261	pcm_cfg * config,
262	bool force)
263{
264	status_t err = B_OK;
265	int m = 0, n = 0, r = 0;	/* parameters for the PLL sample rate synthesizer */
266	int asr = -1;	/* alternate sample rate divisor */
267	uint32 s;	/* size of buffer */
268
269	ddprintf(("cmedia_pci: configure_pcm()\n"));
270
271	/* check args */
272	if (config->sample_rate < 4000.0) {
273		config->sample_rate = default_pcm.sample_rate;
274	}
275	if (config->sample_rate > 48000.0) {
276		config->sample_rate = 48000.0;
277	}
278	if (config->channels < 1) {
279		config->channels = default_pcm.channels;
280	}
281	if (config->channels > 2) {
282		config->channels = default_pcm.channels;
283	}
284	/* secret format of format: upper nybble = signed, unsigned, float */
285	/* lower nybble = bytes per sample */
286	if ((config->format != 0x11) && (config->format != 0x2) &&
287		(config->format != 0x24) && (config->format != 0x4)) {
288		config->format = default_pcm.format;
289	}
290	if (config->buf_header < 0) {
291		config->buf_header = 0;
292	}
293
294	/* figure out buffer size that's a power of two and within size limits */
295	if (!config->play_buf_size) {
296		/* default is 256 samples for a comfy 6 ms latency */
297		s = 256*config->channels*(config->format&0xf);
298	}	/* minimum is 32 samples for a more extreme 0.75ms latency */
299	else for (s = 32*config->channels*(config->format&0xf); s < MIN_MEMORY_SIZE/2; s = (s<<1)) {
300		if (s >= config->play_buf_size) {
301			break;
302		}
303	}
304	config->play_buf_size = s;
305	if (!config->rec_buf_size) {
306		s = 256*config->channels*(config->format&0xf);
307	}
308	else for (s = 32*config->channels*(config->format&0xf); s < MIN_MEMORY_SIZE/2; s = (s<<1)) {
309		if (s >= config->rec_buf_size) {
310			break;
311		}
312	}
313	config->rec_buf_size = s;
314
315	/* calculate m, n and r (and asr) */
316
317	if (!force && abs(config->sample_rate - port->config.sample_rate) < config->sample_rate/250) {
318		n = -1;
319	}
320	else if (config->sample_rate == 48000.0) {
321		asr = 7;
322	}
323	else if (config->sample_rate == 32000.0) {
324		asr = 6;
325	}
326	else if (config->sample_rate == 16000.0) {
327		asr = 5;
328	}
329	else if (config->sample_rate == 8000.0) {
330		asr = 4;
331	}
332	else if (config->sample_rate == 44100.0) {
333		asr = 3;
334	}
335	else if (config->sample_rate == 22050.0) {
336		asr = 2;
337	}
338	else if (config->sample_rate == 11025.0) {
339		asr = 1;
340	}
341	else {
342		float freq;
343		float delta = 1000000.0;
344		int sr = -1;
345		int sn = -1;
346		int sm = -1;
347		float diff;
348
349		for (r=0; r<8; r++) {
350			if ((1<<r)*config->sample_rate*512 < MIN_FREQ) {
351				continue;
352			}
353			break;
354		}
355		if (r == 8) {
356			OLDAPI(("cmedia_pci: r value is 8!\n"));
357			r = 7;
358		}
359		n = 0;
360		do {
361			n++;
362			m = config->sample_rate*512/1000*(n+2)*(1<<r)/(F_REF/1000)-2;
363			if (m < 1) {
364				continue;
365			}
366			if (m > 255) {
367				ddprintf(("cmedia_pci: m > 255; outahere\n"));
368				break;
369			}
370			freq = (m+2)*(F_REF/1000)/(512*(n+2)*(1<<r)/1000);
371			diff = freq-config->sample_rate;
372			if (diff < 0) {
373				diff = -diff;
374			}
375			if (diff < delta) {
376				sr = r;
377				sn = n;
378				sm = m;
379			}
380		} while (n < 31);
381		r = sr;
382		n = sn;
383		m = sm;
384		ddprintf(("cmedia_pci: m = %d   r = %d   n = %d\n", m, r, n));
385	}
386
387	/* configure device */
388
389	if (!force) {
390		stop_dma(port);
391		/* should mute PCM out, too */
392	}
393	if (asr > -1 || n > -1) { /* new sampling rate */
394		if (asr > -1) {
395			port->config.sample_rate = config->sample_rate;
396			set_direct(port->card, 0x05, (asr<<5)|(asr<<2), 0xfc);
397		}
398		else {
399			port->config.sample_rate = ((float)m+2.0)*(F_REF/1000.0)/
400				(0.512*(n+2.0)*(1<<r));
401			config->sample_rate = port->config.sample_rate;
402#if 1
403			/* not exact the frequency supported */
404#else
405			set_indirect(port->card, 0x24, m, 0xff);
406			set_indirect(port->card, 0x25, (r<<5)|n, 0xff);
407			set_indirect(port->card, 0x22, 0x00, 0xff);
408#endif
409		}
410	}
411	if (force || config->channels != port->config.channels ||
412		config->format != port->config.format) {
413		uchar val = 0;
414		if (config->channels == 2) {
415			val |= 0x01;	/* stereo */
416		}
417		if (config->format != 0x11) {
418			val |= 0x02;	/* 16 bits */
419		}
420		set_direct(port->card, 0x08, (val<<2)|val, 0x0f); /* MCE -- may take time to take effect */
421		port->config.channels = config->channels;
422		port->config.format = config->format;
423	}
424	if (force || config->big_endian != port->config.big_endian) {
425		port->config.big_endian = config->big_endian;
426	}
427	if (force || config->buf_header != port->config.buf_header) {
428		port->config.buf_header = config->buf_header;
429	}
430	if (force || config->play_buf_size != port->config.play_buf_size*2) {
431		port->config.play_buf_size = config->play_buf_size*2;	/* because we break it in two */
432	}
433	if (force || config->rec_buf_size != port->config.rec_buf_size*2) {
434		port->config.rec_buf_size = config->rec_buf_size*2;	/* because we break it in two */
435	}
436
437/* here is where we should care about record and playback buffer sizes */
438
439	ddprintf(("cmedia_pci: play %04lx rec %04lx\n", port->config.play_buf_size/2,
440		port->config.rec_buf_size/2));
441
442	port->wr_1 = port->card->low_mem;
443	port->wr_2 = port->wr_1+port->config.play_buf_size/2;
444	port->wr_size = port->config.play_buf_size/2;
445
446	port->rd_1 = port->card->low_mem+port->config.play_buf_size;
447	port->rd_2 = port->rd_1+port->config.rec_buf_size/2;
448	port->rd_size = port->config.rec_buf_size/2;
449
450	if (!force) {
451		/* should un-mute PCM out, if we muted it */
452		start_dma(port);
453	}
454	return err;
455}
456
457
458static status_t
459pcm_open(
460	const char * name,
461	uint32 flags,
462	void ** cookie)
463{
464	int ix;
465	pcm_dev * port = NULL;
466	char name_buf[256];
467	int32 prev_mode;
468
469	ddprintf(("cmedia_pci: pcm_open()\n"));
470
471	*cookie = NULL;
472	for (ix=0; ix<num_cards; ix++) {
473		if (!strcmp(name, cards[ix].pcm.name)) {
474			goto gotit;
475		}
476	}
477	for (ix=0; ix<num_cards; ix++) {
478		if (!strcmp(name, cards[ix].pcm.oldname)) {
479			goto gotit;
480		}
481	}
482	ddprintf(("cmedia_pci: %s not found\n", name));
483	return ENODEV;
484
485gotit:
486	*cookie = port = &cards[ix].pcm;
487
488	acquire_sem(port->init_sem);
489
490	prev_mode = port->open_mode;
491	if ((flags & 3) == O_RDONLY) {
492		atomic_or(&port->open_mode, kRecord);
493	}
494	else if ((flags & 3) == O_WRONLY) {
495		atomic_or(&port->open_mode, kPlayback);
496	}
497	else {
498		atomic_or(&port->open_mode, kPlayback|kRecord);
499	}
500
501	if (atomic_add(&port->open_count, 1) == 0) {
502
503		/* initialize device first time */
504
505		port->card = &cards[ix];
506		port->config = default_pcm;
507		port->config.play_buf_size *= 2;
508		port->config.rec_buf_size *= 2;
509
510		/* playback */
511		B_INITIALIZE_SPINLOCK(&port->wr_lock);
512		port->dma_a = cards[ix].dma_base;
513		port->wr_1 = cards[ix].low_mem;
514		port->wr_2 = cards[ix].low_mem+port->config.play_buf_size/2;
515		port->wr_size = port->config.play_buf_size/2;
516		port->write_waiting = 0;
517		sprintf(name_buf, "WS:%s", port->name);
518		name_buf[B_OS_NAME_LENGTH-1] = 0;
519		port->write_sem = create_sem(0, name_buf);
520		if (port->write_sem < B_OK) {
521			port->open_count = 0;
522			return port->write_sem;
523		}
524		set_sem_owner(port->write_sem, B_SYSTEM_TEAM);
525		name_buf[0] = 'W'; name_buf[1] = 'E';
526		port->wr_entry = create_sem(1, name_buf);
527		if (port->wr_entry < B_OK) {
528			delete_sem(port->write_sem);
529			port->open_count = 0;
530			return port->wr_entry;
531		}
532		set_sem_owner(port->wr_entry, B_SYSTEM_TEAM);
533		name_buf[1] = 'T';
534		port->wr_time_wait = 0;
535		port->wr_time_sem = create_sem(0, name_buf);
536		if (port->wr_time_sem < B_OK) {
537			delete_sem(port->write_sem);
538			delete_sem(port->wr_entry);
539			port->open_count = 0;
540			return port->wr_time_sem;
541		}
542		set_sem_owner(port->wr_time_sem, B_SYSTEM_TEAM);
543
544		/* recording */
545
546		B_INITIALIZE_SPINLOCK(&port->rd_lock);
547		port->dma_c = cards[ix].dma_base+0x08;
548		port->rd_1 = cards[ix].low_mem+port->config.play_buf_size;
549		port->rd_2 = cards[ix].low_mem+port->config.play_buf_size+port->config.rec_buf_size/2;
550		port->rd_size = port->config.rec_buf_size/2;
551		port->read_waiting = 0;
552		name_buf[0] = 'R'; name_buf[1] = 'S';
553		port->read_sem = create_sem(0, name_buf);
554		if (port->read_sem < B_OK) {
555			delete_sem(port->write_sem);
556			delete_sem(port->wr_entry);
557			delete_sem(port->wr_time_sem);
558			port->open_count = 0;
559			return port->read_sem;
560		}
561		set_sem_owner(port->read_sem, B_SYSTEM_TEAM);
562		name_buf[0] = 'R'; name_buf[1] = 'E';
563		port->rd_entry = create_sem(1, name_buf);
564		if (port->rd_entry < B_OK) {
565			delete_sem(port->write_sem);
566			delete_sem(port->wr_entry);
567			delete_sem(port->read_sem);
568			delete_sem(port->wr_time_sem);
569			port->open_count = 0;
570			return port->rd_entry;
571		}
572		set_sem_owner(port->rd_entry, B_SYSTEM_TEAM);
573		name_buf[1] = 'T';
574		port->rd_time_wait = 0;
575		port->rd_time_sem = create_sem(0, name_buf);
576		if (port->rd_time_sem < B_OK) {
577			delete_sem(port->write_sem);
578			delete_sem(port->wr_entry);
579			delete_sem(port->read_sem);
580			delete_sem(port->wr_time_sem);
581			delete_sem(port->rd_entry);
582			port->open_count = 0;
583			return port->rd_time_sem;
584		}
585		set_sem_owner(port->rd_time_sem, B_SYSTEM_TEAM);
586
587		port->rd_time = 0;
588		port->next_rd_time = 0;
589		port->wr_time = 0;
590
591		/* old API */
592
593		port->old_cap_sem = -1;
594		port->old_play_sem = -1;
595
596		/* configuration */
597
598		configure_pcm(port, &default_pcm, true);
599
600		/* interrupts */
601		KTRACE();
602		increment_interrupt_handler(port->card);
603
604		set_direct(port->card, 0x0e, 0x03, 0x03);	/* */
605		start_dma(port);
606
607		/* initialization is done, let other clients of the driver go */
608	} else {
609		if (prev_mode != port->open_mode) {
610			pcm_cfg temp = port->config;
611			temp.play_buf_size /= 2;
612			temp.rec_buf_size /= 2;
613			configure_pcm(port, &temp, false);	/* change rec/play if needed */
614		}
615	}
616	release_sem(port->init_sem);
617
618#if DEBUG
619	dump_card(&cards[ix]);
620#endif
621
622	return B_OK;
623}
624
625
626static status_t
627pcm_close(
628	void * cookie)
629{
630	pcm_dev * port = (pcm_dev *)cookie;
631	cpu_status cp;
632	int spin = 0;
633
634	ddprintf(("cmedia_pci: pcm_close()\n"));
635
636	acquire_sem(port->init_sem);
637
638	if (atomic_add(&port->open_count, -1) == 1) {
639
640		KTRACE();
641		cp = disable_interrupts();
642		acquire_spinlock(&port->card->hardware);
643
644		/* turn off interrupts */
645		stop_dma(port);
646		set_direct(port->card, 0x0e, 0x00, 0x03);	/* */
647
648		if (port->config.format == 0x11) {
649			memset((void *)port->wr_1, 0x80, port->config.play_buf_size);	/* play silence */
650		}
651		else {
652			memset((void *)port->wr_1, 0, port->config.play_buf_size);	/* play silence */
653		}
654		spin = 1;
655
656		release_spinlock(&port->card->hardware);
657		restore_interrupts(cp);
658
659		delete_sem(port->write_sem);
660		delete_sem(port->read_sem);
661		delete_sem(port->wr_entry);
662		delete_sem(port->rd_entry);
663		delete_sem(port->rd_time_sem);
664		delete_sem(port->wr_time_sem);
665		port->write_sem = -1;
666		port->read_sem = -1;
667		port->wr_entry = -1;
668		port->rd_entry = -1;
669		port->rd_time_sem = -1;
670		port->wr_time_sem = -1;
671	}
672	release_sem(port->init_sem);
673
674	if (spin) {
675		/* wait so we know FIFO gets filled with silence */
676		snooze(port->config.play_buf_size*1000/(port->config.sample_rate*
677			(port->config.format&0xf)*port->config.channels/1000));
678	}
679	return B_OK;
680}
681
682
683static status_t
684pcm_free(
685	void * cookie)
686{
687	cpu_status cp;
688	pcm_dev * port = (pcm_dev *)cookie;
689
690	ddprintf(("cmedia_pci: pcm_free()\n"));
691
692	acquire_sem(port->init_sem);
693
694	if (((pcm_dev *)cookie)->open_count == 0) {
695
696		/* the last free will actually stop everything  */
697
698		KTRACE();
699		cp = disable_interrupts();
700		acquire_spinlock(&port->card->hardware);
701
702		decrement_interrupt_handler(port->card);
703
704		release_spinlock(&port->card->hardware);
705		restore_interrupts(cp);
706	}
707	release_sem(port->init_sem);
708
709	return B_OK;
710}
711
712
713static status_t
714pcm_control(
715	void * cookie,
716	uint32 iop,
717	void * data,
718	size_t len)
719{
720	// declarations for SPDIF settings I/O
721	uchar reg_value;
722	char DriverVersion[] = "1.3.2 (Jul 17, 2001)";
723
724	pcm_dev * port = (pcm_dev *)cookie;
725	status_t err = B_BAD_VALUE;
726	pcm_cfg config = port->config;
727	static float rates[7] = { 48000.0, 44100.0, 32000.0, 22050.0, 16000.0, 11025.0, 8000.0 };
728	bool configure = false;
729	config.play_buf_size /= 2;
730	config.rec_buf_size /= 2;
731
732	ddprintf(("cmedia_pci: pcm_control()\n"));
733
734	switch (iop) {
735	case B_AUDIO_GET_AUDIO_FORMAT:
736		memcpy(data, &config, sizeof(port->config));
737		err = B_OK;
738		break;
739	case B_AUDIO_GET_PREFERRED_SAMPLE_RATES:
740		memcpy(data, rates, sizeof(rates));
741		err = B_OK;
742		break;
743	case B_AUDIO_SET_AUDIO_FORMAT:
744		memcpy(&config, data, sizeof(config));
745		configure = true;
746		err = B_OK;
747		break;
748	case SV_RD_TIME_WAIT:
749		atomic_add(&port->rd_time_wait, 1);
750		err = acquire_sem(port->rd_time_sem);
751		if (err >= B_OK) {
752			cpu_status cp;
753			KTRACE();
754			cp = disable_interrupts();
755			acquire_spinlock(&port->rd_lock);
756			((sv_timing *)data)->time = port->rd_time;
757			((sv_timing *)data)->bytes = port->rd_total;
758			((sv_timing *)data)->skipped = port->rd_skipped;
759			((sv_timing *)data)->_reserved_[0] = 0xffffffffUL;
760			release_spinlock(&port->rd_lock);
761			restore_interrupts(cp);
762		}
763		break;
764	case SV_WR_TIME_WAIT:
765		atomic_add(&port->wr_time_wait, 1);
766		err = acquire_sem(port->wr_time_sem);
767		if (err >= B_OK) {
768			cpu_status cp;
769			KTRACE();
770			cp = disable_interrupts();
771			acquire_spinlock(&port->wr_lock);
772			((sv_timing *)data)->time = port->wr_time;
773			((sv_timing *)data)->bytes = port->wr_total;
774			((sv_timing *)data)->skipped = port->wr_skipped;
775			((sv_timing *)data)->_reserved_[0] = 0xffffffffUL;
776			release_spinlock(&port->wr_lock);
777			restore_interrupts(cp);
778		}
779		break;
780	case SV_SECRET_HANDSHAKE: {
781		cpu_status cp;
782		KTRACE();
783		cp = disable_interrupts();
784		acquire_spinlock(&port->wr_lock);
785		acquire_spinlock(&port->rd_lock);
786		((sv_handshake *)data)->wr_time = port->wr_time;
787		((sv_handshake *)data)->wr_skipped = port->wr_skipped;
788		((sv_handshake *)data)->rd_time = port->rd_time;
789		((sv_handshake *)data)->rd_skipped = port->rd_skipped;
790		((sv_handshake *)data)->wr_total = port->wr_total;
791		((sv_handshake *)data)->rd_total = port->rd_total;
792		((sv_handshake *)data)->_reserved_[0] = 0xffffffffUL;
793		err = B_OK;
794		release_spinlock(&port->rd_lock);
795		release_spinlock(&port->wr_lock);
796		restore_interrupts(cp);
797		} break;
798	case SOUND_GET_PARAMS: {
799		cpu_status cp;
800		uchar u;
801		sound_setup * sound = (sound_setup *)data;
802		err = B_OK;
803		cp = disable_interrupts();
804		acquire_spinlock(&port->card->hardware);
805		/* Here we get to hard-code the mix/mux values. */
806		/* Huh-huh; he said "hard-code"! */
807		sound->sample_rate = kHz_44_1;
808		if (!port->config.big_endian == !B_HOST_IS_BENDIAN) {
809			sound->playback_format = linear_16bit_big_endian_stereo;
810			sound->capture_format = linear_16bit_big_endian_stereo;
811		}
812		else {
813			sound->playback_format = linear_16bit_little_endian_stereo;
814			sound->capture_format = linear_16bit_little_endian_stereo;
815		}
816		sound->dither_enable = false;
817		sound->loop_attn = 0;
818		sound->loop_enable = 0;
819		sound->output_boost = 0;
820		sound->highpass_enable = 0;
821		/* this is a master control on C-Media... */
822		u = get_indirect(port->card, 0x30)>>2;
823		sound->mono_gain = u&63;
824		sound->mono_mute = 0;
825
826		/* left channel */
827		u = get_indirect(port->card, 0x3d); // Legacy SB compatible Mixer
828		switch (u)
829		{
830		case 0x10:
831			sound->left.adc_source = line;		//	record line left
832			break;
833
834		case 4:
835			sound->left.adc_source = aux1;		// record CD left ??
836			break;
837
838		case 1:
839			sound->left.adc_source = mic;		// record mic left
840			break;
841
842		default:
843			sound->left.adc_source = loopback;
844			break;
845		}
846		u = get_indirect(port->card, 0x3f)>>4;
847		sound->left.adc_gain = u&15;
848
849		u = get_direct(port->card, 0x25)<<4;
850		sound->left.mic_gain_enable = u&16;
851
852		u = get_indirect(port->card, 0x36)>>3;
853		sound->left.aux1_mix_gain = 31-(u&31);
854
855		u = get_indirect(port->card, 0x3c)<<5;
856		sound->left.aux1_mix_mute = ~u&128;
857
858		u = get_indirect(port->card, 0x34)>>3;
859		sound->left.aux2_mix_gain = 31-(u&31);
860
861		u = get_direct(port->card, 0x24);
862		sound->left.aux2_mix_mute = u&128;
863
864		u = get_indirect(port->card, 0x38)>>3;
865		sound->left.line_mix_gain = 31-(u&31);
866
867		u = get_indirect(port->card, 0x3c)<<3;
868		sound->left.line_mix_mute = ~u&128;
869
870		u = get_indirect(port->card, 0x32)>>2;
871		sound->left.dac_attn = 63-(u&63);
872
873		u = get_direct(port->card, 0x24)<<1;
874		sound->left.dac_mute = u&128;
875
876		/* right channel */
877		u = get_indirect(port->card, 0x3e);
878		switch (u)
879		{
880		case 8:
881			sound->right.adc_source = line;		//record line right
882			break;
883
884		case 2:
885			sound->right.adc_source = aux1;		// record CD right?
886			break;
887
888		case 1:
889			sound->right.adc_source = mic;		// record mic right
890			break;
891
892		default:
893			sound->right.adc_source = loopback;
894			break;
895		}
896		u = get_indirect(port->card, 0x40)>>4;
897		sound->right.adc_gain = u&15;
898		sound->right.mic_gain_enable = sound->left.mic_gain_enable;
899		u = get_indirect(port->card, 0x37)>>3;
900		sound->right.aux1_mix_gain = 31-(u&31);
901		u = get_indirect(port->card, 0x3c)<<6;
902		sound->right.aux1_mix_mute = ~u&128;
903		u = get_indirect(port->card, 0x35)>>3;
904		sound->right.aux2_mix_gain = 31-(u&31);
905		u = get_direct(port->card, 0x24);
906		sound->right.aux2_mix_mute = u&128;
907		u = get_indirect(port->card, 0x39)>>3;
908		sound->right.line_mix_gain = 31-(u&31);
909		u = get_indirect(port->card, 0x3c)<<4;
910		sound->right.line_mix_mute = ~u&128;
911		u = get_indirect(port->card, 0x33)>>2;
912		sound->right.dac_attn = 63-(u&63);
913		u = get_direct(port->card, 0x24)<<1;
914		sound->right.dac_mute = u&128;
915		/* done */
916		release_spinlock(&port->card->hardware);
917		restore_interrupts(cp);
918		} break;
919	case SOUND_SET_PARAMS: {
920		cpu_status cp;
921		uchar u;
922		sound_setup * sound = (sound_setup *)data;
923		err = B_OK;
924		cp = disable_interrupts();
925		acquire_spinlock(&port->card->hardware);
926		/* Here we get to hard-code the mix/mux values. */
927		/* Huh-huh; he said "hard-code"! */
928
929		/* ignore sample rate */
930		sound->sample_rate = kHz_44_1;
931		if (config.sample_rate < 43999 || config.sample_rate > 44201) {
932			config.sample_rate = 44100.0;
933			configure = true;
934		}
935		/* we only support 16-bit formats */
936		if (sound->playback_format == linear_16bit_big_endian_stereo &&
937			sound->capture_format == linear_16bit_big_endian_stereo) {
938			if (!config.big_endian != !B_HOST_IS_BENDIAN || config.format != 0x2) {
939				config.big_endian = B_HOST_IS_BENDIAN;
940				config.format = 0x2;
941				configure = true;
942			}
943			OLDAPI(("same_endian\n"));
944		}
945		else if (sound->playback_format == linear_16bit_little_endian_stereo &&
946			sound->capture_format == linear_16bit_little_endian_stereo) {
947			if (!config.big_endian != !!B_HOST_IS_BENDIAN || config.format != 0x2) {
948				config.big_endian = !B_HOST_IS_BENDIAN;
949				config.format = 0x2;
950				configure = true;
951			}
952			OLDAPI(("other_endian\n"));
953		}
954		else {
955			config.big_endian = !!B_HOST_IS_BENDIAN;
956			configure = true;
957			OLDAPI(("other format!!!\n"));
958		}
959		/* ignore these values */
960		sound->dither_enable = false;
961		sound->loop_attn = 0;
962		sound->loop_enable = 0;
963		sound->output_boost = 0;
964		sound->highpass_enable = 0;
965		/* this is a stereo control on C-Media... */
966		u = (sound->mono_gain>>1)&0x1f;
967		OLDAPI(("output: %x\n", u));
968		set_indirect(port->card, 0x30, u<<3, 0xff);
969		set_indirect(port->card, 0x31, u<<3, 0xff);
970		/* left channel */
971		switch (sound->left.adc_source)
972		{
973		case line:
974			u = 1<<4;
975			break;
976		case aux1:
977			u = 1<<2;
978			break;
979		case mic:
980			u = 1<<0;
981			break;
982		default:
983			u = 0x15;
984			break;
985		}
986		OLDAPI(("input: %x\n", u));
987		set_indirect(port->card, 0x3d, u, 0xff);
988		u = (sound->left.adc_gain&15);
989		set_indirect(port->card, 0x3f, u<<4, 0xff);
990		u = sound->left.mic_gain_enable ? 0 : 0x01;
991		set_direct(port->card, 0x25, u, 0x01);
992		u = 31-(sound->left.aux1_mix_gain&31);
993		OLDAPI(("cd: %x\n", u));
994		set_indirect(port->card, 0x36, u<<3, 0xff);
995		u = sound->left.aux1_mix_mute ? 0 : 0x04;
996		set_indirect(port->card, 0x3c, u, 0x04);
997		u = 31-(sound->left.aux2_mix_gain&31);
998		OLDAPI(("aux2: %x\n", u));
999		set_indirect(port->card, 0x34, u<<3, 0xff);
1000		u = sound->left.aux2_mix_mute ? 0x80 : 0;
1001		set_direct(port->card, 0x24, u, 0x80);
1002		u = 31-(sound->left.line_mix_gain&31);
1003		OLDAPI(("line: %x\n", u));
1004		set_indirect(port->card, 0x38, u<<3, 0xff);
1005		u = sound->left.line_mix_mute ? 0 : 0x10;
1006		set_indirect(port->card, 0x3c, u, 0x10);
1007		u = 63-(sound->left.dac_attn & 63);
1008		OLDAPI(("PCM: %x\n", u));
1009		set_indirect(port->card, 0x32, u<<2, 0xff);
1010		u = sound->left.dac_mute ? 0x40 : 0;
1011		set_direct(port->card, 0x24, u, 0x40);
1012		/* right channel */
1013		switch (sound->right.adc_source) {
1014		case line:
1015			u = 1<<3;
1016			break;
1017		case aux1:
1018			u = 1<<1;
1019			break;
1020		case mic:
1021			u = 1<<0;
1022			break;
1023		default:
1024			u = 0x0a;
1025			break;
1026		}
1027		sound->right.mic_gain_enable = sound->left.mic_gain_enable;
1028		set_indirect(port->card, 0x3e, u, 0xff);
1029		u = (sound->right.adc_gain&15);
1030		set_indirect(port->card, 0x40, u<<4, 0xff);
1031		u = sound->right.mic_gain_enable ? 0 : 0x01;
1032		set_direct(port->card, 0x25, u, 0x01);
1033		u = 31-(sound->right.aux1_mix_gain&31);
1034		set_indirect(port->card, 0x37, u<<3, 0xff);
1035		u = sound->right.aux1_mix_mute ? 0 : 0x02;
1036		set_indirect(port->card, 0x3c, u, 0x02);
1037		u = 31-(sound->right.aux2_mix_gain&31);
1038		set_indirect(port->card, 0x35, u<<3, 0xff);
1039		u = sound->right.aux2_mix_mute ? 0x80 : 0;
1040		set_direct(port->card, 0x24, u, 0x80);
1041		u = 31-(sound->right.line_mix_gain&31);
1042		set_indirect(port->card, 0x39, u<<3, 0xff);
1043		u = sound->right.line_mix_mute ? 0 : 0x08;
1044		set_indirect(port->card, 0x3c, u, 0x08);
1045		u = 63-(sound->right.dac_attn & 63);
1046		set_indirect(port->card, 0x33, u<<2, 0xff);
1047		u = sound->right.dac_mute ? 0x40 : 0;
1048		set_direct(port->card, 0x24, u, 0x40);
1049		/* done */
1050		release_spinlock(&port->card->hardware);
1051		restore_interrupts(cp);
1052		} break;
1053	case SOUND_SET_PLAYBACK_COMPLETION_SEM:
1054		port->old_play_sem = *(sem_id *)data;
1055		err = B_OK;
1056		break;
1057	case SOUND_SET_CAPTURE_COMPLETION_SEM:
1058		port->old_cap_sem = *(sem_id *)data;
1059		err = B_OK;
1060		break;
1061//	case SOUND_GET_PLAYBACK_TIMESTAMP:
1062//		break;
1063//	case SOUND_GET_CAPTURE_TIMESTAMP:
1064//		break;
1065//	case SOUND_DEBUG_ON:
1066//		break;
1067//	case SOUND_DEBUG_OFF:
1068//		break;
1069	case SOUND_UNSAFE_WRITE: {
1070		audio_buffer_header * buf = (audio_buffer_header *)data;
1071		size_t n = buf->reserved_1-sizeof(*buf);
1072		pcm_write(cookie, 0, buf+1, &n);
1073		buf->time = port->wr_time;
1074		buf->sample_clock = port->wr_total/4 * 10000 / 441;
1075		err = release_sem(port->old_play_sem);
1076		} break;
1077	case SOUND_UNSAFE_READ: {
1078		audio_buffer_header * buf = (audio_buffer_header *)data;
1079		size_t n = buf->reserved_1-sizeof(*buf);
1080		pcm_read(cookie, 0, buf+1, &n);
1081		buf->time = port->rd_time;
1082		buf->sample_clock = port->rd_total/4 * 10000 / 441;
1083		err = release_sem(port->old_cap_sem);
1084		} break;
1085	case SOUND_LOCK_FOR_DMA:
1086		err = B_OK;
1087		break;
1088	case SOUND_SET_PLAYBACK_PREFERRED_BUF_SIZE:
1089		config.play_buf_size = (intptr_t)data;
1090		configure = true;
1091		err = B_OK;
1092		break;
1093	case SOUND_SET_CAPTURE_PREFERRED_BUF_SIZE:
1094		config.rec_buf_size = (intptr_t)data;
1095		configure = true;
1096		err = B_OK;
1097		break;
1098	case SOUND_GET_PLAYBACK_PREFERRED_BUF_SIZE:
1099		*(int32*)data = config.play_buf_size;
1100		err = B_OK;
1101		break;
1102	case SOUND_GET_CAPTURE_PREFERRED_BUF_SIZE:
1103		*(int32*)data = config.rec_buf_size;
1104		err = B_OK;
1105		break;
1106
1107
1108// control ports for SPDIF settings
1109	case SOUND_GET_SPDIF_IN_OUT_LOOPBACK:
1110		*(int8 *)data = 0;
1111		reg_value = get_direct( port->card, 0x04 );
1112		if( reg_value && 0x80 ) *(int8 *)data = 1;
1113		err = B_OK;
1114		break;
1115
1116	case SOUND_SET_SPDIF_IN_OUT_LOOPBACK:
1117		if( *(int8 *)data == 0 ) // disable SPDIF-IN loopback to SPDIF (bypass)
1118			set_direct( port->card, 0x04, 0x00, 0x80 );
1119		else // enable SPDIF-IN loopback to SPDIF (bypass)
1120			set_direct( port->card, 0x04, 0x80, 0x80 );
1121		err = B_OK;
1122		break;
1123
1124
1125
1126
1127	case SOUND_GET_SPDIF_OUT:
1128		*(int8 *)data = 0;
1129		reg_value = get_direct( port->card, 0x16 );			// Adresse 0x16
1130		if( reg_value && 0x80 ) *(int8 *)data = 1;
1131		err = B_OK;
1132		break;
1133
1134	case SOUND_SET_SPDIF_OUT:
1135		if( *(int8 *)data == 0 ) // disable SPDIF-OUT
1136			set_direct( port->card, 0x16, 0x00, 0x80);
1137		else // enable SPDIF-OUT
1138			set_direct( port->card, 0x16, 0x80, 0x80 );
1139		err = B_OK;
1140		break;
1141
1142
1143
1144	case SOUND_GET_SPDIF_MONITOR:
1145		*(int8 *)data = 0;
1146		reg_value = get_direct( port->card, 0x24 );
1147		if( reg_value && 0x01 ) *(int8 *)data = 1;
1148		err = B_OK;
1149		break;
1150
1151
1152	case SOUND_SET_SPDIF_MONITOR:
1153		if( *(int8 *)data == 0 ) // disable SPDIF_IN PCM to DAC (CDPlay)
1154			set_direct( port->card, 0x24, 0x00, 0x01 );
1155		else // enable SPDIF_IN PCM to DAC (CDPlay)
1156			set_direct( port->card, 0x24, 0x01, 0x01 );
1157		err = B_OK;
1158		break;
1159
1160	case SOUND_GET_SPDIF_OUT_LEVEL:
1161		*(int8 *)data = 0;
1162		reg_value = get_direct( port->card, 0x1b );
1163		if( reg_value && 0x02 ) *(int8 *)data = 1;
1164		err = B_OK;
1165		break;
1166
1167	case SOUND_SET_SPDIF_OUT_LEVEL:
1168		if( *(int8 *)data == 0 ) // enable SPDIF-OUT optical
1169			set_direct( port->card, 0x1b, 0x00, 0x02 );
1170		else // enable SPDIF-OUT coaxial
1171			set_direct( port->card, 0x1b, 0x02, 0x02 );
1172		break;
1173
1174	case SOUND_GET_SPDIF_IN_FORMAT:
1175		*(int8 *)data = 0;
1176		reg_value = get_direct( port->card, 0x08 );		// Adresse 0x08
1177		if( reg_value && 0x80 ) *(int8 *)data = 1;
1178		err = B_OK;
1179		break;
1180
1181
1182	case SOUND_SET_SPDIF_IN_FORMAT:
1183		if( *(int8 *)data == 0 ) // disable SPDIF inverse (SPDIF normal)
1184			set_direct( port->card, 0x08, 0x00, 0x80 );
1185		else // enable SPDIF inverse
1186			set_direct( port->card, 0x08, 0x80, 0x80 );	// Adresse 0x08, Daten 0x80
1187		err = B_OK;
1188		break;
1189
1190
1191	case SOUND_GET_SPDIF_IN_OUT_COPYRIGHT:
1192		*(int8 *)data = 0;
1193		reg_value = get_direct( port->card, 0x16 );
1194		if( reg_value && 0x40 ) *(int8 *)data = 1;
1195		err = B_OK;
1196		break;
1197
1198	case SOUND_SET_SPDIF_IN_OUT_COPYRIGHT:
1199		if( *(int8 *)data == 0 ) // disable SPDIF-IN/OUT copyright protection
1200			set_direct( port->card, 0x16, 0x00, 0x40 );
1201		else // enable SPDIF-IN/OUT copyright protection
1202			set_direct( port->card, 0x16, 0x40, 0x40 );
1203		err = B_OK;
1204		break;
1205
1206	case SOUND_GET_SPDIF_IN_VALIDITY:
1207		*(int8 *)data = 0;
1208		reg_value = get_direct( port->card, 0x27 );
1209		if( reg_value && 0x02 ) *(int8 *)data = 1;
1210		err = B_OK;
1211		break;
1212
1213	case SOUND_SET_SPDIF_IN_VALIDITY:
1214		if( *(int8 *)data == 0 ) // disable SPDIF-IN validity detection
1215			set_direct( port->card, 0x27, 0x00, 0x02 );
1216		else // enable SPDIF-IN validity detection
1217			set_direct( port->card, 0x27, 0x02, 0x02 );
1218		err = B_OK;
1219		break;
1220// control ports for analog settings
1221
1222	case SOUND_GET_4_CHANNEL_DUPLICATE:
1223		*(int8 *)data = 0;
1224		reg_value = get_direct( port->card, 0x1b );
1225		if( reg_value && 0x04 ) *(int8 *)data = 1;
1226
1227//		0x1b, 0x04, 0x04,	/* dual channel mode enable */
1228//		0x1a, 0x00, 0x80,	/* Double DAC structure disable */
1229
1230		err = B_OK;
1231		break;
1232
1233	case SOUND_SET_4_CHANNEL_DUPLICATE:
1234		if( *(int8 *)data == 0 ) // disable 4 channel analog duplicate mode
1235			set_direct( port->card, 0x1b, 0x00, 0x04 );
1236		else // enable 4 channel analog duplicate mode
1237			set_direct( port->card, 0x1b, 0x04, 0x04 );
1238		err = B_OK;
1239		break;
1240// control ports for additional info
1241
1242	case SOUND_GET_DEVICE_ID:
1243//		*(int32*)data.vendor_id = cards[0].info.vendor_id;
1244//		*(int32*)data.device_id = cards[0].info.device_id;
1245
1246//		static int32 chipinfo[] = { 0,0 };
1247//		chipinfo[0] = cards[0].info.vendor_id;
1248		*(int32*)data = cards[0].info.device_id;
1249
1250//		memcpy(data, &chipinfo, sizeof(chipinfo));
1251		err = B_OK;
1252		break;
1253
1254	case SOUND_GET_INTERNAL_CHIP_ID:
1255		// XXX
1256		break;
1257
1258	case SOUND_GET_DRIVER_VERSION:
1259		memcpy(data, &DriverVersion, sizeof(DriverVersion));
1260		break;
1261
1262	default:
1263		OLDAPI(("cmedia_pci: unknown code %ld\n", iop));
1264		err = B_BAD_VALUE;
1265		break;
1266	}
1267	if ((err == B_OK) && configure) {
1268		cpu_status cp;
1269		KTRACE();
1270		cp = disable_interrupts();
1271		acquire_spinlock(&port->card->hardware);
1272		err = configure_pcm(port, &config, false);
1273		release_spinlock(&port->card->hardware);
1274		restore_interrupts(cp);
1275	}
1276	return err;
1277}
1278
1279
1280static void
1281copy_short_to_float(
1282	float * f,
1283	const short * s,
1284	int c,
1285	int endian)	/*	endian means float data in big-endian	*/
1286{
1287	if (endian) {
1288		while (c > 1) {
1289			short sh = B_LENDIAN_TO_HOST_FLOAT(*s);
1290			*(f++) = B_HOST_TO_BENDIAN_FLOAT((float)B_LENDIAN_TO_HOST_INT16(sh));
1291			s++;
1292			c -= 2;
1293		}
1294	}
1295	else {
1296		while (c > 1) {
1297			short sh = B_LENDIAN_TO_HOST_FLOAT(*s);
1298			*(f++) = B_HOST_TO_LENDIAN_FLOAT((float)B_LENDIAN_TO_HOST_INT16(sh));
1299			s++;
1300			c -= 2;
1301		}
1302	}
1303}
1304
1305
1306static void
1307copy_float_to_short(
1308	short * s,
1309	const float * f,
1310	int c,
1311	int endian)	/*	endian means float data in big-endian	*/
1312{
1313	if (endian) {
1314		while (c > 1) {
1315			float fl = *(f++);
1316			*(s++) = B_HOST_TO_LENDIAN_INT16((float)B_BENDIAN_TO_HOST_FLOAT(fl));
1317			c -= 2;
1318		}
1319	}
1320	else {
1321		while (c > 1) {
1322			float fl = *(f++);
1323			*(s++) = B_HOST_TO_LENDIAN_INT16((float)B_LENDIAN_TO_HOST_FLOAT(fl));
1324			c -= 2;
1325		}
1326	}
1327}
1328
1329
1330static void
1331swap_copy(
1332	short * dest,
1333	const short * src,
1334	int c)
1335{
1336	while (c > 1) {
1337		unsigned short sh = *(src++);
1338		*(dest++) = ((sh << 8) | (sh >> 8));
1339		c -= 2;
1340	}
1341}
1342
1343
1344static status_t
1345pcm_read(
1346	void * cookie,
1347	off_t pos,
1348	void * data,
1349	size_t * nread)
1350{
1351	pcm_dev * port = (pcm_dev *)cookie;
1352	size_t to_read = *nread;
1353	status_t err;
1354	size_t block;
1355	cpu_status cp;
1356	int bytes_xferred;
1357	void * hdrptr = data;
1358	int hdrsize = port->config.buf_header;
1359	cmedia_pci_audio_buf_header hdr;
1360
1361//	ddprintf(("cmedia_pci: pcm_read()\n")); /* we're here */
1362
1363	*nread = 0;
1364	data = ((char *)data)+hdrsize;
1365	to_read -= hdrsize;
1366
1367	err = acquire_sem_etc(port->rd_entry, 1, B_CAN_INTERRUPT, 0);
1368	if (err < B_OK) {
1369		return err;
1370	}
1371
1372	hdr.capture_time = port->rd_time;
1373
1374	goto first_time;
1375
1376	while (to_read > 0) {
1377		/* wait for more data */
1378		atomic_add(&port->read_waiting, 1);
1379		err = acquire_sem_etc(port->read_sem, 1, B_CAN_INTERRUPT, 0);
1380		if (err < B_OK) {
1381			release_sem(port->rd_entry);
1382			return err;
1383		}
1384
1385first_time:	/* we need to check whether anything's available first */
1386		KTRACE();
1387		cp = disable_interrupts();
1388		acquire_spinlock(&port->rd_lock);
1389
1390		block = port->rd_size-port->was_read;
1391
1392		if (port->config.format == 0x24) {
1393			if (block > (to_read>>1)) {	/*	floats expand by factor 2	*/
1394				block = to_read>>1;
1395			}
1396		}
1397		else if (block > to_read) {
1398			block = to_read;
1399		}
1400		switch (port->config.format) {
1401		case 0x24:	/*	floats	*/
1402			copy_short_to_float((float *)data, (const short *)(port->rd_cur+port->was_read),
1403				block, !B_HOST_IS_LENDIAN == !port->config.big_endian);
1404			bytes_xferred = block * 2;
1405			break;
1406		case 0x02:	/*	shorts	*/
1407			if (!B_HOST_IS_LENDIAN == !port->config.big_endian) {
1408				/*	we need to swap	*/
1409				swap_copy((short *)data, (const short *)(port->rd_cur+port->was_read), block);
1410				bytes_xferred = block;
1411				break;
1412			}
1413			/*	else fall through to default case	*/
1414		case 0x11:	/*	bytes	*/
1415		default:
1416			memcpy(data, (void *)(port->rd_cur+port->was_read), block);
1417			bytes_xferred = block;
1418			break;
1419		}
1420		port->was_read += block;
1421
1422		release_spinlock(&port->rd_lock);
1423		restore_interrupts(cp);
1424
1425		to_read -= bytes_xferred;
1426		data = ((char *)data)+bytes_xferred;
1427		*nread += bytes_xferred;
1428	}
1429
1430	/*	provide header if requested	*/
1431	if (hdrsize > 0) {
1432		ddprintf(("header %d\n", hdrsize));
1433		*nread += hdrsize;
1434		hdr.capture_size = *nread;
1435		hdr.sample_rate = port->config.sample_rate;
1436		if ((uint32)hdrsize > sizeof(hdr))
1437			hdrsize = sizeof(hdr);
1438
1439		memcpy(hdrptr, &hdr, hdrsize);
1440	}
1441
1442	release_sem(port->rd_entry);
1443
1444	return B_OK;
1445}
1446
1447
1448static status_t
1449pcm_write(
1450	void * cookie,
1451	off_t pos,
1452	const void * data,
1453	size_t * nwritten)
1454{
1455	pcm_dev * port = (pcm_dev *)cookie;
1456	status_t err;
1457	cpu_status cp;
1458	int written = 0;
1459	int to_write = *nwritten;	/*	 in play bytes, not input bytes!	*/
1460	int block;
1461	int bytes_xferred;
1462
1463//	ddprintf(("cmedia_pci: pcm_write()\n")); /* we're here */
1464
1465	*nwritten = 0;
1466
1467	err = acquire_sem_etc(port->wr_entry, 1, B_CAN_INTERRUPT, 0);
1468	if (err < B_OK) {
1469		return err;
1470	}
1471
1472	atomic_add(&port->write_waiting, 1);
1473	if (port->config.format == 0x24) {
1474		to_write >>= 1;	/*	floats collapse by 2	*/
1475	}
1476	while (to_write > 0) {
1477
1478		/* wait to write */
1479
1480		err = acquire_sem_etc(port->write_sem, 1, B_CAN_INTERRUPT, 0);
1481		if (err < B_OK) {
1482			release_sem(port->wr_entry);
1483			return err;
1484		}
1485
1486#if DEBUG
1487		put_cnt++;
1488		{
1489			bigtime_t delta = system_time() - the_time;
1490			if (delta < 1) {
1491				ddprintf(("cmedia_pci: delta %lld (low!) #%ld\n", delta, put_cnt));
1492			}
1493			else if (delta > 2000) {
1494				ddprintf(("cmedia_pci: delta %lld (high!) #%ld\n", delta, put_cnt));
1495			}
1496		}
1497		if (put_cnt != int_cnt) {
1498	static int last;
1499			if (last != int_cnt-put_cnt)
1500				OLDAPI(("cmedia_pci: %ld mismatch\n", int_cnt-put_cnt));
1501			last = int_cnt-put_cnt;
1502		}
1503#endif /* DEBUG */
1504
1505		KTRACE();
1506		cp = disable_interrupts();
1507		acquire_spinlock(&port->wr_lock);
1508
1509		block = port->wr_size-port->was_written;
1510		if (block > to_write) {
1511			/* must let next guy in */
1512			if (atomic_add(&port->write_waiting, -1) > 0) {
1513				release_sem_etc(port->write_sem, 1, B_DO_NOT_RESCHEDULE);
1514			}
1515			else {
1516				atomic_add(&port->write_waiting, 1); /* undo damage */
1517			}
1518			block = to_write;
1519		}
1520		else if (block < to_write) {
1521			atomic_add(&port->write_waiting, 1); /* we will loop back */
1522		}
1523		switch (port->config.format) {
1524		case 0x24:	/*	floats	*/
1525			copy_float_to_short((short *)(port->wr_cur+port->was_written), (const float *)data,
1526				block, !B_HOST_IS_LENDIAN == !port->config.big_endian);
1527			bytes_xferred = block * 2;
1528			break;
1529		case 0x02:	/*	shorts	*/
1530			if (!B_HOST_IS_LENDIAN == !port->config.big_endian) {
1531				/*	we need to swap	*/
1532				swap_copy((short *)(port->wr_cur+port->was_written), (const short *)data, block);
1533				bytes_xferred = block;
1534				break;
1535			}
1536			/*	else fall through to default case	*/
1537		case 0x11:	/*	bytes	*/
1538		default:
1539			memcpy((void *)(port->wr_cur+port->was_written), data, block);
1540			bytes_xferred = block;
1541			break;
1542		}
1543		port->was_written += block;
1544		port->wr_silence = 0;
1545
1546		release_spinlock(&port->wr_lock);
1547		restore_interrupts(cp);
1548
1549		data = ((char *)data)+bytes_xferred;
1550		written += bytes_xferred;
1551		to_write -= block;
1552	}
1553
1554	*nwritten = written;
1555	release_sem(port->wr_entry);
1556
1557	return B_OK;
1558}
1559
1560
1561bool
1562dma_a_interrupt(
1563	cmedia_pci_dev * dev)
1564{
1565	bool ret = false;
1566	pcm_dev * port = &dev->pcm;
1567	volatile uchar * ptr;
1568	uint32 addr;
1569	uint32 offs;
1570	bigtime_t st = system_time();
1571	int32 ww;
1572
1573#if 0
1574ddprintf(("cmedia_pci: dma_a 0x%x+0x%x\n", PCI_IO_RD_32((int)port->dma_a), PCI_IO_RD_32((int)port->dma_a+4)));
1575#endif
1576//	KTRACE(); /* */
1577	acquire_spinlock(&port->wr_lock);
1578
1579	if (port->write_sem < 0) {
1580		kprintf("cmedia_pci: spurious DMA A interrupt!\n");
1581		release_spinlock(&port->wr_lock);
1582		return false;
1583	}
1584	/* copy possible silence into playback buffer */
1585
1586	if (port->was_written > 0 && port->was_written < port->wr_size) {
1587		if (port->config.format == 0x11) {
1588			memset((void *)(port->wr_cur+port->was_written), 0x80, port->wr_size-port->was_written);
1589		}
1590		else {
1591			memset((void *)(port->wr_cur+port->was_written), 0, port->wr_size-port->was_written);
1592		}
1593	}
1594
1595	/* because the system may be lacking and not hand us the */
1596	/* interrupt in time, we check which half is currently being */
1597	/* played, and set the pointer to the other half */
1598
1599	addr = PCI_IO_RD_32((uint32)port->dma_a);
1600	if ((offs = addr-(uint32)port->card->low_phys) < port->wr_size) {
1601		ptr = port->wr_2;
1602	}
1603	else {
1604		ptr = port->wr_1;
1605	}
1606	port->wr_total += port->config.play_buf_size/2;
1607	/* compensate for interrupt latency */
1608	/* assuming 4 byte frames */
1609	port->wr_time = st-(offs&(port->config.play_buf_size/2-1))*250000LL/(int64)port->config.sample_rate;
1610	if ((ww = atomic_add(&port->wr_time_wait, -1)) > 0) {
1611		release_sem_etc(port->wr_time_sem, 1, B_DO_NOT_RESCHEDULE);
1612		ret = true;
1613	}
1614	else {
1615		atomic_add(&port->wr_time_wait, 1); /* re-set to 0 */
1616	}
1617
1618	if (port->wr_cur == ptr) {
1619		port->wr_skipped++;
1620		OLDAPI(("cmedia_pci: write skipped %ld\n", port->wr_skipped));
1621	}
1622	port->wr_cur = ptr;
1623	port->was_written = 0;
1624
1625	/* check for client there to write into buffer */
1626
1627	if (atomic_add(&port->write_waiting, -1) > 0) {
1628#if DEBUG
1629		int_cnt++;
1630		the_time = st;
1631#endif
1632		release_sem_etc(port->write_sem, 1, B_DO_NOT_RESCHEDULE);
1633		ret = true;
1634	}
1635	else {
1636		atomic_add(&port->write_waiting, 1);
1637		/* if none there, fill with silence */
1638		if (port->wr_silence < (int32)port->config.play_buf_size * 2) {
1639			if (port->config.format == 0x11) {
1640				memset((void *)ptr, 0x80, port->wr_size);
1641			}
1642			else {
1643				memset((void *)ptr, 0, port->wr_size);
1644			}
1645			port->wr_silence += port->wr_size;
1646		}
1647	}
1648	/* copying will be done in user thread */
1649
1650	release_spinlock(&port->wr_lock);
1651	return ret;
1652}
1653
1654
1655bool
1656dma_c_interrupt(
1657	cmedia_pci_dev * dev)
1658{
1659	bool ret = false;
1660	pcm_dev * port = &dev->pcm;
1661	volatile uchar * ptr;
1662	uint32 addr;
1663	uint32 offs;
1664	int32 rr;
1665	bigtime_t st = system_time();
1666
1667	/* mark data as readable in record buffer */
1668#if 0
1669ddprintf(("cmedia_pci: dma_c 0x%x+0x%x\n", PCI_IO_RD_32((int)port->dma_c), PCI_IO_RD_32((int)port->dma_c+4)));
1670#endif
1671//	KTRACE(); /* */
1672	acquire_spinlock(&port->rd_lock);
1673
1674	if (port->read_sem < 0) {
1675		kprintf("cmedia_pci: spurious DMA C interrupt!\n");
1676		release_spinlock(&port->rd_lock);
1677		return false;
1678	}
1679	/* if we lose an interrupt, we automatically avoid constant glitching by setting */
1680	/* the write pointer based on where the DMA counter is everytime */
1681	addr = PCI_IO_RD_32((uint32)port->dma_c);
1682	if ((offs = addr-port->config.play_buf_size-(uint32)port->card->low_phys) < port->rd_size) {
1683		ptr = port->rd_2;
1684	}
1685	else {
1686		ptr = port->rd_1;
1687	}
1688	if (port->rd_cur == ptr) {
1689		port->rd_skipped++;
1690		OLDAPI(("cmedia_pci: read skipped %ld\n", port->rd_skipped));
1691	}
1692	port->rd_total += port->rd_size;
1693
1694	port->rd_cur = ptr;
1695	port->was_read = 0;
1696	port->rd_time = port->next_rd_time;
1697	/*	time stamp when this buffer became available -- compensate for interrupt latency	*/
1698	port->next_rd_time = st-(offs&(port->config.rec_buf_size/2-1))*1000000LL/(int64)port->config.sample_rate;
1699	if ((rr = atomic_add(&port->rd_time_wait, -1)) > 0) {
1700		release_sem_etc(port->rd_time_sem, 1, B_DO_NOT_RESCHEDULE);
1701		ret = true;
1702	}
1703	else {
1704		atomic_add(&port->rd_time_wait, 1); /* re-set to 0 */
1705	}
1706
1707	if (atomic_add(&port->read_waiting, -1) > 0) {
1708		release_sem_etc(port->read_sem, 1, B_DO_NOT_RESCHEDULE);
1709		ret = true;
1710	}
1711	else {
1712		atomic_add(&port->read_waiting, 1);
1713	}
1714	/* copying will be done in the user thread */
1715	release_spinlock(&port->rd_lock);
1716	return ret;
1717}
1718
1719