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
map_input(uchar val)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
mux_open(const char * name,uint32 flags,void ** cookie)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
mux_close(void * cookie)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
mux_free(void * cookie)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
get_mux_value(cmedia_pci_dev * card,int ix)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
gather_info(mux_dev * mux,cmedia_pci_routing * data,int count)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
set_mux_value(cmedia_pci_dev * card,int selector,int value)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
disperse_info(mux_dev * mux,cmedia_pci_routing * data,int count)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
mux_control(void * cookie,uint32 iop,void * data,size_t len)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
mux_read(void * cookie,off_t pos,void * data,size_t * nread)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
mux_write(void * cookie,off_t pos,const void * data,size_t * nwritten)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