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