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