The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/drivers/sb16/sb16_mixer.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* This file contains the driver for the mixer on
    2  * a SoundBlaster 16 soundcard.
    3  *
    4  * The driver supports the following operations (using message format m2):
    5  *
    6  *    m_type      DEVICE    PROC_NR     COUNT    POSITION  ADRRESS
    7  * ----------------------------------------------------------------
    8  * |  DEV_OPEN  | device  | proc nr |         |         |         |
    9  * |------------+---------+---------+---------+---------+---------|
   10  * |  DEV_CLOSE | device  | proc nr |         |         |         |
   11  * |------------+---------+---------+---------+---------+---------|
   12  * |  DEV_IOCTL | device  | proc nr |func code|         | buf_ptr |
   13  * ----------------------------------------------------------------
   14  *
   15  * The file contains one entry point:
   16  *
   17  *   sb16mixer_task:  main entry when system is brought up
   18  *
   19  *      August 24 2005          Ported driver to user space (Peter Boonstoppel)
   20  *  May 20 1995                 Author: Michel R. Prevenier 
   21  */
   22 
   23 
   24 #include "sb16.h"
   25 
   26 
   27 _PROTOTYPE(void main, (void));
   28 FORWARD _PROTOTYPE( int mixer_init, (void)); 
   29 FORWARD _PROTOTYPE( int mixer_open, (message *m_ptr));
   30 FORWARD _PROTOTYPE( int mixer_close, (message *m_ptr));
   31 FORWARD _PROTOTYPE( int mixer_ioctl, (message *m_ptr));
   32 FORWARD _PROTOTYPE( int mixer_get, (int reg));
   33 FORWARD _PROTOTYPE( int get_set_volume, (message *m_ptr, int flag));
   34 FORWARD _PROTOTYPE( int get_set_input, (message *m_ptr, int flag, int channel));
   35 FORWARD _PROTOTYPE( int get_set_output, (message *m_ptr, int flag));
   36 
   37 
   38 PRIVATE int mixer_avail = 0;    /* Mixer exists? */
   39 
   40 
   41 #define dprint (void)
   42 
   43 
   44 /*===========================================================================*
   45  *                              main
   46  *===========================================================================*/
   47 PUBLIC void main() {
   48 message mess;
   49         int err, caller, proc_nr;
   50 
   51         /* Here is the main loop of the mixer task. It waits for a message, carries
   52         * it out, and sends a reply.
   53         */
   54         while (TRUE) {
   55                 receive(ANY, &mess);
   56 
   57                 caller = mess.m_source;
   58                 proc_nr = mess.PROC_NR;
   59 
   60                 switch (caller) {
   61                         case HARDWARE: /* Leftover interrupt. */
   62                                 continue;
   63                         case FS_PROC_NR: /* The only legitimate caller. */
   64                                 break;
   65                         default:
   66                                 dprint("sb16: got message from %d\n", caller);
   67                                 continue;
   68                 }
   69 
   70                 /* Now carry out the work. */
   71                 switch(mess.m_type) {
   72                         case DEV_OPEN:      err = mixer_open(&mess); break;     
   73                         case DEV_CLOSE:     err = mixer_close(&mess); break; 
   74                         case DEV_IOCTL:     err = mixer_ioctl(&mess); break;
   75                         default:                err = EINVAL; break;
   76                 }
   77 
   78                 /* Finally, prepare and send the reply message. */
   79                 mess.m_type = TASK_REPLY;
   80                 mess.REP_PROC_NR = proc_nr;
   81         
   82                 dprint("%d %d", err, OK);
   83                 
   84                 mess.REP_STATUS = err;  /* error code */
   85                 send(caller, &mess);    /* send reply to caller */
   86         }
   87 }
   88 
   89 
   90 /*=========================================================================*
   91  *                              mixer_open                                      
   92  *=========================================================================*/
   93 PRIVATE int mixer_open(m_ptr)
   94 message *m_ptr;
   95 {
   96         dprint("mixer_open\n");
   97 
   98         /* try to detect the mixer type */
   99         if (!mixer_avail && mixer_init() != OK) return EIO;
  100 
  101         return OK;
  102 }
  103 
  104 
  105 /*=========================================================================*
  106  *                              mixer_close                                     
  107  *=========================================================================*/
  108 PRIVATE int mixer_close(m_ptr)
  109 message *m_ptr;
  110 {
  111         dprint("mixer_close\n");
  112 
  113         return OK;
  114 }
  115 
  116 
  117 /*=========================================================================*
  118  *                              mixer_ioctl                                     
  119  *=========================================================================*/
  120 PRIVATE int mixer_ioctl(m_ptr)
  121 message *m_ptr;
  122 {
  123         int status;
  124 
  125         dprint("mixer: got ioctl %d\n", m_ptr->REQUEST);
  126 
  127 
  128         switch(m_ptr->REQUEST) {
  129                 case MIXIOGETVOLUME:      status = get_set_volume(m_ptr, 0); break;
  130                 case MIXIOSETVOLUME:      status = get_set_volume(m_ptr, 1); break;
  131                 case MIXIOGETINPUTLEFT:   status = get_set_input(m_ptr, 0, 0); break;
  132                 case MIXIOGETINPUTRIGHT:  status = get_set_input(m_ptr, 0, 1); break;
  133                 case MIXIOGETOUTPUT:      status = get_set_output(m_ptr, 0); break;
  134                 case MIXIOSETINPUTLEFT:   status = get_set_input(m_ptr, 1, 0); break;
  135                 case MIXIOSETINPUTRIGHT:  status = get_set_input(m_ptr, 1, 1); break;
  136                 case MIXIOSETOUTPUT:      status = get_set_output(m_ptr, 1); break;
  137                 default:                  status = ENOTTY;
  138         }
  139 
  140         return status;
  141 }
  142 
  143 
  144 /*=========================================================================*
  145  *                              mixer_init                                 
  146  *=========================================================================*/
  147 PRIVATE int mixer_init()
  148 {
  149         /* Try to detect the mixer by writing to MIXER_DAC_LEVEL if the
  150         * value written can be read back the mixer is there
  151         */
  152 
  153         mixer_set(MIXER_DAC_LEVEL, 0x10);       /* write something to it */
  154         if(mixer_get(MIXER_DAC_LEVEL) != 0x10) {
  155                 dprint("sb16: Mixer not detected\n");
  156                 return EIO;
  157         }
  158 
  159         /* Enable Automatic Gain Control */
  160         mixer_set(MIXER_AGC, 0x01);
  161 
  162         dprint("Mixer detected\n");
  163 
  164         mixer_avail = 1;
  165         return OK;
  166 }
  167 
  168 
  169 /*=========================================================================*
  170  *                              mixer_get                                 
  171  *=========================================================================*/
  172 PRIVATE int mixer_get(reg)
  173 int reg;
  174 {
  175         int i;
  176 
  177         sb16_outb(MIXER_REG, reg);
  178         for(i = 0; i < 100; i++);
  179         return sb16_inb(MIXER_DATA) & 0xff;
  180 }  
  181 
  182 
  183 /*=========================================================================*
  184  *                              get_set_volume                             *
  185  *=========================================================================*/
  186 PRIVATE int get_set_volume(m_ptr, flag)
  187 message *m_ptr;
  188 int flag;       /* 0 = get, 1 = set */
  189 {
  190         phys_bytes user_phys;
  191         struct volume_level level;
  192         int cmd_left, cmd_right, shift, max_level;
  193 
  194         sys_datacopy(m_ptr->PROC_NR, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)&level, (phys_bytes)sizeof(level));
  195 
  196         shift = 3;
  197         max_level = 0x1F;
  198 
  199         switch(level.device) {
  200                 case Master:
  201                         cmd_left = MIXER_MASTER_LEFT;
  202                         cmd_right = MIXER_MASTER_RIGHT;
  203                         break;
  204                 case Dac:
  205                         cmd_left = MIXER_DAC_LEFT;
  206                         cmd_right = MIXER_DAC_RIGHT;
  207                         break;
  208                 case Fm:
  209                         cmd_left = MIXER_FM_LEFT;
  210                         cmd_right = MIXER_FM_RIGHT;
  211                         break;
  212                 case Cd:
  213                         cmd_left = MIXER_CD_LEFT;
  214                         cmd_right = MIXER_CD_RIGHT;
  215                         break;
  216                 case Line:
  217                         cmd_left = MIXER_LINE_LEFT;
  218                         cmd_right = MIXER_LINE_RIGHT;
  219                         break;
  220                 case Mic:
  221                         cmd_left = cmd_right = MIXER_MIC_LEVEL;
  222                         break;
  223                 case Speaker:
  224                         cmd_left = cmd_right = MIXER_PC_LEVEL;
  225                         shift = 6;
  226                         max_level = 0x03;
  227                         break;
  228                 case Treble:
  229                         cmd_left = MIXER_TREBLE_LEFT;
  230                         cmd_right = MIXER_TREBLE_RIGHT;
  231                         shift = 4;
  232                         max_level = 0x0F;
  233                         break;
  234                 case Bass:  
  235                         cmd_left = MIXER_BASS_LEFT;
  236                         cmd_right = MIXER_BASS_RIGHT;
  237                         shift = 4;
  238                         max_level = 0x0F;
  239                         break;
  240                 default:     
  241                         return EINVAL;
  242         }
  243 
  244         if(flag) { /* Set volume level */
  245                 if(level.right < 0) level.right = 0;
  246                 else if(level.right > max_level) level.right = max_level;
  247                 if(level.left < 0) level.left = 0;
  248                 else if(level.left > max_level) level.left = max_level;
  249 
  250                 mixer_set(cmd_right, (level.right << shift));
  251                 mixer_set(cmd_left, (level.left << shift));
  252         } else { /* Get volume level */
  253                 level.left = mixer_get(cmd_left);
  254                 level.right = mixer_get(cmd_right);
  255 
  256                 level.left >>= shift;
  257                 level.right >>= shift;
  258 
  259                 /* Copy back to user */
  260                 sys_datacopy(SELF, (vir_bytes)&level, m_ptr->PROC_NR, (vir_bytes)m_ptr->ADDRESS, (phys_bytes)sizeof(level));
  261         }
  262 
  263         return OK;
  264 }
  265 
  266 
  267 /*=========================================================================*
  268  *                              get_set_input                              *
  269  *=========================================================================*/
  270 PRIVATE int get_set_input(m_ptr, flag, channel)
  271 message *m_ptr;
  272 int flag;       /* 0 = get, 1 = set */
  273 int channel;    /* 0 = left, 1 = right */
  274 {
  275         phys_bytes user_phys;
  276         struct inout_ctrl input;
  277         int input_cmd, input_mask, mask, del_mask, shift;
  278 
  279         sys_datacopy(m_ptr->PROC_NR, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)&input, (phys_bytes)sizeof(input));
  280 
  281         input_cmd = (channel == 0 ? MIXER_IN_LEFT : MIXER_IN_RIGHT);
  282 
  283         mask = mixer_get(input_cmd); 
  284 
  285         switch (input.device) {
  286                 case Fm:
  287                         shift = 5;
  288                         del_mask = 0x1F; 
  289                         break;
  290                 case Cd: 
  291                         shift = 1;
  292                         del_mask = 0x79;
  293                         break;
  294                 case Line:
  295                         shift = 3;
  296                         del_mask = 0x67;
  297                         break;
  298                 case Mic: 
  299                         shift = 0;
  300                         del_mask = 0x7E;
  301                         break;
  302                 default:   
  303                         return EINVAL;
  304         }
  305 
  306         if (flag) {  /* Set input */
  307                 input_mask = ((input.left == ON ? 1 : 0) << 1) | (input.right == ON ? 1 : 0);
  308 
  309                 if (shift > 0) input_mask <<= shift;
  310                 else input_mask >>= 1;
  311 
  312                 mask &= del_mask;   
  313                 mask |= input_mask;
  314 
  315                 mixer_set(input_cmd, mask);
  316         } else {        /* Get input */
  317                 if (shift > 0) {
  318                         input.left = ((mask >> (shift+1)) & 1 == 1 ? ON : OFF);
  319                         input.right = ((mask >> shift) & 1 == 1 ? ON : OFF);
  320                 } else {
  321                         input.left = ((mask & 1) == 1 ? ON : OFF);
  322                 }
  323 
  324                 /* Copy back to user */
  325                 sys_datacopy(SELF, (vir_bytes)&input, m_ptr->PROC_NR, (vir_bytes)m_ptr->ADDRESS, (phys_bytes)sizeof(input));
  326         }
  327 
  328         return OK;
  329 }
  330 
  331 
  332 /*=========================================================================*
  333  *                              get_set_output                             *
  334  *=========================================================================*/
  335 PRIVATE int get_set_output(m_ptr, flag)
  336 message *m_ptr;
  337 int flag;       /* 0 = get, 1 = set */
  338 {
  339         phys_bytes user_phys;
  340         struct inout_ctrl output;
  341         int output_mask, mask, del_mask, shift;
  342 
  343         sys_datacopy(m_ptr->PROC_NR, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)&output, (phys_bytes)sizeof(output));
  344 
  345         mask = mixer_get(MIXER_OUTPUT_CTRL); 
  346 
  347         switch (output.device) {
  348                 case Cd:
  349                         shift = 1;
  350                         del_mask = 0x79;
  351                         break;
  352                 case Line:
  353                         shift = 3;
  354                         del_mask = 0x67;
  355                         break;
  356                 case Mic:
  357                         shift = 0;
  358                         del_mask = 0x7E;
  359                         break;
  360                 default:   
  361                         return EINVAL;
  362         }
  363 
  364         if (flag) {  /* Set input */
  365                 output_mask = ((output.left == ON ? 1 : 0) << 1) | (output.right == ON ? 1 : 0);
  366 
  367                 if (shift > 0) output_mask <<= shift;
  368                 else output_mask >>= 1;
  369 
  370                 mask &= del_mask;   
  371                 mask |= output_mask;
  372 
  373                 mixer_set(MIXER_OUTPUT_CTRL, mask);
  374         } else {    /* Get input */
  375                 if (shift > 0) {
  376                         output.left = ((mask >> (shift+1)) & 1 == 1 ? ON : OFF);
  377                         output.right = ((mask >> shift) & 1 == 1 ? ON : OFF);
  378                 } else {
  379                         output.left = ((mask & 1) == 1 ? ON : OFF);
  380                 }
  381 
  382                 /* Copy back to user */
  383                 sys_datacopy(SELF, (vir_bytes)&output, m_ptr->PROC_NR, (vir_bytes)m_ptr->ADDRESS, (phys_bytes)sizeof(output));
  384         }
  385 
  386         return OK;

Cache object: 6f19c62d475f67c9ff44d3c3b6949a74


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.