xref: /haiku/src/add-ons/kernel/drivers/audio/cmedia/pcm.c (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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 
15 extern int sprintf(char *, const char *, ...);
16 
17 
18 extern void dump_card(cmedia_pci_dev * card);
19 
20 // Buffer header for audio server from BeOS R3 MediaDefs.h
21 
22 typedef 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
40 int32 int_cnt;
41 int32 put_cnt;
42 bigtime_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 
52 static 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 
76 static status_t pcm_open(const char *name, uint32 flags, void **cookie);
77 static status_t pcm_close(void *cookie);
78 static status_t pcm_free(void *cookie);
79 static status_t pcm_control(void *cookie, uint32 op, void *data, size_t len);
80 static status_t pcm_read(void *cookie, off_t pos, void *data, size_t *len);
81 static 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 
84 device_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 
97 static 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 
114 typedef struct {
115 	uint8 control;
116 	uint8 imask;
117 	uint8 regs[0x2e];
118 } chip_state;
119 
120 static void
121 save_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 
136 static void
137 restore_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 
152 static void
153 reset_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 
164 static void
165 stop_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 
177 static void
178 start_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 
258 static status_t
259 configure_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 
458 static status_t
459 pcm_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 
485 gotit:
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 
626 static status_t
627 pcm_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 
683 static status_t
684 pcm_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 
713 static status_t
714 pcm_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 
1280 static void
1281 copy_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 
1306 static void
1307 copy_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 
1330 static void
1331 swap_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 
1344 static status_t
1345 pcm_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 
1385 first_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 
1448 static status_t
1449 pcm_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 
1561 bool
1562 dma_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
1574 ddprintf(("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 
1655 bool
1656 dma_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
1669 ddprintf(("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