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	static int32 chipinfo[] = { 0,0 };
722	uchar reg_value;
723	char DriverVersion[] = "1.3.2 (Jul 17, 2001)";
724
725	pcm_dev * port = (pcm_dev *)cookie;
726	status_t err = B_BAD_VALUE;
727	pcm_cfg config = port->config;
728	static float rates[7] = { 48000.0, 44100.0, 32000.0, 22050.0, 16000.0, 11025.0, 8000.0 };
729	bool configure = false;
730	config.play_buf_size /= 2;
731	config.rec_buf_size /= 2;
732
733	ddprintf(("cmedia_pci: pcm_control()\n"));
734
735	switch (iop) {
736	case B_AUDIO_GET_AUDIO_FORMAT:
737		memcpy(data, &config, sizeof(port->config));
738		err = B_OK;
739		break;
740	case B_AUDIO_GET_PREFERRED_SAMPLE_RATES:
741		memcpy(data, rates, sizeof(rates));
742		err = B_OK;
743		break;
744	case B_AUDIO_SET_AUDIO_FORMAT:
745		memcpy(&config, data, sizeof(config));
746		configure = true;
747		err = B_OK;
748		break;
749	case SV_RD_TIME_WAIT:
750		atomic_add(&port->rd_time_wait, 1);
751		err = acquire_sem(port->rd_time_sem);
752		if (err >= B_OK) {
753			cpu_status cp;
754			KTRACE();
755			cp = disable_interrupts();
756			acquire_spinlock(&port->rd_lock);
757			((sv_timing *)data)->time = port->rd_time;
758			((sv_timing *)data)->bytes = port->rd_total;
759			((sv_timing *)data)->skipped = port->rd_skipped;
760			((sv_timing *)data)->_reserved_[0] = 0xffffffffUL;
761			release_spinlock(&port->rd_lock);
762			restore_interrupts(cp);
763		}
764		break;
765	case SV_WR_TIME_WAIT:
766		atomic_add(&port->wr_time_wait, 1);
767		err = acquire_sem(port->wr_time_sem);
768		if (err >= B_OK) {
769			cpu_status cp;
770			KTRACE();
771			cp = disable_interrupts();
772			acquire_spinlock(&port->wr_lock);
773			((sv_timing *)data)->time = port->wr_time;
774			((sv_timing *)data)->bytes = port->wr_total;
775			((sv_timing *)data)->skipped = port->wr_skipped;
776			((sv_timing *)data)->_reserved_[0] = 0xffffffffUL;
777			release_spinlock(&port->wr_lock);
778			restore_interrupts(cp);
779		}
780		break;
781	case SV_SECRET_HANDSHAKE: {
782		cpu_status cp;
783		KTRACE();
784		cp = disable_interrupts();
785		acquire_spinlock(&port->wr_lock);
786		acquire_spinlock(&port->rd_lock);
787		((sv_handshake *)data)->wr_time = port->wr_time;
788		((sv_handshake *)data)->wr_skipped = port->wr_skipped;
789		((sv_handshake *)data)->rd_time = port->rd_time;
790		((sv_handshake *)data)->rd_skipped = port->rd_skipped;
791		((sv_handshake *)data)->wr_total = port->wr_total;
792		((sv_handshake *)data)->rd_total = port->rd_total;
793		((sv_handshake *)data)->_reserved_[0] = 0xffffffffUL;
794		err = B_OK;
795		release_spinlock(&port->rd_lock);
796		release_spinlock(&port->wr_lock);
797		restore_interrupts(cp);
798		} break;
799	case SOUND_GET_PARAMS: {
800		cpu_status cp;
801		uchar u;
802		sound_setup * sound = (sound_setup *)data;
803		err = B_OK;
804		cp = disable_interrupts();
805		acquire_spinlock(&port->card->hardware);
806		/* Here we get to hard-code the mix/mux values. */
807		/* Huh-huh; he said "hard-code"! */
808		sound->sample_rate = kHz_44_1;
809		if (!port->config.big_endian == !B_HOST_IS_BENDIAN) {
810			sound->playback_format = linear_16bit_big_endian_stereo;
811			sound->capture_format = linear_16bit_big_endian_stereo;
812		}
813		else {
814			sound->playback_format = linear_16bit_little_endian_stereo;
815			sound->capture_format = linear_16bit_little_endian_stereo;
816		}
817		sound->dither_enable = false;
818		sound->loop_attn = 0;
819		sound->loop_enable = 0;
820		sound->output_boost = 0;
821		sound->highpass_enable = 0;
822		/* this is a master control on C-Media... */
823		u = get_indirect(port->card, 0x30)>>2;
824		sound->mono_gain = u&63;
825		sound->mono_mute = 0;
826
827		/* left channel */
828		u = get_indirect(port->card, 0x3d); // Legacy SB compatible Mixer
829		switch (u)
830		{
831		case 0x10:
832			sound->left.adc_source = line;		//	record line left
833			break;
834
835		case 4:
836			sound->left.adc_source = aux1;		// record CD left ??
837			break;
838
839		case 1:
840			sound->left.adc_source = mic;		// record mic left
841			break;
842
843		default:
844			sound->left.adc_source = loopback;
845			break;
846		}
847		u = get_indirect(port->card, 0x3f)>>4;
848		sound->left.adc_gain = u&15;
849
850		u = get_direct(port->card, 0x25)<<4;
851		sound->left.mic_gain_enable = u&16;
852
853		u = get_indirect(port->card, 0x36)>>3;
854		sound->left.aux1_mix_gain = 31-(u&31);
855
856		u = get_indirect(port->card, 0x3c)<<5;
857		sound->left.aux1_mix_mute = ~u&128;
858
859		u = get_indirect(port->card, 0x34)>>3;
860		sound->left.aux2_mix_gain = 31-(u&31);
861
862		u = get_direct(port->card, 0x24);
863		sound->left.aux2_mix_mute = u&128;
864
865		u = get_indirect(port->card, 0x38)>>3;
866		sound->left.line_mix_gain = 31-(u&31);
867
868		u = get_indirect(port->card, 0x3c)<<3;
869		sound->left.line_mix_mute = ~u&128;
870
871		u = get_indirect(port->card, 0x32)>>2;
872		sound->left.dac_attn = 63-(u&63);
873
874		u = get_direct(port->card, 0x24)<<1;
875		sound->left.dac_mute = u&128;
876
877		/* right channel */
878		u = get_indirect(port->card, 0x3e);
879		switch (u)
880		{
881		case 8:
882			sound->right.adc_source = line;		//record line right
883			break;
884
885		case 2:
886			sound->right.adc_source = aux1;		// record CD right?
887			break;
888
889		case 1:
890			sound->right.adc_source = mic;		// record mic right
891			break;
892
893		default:
894			sound->right.adc_source = loopback;
895			break;
896		}
897		u = get_indirect(port->card, 0x40)>>4;
898		sound->right.adc_gain = u&15;
899		sound->right.mic_gain_enable = sound->left.mic_gain_enable;
900		u = get_indirect(port->card, 0x37)>>3;
901		sound->right.aux1_mix_gain = 31-(u&31);
902		u = get_indirect(port->card, 0x3c)<<6;
903		sound->right.aux1_mix_mute = ~u&128;
904		u = get_indirect(port->card, 0x35)>>3;
905		sound->right.aux2_mix_gain = 31-(u&31);
906		u = get_direct(port->card, 0x24);
907		sound->right.aux2_mix_mute = u&128;
908		u = get_indirect(port->card, 0x39)>>3;
909		sound->right.line_mix_gain = 31-(u&31);
910		u = get_indirect(port->card, 0x3c)<<4;
911		sound->right.line_mix_mute = ~u&128;
912		u = get_indirect(port->card, 0x33)>>2;
913		sound->right.dac_attn = 63-(u&63);
914		u = get_direct(port->card, 0x24)<<1;
915		sound->right.dac_mute = u&128;
916		/* done */
917		release_spinlock(&port->card->hardware);
918		restore_interrupts(cp);
919		} break;
920	case SOUND_SET_PARAMS: {
921		cpu_status cp;
922		uchar u;
923		sound_setup * sound = (sound_setup *)data;
924		err = B_OK;
925		cp = disable_interrupts();
926		acquire_spinlock(&port->card->hardware);
927		/* Here we get to hard-code the mix/mux values. */
928		/* Huh-huh; he said "hard-code"! */
929
930		/* ignore sample rate */
931		sound->sample_rate = kHz_44_1;
932		if (config.sample_rate < 43999 || config.sample_rate > 44201) {
933			config.sample_rate = 44100.0;
934			configure = true;
935		}
936		/* we only support 16-bit formats */
937		if (sound->playback_format == linear_16bit_big_endian_stereo &&
938			sound->capture_format == linear_16bit_big_endian_stereo) {
939			if (!config.big_endian != !B_HOST_IS_BENDIAN || config.format != 0x2) {
940				config.big_endian = B_HOST_IS_BENDIAN;
941				config.format = 0x2;
942				configure = true;
943			}
944			OLDAPI(("same_endian\n"));
945		}
946		else if (sound->playback_format == linear_16bit_little_endian_stereo &&
947			sound->capture_format == linear_16bit_little_endian_stereo) {
948			if (!config.big_endian != !!B_HOST_IS_BENDIAN || config.format != 0x2) {
949				config.big_endian = !B_HOST_IS_BENDIAN;
950				config.format = 0x2;
951				configure = true;
952			}
953			OLDAPI(("other_endian\n"));
954		}
955		else {
956			config.big_endian = !!B_HOST_IS_BENDIAN;
957			configure = true;
958			OLDAPI(("other format!!!\n"));
959		}
960		/* ignore these values */
961		sound->dither_enable = false;
962		sound->loop_attn = 0;
963		sound->loop_enable = 0;
964		sound->output_boost = 0;
965		sound->highpass_enable = 0;
966		/* this is a stereo control on C-Media... */
967		u = (sound->mono_gain>>1)&0x1f;
968		OLDAPI(("output: %x\n", u));
969		set_indirect(port->card, 0x30, u<<3, 0xff);
970		set_indirect(port->card, 0x31, u<<3, 0xff);
971		/* left channel */
972		switch (sound->left.adc_source)
973		{
974		case line:
975			u = 1<<4;
976			break;
977		case aux1:
978			u = 1<<2;
979			break;
980		case mic:
981			u = 1<<0;
982			break;
983		default:
984			u = 0x15;
985			break;
986		}
987		OLDAPI(("input: %x\n", u));
988		set_indirect(port->card, 0x3d, u, 0xff);
989		u = (sound->left.adc_gain&15);
990		set_indirect(port->card, 0x3f, u<<4, 0xff);
991		u = sound->left.mic_gain_enable ? 0 : 0x01;
992		set_direct(port->card, 0x25, u, 0x01);
993		u = 31-(sound->left.aux1_mix_gain&31);
994		OLDAPI(("cd: %x\n", u));
995		set_indirect(port->card, 0x36, u<<3, 0xff);
996		u = sound->left.aux1_mix_mute ? 0 : 0x04;
997		set_indirect(port->card, 0x3c, u, 0x04);
998		u = 31-(sound->left.aux2_mix_gain&31);
999		OLDAPI(("aux2: %x\n", u));
1000		set_indirect(port->card, 0x34, u<<3, 0xff);
1001		u = sound->left.aux2_mix_mute ? 0x80 : 0;
1002		set_direct(port->card, 0x24, u, 0x80);
1003		u = 31-(sound->left.line_mix_gain&31);
1004		OLDAPI(("line: %x\n", u));
1005		set_indirect(port->card, 0x38, u<<3, 0xff);
1006		u = sound->left.line_mix_mute ? 0 : 0x10;
1007		set_indirect(port->card, 0x3c, u, 0x10);
1008		u = 63-(sound->left.dac_attn & 63);
1009		OLDAPI(("PCM: %x\n", u));
1010		set_indirect(port->card, 0x32, u<<2, 0xff);
1011		u = sound->left.dac_mute ? 0x40 : 0;
1012		set_direct(port->card, 0x24, u, 0x40);
1013		/* right channel */
1014		switch (sound->right.adc_source) {
1015		case line:
1016			u = 1<<3;
1017			break;
1018		case aux1:
1019			u = 1<<1;
1020			break;
1021		case mic:
1022			u = 1<<0;
1023			break;
1024		default:
1025			u = 0x0a;
1026			break;
1027		}
1028		sound->right.mic_gain_enable = sound->left.mic_gain_enable;
1029		set_indirect(port->card, 0x3e, u, 0xff);
1030		u = (sound->right.adc_gain&15);
1031		set_indirect(port->card, 0x40, u<<4, 0xff);
1032		u = sound->right.mic_gain_enable ? 0 : 0x01;
1033		set_direct(port->card, 0x25, u, 0x01);
1034		u = 31-(sound->right.aux1_mix_gain&31);
1035		set_indirect(port->card, 0x37, u<<3, 0xff);
1036		u = sound->right.aux1_mix_mute ? 0 : 0x02;
1037		set_indirect(port->card, 0x3c, u, 0x02);
1038		u = 31-(sound->right.aux2_mix_gain&31);
1039		set_indirect(port->card, 0x35, u<<3, 0xff);
1040		u = sound->right.aux2_mix_mute ? 0x80 : 0;
1041		set_direct(port->card, 0x24, u, 0x80);
1042		u = 31-(sound->right.line_mix_gain&31);
1043		set_indirect(port->card, 0x39, u<<3, 0xff);
1044		u = sound->right.line_mix_mute ? 0 : 0x08;
1045		set_indirect(port->card, 0x3c, u, 0x08);
1046		u = 63-(sound->right.dac_attn & 63);
1047		set_indirect(port->card, 0x33, u<<2, 0xff);
1048		u = sound->right.dac_mute ? 0x40 : 0;
1049		set_direct(port->card, 0x24, u, 0x40);
1050		/* done */
1051		release_spinlock(&port->card->hardware);
1052		restore_interrupts(cp);
1053		} break;
1054	case SOUND_SET_PLAYBACK_COMPLETION_SEM:
1055		port->old_play_sem = *(sem_id *)data;
1056		err = B_OK;
1057		break;
1058	case SOUND_SET_CAPTURE_COMPLETION_SEM:
1059		port->old_cap_sem = *(sem_id *)data;
1060		err = B_OK;
1061		break;
1062//	case SOUND_GET_PLAYBACK_TIMESTAMP:
1063//		break;
1064//	case SOUND_GET_CAPTURE_TIMESTAMP:
1065//		break;
1066//	case SOUND_DEBUG_ON:
1067//		break;
1068//	case SOUND_DEBUG_OFF:
1069//		break;
1070	case SOUND_UNSAFE_WRITE: {
1071		audio_buffer_header * buf = (audio_buffer_header *)data;
1072		size_t n = buf->reserved_1-sizeof(*buf);
1073		pcm_write(cookie, 0, buf+1, &n);
1074		buf->time = port->wr_time;
1075		buf->sample_clock = port->wr_total/4 * 10000 / 441;
1076		err = release_sem(port->old_play_sem);
1077		} break;
1078	case SOUND_UNSAFE_READ: {
1079		audio_buffer_header * buf = (audio_buffer_header *)data;
1080		size_t n = buf->reserved_1-sizeof(*buf);
1081		pcm_read(cookie, 0, buf+1, &n);
1082		buf->time = port->rd_time;
1083		buf->sample_clock = port->rd_total/4 * 10000 / 441;
1084		err = release_sem(port->old_cap_sem);
1085		} break;
1086	case SOUND_LOCK_FOR_DMA:
1087		err = B_OK;
1088		break;
1089	case SOUND_SET_PLAYBACK_PREFERRED_BUF_SIZE:
1090		config.play_buf_size = (int32)data;
1091		configure = true;
1092		err = B_OK;
1093		break;
1094	case SOUND_SET_CAPTURE_PREFERRED_BUF_SIZE:
1095		config.rec_buf_size = (int32)data;
1096		configure = true;
1097		err = B_OK;
1098		break;
1099	case SOUND_GET_PLAYBACK_PREFERRED_BUF_SIZE:
1100		*(int32*)data = config.play_buf_size;
1101		err = B_OK;
1102		break;
1103	case SOUND_GET_CAPTURE_PREFERRED_BUF_SIZE:
1104		*(int32*)data = config.rec_buf_size;
1105		err = B_OK;
1106		break;
1107
1108
1109// control ports for SPDIF settings
1110	case SOUND_GET_SPDIF_IN_OUT_LOOPBACK:
1111		*(int8 *)data = 0;
1112		reg_value = get_direct( port->card, 0x04 );
1113		if( reg_value && 0x80 ) *(int8 *)data = 1;
1114		err = B_OK;
1115		break;
1116
1117	case SOUND_SET_SPDIF_IN_OUT_LOOPBACK:
1118		if( *(int8 *)data == 0 ) // disable SPDIF-IN loopback to SPDIF (bypass)
1119			set_direct( port->card, 0x04, 0x00, 0x80 );
1120		else // enable SPDIF-IN loopback to SPDIF (bypass)
1121			set_direct( port->card, 0x04, 0x80, 0x80 );
1122		err = B_OK;
1123		break;
1124
1125
1126
1127
1128	case SOUND_GET_SPDIF_OUT:
1129		*(int8 *)data = 0;
1130		reg_value = get_direct( port->card, 0x16 );			// Adresse 0x16
1131		if( reg_value && 0x80 ) *(int8 *)data = 1;
1132		err = B_OK;
1133		break;
1134
1135	case SOUND_SET_SPDIF_OUT:
1136		if( *(int8 *)data == 0 ) // disable SPDIF-OUT
1137			set_direct( port->card, 0x16, 0x00, 0x80);
1138		else // enable SPDIF-OUT
1139			set_direct( port->card, 0x16, 0x80, 0x80 );
1140		err = B_OK;
1141		break;
1142
1143
1144
1145	case SOUND_GET_SPDIF_MONITOR:
1146		*(int8 *)data = 0;
1147		reg_value = get_direct( port->card, 0x24 );
1148		if( reg_value && 0x01 ) *(int8 *)data = 1;
1149		err = B_OK;
1150		break;
1151
1152
1153	case SOUND_SET_SPDIF_MONITOR:
1154		if( *(int8 *)data == 0 ) // disable SPDIF_IN PCM to DAC (CDPlay)
1155			set_direct( port->card, 0x24, 0x00, 0x01 );
1156		else // enable SPDIF_IN PCM to DAC (CDPlay)
1157			set_direct( port->card, 0x24, 0x01, 0x01 );
1158		err = B_OK;
1159		break;
1160
1161	case SOUND_GET_SPDIF_OUT_LEVEL:
1162		*(int8 *)data = 0;
1163		reg_value = get_direct( port->card, 0x1b );
1164		if( reg_value && 0x02 ) *(int8 *)data = 1;
1165		err = B_OK;
1166		break;
1167
1168	case SOUND_SET_SPDIF_OUT_LEVEL:
1169		if( *(int8 *)data == 0 ) // enable SPDIF-OUT optical
1170			set_direct( port->card, 0x1b, 0x00, 0x02 );
1171		else // enable SPDIF-OUT coaxial
1172			set_direct( port->card, 0x1b, 0x02, 0x02 );
1173		break;
1174
1175	case SOUND_GET_SPDIF_IN_FORMAT:
1176		*(int8 *)data = 0;
1177		reg_value = get_direct( port->card, 0x08 );		// Adresse 0x08
1178		if( reg_value && 0x80 ) *(int8 *)data = 1;
1179		err = B_OK;
1180		break;
1181
1182
1183	case SOUND_SET_SPDIF_IN_FORMAT:
1184		if( *(int8 *)data == 0 ) // disable SPDIF inverse (SPDIF normal)
1185			set_direct( port->card, 0x08, 0x00, 0x80 );
1186		else // enable SPDIF inverse
1187			set_direct( port->card, 0x08, 0x80, 0x80 );	// Adresse 0x08, Daten 0x80
1188		err = B_OK;
1189		break;
1190
1191
1192	case SOUND_GET_SPDIF_IN_OUT_COPYRIGHT:
1193		*(int8 *)data = 0;
1194		reg_value = get_direct( port->card, 0x16 );
1195		if( reg_value && 0x40 ) *(int8 *)data = 1;
1196		err = B_OK;
1197		break;
1198
1199	case SOUND_SET_SPDIF_IN_OUT_COPYRIGHT:
1200		if( *(int8 *)data == 0 ) // disable SPDIF-IN/OUT copyright protection
1201			set_direct( port->card, 0x16, 0x00, 0x40 );
1202		else // enable SPDIF-IN/OUT copyright protection
1203			set_direct( port->card, 0x16, 0x40, 0x40 );
1204		err = B_OK;
1205		break;
1206
1207	case SOUND_GET_SPDIF_IN_VALIDITY:
1208		*(int8 *)data = 0;
1209		reg_value = get_direct( port->card, 0x27 );
1210		if( reg_value && 0x02 ) *(int8 *)data = 1;
1211		err = B_OK;
1212		break;
1213
1214	case SOUND_SET_SPDIF_IN_VALIDITY:
1215		if( *(int8 *)data == 0 ) // disable SPDIF-IN validity detection
1216			set_direct( port->card, 0x27, 0x00, 0x02 );
1217		else // enable SPDIF-IN validity detection
1218			set_direct( port->card, 0x27, 0x02, 0x02 );
1219		err = B_OK;
1220		break;
1221// control ports for analog settings
1222
1223	case SOUND_GET_4_CHANNEL_DUPLICATE:
1224		*(int8 *)data = 0;
1225		reg_value = get_direct( port->card, 0x1b );
1226		if( reg_value && 0x04 ) *(int8 *)data = 1;
1227
1228//		0x1b, 0x04, 0x04,	/* dual channel mode enable */
1229//		0x1a, 0x00, 0x80,	/* Double DAC structure disable */
1230
1231		err = B_OK;
1232		break;
1233
1234	case SOUND_SET_4_CHANNEL_DUPLICATE:
1235		if( *(int8 *)data == 0 ) // disable 4 channel analog duplicate mode
1236			set_direct( port->card, 0x1b, 0x00, 0x04 );
1237		else // enable 4 channel analog duplicate mode
1238			set_direct( port->card, 0x1b, 0x04, 0x04 );
1239		err = B_OK;
1240		break;
1241// control ports for additional info
1242
1243	case SOUND_GET_DEVICE_ID:
1244//		*(int32*)data.vendor_id = cards[0].info.vendor_id;
1245//		*(int32*)data.device_id = cards[0].info.device_id;
1246
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	int 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 (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 %Ld (low!) #%ld\n", delta, put_cnt));
1492			}
1493			else if (delta > 2000) {
1494				ddprintf(("cmedia_pci: delta %Ld (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 < 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