make midimap obey channels
[galan.git] / plugins / emu10k1-lib / dsp.c
blob9620eddf788f393ebf28ee5fadb848e36888c976
1 /*********************************************************************
2 * dsp.c - dsp patch manager library
3 *
4 * Copyright (C) 2000 Rui Sousa
5 *********************************************************************
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
19 * USA.
20 *********************************************************************
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <sys/ioctl.h>
27 #include <sys/soundcard.h>
28 #include <fcntl.h>
30 #include "../emu10k1-include/dsp.h"
31 #include "../emu10k1-include/list.h"
33 #include "../emu10k1-include/internal.h"
35 __u32 addr_change[0x400];
37 __s32 constants[CONSTANTS_SIZE] = {
38 0x0,
39 0x1,
40 0x2,
41 0x3,
42 0x4,
43 0x8,
44 0x10,
45 0x20,
46 0x100,
47 0x10000,
48 0x80000,
49 0x10000000,
50 0x20000000,
51 0x40000000,
52 0x80000000,
53 0x7fffffff,
54 0xffffffff,
55 0xfffffffe,
56 0xc0000000,
57 0x4f1bbcdc,
58 0x5a7ef9db,
59 0x00100000
62 /* FIXME */
63 /* these should have better names (and probably dependent on the card model) */
64 char dsp_in_name[DSP_NUM_INPUTS][DSP_LINE_NAME_SIZE] =
65 { "Pcm L", "Pcm R", "fx2", "fx3", "Pcm1 L", "Pcm1 R", "fx6", "fx7",
66 "fx8", "fx9", "fx10", "fx11", "fx12", "fx13", "fx14", "fx15",
67 "Analog L", "Analog R", "CD-Spdif L", "CD-Spdif R", "in2l", "in2r", "Opt. Spdif L", "Opt. Spdif R",
68 "Line2/Mic2 L", "Line2/Mic2 R", "RCA Spdif L", "RCA Spdif R","RCA Aux L", "RCA Aux R", "in7l", "in7r"
70 char dsp_out_name[DSP_NUM_OUTPUTS][DSP_LINE_NAME_SIZE] =
71 { "Front L", "Front R", "Digital L", "Digital R", "Digital Center", "Digital LFE", "Phones L", "Phones R",
72 "Rear L", "Rear R", "ADC Rec L", "ADC Rec R", "Mic Rec", "out6r", "out7l", "out7r",
73 "out8l", "Analog Center", "Analog LFE", "out9r", "out10l", "out10r", "out11l", "out11r",
74 "out12l", "out12r", "out13l", "out13r", "out14l", "out14r", "out15l", "out15r"
76 char dsp_stereo_in_name[DSP_NUM_INPUTS/2][DSP_LINE_NAME_SIZE] =
77 { "Pcm", "fx2-3", "Pcm1", "fx6-7",
78 "fx8-9", "fx10-11", "fx12-13", "fx14-15",
79 "Analog", "CD-Spdif", "in2", "Opt. Spdif",
80 "Line2/Mic2", "RCA Spdif","RCA Aux", "in7"
82 char dsp_stereo_out_name[DSP_NUM_OUTPUTS/2][DSP_LINE_NAME_SIZE] =
83 { "Front", "Digital", "Digital Ctr/lfe", "Phones",
84 "Rear", "ADC Rec", "out6", "out7",
85 "out8", "out9", "out10", "out11",
86 "out12", "out13", "out14", "out15"
88 char *oss_mixer_name[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
91 int find_control_gpr_addr(struct dsp_patch_manager *mgr, const char *patch_name, const char *gpr_name)
93 struct dsp_rpatch *rpatch;
94 struct dsp_patch *patch;
95 struct list_head *entry;
96 char s[DSP_PATCH_NAME_SIZE + 4];
97 __u32 *gpr_used;
98 int i;
100 list_for_each(entry, &mgr->ipatch_list) {
101 patch = list_entry(entry, struct dsp_patch, list);
102 if (patch->id)
103 sprintf(s, "%s %d", patch->name, patch->id);
104 else
105 sprintf(s, "%s", patch->name);
107 if (!strcmp(s, patch_name)) {
108 gpr_used = patch->gpr_used;
109 goto match;
114 rpatch = &mgr->rpatch;
115 if (!strcmp(rpatch->name, patch_name)) {
116 gpr_used = rpatch->gpr_used;
117 goto match;
121 list_for_each(entry, &mgr->opatch_list) {
122 patch = list_entry(entry, struct dsp_patch, list);
123 if (patch->id)
124 sprintf(s, "%s %d", patch->name, patch->id);
125 else
126 sprintf(s, "%s", patch->name);
128 if (!strcmp(s, patch_name)) {
129 gpr_used = patch->gpr_used;
130 goto match;
134 return -1;
136 match:
138 for (i = 0; i < DSP_NUM_GPRS; i++) {
139 if ((mgr->gpr[i].type == GPR_TYPE_CONTROL)
140 && test_bit(i, gpr_used)
141 && !strcmp(mgr->gpr[i].name, gpr_name))
142 return GPR_BASE + i;
145 return -1;
148 int get_constant_gpr(struct dsp_patch_manager *mgr, __s32 val, __u32 * used)
150 int i;
152 for (i = 0; i < CONSTANTS_SIZE; i++)
153 /* if it's a hardwired constant use it */
154 if (constants[i] == val)
155 return CONSTANTS_BASE + i;
157 for (i = 0; i < DSP_NUM_GPRS; i++) {
158 /* see if he have this global gpr already */
159 if (mgr->gpr[i].type == GPR_TYPE_CONSTANT && mgr->gpr[i].value == val && mgr->gpr[i].usage < 255)
160 goto match;
163 for (i = 0; i < DSP_NUM_GPRS; i++) {
164 /* assign a new free GPR */
165 if (mgr->gpr[i].type == GPR_TYPE_NULL){
166 mgr->gpr[i].usage=0;
167 goto match;
172 fprintf(stderr, "get_constant_gpr(): no available gprs\n");
173 return -1;
175 match:
177 if (!test_and_set_bit(i, used)) {
178 mgr->gpr[i].type = GPR_TYPE_CONSTANT;
179 mgr->gpr[i].addr = i;
180 mgr->gpr[i].usage++;
181 mgr->gpr[i].value = val;
184 return GPR_BASE + i;
187 int get_dynamic_gpr(struct dsp_patch_manager *mgr, __u32 * used)
189 int i;
191 for (i = 0; i < DSP_NUM_GPRS; i++) {
192 /* overlap DYNAMIC gprs from different patches */
193 if ((mgr->gpr[i].type == GPR_TYPE_DYNAMIC)
194 && !test_bit(i, used) && mgr->gpr[i].usage < 255)
195 goto match;
198 for (i = 0; i < DSP_NUM_GPRS; i++) {
199 /* assign a new free GPR */
200 if (mgr->gpr[i].type == GPR_TYPE_NULL){
201 mgr->gpr[i].usage=0;
202 goto match;
208 fprintf(stderr, "get_dynamic_gpr(): no available gprs\n");
209 return -1;
211 match:
213 set_bit(i, used);
214 mgr->gpr[i].type = GPR_TYPE_DYNAMIC;
215 mgr->gpr[i].addr = i;
216 mgr->gpr[i].usage++;
218 return i + GPR_BASE;
221 int get_static_gpr(struct dsp_patch_manager *mgr, __s32 val, __u32 * used)
223 int i;
225 /* these can't be shared so just get a new one */
226 for (i = 0; i < DSP_NUM_GPRS; i++) {
227 /* free */
228 if (mgr->gpr[i].type == GPR_TYPE_NULL)
229 goto match;
232 fprintf(stderr, "get_static_gpr(): no available gprs\n");
233 return -1;
235 match:
237 set_bit(i, used);
238 mgr->gpr[i].type = GPR_TYPE_STATIC;
239 mgr->gpr[i].addr = i;
240 mgr->gpr[i].usage=1;
241 mgr->gpr[i].value = val;
243 return GPR_BASE + i;
246 /* We don't match IO gprs here, we just don't waste any (maximum of 2 per line) */
247 int get_io_gpr(struct dsp_patch_manager *mgr, int line, int type, __u32 * used, __u32 * input)
249 int i;
251 line &= 0x1f;
253 /* return an already allocated one (but not in use by this patch */
254 if (mgr->io[line][0] >= 0) {
255 if (!test_bit(mgr->io[line][0], used)) {
256 i = mgr->io[line][0];
257 goto match;
261 if (mgr->io[line][1] >= 0) {
262 if (!test_bit(mgr->io[line][1], used)) {
263 i = mgr->io[line][1];
264 goto match;
268 /* get a free one */
269 for (i = 0; i < DSP_NUM_GPRS; i++) {
270 if (mgr->gpr[i].type == GPR_TYPE_NULL) {
271 mgr->gpr[i].usage=0;
272 if (mgr->io[line][0] < 0)
273 mgr->io[line][0] = i;
274 else if (mgr->io[line][1] < 0)
275 mgr->io[line][1] = i;
276 else {
277 fprintf(stderr, "get_io_gpr(): more than two io gprs per line\n");
278 return -1;
280 goto match;
284 fprintf(stderr, "get_io_gpr(): no available gprs\n");
285 return -1;
287 match:
289 set_bit(i, used);
290 if (type == GPR_INPUT)
291 set_bit(i, input);
293 mgr->gpr[i].type = GPR_TYPE_IO;
294 mgr->gpr[i].addr = i;
295 mgr->gpr[i].line = line;
296 mgr->gpr[i].usage++;
297 mgr->gpr[i].value = 0;
299 return GPR_BASE + i;
302 int get_control_gpr(struct dsp_patch_manager *mgr, __s32 val, __s32 min, __s32 max,
303 const char *name, __u32 * used, const char *patch_name)
305 int i;
307 //if another instance of same patch is loaded, we'll use it's control gpr:
308 if(patch_name!=NULL)
309 if( (i=find_control_gpr_addr(mgr, patch_name, name)) != -1){
310 mgr->gpr[i-GPR_BASE].usage++;
311 set_bit(i-GPR_BASE, used);
312 return i;
315 for (i = 0; i < DSP_NUM_GPRS; i++) {
316 /* free */
317 if (mgr->gpr[i].type == GPR_TYPE_NULL){
318 mgr->gpr[i].usage=0;
319 mgr->gpr[i].mixer_id = SOUND_MIXER_NONE;
320 goto match;
324 fprintf(stderr, "get_control_gpr(): no available gprs\n");
325 return -1;
327 match:
329 set_bit(i, used);
330 mgr->gpr[i].type = GPR_TYPE_CONTROL;
331 mgr->gpr[i].addr = i;
332 mgr->gpr[i].value = val;
333 mgr->gpr[i].min_val = min;
334 mgr->gpr[i].max_val = max;
335 mgr->gpr[i].usage++;
336 strncpy(mgr->gpr[i].name, name, DSP_GPR_NAME_SIZE);
337 mgr->gpr[i].name[DSP_GPR_NAME_SIZE - 1] = '\0';
339 return GPR_BASE + i;
342 /* get an already allocated gpr by address */
343 int get_gpr(struct dsp_patch_manager *mgr, int addr, __u32 * used)
345 if (test_bit(addr, used))
346 return GPR_BASE + addr;
347 else {
348 if (mgr->gpr[addr].type == GPR_TYPE_NULL)
349 return -1;
351 if (mgr->gpr[addr].usage == 1 && mgr->gpr[addr].type == GPR_TYPE_STATIC)
352 return -1;
354 if (mgr->gpr[addr].usage == 255)
355 return -1;
357 set_bit(addr, used);
358 mgr->gpr[addr].usage++;
361 return GPR_BASE + addr;
364 int free_gpr(struct dsp_patch_manager *mgr, int addr, __u32 * used)
366 if (!test_bit(addr, used))
367 return -1;
369 clear_bit(addr, used);
371 mgr->gpr[addr].usage--;
373 if (mgr->gpr[addr].usage == 0) {
374 if (mgr->gpr[addr].type == GPR_TYPE_IO) {
375 if (mgr->io[mgr->gpr[addr].line][0] == addr)
376 mgr->io[mgr->gpr[addr].line][0] = -1;
377 else
378 mgr->io[mgr->gpr[addr].line][1] = -1;
381 mgr->gpr[addr].type = GPR_TYPE_NULL;
384 return 0;
387 static void free_all_gprs(struct dsp_patch_manager *mgr, __u32 * used)
389 int i;
391 for (i = 0; i < DSP_NUM_GPRS; i++)
392 free_gpr(mgr, i, used);
397 /* returns 1 if the code contains a particular address (val) */
398 static int search_code(struct dsp_patch *patch, int val)
400 int i;
402 for (i = 0; i < patch->code_size / 2; i++)
403 if (((patch->code[i * 2 + 1] >> 10) & 0x3ff) == val ||
404 (patch->code[i * 2 + 1] & 0x3ff) == val ||
405 ((patch->code[i * 2] >> 10) & 0x3ff) == val || (patch->code[i * 2] & 0x3ff) == val)
406 return 1;
408 return 0;
411 void init_io_gprs_table(struct dsp_patch_manager *mgr)
413 int line, i;
415 for (i = 0; i < DSP_NUM_INPUTS; i++) {
416 mgr->io[i][0] = -1;
417 mgr->io[i][1] = -1;
420 /* construct table of possible io gprs for each line */
421 for (i = 0; i < DSP_NUM_GPRS; i++)
422 if (mgr->gpr[i].type == GPR_TYPE_IO) {
423 line = mgr->gpr[i].line & 0x3f;
424 if (mgr->io[line][0] == -1)
425 mgr->io[line][0] = mgr->gpr[i].addr;
426 else if (mgr->io[line][1] == -1)
427 mgr->io[line][1] = mgr->gpr[i].addr;
428 else {
429 fprintf(stderr, "init_io_gprs_table(): more than 2 io gprs\n");
430 exit(EXIT_FAILURE);
437 void determine_io(struct dsp_patch_manager *mgr, struct dsp_patch *patch)
439 int gpr0, gpr1;
440 int i;
442 for (i=0;i<DSP_NUM_INPUTS;i++){
443 if(test_bit(i,&patch->input)){
444 gpr0 = mgr->io[i][0];
445 gpr1 = mgr->io[i][1];
446 /* determine patch input */
447 if (gpr0 != -1 && test_bit(gpr0, patch->gpr_input))
448 patch->in_gprs[i] = GPR_BASE + gpr0;
449 else if (gpr1 != -1 && test_bit(gpr1, patch->gpr_input))
450 patch->in_gprs[i] = GPR_BASE + gpr1;
451 else if (search_code(patch, i))
452 patch->in_gprs[i] = i;
453 else
454 patch->in_gprs[i] = -1;
458 for(i=0;i<DSP_NUM_OUTPUTS;i++){
459 if(test_bit(i,&patch->output)){
461 gpr0 = mgr->io[i][0];
462 gpr1 = mgr->io[i][1];
464 /* determine patch output */
465 if (gpr0 != -1 && test_bit(gpr0, patch->gpr_used) && !test_bit(gpr0, patch->gpr_input))
466 patch->out_gprs[i] = GPR_BASE + gpr0;
467 else if (gpr1 != -1 && test_bit(gpr1, patch->gpr_used) && !test_bit(gpr1, patch->gpr_input))
468 patch->out_gprs[i] = GPR_BASE + gpr1;
469 else if (search_code(patch, OUTPUT_BASE + i))
470 patch->out_gprs[i] = OUTPUT_BASE + i;
471 else
472 patch->out_gprs[i] = -1;
477 void init_addr_change_table(__u32 * table, __u32 min, __u32 max)
479 int i;
481 for (i = min; i < max; i++)
482 table[i - min] = i;
486 void search_and_replace(__u32 * code, __u32 size, __u32 * table, __u32 min, __u32 max)
488 __u32 operand[2];
489 int i;
491 for (i = 0; i < size; i++) {
492 operand[0] = code[i] & 0x000003ff;
493 operand[1] = (code[i] & 0x000ffc00) >> 10;
495 if (operand[0] < max && operand[0] >= min)
496 operand[0] = table[operand[0] - min];
498 if (operand[1] < max && operand[1] >= min)
499 operand[1] = table[operand[1] - min];
501 code[i] = (code[i] & ~0x000fffff) | ((operand[1] & 0x3ff) << 10)
502 | (operand[0] & 0x3ff);
505 return;
508 int dsp_find_patch(struct dsp_patch_manager *mgr, const char *name, struct dsp_patch **patch_in)
510 struct dsp_patch *patch;
511 struct list_head *entry;
512 char s[DSP_PATCH_NAME_SIZE + 4];
514 list_for_each(entry, &mgr->ipatch_list) {
515 patch = list_entry(entry, struct dsp_patch, list);
516 if (patch->id)
517 sprintf(s, "%s %d", patch->name, patch->id);
518 else
519 sprintf(s, "%s", patch->name);
521 if (!strcmp(s, name)) {
522 *patch_in=patch;
523 return 0;
527 list_for_each(entry, &mgr->opatch_list) {
528 patch = list_entry(entry, struct dsp_patch, list);
530 if (patch->id)
531 sprintf(s, "%s %d", patch->name, patch->id);
532 else
533 sprintf(s, "%s", patch->name);
535 if (!strcmp(s, name)){
536 *patch_in=patch;
537 return 0;
540 *patch_in=NULL;
541 return -1;
544 int dsp_unload_patch(struct dsp_patch_manager *mgr, const char *name)
546 struct dsp_patch *patch;
549 if (!mgr->init)
550 dsp_init(mgr);
552 if(dsp_find_patch(mgr, name, &patch) < 0 )
553 return -1;
555 list_del(&patch->list);
556 free_all_gprs(mgr, patch->gpr_used);
557 mgr->code_free_start -= patch->code_size;
558 mgr->traml_efree_start -= patch->traml_esize;
559 mgr->traml_ifree_start -= patch->traml_isize;
560 mgr->tramb_efree_start -= patch->tramb_esize;
561 mgr->tramb_ifree_start -= patch->tramb_isize;
562 free(patch->traml_iaddr);
563 free(patch->traml_eaddr);
564 free(patch->code);
565 free(patch);
567 return 0;
570 int dsp_set_patch_name(struct dsp_patch_manager *mgr, const char *patch, const char *new)
572 return -1;
575 int dsp_set_control_gpr_value(struct dsp_patch_manager *mgr, const char *patch, const char *gpr, __s32 val)
577 struct mixer_private_ioctl ctl;
578 int addr,ret;
580 if (mgr->init) {
581 addr = find_control_gpr_addr(mgr, patch, gpr);
582 if (addr < 0)
583 return addr;
585 addr -= GPR_BASE;
587 if (val > mgr->gpr[addr].max_val)
588 val = mgr->gpr[addr].max_val;
589 else if (val < mgr->gpr[addr].min_val)
590 val = mgr->gpr[addr].min_val;
592 mgr->gpr[addr].value = val;
596 ctl.cmd = CMD_SETCTLGPR;
597 memcpy((char *) ctl.val, patch, DSP_PATCH_NAME_SIZE);
598 memcpy((char *) ctl.val + DSP_PATCH_NAME_SIZE, gpr, DSP_PATCH_NAME_SIZE);
599 memcpy((char *) ctl.val + 2 * DSP_PATCH_NAME_SIZE, &val, sizeof(__s32));
601 ret = ioctl(mgr->mixer_fd, SOUND_MIXER_PRIVATE3, &ctl);
602 if (ret < 0) {
603 perror("SOUND_MIXER_PRIVATE3");
604 return ret;
607 return 0;
610 int dsp_get_control_gpr_value(struct dsp_patch_manager *mgr, const char *patch, const char *gpr, __s32 * val)
612 struct mixer_private_ioctl ctl;
613 int addr;
614 int ret;
616 if (mgr->init) {
617 addr = find_control_gpr_addr(mgr, patch, gpr);
618 if (addr < 0)
619 return addr;
621 addr -= GPR_BASE;
623 *val = mgr->gpr[addr].value;
624 } else {
626 ctl.cmd = CMD_GETCTLGPR;
627 memcpy(ctl.val, patch, DSP_PATCH_NAME_SIZE);
628 memcpy((char *) ctl.val + DSP_PATCH_NAME_SIZE, gpr, DSP_PATCH_NAME_SIZE);
630 ret = ioctl(mgr->mixer_fd, SOUND_MIXER_PRIVATE3, &ctl);
631 if (ret < 0) {
632 perror("SOUND_MIXER_PRIVATE3");
633 return ret;
636 *val = (__s32) ctl.val[0];
639 return 0;
642 static void construct_input_buffer(struct dsp_patch_manager *mgr, __u32 * operand, __u32 * buffer_code,
643 int *buffer_size)
645 int addr;
646 int i;
648 for (i = 1; i < 3; i++)
649 if (operand[i] < OUTPUT_BASE && operand[i + 1] < OUTPUT_BASE &&
650 addr_change[operand[i]] < OUTPUT_BASE && addr_change[operand[i + 1]] < OUTPUT_BASE) {
651 addr = get_dynamic_gpr(mgr, mgr->rpatch.gpr_used);
652 addr_change[operand[i]] = addr;
653 buffer_code[*buffer_size + 1] = 0x6 << 20 | addr << 10 | operand[i];
654 buffer_code[*buffer_size] = 0x40 << 10 | 0x40;
655 *buffer_size += 2;
659 int construct_routing(struct dsp_patch_manager *mgr)
661 struct dsp_rpatch *rpatch;
662 struct list_head *entry;
663 struct dsp_patch *patch;
664 __u32 op, operand[4];
665 char name[DSP_GPR_NAME_SIZE];
666 __u32 buffer_code[DSP_NUM_INPUTS * 2];
667 int buffer_size;
668 int i, j;
669 int route, route_v;
670 int addr;
672 /* release io and dynamic gprs of the routing patch */
673 for (i = 0; i < DSP_NUM_GPRS; i++)
674 if (test_bit(i, mgr->rpatch.gpr_used) &&
675 (mgr->gpr[i].type == GPR_TYPE_IO ||
676 mgr->gpr[i].type == GPR_TYPE_DYNAMIC)) free_gpr(mgr, i, mgr->rpatch.gpr_used);
678 rpatch = &mgr->rpatch;
680 for (i = 0; i < DSP_NUM_INPUTS; i++)
681 if (rpatch->in[i] >= GPR_BASE) {
682 get_gpr(mgr, rpatch->in[i] - GPR_BASE, rpatch->gpr_used);
683 set_bit(rpatch->in[i] - GPR_BASE, rpatch->gpr_input);
686 for (i = 0; i < DSP_NUM_OUTPUTS; i++)
687 rpatch->out[i] = -1;
689 buffer_size = 0;
690 mgr->code_free_start -= rpatch->code_size;
691 rpatch->code_size = 0;
693 init_addr_change_table(addr_change, 0, OUTPUT_BASE);
695 for (i = 0; i < DSP_NUM_OUTPUTS; i++) {
696 if (mgr->rpatch.route[i] != 0 || mgr->rpatch.route_v[i] != 0) {
697 route = 0;
698 route_v = 0;
699 j = 1;
700 op = 0x6;
702 while (route < DSP_NUM_INPUTS || route_v < DSP_NUM_INPUTS) {
704 /* find next active route */
705 while (!test_bit(route, &mgr->rpatch.route[i])
706 && route < DSP_NUM_INPUTS)
707 route++;
709 while (!test_bit(route_v, &mgr->rpatch.route_v[i])
710 && route_v < DSP_NUM_INPUTS)
711 route_v++;
713 /* a complete op and there are more arguments */
714 if (j == 4 && (route < DSP_NUM_INPUTS || route_v < DSP_NUM_INPUTS)) {
715 /* if we need an output gpr use it also for temporary storage */
716 if (rpatch->out[i] < 0)
717 rpatch->out[i] =
718 get_io_gpr(mgr, i, GPR_OUTPUT, rpatch->gpr_used, rpatch->gpr_input);
720 if (rpatch->out[i] < 0)
721 return -1;
723 operand[0] = rpatch->out[i];
725 rpatch->code[rpatch->code_size + 1] = op << 20 | operand[0] << 10 | operand[1];
728 rpatch->code[rpatch->code_size] = operand[2] << 10 | operand[3];
730 rpatch->code_size += 2;
732 construct_input_buffer(mgr, operand, buffer_code, &buffer_size);
734 op = 0x6;
735 operand[1] = rpatch->out[i];
736 j = 2;
739 if ((j == 2 || route >= DSP_NUM_INPUTS) && route_v < DSP_NUM_INPUTS) {
740 if (j == 1)
741 operand[1] = 0x40;
743 operand[2] = rpatch->in[route_v];
745 sprintf(name, "Vol %s:%s", dsp_in_name[route_v], dsp_out_name[i]);
747 /* find control gpr for this route */
748 /* if there isn't any create one */
749 addr = find_control_gpr_addr(mgr, rpatch->name, name);
750 if (addr < 0) {
751 addr =
752 get_control_gpr(mgr, 0x7fffffff, 0, 0x7fffffff,
753 name, rpatch->gpr_used, NULL);
754 if (addr < 0)
755 return -1;
758 op = 0x0;
759 operand[3] = addr;
760 j = 4;
761 route_v++;
763 } else if (route < DSP_NUM_INPUTS) {
764 operand[j++] = rpatch->in[route];
765 route++;
769 while (j < 4)
770 operand[j++] = 0x40;
772 addr = rpatch->out[i];
773 rpatch->out[i] = OUTPUT_BASE + i;
775 list_for_each(entry, &mgr->opatch_list) {
777 patch = list_entry(entry, struct dsp_patch, list);
778 //Reminder: check this to make sure its ok:
779 if(patch_uses_output(patch,i)){
781 if (patch->in_gprs[i] > 0) {
782 if (addr < 0)
783 rpatch->out[i] = get_io_gpr(mgr, i,
784 GPR_OUTPUT, rpatch->gpr_used,
785 rpatch->gpr_input);
786 else
787 rpatch->out[i] = addr;
788 break;
794 operand[0] = rpatch->out[i];
796 rpatch->code[rpatch->code_size + 1] = op << 20 | operand[0] << 10 | operand[1];
798 rpatch->code[rpatch->code_size] = operand[2] << 10 | operand[3];
799 rpatch->code_size += 2;
801 construct_input_buffer(mgr, operand, buffer_code, &buffer_size);
805 search_and_replace(rpatch->code, rpatch->code_size, addr_change, 0, OUTPUT_BASE);
807 if (buffer_size + rpatch->code_size > DSP_CODE_SIZE) {
808 fprintf(stderr, "routing patch to big\n");
809 return -1;
812 memmove(rpatch->code + buffer_size, rpatch->code, rpatch->code_size * sizeof(__u32));
813 memcpy(rpatch->code, buffer_code, buffer_size * sizeof(__u32));
814 rpatch->code_size += buffer_size;
815 mgr->code_free_start += rpatch->code_size;
817 if (mgr->code_free_start > DSP_CODE_SIZE) {
818 fprintf(stderr, "no free dsp code memory\n");
819 return -1;
822 return 0;
826 int get_input_name(const char *input)
828 int i;
830 for (i = 0; i < DSP_NUM_INPUTS; i++)
831 if (!strcasecmp(input, dsp_in_name[i]))
832 return i;
834 return -1;
837 int get_output_name(const char *output)
839 int i;
841 for (i = 0; i < DSP_NUM_OUTPUTS; i++)
842 if (!strcasecmp(output, dsp_out_name[i]))
843 return i;
845 return -1;
848 int get_stereo_input_name(const char *input)
850 int i;
852 for (i = 0; i < DSP_NUM_INPUTS/2; i++)
853 if (!strcasecmp(input, dsp_stereo_in_name[i]))
854 return i*2;
855 return -1;
858 int get_stereo_output_name(const char *output)
860 int i;
862 for (i = 0; i < DSP_NUM_OUTPUTS/2; i++)
863 if (!strcasecmp(output, dsp_stereo_out_name[i]))
864 return i*2;
865 return -1;
868 static int get_stereo_route_name(struct dsp_patch_manager *mgr, const char *name, int *in1, int *in2, int *out1, int *out2)
870 char route_name[2 *DSP_LINE_NAME_SIZE +2],*out_ptr;
871 int ret=0;
873 strcpy(route_name,name);
874 strtok_r(route_name,":" , &out_ptr);
876 if((ret = get_input_name(route_name)) >= 0){
877 *in1=ret;
878 *in2=-1;
879 }else if((ret = get_stereo_input_name(route_name)) >= 0){
880 *in1=ret;
881 *in2=ret+1;
882 }else
883 return -1;
885 if((ret = get_output_name(out_ptr)) >= 0){
886 *out1=ret;
887 *out2=-1;
888 }else if ( (ret = get_stereo_output_name(out_ptr)) >= 0 ){
889 *out1=ret;
890 *out2=ret+1;
891 }else
892 return -1;
895 return 0;
898 static int get_route_name(struct dsp_patch_manager *mgr, const char *name, int *in, int *out)
900 char route_name[2 * DSP_LINE_NAME_SIZE + 2];
902 for (*in = 0; *in < DSP_NUM_INPUTS; (*in)++)
903 for (*out = 0; *out < DSP_NUM_OUTPUTS; (*out)++) {
904 sprintf(route_name, "%s:%s", dsp_in_name[*in], dsp_out_name[*out]);
905 if (!strcmp(name, route_name))
906 return 0;
909 return -1;
912 int dsp_check_input(struct dsp_patch_manager *mgr, int in)
914 struct dsp_rpatch *rpatch = &mgr->rpatch;
915 int i;
917 if (in < 0 || in > DSP_NUM_INPUTS)
918 return 0;
920 for (i = 0; i < DSP_NUM_OUTPUTS; i++)
921 if (test_bit(in, &rpatch->route[i]) || test_bit(in, &rpatch->route_v[i]))
922 return 1;
924 return 0;
927 int dsp_check_input_name(struct dsp_patch_manager *mgr, const char *input)
929 int in;
931 in = get_input_name(input);
932 return dsp_check_input(mgr, in);
935 int dsp_check_output(struct dsp_patch_manager *mgr, int out)
937 struct dsp_rpatch *rpatch = &mgr->rpatch;
939 if (out < 0 || out > DSP_NUM_OUTPUTS)
940 return 0;
942 if (rpatch->route[out] || rpatch->route_v[out])
943 return 1;
945 return 0;
948 int dsp_check_output_name(struct dsp_patch_manager *mgr, const char *output)
950 int out;
952 out = get_output_name(output);
953 return dsp_check_output(mgr, out);
956 int dsp_check_route(struct dsp_patch_manager *mgr, int in, int out)
958 struct dsp_rpatch *rpatch = &mgr->rpatch;
960 if (in < 0 || in > DSP_NUM_INPUTS || out < 0 || out > DSP_NUM_OUTPUTS)
961 return 0;
963 if (test_bit(in, &rpatch->route[out]) || test_bit(in, &rpatch->route_v[out]))
964 return 1;
966 return 0;
969 int dsp_check_route_volume(struct dsp_patch_manager *mgr, int in, int out)
971 struct dsp_rpatch *rpatch = &mgr->rpatch;
973 if (in < 0 || in > DSP_NUM_INPUTS || out < 0 || out > DSP_NUM_OUTPUTS)
974 return 0;
976 if (test_bit(in, &rpatch->route_v[out]))
977 return 1;
979 return 0;
982 int dsp_check_route_name(struct dsp_patch_manager *mgr, const char *name)
984 int in, out;
986 get_route_name(mgr, name, &in, &out);
987 return dsp_check_route(mgr, in, out);
990 int dsp_input_unused( struct list_head *list, int line)
992 struct list_head *entry;
993 struct dsp_patch *patch;
995 list_for_each(entry, list) {
996 patch = list_entry(entry, struct dsp_patch, list);
997 if (test_bit(line,&patch->input))
998 return 0;
1000 return 1;
1003 int dsp_output_unused( struct list_head *list, int line)
1005 struct list_head *entry;
1006 struct dsp_patch *patch;
1008 list_for_each(entry, list) {
1009 patch = list_entry(entry, struct dsp_patch, list);
1010 if (test_bit(line,&patch->output))
1011 return 0;
1013 return 1;
1017 int dsp_del_route(struct dsp_patch_manager *mgr, int in, int out)
1019 struct dsp_rpatch *rpatch = &mgr->rpatch;
1020 char s[2 * DSP_LINE_NAME_SIZE + 5];
1021 int addr;
1022 int i;
1024 if (in < 0 || in > DSP_NUM_INPUTS || out < 0 || out > DSP_NUM_OUTPUTS)
1025 return -1;
1027 if (!mgr->init)
1028 dsp_init(mgr);
1030 if (test_and_clear_bit(in, &rpatch->route[out])) {
1031 /* don't remove the route if it is the last one connected to a dsp program */
1032 if ( ( rpatch->route[out] || rpatch->route_v[out] || dsp_output_unused(&mgr->opatch_list,out) )) {
1034 if (dsp_input_unused(&mgr->ipatch_list,in))
1037 return 0;
1040 for (i = 0; i < DSP_NUM_OUTPUTS; i++)
1041 if ( test_bit(in, &rpatch->route[i]) || test_bit(in, &rpatch->route_v[i]))
1042 return 0;
1045 set_bit(in, &rpatch->route[out]);
1046 return -2;
1047 } else if (test_and_clear_bit(in, &rpatch->route_v[out])) {
1048 sprintf(s, "Vol %s:%s", dsp_in_name[in], dsp_out_name[out]);
1049 addr = find_control_gpr_addr(mgr, rpatch->name, s) - GPR_BASE;
1050 if (addr < 0)
1051 return -2;
1053 if (rpatch->route_v[out] || rpatch->route[out] ||dsp_output_unused(&mgr->opatch_list,out)) {
1055 if (dsp_input_unused(&mgr->ipatch_list,in)){
1056 free_gpr(mgr, addr, rpatch->gpr_used);
1057 return 0;
1060 for (i = 0; i < DSP_NUM_OUTPUTS; i++)
1061 if (test_bit(in, &rpatch->route[i]) || test_bit(in, &rpatch->route_v[i])) {
1062 free_gpr(mgr, addr, rpatch->gpr_used);
1063 return 0;
1067 set_bit(in, &rpatch->route_v[out]);
1068 return -2;
1071 return -3;
1074 int dsp_del_route_name(struct dsp_patch_manager *mgr, const char *name)
1076 int in1, in2, out1, out2, ret;
1078 if(!get_stereo_route_name(mgr, name, &in1, &in2, &out1, &out2)){
1079 if((ret=dsp_del_route(mgr, in1, out1)))
1080 return ret;
1081 if(in2<0 && out2>0 )
1082 return dsp_del_route(mgr, in1, out2);
1083 else if(in2 > 0)
1084 if( out2>0)
1085 return dsp_del_route(mgr, in2, out2);
1086 else
1087 return dsp_del_route(mgr, in2, out1);
1088 else
1089 return 0;
1091 return -1;
1094 int dsp_add_route(struct dsp_patch_manager *mgr, int in, int out)
1096 struct dsp_rpatch *rpatch = &mgr->rpatch;
1097 char s[2 * DSP_LINE_NAME_SIZE + 5];
1098 int addr;
1100 if (in < 0 || in > DSP_NUM_INPUTS || out < 0 || out > DSP_NUM_OUTPUTS)
1101 return -1;
1103 if (!mgr->init)
1104 dsp_init(mgr);
1106 set_bit(in, &rpatch->route[out]);
1108 if (test_bit(in, &rpatch->route_v[out])) {
1109 sprintf(s, "Vol %s:%s", dsp_in_name[in], dsp_out_name[out]);
1110 addr = find_control_gpr_addr(mgr, rpatch->name, s) - GPR_BASE;
1111 if (addr < 0)
1112 return -1;
1114 free_gpr(mgr, addr, rpatch->gpr_used);
1115 clear_bit(in, &rpatch->route_v[out]);
1118 return 0;
1121 int dsp_add_route_name(struct dsp_patch_manager *mgr, const char *name)
1123 int in1, in2, out1, out2, ret;
1125 if(!get_stereo_route_name(mgr, name, &in1, &in2, &out1, &out2)){
1127 if((ret=dsp_add_route(mgr, in1, out1)))
1128 return ret;
1129 if(in2<0 && out2>0 )
1130 return dsp_add_route(mgr, in1, out2);
1131 else if(in2 >= 0)
1132 if( out2>=0)
1133 return dsp_add_route(mgr, in2, out2);
1134 else
1135 return dsp_add_route(mgr, in2, out1);
1136 else
1137 return 0;
1139 return -1;
1144 int dsp_add_route_v(struct dsp_patch_manager *mgr, int in, int out)
1146 char gpr_name[DSP_GPR_NAME_SIZE];
1148 if (in < 0 || in > DSP_NUM_INPUTS || out < 0 || out > DSP_NUM_OUTPUTS)
1149 return -1;
1151 if (!mgr->init)
1152 dsp_init(mgr);
1154 if (!test_and_set_bit(in, &mgr->rpatch.route_v[out])) {
1155 sprintf(gpr_name, "Vol %s:%s", dsp_in_name[in], dsp_out_name[out]);
1156 if (get_control_gpr(mgr, 0x7fffffff, 0, 0x7fffffff, gpr_name, mgr->rpatch.gpr_used, NULL) < 0)
1157 return -1;
1160 clear_bit(in, &mgr->rpatch.route[out]);
1161 return 0;
1164 int dsp_add_route_v_name(struct dsp_patch_manager *mgr, const char *name)
1166 int in1, in2, out1, out2, ret;
1168 if(!get_stereo_route_name(mgr, name, &in1, &in2, &out1, &out2)){
1170 if((ret=dsp_add_route_v(mgr, in1, out1)))
1171 return ret;
1172 if(in2<0 && out2>0 )
1173 return dsp_add_route_v(mgr, in1, out2);
1174 else if(in2 >= 0)
1175 if( out2>=0)
1176 return dsp_add_route_v(mgr, in2, out2);
1177 else
1178 return dsp_add_route_v(mgr, in2, out1);
1179 else
1180 return 0;
1182 return -1;
1185 void dsp_print_inputs_name(void)
1187 int i;
1189 printf("Inputs:\n");
1191 for (i = 0; i < DSP_NUM_INPUTS; i++)
1192 printf(" %s\n", dsp_in_name[i]);
1194 void dsp_print_outputs_name(void)
1196 int i;
1198 printf("Outputs:\n");
1200 for (i = 0; i < DSP_NUM_OUTPUTS; i++)
1201 printf(" %s\n", dsp_out_name[i]);
1204 int dsp_set_oss_control_gpr(struct dsp_patch_manager *mgr, const char *patch_name, const char *gpr_name, const char *mixer_name)
1206 int addr, i, mix, ch;
1208 static char channel_name[2][3] = { "_l", "_r" };
1210 for (mix = 0; mix < SOUND_MIXER_NRDEVICES; mix++) {
1211 i = strlen(oss_mixer_name[mix]);
1213 if (strncmp(mixer_name, oss_mixer_name[mix], i) == 0) {
1214 ch = 0;
1215 if (mixer_name[i] == '\0')
1216 goto match;
1218 for (; ch < 2; ch++) {
1219 if (strcmp(&mixer_name[i], channel_name[ch]) == 0)
1220 goto match;
1225 return -1;
1227 match:
1228 if (!mgr->init)
1229 dsp_init(mgr);
1231 for (i = 0; i < DSP_NUM_GPRS; i++) {
1232 if ((mgr->gpr[i].mixer_id == mix) &&
1233 (mgr->gpr[i].mixer_ch == ch))
1234 mgr->gpr[i].mixer_id = SOUND_MIXER_NONE;
1237 if((*patch_name==0) &&(*gpr_name==0))
1238 return 0;
1240 addr = find_control_gpr_addr(mgr, patch_name, gpr_name);
1241 if (addr > 0) {
1242 mgr->gpr[addr - GPR_BASE].mixer_id = mix;
1243 mgr->gpr[addr - GPR_BASE].mixer_ch = ch;
1244 return 0;
1245 }else
1246 return -2;
1249 void dsp_unload_all(struct dsp_patch_manager *mgr)
1251 int i;
1253 for (i = 0; i < DSP_NUM_INPUTS; i++)
1254 INIT_LIST_HEAD(&mgr->ipatch_list);
1256 for (i = 0; i < DSP_NUM_OUTPUTS; i++)
1257 INIT_LIST_HEAD(&mgr->opatch_list);
1259 mgr->traml_efree_start = 0;
1260 mgr->traml_ifree_start = 0;
1262 mgr->tramb_efree_start = 0;
1263 mgr->tramb_ifree_start = 0;
1265 mgr->code_free_start = 0;
1266 mgr->icode_free_start = DSP_CODE_SIZE;
1268 memset(&mgr->rpatch, 0, sizeof(struct dsp_rpatch));
1269 strcpy(mgr->rpatch.name, "Routing");
1270 mgr->rpatch.code = (__u32 *) malloc(DSP_CODE_SIZE * sizeof(__u32));
1272 for (i = 0; i < DSP_NUM_GPRS; i++){
1273 mgr->gpr[i].type = GPR_TYPE_NULL;
1274 mgr->gpr[i].usage=0;
1277 init_io_gprs_table(mgr);
1279 mgr->init = 1;