xref: /haiku/src/add-ons/kernel/drivers/audio/cmedia/mux.c (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
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 
6 #include "cm_private.h"
7 #include <string.h>
8 
9 #if !defined(_KERNEL_EXPORT_H)
10 #include <KernelExport.h>
11 #endif /* _KERNEL_EXPORT_H */
12 
13 
14 static status_t mux_open(const char *name, uint32 flags, void **cookie);
15 static status_t mux_close(void *cookie);
16 static status_t mux_free(void *cookie);
17 static status_t mux_control(void *cookie, uint32 op, void *data, size_t len);
18 static status_t mux_read(void *cookie, off_t pos, void *data, size_t *len);
19 static status_t mux_write(void *cookie, off_t pos, const void *data, size_t *len);
20 
21 device_hooks mux_hooks = {
22     &mux_open,
23     &mux_close,
24     &mux_free,
25     &mux_control,
26     &mux_read,
27     &mux_write,
28     NULL,		/* select */
29     NULL,		/* deselect */
30     NULL,		/* readv */
31     NULL		/* writev */
32 };
33 
34 
35 typedef struct {
36 	int port_l;
37 	int port_r;
38 	int minval;
39 	int maxval;
40 	int leftshift;
41 	int mask;
42 	char name[B_OS_NAME_LENGTH];
43 } mux_info;
44 
45 const mux_info the_muxes[] = {
46 	{ 0, 1, 1, 7, 5, 0xe0, "Sampling input" },
47 	{ 0, -1, 0, 1, 4, 0x10, "Mic +20dB selection" },
48 	{ 0x2a, -1, 0, 1, 0, 0x01, "MIDI output to synth" },
49 	{ 0x2a, -1, 0, 1, 1, 0x02, "MIDI input to synth" },
50 	{ 0x2a, -1, 0, 1, 2, 0x04, "MIDI output to port" },
51 };
52 
53 static const uchar unmap_input[] = {
54   0,
55   CMEDIA_PCI_INPUT_CD,
56   CMEDIA_PCI_INPUT_DAC,
57   CMEDIA_PCI_INPUT_AUX2,
58   CMEDIA_PCI_INPUT_LINE,
59   CMEDIA_PCI_INPUT_AUX1,
60   CMEDIA_PCI_INPUT_MIC,
61   CMEDIA_PCI_INPUT_MIX_OUT
62 };
63 
64 static uchar
65 map_input(uchar val) {
66   int i;
67   for (i = 0; i < 8; i++)
68 	if (unmap_input[i] == val)
69 	  return i;
70   return 0;
71 }
72 
73 
74 static status_t
75 mux_open(
76 	const char * name,
77 	uint32 flags,
78 	void ** cookie)
79 {
80 	int ix;
81 	/* mux_dev * plex = NULL; */
82 
83 	ddprintf(("cmedia_pci: mux_open()\n"));
84 
85 	*cookie = NULL;
86 	for (ix=0; ix<num_cards; ix++) {
87 		if (!strcmp(name, cards[ix].mux.name)) {
88 			break;
89 		}
90 	}
91 	if (ix == num_cards) {
92 		return ENODEV;
93 	}
94 
95 	atomic_add(&cards[ix].mux.open_count, 1);
96 	cards[ix].mux.card = &cards[ix];
97 	*cookie = &cards[ix].mux;
98 
99 	return B_OK;
100 }
101 
102 
103 static status_t
104 mux_close(
105 	void * cookie)
106 {
107 	mux_dev * plex = (mux_dev *)cookie;
108 
109 	atomic_add(&plex->open_count, -1);
110 
111 	return B_OK;
112 }
113 
114 
115 static status_t
116 mux_free(
117 	void * cookie)
118 {
119 	ddprintf(("cmedia_pci: mux_free()\n"));
120 
121 	if (((mux_dev *)cookie)->open_count != 0) {
122 		dprintf("cmedia_pci: mux open_count is bad in mux_free()!\n");
123 	}
124 	return B_OK;	/* already done in close */
125 }
126 
127 
128 static int
129 get_mux_value(
130 	cmedia_pci_dev * card,
131 	int ix)
132 {
133 	uchar val;
134 	if (ix < 0) {
135 		return -1;
136 	}
137 	if (ix > 4) {
138 		return -1;
139 	}
140 	val = get_indirect(card, the_muxes[ix].port_l);
141 	val &= the_muxes[ix].mask;
142 	val >>= the_muxes[ix].leftshift;
143 	if (ix == CMEDIA_PCI_INPUT_MUX)
144 	  return unmap_input[val];
145 	return val;
146 }
147 
148 
149 static int
150 gather_info(
151 	mux_dev * mux,
152 	cmedia_pci_routing * data,
153 	int count)
154 {
155 	int ix;
156 	cpu_status cp;
157 
158 	cp = disable_interrupts();
159 	acquire_spinlock(&mux->card->hardware);
160 
161 	for (ix=0; ix<count; ix++) {
162 		data[ix].value = get_mux_value(mux->card, data[ix].selector);
163 		if (data[ix].value < 0) {
164 			break;
165 		}
166 	}
167 
168 	release_spinlock(&mux->card->hardware);
169 	restore_interrupts(cp);
170 
171 	return ix;
172 }
173 
174 
175 static status_t
176 set_mux_value(
177 	cmedia_pci_dev * card,
178 	int selector,
179 	int value)
180 {
181 	ddprintf(("set_mux_value(%d,%d)\n", selector, value));
182 	if (selector < 0 || selector > 4) {
183 		ddprintf(("selector EINVAL\n"));
184 		return EINVAL;
185 	}
186 	if (selector == CMEDIA_PCI_INPUT_MUX)
187 	    value = map_input(value);
188 	if (value < the_muxes[selector].minval ||
189 		value > the_muxes[selector].maxval) {
190 		ddprintf(("value EINVAL\n"));
191 		return EINVAL;
192 	}
193 	set_indirect(card, the_muxes[selector].port_l,
194 		(value << the_muxes[selector].leftshift),
195 		the_muxes[selector].mask);
196 	if (the_muxes[selector].port_r > -1) {
197 		set_indirect(card, the_muxes[selector].port_r,
198 			(value << the_muxes[selector].leftshift),
199 			the_muxes[selector].mask);
200 	}
201 	return B_OK;
202 }
203 
204 
205 static int
206 disperse_info(
207 	mux_dev * mux,
208 	cmedia_pci_routing * data,
209 	int count)
210 {
211 	int ix;
212 	cpu_status cp;
213 
214 	cp = disable_interrupts();
215 	acquire_spinlock(&mux->card->hardware);
216 
217 	for (ix=0; ix<count; ix++) {
218 		if (set_mux_value(mux->card, data[ix].selector, data[ix].value) < B_OK) {
219 			break;
220 		}
221 	}
222 
223 	release_spinlock(&mux->card->hardware);
224 	restore_interrupts(cp);
225 
226 	return ix;
227 }
228 
229 
230 static status_t
231 mux_control(
232 	void * cookie,
233 	uint32 iop,
234 	void * data,
235 	size_t len)
236 {
237 	mux_dev * plex = (mux_dev *)cookie;
238 	status_t err = B_OK;
239 
240 	ddprintf(("cmedia_pci: mux_control()\n")); /* slow printing */
241 
242 	switch (iop) {
243 	case B_ROUTING_GET_VALUES:
244 		((cmedia_pci_routing_cmd *)data)->count =
245 			gather_info(plex, ((cmedia_pci_routing_cmd *)data)->data,
246 				((cmedia_pci_routing_cmd *)data)->count);
247 		break;
248 	case B_ROUTING_SET_VALUES:
249 		((cmedia_pci_routing_cmd *)data)->count =
250 			disperse_info(plex, ((cmedia_pci_routing_cmd *)data)->data,
251 				((cmedia_pci_routing_cmd *)data)->count);
252 		break;
253 	default:
254 		err = B_BAD_VALUE;
255 		break;
256 	}
257 	return err;
258 }
259 
260 
261 static status_t
262 mux_read(
263 	void * cookie,
264 	off_t pos,
265 	void * data,
266 	size_t * nread)
267 {
268 	return EPERM;
269 }
270 
271 
272 static status_t
273 mux_write(
274 	void * cookie,
275 	off_t pos,
276 	const void * data,
277 	size_t * nwritten)
278 {
279 	return EPERM;
280 }
281 
282