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 14static status_t mux_open(const char *name, uint32 flags, void **cookie); 15static status_t mux_close(void *cookie); 16static status_t mux_free(void *cookie); 17static status_t mux_control(void *cookie, uint32 op, void *data, size_t len); 18static status_t mux_read(void *cookie, off_t pos, void *data, size_t *len); 19static status_t mux_write(void *cookie, off_t pos, const void *data, size_t *len); 20 21device_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 35typedef 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 45const 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 53static 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 64static uchar 65map_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 74static status_t 75mux_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 103static status_t 104mux_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 115static status_t 116mux_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 128static int 129get_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 149static int 150gather_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 175static status_t 176set_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 205static int 206disperse_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 230static status_t 231mux_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 261static status_t 262mux_read( 263 void * cookie, 264 off_t pos, 265 void * data, 266 size_t * nread) 267{ 268 return EPERM; 269} 270 271 272static status_t 273mux_write( 274 void * cookie, 275 off_t pos, 276 const void * data, 277 size_t * nwritten) 278{ 279 return EPERM; 280} 281 282