root/drivers/sound/sb16_midi.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sb16midi_input_loop
  2. sb16midiintr
  3. poll_sb16midi
  4. sb16midi_open
  5. sb16midi_close
  6. sb16midi_out
  7. sb16midi_command
  8. sb16midi_start_read
  9. sb16midi_end_read
  10. sb16midi_ioctl
  11. sb16midi_kick
  12. sb16midi_buffer_status
  13. attach_sb16midi
  14. reset_sb16midi
  15. probe_sb16midi

   1 /*
   2  * sound/sb16_midi.c
   3  * 
   4  * The low level driver for the MPU-401 UART emulation of the SB16.
   5  * 
   6  * Copyright by Hannu Savolainen 1993
   7  * 
   8  * Redistribution and use in source and binary forms, with or without
   9  * modification, are permitted provided that the following conditions are
  10  * met: 1. Redistributions of source code must retain the above copyright
  11  * notice, this list of conditions and the following disclaimer. 2.
  12  * Redistributions in binary form must reproduce the above copyright notice,
  13  * this list of conditions and the following disclaimer in the documentation
  14  * and/or other materials provided with the distribution.
  15  * 
  16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26  * SUCH DAMAGE.
  27  * 
  28  */
  29 
  30 #include "sound_config.h"
  31 
  32 #ifdef CONFIGURE_SOUNDCARD
  33 
  34 #if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI)
  35 
  36 #define DATAPORT   (sb16midi_base)      /* MPU-401 Data I/O Port on IBM */
  37 #define COMDPORT   (sb16midi_base+1)    /* MPU-401 Command Port on IBM */
  38 #define STATPORT   (sb16midi_base+1)    /* MPU-401 Status Port on IBM */
  39 
  40 #define sb16midi_status()               INB(STATPORT)
  41 #define input_avail()           (!(sb16midi_status()&INPUT_AVAIL))
  42 #define output_ready()          (!(sb16midi_status()&OUTPUT_READY))
  43 #define sb16midi_cmd(cmd)               OUTB(cmd, COMDPORT)
  44 #define sb16midi_read()         INB(DATAPORT)
  45 #define sb16midi_write(byte)    OUTB(byte, DATAPORT)
  46 
  47 #define OUTPUT_READY    0x40    /* Mask for Data Read Redy Bit */
  48 #define INPUT_AVAIL     0x80    /* Mask for Data Send Ready Bit */
  49 #define MPU_ACK         0xFE    /* MPU-401 Acknowledge Response */
  50 #define MPU_RESET       0xFF    /* MPU-401 Total Reset Command */
  51 #define UART_MODE_ON    0x3F    /* MPU-401 "Dumb UART Mode" */
  52 
  53 static int      sb16midi_opened = 0;
  54 static int      sb16midi_base = 0x330;
  55 static int      sb16midi_detected = 0;
  56 static int      my_dev;
  57 
  58 static int      reset_sb16midi (void);
  59 static void     (*midi_input_intr) (int dev, unsigned char data);
  60 
  61 static void
  62 sb16midi_input_loop (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64   int             count;
  65 
  66   count = 10;
  67 
  68   while (count)                 /* Not timed out */
  69     if (input_avail ())
  70       {
  71         unsigned char   c = sb16midi_read ();
  72 
  73         count = 100;
  74 
  75         if (sb16midi_opened & OPEN_READ)
  76           midi_input_intr (my_dev, c);
  77       }
  78     else
  79       while (!input_avail () && count)
  80         count--;
  81 }
  82 
  83 void
  84 sb16midiintr (int unit)
     /* [previous][next][first][last][top][bottom][index][help] */
  85 {
  86   if (input_avail ())
  87     sb16midi_input_loop ();
  88 }
  89 
  90 /*
  91  * It looks like there is no input interrupts in the UART mode. Let's try
  92  * polling.
  93  */
  94 
  95 static void
  96 poll_sb16midi (unsigned long dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
  97 {
  98   unsigned long   flags;
  99 
 100   DEFINE_TIMER(sb16midi_timer, poll_sb16midi);
 101 
 102   if (!(sb16midi_opened & OPEN_READ))
 103     return;                     /* No longer required */
 104 
 105   DISABLE_INTR (flags);
 106 
 107   if (input_avail ())
 108     sb16midi_input_loop ();
 109 
 110   ACTIVATE_TIMER(sb16midi_timer, poll_sb16midi, 1); /* Come back later */
 111 
 112   RESTORE_INTR (flags);
 113 }
 114 
 115 static int
 116 sb16midi_open (int dev, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 117              void            (*input) (int dev, unsigned char data),
 118              void            (*output) (int dev)
 119 )
 120 {
 121   if (sb16midi_opened)
 122     {
 123       return RET_ERROR (EBUSY);
 124     }
 125 
 126   sb16midi_input_loop ();
 127 
 128   midi_input_intr = input;
 129   sb16midi_opened = mode;
 130   poll_sb16midi (0);            /* Enable input polling */
 131 
 132   return 0;
 133 }
 134 
 135 static void
 136 sb16midi_close (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138   sb16midi_opened = 0;
 139 }
 140 
 141 static int
 142 sb16midi_out (int dev, unsigned char midi_byte)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144   int             timeout;
 145   unsigned long   flags;
 146 
 147   /*
 148    * Test for input since pending input seems to block the output.
 149    */
 150 
 151   DISABLE_INTR (flags);
 152 
 153   if (input_avail ())
 154     sb16midi_input_loop ();
 155 
 156   RESTORE_INTR (flags);
 157 
 158   /*
 159    * Sometimes it takes about 13000 loops before the output becomes ready
 160    * (After reset). Normally it takes just about 10 loops.
 161    */
 162 
 163   for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);    /* Wait */
 164 
 165   if (!output_ready ())
 166     {
 167       printk ("MPU-401: Timeout\n");
 168       return 0;
 169     }
 170 
 171   sb16midi_write (midi_byte);
 172   return 1;
 173 }
 174 
 175 static int
 176 sb16midi_command (int dev, unsigned char midi_byte)
     /* [previous][next][first][last][top][bottom][index][help] */
 177 {
 178   return 1;
 179 }
 180 
 181 static int
 182 sb16midi_start_read (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184   return 0;
 185 }
 186 
 187 static int
 188 sb16midi_end_read (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190   return 0;
 191 }
 192 
 193 static int
 194 sb16midi_ioctl (int dev, unsigned cmd, unsigned arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 195 {
 196   return RET_ERROR (EINVAL);
 197 }
 198 
 199 static void
 200 sb16midi_kick (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202 }
 203 
 204 static int
 205 sb16midi_buffer_status (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 206 {
 207   return 0;                     /* No data in buffers */
 208 }
 209 
 210 static struct midi_operations sb16midi_operations =
 211 {
 212   {"SoundBlaster MPU-401", 0, 0, SNDCARD_SB16MIDI},
 213   sb16midi_open,
 214   sb16midi_close,
 215   sb16midi_ioctl,
 216   sb16midi_out,
 217   sb16midi_start_read,
 218   sb16midi_end_read,
 219   sb16midi_kick,
 220   sb16midi_command,
 221   sb16midi_buffer_status
 222 };
 223 
 224 
 225 long
 226 attach_sb16midi (long mem_start, struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228   int             ok, timeout;
 229   unsigned long   flags;
 230 
 231   sb16midi_base = hw_config->io_base;
 232 
 233   if (!sb16midi_detected)
 234     return RET_ERROR (EIO);
 235 
 236   DISABLE_INTR (flags);
 237   for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);    /* Wait */
 238   sb16midi_cmd (UART_MODE_ON);
 239 
 240   ok = 0;
 241   for (timeout = 50000; timeout > 0 && !ok; timeout--)
 242     if (input_avail ())
 243       if (sb16midi_read () == MPU_ACK)
 244         ok = 1;
 245 
 246   RESTORE_INTR (flags);
 247 
 248   printk (" <SoundBlaster MPU-401>");
 249 
 250   my_dev = num_midis;
 251   midi_devs[num_midis++] = &sb16midi_operations;
 252   return mem_start;
 253 }
 254 
 255 static int
 256 reset_sb16midi (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 257 {
 258   unsigned long   flags;
 259   int             ok, timeout, n;
 260 
 261   /*
 262    * Send the RESET command. Try again if no success at the first time.
 263    */
 264 
 265   ok = 0;
 266 
 267   DISABLE_INTR (flags);
 268 
 269   for (n = 0; n < 2 && !ok; n++)
 270     {
 271       for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);        /* Wait */
 272       sb16midi_cmd (MPU_RESET); /* Send MPU-401 RESET Command */
 273 
 274       /*
 275        * Wait at least 25 msec. This method is not accurate so let's make the
 276        * loop bit longer. Cannot sleep since this is called during boot.
 277        */
 278 
 279       for (timeout = 50000; timeout > 0 && !ok; timeout--)
 280         if (input_avail ())
 281           if (sb16midi_read () == MPU_ACK)
 282             ok = 1;
 283 
 284     }
 285 
 286   sb16midi_opened = 0;
 287   if (ok)
 288     sb16midi_input_loop ();     /* Flush input before enabling interrupts */
 289 
 290   RESTORE_INTR (flags);
 291 
 292   return ok;
 293 }
 294 
 295 
 296 int
 297 probe_sb16midi (struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 298 {
 299   int             ok = 0;
 300 
 301   sb16midi_base = hw_config->io_base;
 302 
 303   if (sb_get_irq () < 0)
 304     return 0;
 305 
 306   ok = reset_sb16midi ();
 307 
 308   sb16midi_detected = ok;
 309   return ok;
 310 }
 311 
 312 #endif
 313 
 314 #endif

/* [previous][next][first][last][top][bottom][index][help] */