[BACK]Return to audio.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / audio

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/dev/audio/audio.c between version 1.28 and 1.28.2.14

version 1.28, 2019/07/10 13:26:47 version 1.28.2.14, 2020/05/18 18:05:34
Line 118 
Line 118 
  *      set_port                -       x +   *      set_port                -       x +
  *      get_port                -       x +   *      get_port                -       x +
  *      query_devinfo           -       x   *      query_devinfo           -       x
  *      allocm                  -       - +     (*1)   *      allocm                  -       - +
  *      freem                   -       - +     (*1)   *      freem                   -       - +
  *      round_buffersize        -       x   *      round_buffersize        -       x
  *      get_props               -       x       Called at attach time   *      get_props               -       x       Called at attach time
  *      trigger_output          x       x +   *      trigger_output          x       x +
Line 127 
Line 127 
  *      dev_ioctl               -       x   *      dev_ioctl               -       x
  *      get_locks               -       -       Called at attach time   *      get_locks               -       -       Called at attach time
  *   *
  * *1 Note: Before 8.0, since these have been called only at attach time,  
  *   neither lock were necessary.  Currently, on the other hand, since  
  *   these may be also called after attach, the thread lock is required.  
  *  
  * In addition, there is an additional lock.   * In addition, there is an additional lock.
  *   *
  * - track->lock.  This is an atomic variable and is similar to the   * - track->lock.  This is an atomic variable and is similar to the
Line 466  audio_track_bufstat(audio_track_t *track
Line 462  audio_track_bufstat(audio_track_t *track
 int audio_idle_timeout = 30;  int audio_idle_timeout = 30;
 #endif  #endif
   
   /* Number of elements of async mixer's pid */
   #define AM_CAPACITY     (4)
   
 struct portname {  struct portname {
         const char *name;          const char *name;
         int mask;          int mask;
Line 497  static void audio_mixer_restore(struct a
Line 496  static void audio_mixer_restore(struct a
 static void audio_softintr_rd(void *);  static void audio_softintr_rd(void *);
 static void audio_softintr_wr(void *);  static void audio_softintr_wr(void *);
   
 static int  audio_enter_exclusive(struct audio_softc *);  static int audio_exlock_mutex_enter(struct audio_softc *);
 static void audio_exit_exclusive(struct audio_softc *);  static void audio_exlock_mutex_exit(struct audio_softc *);
   static int audio_exlock_enter(struct audio_softc *);
   static void audio_exlock_exit(struct audio_softc *);
   static struct audio_softc *audio_file_enter(audio_file_t *, struct psref *);
   static void audio_file_exit(struct audio_softc *, struct psref *);
 static int audio_track_waitio(struct audio_softc *, audio_track_t *);  static int audio_track_waitio(struct audio_softc *, audio_track_t *);
   
 static int audioclose(struct file *);  static int audioclose(struct file *);
Line 519  static int  filt_audioread_event(struct 
Line 522  static int  filt_audioread_event(struct 
 static int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *,  static int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *,
         audio_file_t **);          audio_file_t **);
 static int audio_close(struct audio_softc *, audio_file_t *);  static int audio_close(struct audio_softc *, audio_file_t *);
   static int audio_unlink(struct audio_softc *, audio_file_t *);
 static int audio_read(struct audio_softc *, struct uio *, int, audio_file_t *);  static int audio_read(struct audio_softc *, struct uio *, int, audio_file_t *);
 static int audio_write(struct audio_softc *, struct uio *, int, audio_file_t *);  static int audio_write(struct audio_softc *, struct uio *, int, audio_file_t *);
 static void audio_file_clear(struct audio_softc *, audio_file_t *);  static void audio_file_clear(struct audio_softc *, audio_file_t *);
Line 539  static int audio_query_devinfo(struct au
Line 543  static int audio_query_devinfo(struct au
 static __inline int audio_track_readablebytes(const audio_track_t *);  static __inline int audio_track_readablebytes(const audio_track_t *);
 static int audio_file_setinfo(struct audio_softc *, audio_file_t *,  static int audio_file_setinfo(struct audio_softc *, audio_file_t *,
         const struct audio_info *);          const struct audio_info *);
 static int audio_track_setinfo_check(audio_format2_t *,  static int audio_track_setinfo_check(audio_track_t *,
         const struct audio_prinfo *);          audio_format2_t *, const struct audio_prinfo *);
 static void audio_track_setinfo_water(audio_track_t *,  static void audio_track_setinfo_water(audio_track_t *,
         const struct audio_info *);          const struct audio_info *);
 static int audio_hw_setinfo(struct audio_softc *, const struct audio_info *,  static int audio_hw_setinfo(struct audio_softc *, const struct audio_info *,
Line 557  static int audio_mixers_init(struct audi
Line 561  static int audio_mixers_init(struct audi
         const audio_format2_t *, const audio_format2_t *,          const audio_format2_t *, const audio_format2_t *,
         const audio_filter_reg_t *, const audio_filter_reg_t *);          const audio_filter_reg_t *, const audio_filter_reg_t *);
 static int audio_select_freq(const struct audio_format *);  static int audio_select_freq(const struct audio_format *);
 static int audio_hw_probe(struct audio_softc *, int, int *,  static int audio_hw_probe(struct audio_softc *, audio_format2_t *, int);
         audio_format2_t *, audio_format2_t *);  
 static int audio_hw_probe_fmt(struct audio_softc *, audio_format2_t *, int);  
 static int audio_hw_validate_format(struct audio_softc *, int,  static int audio_hw_validate_format(struct audio_softc *, int,
         const audio_format2_t *);          const audio_format2_t *);
 static int audio_mixers_set_format(struct audio_softc *,  static int audio_mixers_set_format(struct audio_softc *,
Line 606  static void mixer_init(struct audio_soft
Line 608  static void mixer_init(struct audio_soft
 static int mixer_open(dev_t, struct audio_softc *, int, int, struct lwp *);  static int mixer_open(dev_t, struct audio_softc *, int, int, struct lwp *);
 static int mixer_close(struct audio_softc *, audio_file_t *);  static int mixer_close(struct audio_softc *, audio_file_t *);
 static int mixer_ioctl(struct audio_softc *, u_long, void *, int, struct lwp *);  static int mixer_ioctl(struct audio_softc *, u_long, void *, int, struct lwp *);
 static void mixer_remove(struct audio_softc *);  static void mixer_async_add(struct audio_softc *, pid_t);
   static void mixer_async_remove(struct audio_softc *, pid_t);
 static void mixer_signal(struct audio_softc *);  static void mixer_signal(struct audio_softc *);
   
 static int au_portof(struct audio_softc *, char *, int);  static int au_portof(struct audio_softc *, char *, int);
Line 810  static const struct portname otable[] = 
Line 813  static const struct portname otable[] = 
         { 0, 0 }          { 0, 0 }
 };  };
   
   static struct psref_class *audio_psref_class __read_mostly;
   
 CFATTACH_DECL3_NEW(audio, sizeof(struct audio_softc),  CFATTACH_DECL3_NEW(audio, sizeof(struct audio_softc),
     audiomatch, audioattach, audiodetach, audioactivate, audiorescan,      audiomatch, audioattach, audiodetach, audioactivate, audiorescan,
     audiochilddet, DVF_DETACH_SHUTDOWN);      audiochilddet, DVF_DETACH_SHUTDOWN);
Line 877  audioattach(device_t parent, device_t se
Line 882  audioattach(device_t parent, device_t se
         sc->hw_hdl = hdlp;          sc->hw_hdl = hdlp;
         sc->hw_dev = parent;          sc->hw_dev = parent;
   
           sc->sc_exlock = 1;
         sc->sc_blk_ms = AUDIO_BLK_MS;          sc->sc_blk_ms = AUDIO_BLK_MS;
         SLIST_INIT(&sc->sc_files);          SLIST_INIT(&sc->sc_files);
         cv_init(&sc->sc_exlockcv, "audiolk");          cv_init(&sc->sc_exlockcv, "audiolk");
           sc->sc_am_capacity = 0;
           sc->sc_am_used = 0;
           sc->sc_am = NULL;
   
         mutex_enter(sc->sc_lock);          mutex_enter(sc->sc_lock);
         sc->sc_props = hw_if->get_props(sc->hw_hdl);          sc->sc_props = hw_if->get_props(sc->hw_hdl);
Line 927  audioattach(device_t parent, device_t se
Line 936  audioattach(device_t parent, device_t se
         memset(&rhwfmt, 0, sizeof(rhwfmt));          memset(&rhwfmt, 0, sizeof(rhwfmt));
         memset(&pfil, 0, sizeof(pfil));          memset(&pfil, 0, sizeof(pfil));
         memset(&rfil, 0, sizeof(rfil));          memset(&rfil, 0, sizeof(rfil));
         mutex_enter(sc->sc_lock);          if (has_indep) {
         error = audio_hw_probe(sc, has_indep, &mode, &phwfmt, &rhwfmt);                  int perror, rerror;
         if (error) {  
                 mutex_exit(sc->sc_lock);                  /* On independent devices, probe separately. */
                 aprint_error_dev(self, "audio_hw_probe failed, "                  perror = audio_hw_probe(sc, &phwfmt, AUMODE_PLAY);
                     "error = %d\n", error);                  rerror = audio_hw_probe(sc, &rhwfmt, AUMODE_RECORD);
                 goto bad;                  if (perror && rerror) {
         }                          aprint_error_dev(self, "audio_hw_probe failed, "
         if (mode == 0) {                              "perror = %d, rerror = %d\n", perror, rerror);
                 mutex_exit(sc->sc_lock);                          goto bad;
                 aprint_error_dev(self, "audio_hw_probe failed, no mode\n");                  }
                 goto bad;                  if (perror) {
                           mode &= ~AUMODE_PLAY;
                           aprint_error_dev(self, "audio_hw_probe failed with "
                               "%d, playback disabled\n", perror);
                   }
                   if (rerror) {
                           mode &= ~AUMODE_RECORD;
                           aprint_error_dev(self, "audio_hw_probe failed with "
                               "%d, capture disabled\n", rerror);
                   }
           } else {
                   /*
                    * On non independent devices or uni-directional devices,
                    * probe once (simultaneously).
                    */
                   audio_format2_t *fmt = has_playback ? &phwfmt : &rhwfmt;
                   error = audio_hw_probe(sc, fmt, mode);
                   if (error) {
                           aprint_error_dev(self, "audio_hw_probe failed, "
                               "error = %d\n", error);
                           goto bad;
                   }
                   if (has_playback && has_capture)
                           rhwfmt = phwfmt;
         }          }
   
         /* Init hardware. */          /* Init hardware. */
         /* hw_probe() also validates [pr]hwfmt.  */          /* hw_probe() also validates [pr]hwfmt.  */
         error = audio_hw_set_format(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil);          error = audio_hw_set_format(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil);
         if (error) {          if (error) {
                 mutex_exit(sc->sc_lock);  
                 aprint_error_dev(self, "audio_hw_set_format failed, "                  aprint_error_dev(self, "audio_hw_set_format failed, "
                     "error = %d\n", error);                      "error = %d\n", error);
                 goto bad;                  goto bad;
Line 955  audioattach(device_t parent, device_t se
Line 987  audioattach(device_t parent, device_t se
          * attach time, we assume a success.           * attach time, we assume a success.
          */           */
         error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil);          error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil);
         mutex_exit(sc->sc_lock);  
         if (sc->sc_pmixer == NULL && sc->sc_rmixer == NULL) {          if (sc->sc_pmixer == NULL && sc->sc_rmixer == NULL) {
                 aprint_error_dev(self, "audio_mixers_init failed, "                  aprint_error_dev(self, "audio_mixers_init failed, "
                     "error = %d\n", error);                      "error = %d\n", error);
                 goto bad;                  goto bad;
         }          }
   
           sc->sc_psz = pserialize_create();
           psref_target_init(&sc->sc_psref, audio_psref_class);
   
         selinit(&sc->sc_wsel);          selinit(&sc->sc_wsel);
         selinit(&sc->sc_rsel);          selinit(&sc->sc_rsel);
   
Line 1044  audioattach(device_t parent, device_t se
Line 1078  audioattach(device_t parent, device_t se
 #endif  #endif
   
         audiorescan(self, "audio", NULL);          audiorescan(self, "audio", NULL);
           sc->sc_exlock = 0;
         return;          return;
   
 bad:  bad:
         /* Clearing hw_if means that device is attached but disabled. */          /* Clearing hw_if means that device is attached but disabled. */
         sc->hw_if = NULL;          sc->hw_if = NULL;
           sc->sc_exlock = 0;
         aprint_error_dev(sc->sc_dev, "disabled\n");          aprint_error_dev(sc->sc_dev, "disabled\n");
         return;          return;
 }  }
Line 1219  static int
Line 1255  static int
 audiodetach(device_t self, int flags)  audiodetach(device_t self, int flags)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
         int maj, mn;          struct audio_file *file;
         int error;          int error;
   
         sc = device_private(self);          sc = device_private(self);
Line 1234  audiodetach(device_t self, int flags)
Line 1270  audiodetach(device_t self, int flags)
         if (error)          if (error)
                 return error;                  return error;
   
           /* delete sysctl nodes */
           sysctl_teardown(&sc->sc_log);
   
         mutex_enter(sc->sc_lock);          mutex_enter(sc->sc_lock);
         sc->sc_dying = true;          sc->sc_dying = true;
         cv_broadcast(&sc->sc_exlockcv);          cv_broadcast(&sc->sc_exlockcv);
Line 1241  audiodetach(device_t self, int flags)
Line 1280  audiodetach(device_t self, int flags)
                 cv_broadcast(&sc->sc_pmixer->outcv);                  cv_broadcast(&sc->sc_pmixer->outcv);
         if (sc->sc_rmixer)          if (sc->sc_rmixer)
                 cv_broadcast(&sc->sc_rmixer->outcv);                  cv_broadcast(&sc->sc_rmixer->outcv);
         mutex_exit(sc->sc_lock);  
   
         /* delete sysctl nodes */          /* Prevent new users */
         sysctl_teardown(&sc->sc_log);          SLIST_FOREACH(file, &sc->sc_files, entry) {
                   atomic_store_relaxed(&file->dying, true);
           }
   
         /* locate the major number */          /*
         maj = cdevsw_lookup_major(&audio_cdevsw);           * Wait for existing users to drain.
            * - pserialize_perform waits for all pserialize_read sections on
            *   all CPUs; after this, no more new psref_acquire can happen.
            * - psref_target_destroy waits for all extant acquired psrefs to
            *   be psref_released.
            */
           pserialize_perform(sc->sc_psz);
           mutex_exit(sc->sc_lock);
           psref_target_destroy(&sc->sc_psref, audio_psref_class);
   
         /*          /*
          * Nuke the vnodes for any open instances (calls close).           * We are now guaranteed that there are no calls to audio fileops
          * Will wait until any activity on the device nodes has ceased.           * that hold sc, and any new calls with files that were for sc will
            * fail.  Thus, we now have exclusive access to the softc.
          */           */
         mn = device_unit(self);          sc->sc_exlock = 1;
         vdevgone(maj, mn | SOUND_DEVICE,    mn | SOUND_DEVICE, VCHR);  
         vdevgone(maj, mn | AUDIO_DEVICE,    mn | AUDIO_DEVICE, VCHR);          /*
         vdevgone(maj, mn | AUDIOCTL_DEVICE, mn | AUDIOCTL_DEVICE, VCHR);           * Nuke all open instances.
         vdevgone(maj, mn | MIXER_DEVICE,    mn | MIXER_DEVICE, VCHR);           * Here, we no longer need any locks to traverse sc_files.
            */
           while ((file = SLIST_FIRST(&sc->sc_files)) != NULL) {
                   audio_unlink(sc, file);
           }
   
         pmf_event_deregister(self, PMFE_AUDIO_VOLUME_DOWN,          pmf_event_deregister(self, PMFE_AUDIO_VOLUME_DOWN,
             audio_volume_down, true);              audio_volume_down, true);
Line 1275  audiodetach(device_t self, int flags)
Line 1328  audiodetach(device_t self, int flags)
         pmf_device_deregister(self);          pmf_device_deregister(self);
   
         /* Free resources */          /* Free resources */
         mutex_enter(sc->sc_lock);  
         if (sc->sc_pmixer) {          if (sc->sc_pmixer) {
                 audio_mixer_destroy(sc, sc->sc_pmixer);                  audio_mixer_destroy(sc, sc->sc_pmixer);
                 kmem_free(sc->sc_pmixer, sizeof(*sc->sc_pmixer));                  kmem_free(sc->sc_pmixer, sizeof(*sc->sc_pmixer));
Line 1284  audiodetach(device_t self, int flags)
Line 1336  audiodetach(device_t self, int flags)
                 audio_mixer_destroy(sc, sc->sc_rmixer);                  audio_mixer_destroy(sc, sc->sc_rmixer);
                 kmem_free(sc->sc_rmixer, sizeof(*sc->sc_rmixer));                  kmem_free(sc->sc_rmixer, sizeof(*sc->sc_rmixer));
         }          }
         mutex_exit(sc->sc_lock);          if (sc->sc_am)
                   kern_free(sc->sc_am);
   
         seldestroy(&sc->sc_wsel);          seldestroy(&sc->sc_wsel);
         seldestroy(&sc->sc_rsel);          seldestroy(&sc->sc_rsel);
Line 1354  audio_attach_mi(const struct audio_hw_if
Line 1407  audio_attach_mi(const struct audio_hw_if
 }  }
   
 /*  /*
  * Acquire sc_lock and enter exlock critical section.   * Enter critical section and also keep sc_lock.
  * If successful, it returns 0.  Otherwise returns errno.   * If successful, returns 0 with sc_lock held.  Otherwise returns errno.
    * Must be called without sc_lock held.
  */   */
 static int  static int
 audio_enter_exclusive(struct audio_softc *sc)  audio_exlock_mutex_enter(struct audio_softc *sc)
 {  {
         int error;          int error;
   
         KASSERT(!mutex_owned(sc->sc_lock));  
   
         mutex_enter(sc->sc_lock);          mutex_enter(sc->sc_lock);
         if (sc->sc_dying) {          if (sc->sc_dying) {
                 mutex_exit(sc->sc_lock);                  mutex_exit(sc->sc_lock);
Line 1386  audio_enter_exclusive(struct audio_softc
Line 1438  audio_enter_exclusive(struct audio_softc
 }  }
   
 /*  /*
  * Leave exlock critical section and release sc_lock.   * Exit critical section and exit sc_lock.
  * Must be called with sc_lock held.   * Must be called with sc_lock held.
  */   */
 static void  static void
 audio_exit_exclusive(struct audio_softc *sc)  audio_exlock_mutex_exit(struct audio_softc *sc)
 {  {
   
         KASSERT(mutex_owned(sc->sc_lock));          KASSERT(mutex_owned(sc->sc_lock));
         KASSERT(sc->sc_exlock);  
   
         /* Leave critical section */  
         sc->sc_exlock = 0;          sc->sc_exlock = 0;
         cv_broadcast(&sc->sc_exlockcv);          cv_broadcast(&sc->sc_exlockcv);
         mutex_exit(sc->sc_lock);          mutex_exit(sc->sc_lock);
 }  }
   
 /*  /*
    * Enter critical section.
    * If successful, it returns 0.  Otherwise returns errno.
    * Must be called without sc_lock held.
    * This function returns without sc_lock held.
    */
   static int
   audio_exlock_enter(struct audio_softc *sc)
   {
           int error;
   
           error = audio_exlock_mutex_enter(sc);
           if (error)
                   return error;
           mutex_exit(sc->sc_lock);
           return 0;
   }
   
   /*
    * Exit critical section.
    * Must be called without sc_lock held.
    */
   static void
   audio_exlock_exit(struct audio_softc *sc)
   {
   
           mutex_enter(sc->sc_lock);
           audio_exlock_mutex_exit(sc);
   }
   
   /*
    * Acquire sc from file, and increment the psref count.
    * If successful, returns sc.  Otherwise returns NULL.
    */
   struct audio_softc *
   audio_file_enter(audio_file_t *file, struct psref *refp)
   {
           int s;
           bool dying;
   
           /* psref(9) forbids to migrate CPUs */
           curlwp_bind();
   
           /* Block audiodetach while we acquire a reference */
           s = pserialize_read_enter();
   
           /* If close or audiodetach already ran, tough -- no more audio */
           dying = atomic_load_relaxed(&file->dying);
           if (dying) {
                   pserialize_read_exit(s);
                   return NULL;
           }
   
           /* Acquire a reference */
           psref_acquire(refp, &file->sc->sc_psref, audio_psref_class);
   
           /* Now sc won't go away until we drop the reference count */
           pserialize_read_exit(s);
   
           return file->sc;
   }
   
   /*
    * Decrement the psref count.
    */
   void
   audio_file_exit(struct audio_softc *sc, struct psref *refp)
   {
   
           psref_release(refp, &sc->sc_psref, audio_psref_class);
   }
   
   /*
  * Wait for I/O to complete, releasing sc_lock.   * Wait for I/O to complete, releasing sc_lock.
  * Must be called with sc_lock held.   * Must be called with sc_lock held.
  */   */
Line 1474  audioopen(dev_t dev, int flags, int ifmt
Line 1596  audioopen(dev_t dev, int flags, int ifmt
         if (sc == NULL || sc->hw_if == NULL)          if (sc == NULL || sc->hw_if == NULL)
                 return ENXIO;                  return ENXIO;
   
         error = audio_enter_exclusive(sc);          error = audio_exlock_enter(sc);
         if (error)          if (error)
                 return error;                  return error;
   
Line 1494  audioopen(dev_t dev, int flags, int ifmt
Line 1616  audioopen(dev_t dev, int flags, int ifmt
                 error = ENXIO;                  error = ENXIO;
                 break;                  break;
         }          }
         audio_exit_exclusive(sc);          audio_exlock_exit(sc);
   
         return error;          return error;
 }  }
Line 1503  static int
Line 1625  static int
 audioclose(struct file *fp)  audioclose(struct file *fp)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
           struct psref sc_ref;
         audio_file_t *file;          audio_file_t *file;
         int error;          int error;
         dev_t dev;          dev_t dev;
   
         KASSERT(fp->f_audioctx);          KASSERT(fp->f_audioctx);
         file = fp->f_audioctx;          file = fp->f_audioctx;
         sc = file->sc;  
         dev = file->dev;          dev = file->dev;
           error = 0;
   
         /* audio_{enter,exit}_exclusive() is called by lower audio_close() */          /*
            * audioclose() must
            * - unplug track from the trackmixer (and unplug anything from softc),
            *   if sc exists.
            * - free all memory objects, regardless of sc.
            */
   
         device_active(sc->sc_dev, DVA_SYSTEM);          sc = audio_file_enter(file, &sc_ref);
         switch (AUDIODEV(dev)) {          if (sc) {
         case SOUND_DEVICE:                  switch (AUDIODEV(dev)) {
         case AUDIO_DEVICE:                  case SOUND_DEVICE:
                 error = audio_close(sc, file);                  case AUDIO_DEVICE:
                 break;                          error = audio_close(sc, file);
         case AUDIOCTL_DEVICE:                          break;
                 error = 0;                  case AUDIOCTL_DEVICE:
                 break;                          error = 0;
         case MIXER_DEVICE:                          break;
                 error = mixer_close(sc, file);                  case MIXER_DEVICE:
                 break;                          error = mixer_close(sc, file);
         default:                          break;
                 error = ENXIO;                  default:
                 break;                          error = ENXIO;
         }                          break;
         if (error == 0) {                  }
                 kmem_free(fp->f_audioctx, sizeof(audio_file_t));  
                 fp->f_audioctx = NULL;                  audio_file_exit(sc, &sc_ref);
         }          }
   
           /* Free memory objects anyway */
           TRACEF(2, file, "free memory");
           if (file->ptrack)
                   audio_track_destroy(file->ptrack);
           if (file->rtrack)
                   audio_track_destroy(file->rtrack);
           kmem_free(file, sizeof(*file));
           fp->f_audioctx = NULL;
   
         return error;          return error;
 }  }
   
Line 1543  audioread(struct file *fp, off_t *offp, 
Line 1680  audioread(struct file *fp, off_t *offp, 
         int ioflag)          int ioflag)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
           struct psref sc_ref;
         audio_file_t *file;          audio_file_t *file;
         int error;          int error;
         dev_t dev;          dev_t dev;
   
         KASSERT(fp->f_audioctx);          KASSERT(fp->f_audioctx);
         file = fp->f_audioctx;          file = fp->f_audioctx;
         sc = file->sc;  
         dev = file->dev;          dev = file->dev;
   
           sc = audio_file_enter(file, &sc_ref);
           if (sc == NULL)
                   return EIO;
   
         if (fp->f_flag & O_NONBLOCK)          if (fp->f_flag & O_NONBLOCK)
                 ioflag |= IO_NDELAY;                  ioflag |= IO_NDELAY;
   
Line 1569  audioread(struct file *fp, off_t *offp, 
Line 1710  audioread(struct file *fp, off_t *offp, 
                 break;                  break;
         }          }
   
           audio_file_exit(sc, &sc_ref);
         return error;          return error;
 }  }
   
Line 1577  audiowrite(struct file *fp, off_t *offp,
Line 1719  audiowrite(struct file *fp, off_t *offp,
         int ioflag)          int ioflag)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
           struct psref sc_ref;
         audio_file_t *file;          audio_file_t *file;
         int error;          int error;
         dev_t dev;          dev_t dev;
   
         KASSERT(fp->f_audioctx);          KASSERT(fp->f_audioctx);
         file = fp->f_audioctx;          file = fp->f_audioctx;
         sc = file->sc;  
         dev = file->dev;          dev = file->dev;
   
           sc = audio_file_enter(file, &sc_ref);
           if (sc == NULL)
                   return EIO;
   
         if (fp->f_flag & O_NONBLOCK)          if (fp->f_flag & O_NONBLOCK)
                 ioflag |= IO_NDELAY;                  ioflag |= IO_NDELAY;
   
Line 1603  audiowrite(struct file *fp, off_t *offp,
Line 1749  audiowrite(struct file *fp, off_t *offp,
                 break;                  break;
         }          }
   
           audio_file_exit(sc, &sc_ref);
         return error;          return error;
 }  }
   
Line 1610  static int
Line 1757  static int
 audioioctl(struct file *fp, u_long cmd, void *addr)  audioioctl(struct file *fp, u_long cmd, void *addr)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
           struct psref sc_ref;
         audio_file_t *file;          audio_file_t *file;
         struct lwp *l = curlwp;          struct lwp *l = curlwp;
         int error;          int error;
Line 1617  audioioctl(struct file *fp, u_long cmd, 
Line 1765  audioioctl(struct file *fp, u_long cmd, 
   
         KASSERT(fp->f_audioctx);          KASSERT(fp->f_audioctx);
         file = fp->f_audioctx;          file = fp->f_audioctx;
         sc = file->sc;  
         dev = file->dev;          dev = file->dev;
   
           sc = audio_file_enter(file, &sc_ref);
           if (sc == NULL)
                   return EIO;
   
         switch (AUDIODEV(dev)) {          switch (AUDIODEV(dev)) {
         case SOUND_DEVICE:          case SOUND_DEVICE:
         case AUDIO_DEVICE:          case AUDIO_DEVICE:
Line 1641  audioioctl(struct file *fp, u_long cmd, 
Line 1792  audioioctl(struct file *fp, u_long cmd, 
                 break;                  break;
         }          }
   
           audio_file_exit(sc, &sc_ref);
         return error;          return error;
 }  }
   
 static int  static int
 audiostat(struct file *fp, struct stat *st)  audiostat(struct file *fp, struct stat *st)
 {  {
           struct audio_softc *sc;
           struct psref sc_ref;
         audio_file_t *file;          audio_file_t *file;
   
         KASSERT(fp->f_audioctx);          KASSERT(fp->f_audioctx);
         file = fp->f_audioctx;          file = fp->f_audioctx;
   
           sc = audio_file_enter(file, &sc_ref);
           if (sc == NULL)
                   return EIO;
   
         memset(st, 0, sizeof(*st));          memset(st, 0, sizeof(*st));
   
         st->st_dev = file->dev;          st->st_dev = file->dev;
         st->st_uid = kauth_cred_geteuid(fp->f_cred);          st->st_uid = kauth_cred_geteuid(fp->f_cred);
         st->st_gid = kauth_cred_getegid(fp->f_cred);          st->st_gid = kauth_cred_getegid(fp->f_cred);
         st->st_mode = S_IFCHR;          st->st_mode = S_IFCHR;
   
           audio_file_exit(sc, &sc_ref);
         return 0;          return 0;
 }  }
   
Line 1665  static int
Line 1825  static int
 audiopoll(struct file *fp, int events)  audiopoll(struct file *fp, int events)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
           struct psref sc_ref;
         audio_file_t *file;          audio_file_t *file;
         struct lwp *l = curlwp;          struct lwp *l = curlwp;
         int revents;          int revents;
Line 1672  audiopoll(struct file *fp, int events)
Line 1833  audiopoll(struct file *fp, int events)
   
         KASSERT(fp->f_audioctx);          KASSERT(fp->f_audioctx);
         file = fp->f_audioctx;          file = fp->f_audioctx;
         sc = file->sc;  
         dev = file->dev;          dev = file->dev;
   
           sc = audio_file_enter(file, &sc_ref);
           if (sc == NULL)
                   return EIO;
   
         switch (AUDIODEV(dev)) {          switch (AUDIODEV(dev)) {
         case SOUND_DEVICE:          case SOUND_DEVICE:
         case AUDIO_DEVICE:          case AUDIO_DEVICE:
Line 1689  audiopoll(struct file *fp, int events)
Line 1853  audiopoll(struct file *fp, int events)
                 break;                  break;
         }          }
   
           audio_file_exit(sc, &sc_ref);
         return revents;          return revents;
 }  }
   
Line 1696  static int
Line 1861  static int
 audiokqfilter(struct file *fp, struct knote *kn)  audiokqfilter(struct file *fp, struct knote *kn)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
           struct psref sc_ref;
         audio_file_t *file;          audio_file_t *file;
         dev_t dev;          dev_t dev;
         int error;          int error;
   
         KASSERT(fp->f_audioctx);          KASSERT(fp->f_audioctx);
         file = fp->f_audioctx;          file = fp->f_audioctx;
         sc = file->sc;  
         dev = file->dev;          dev = file->dev;
   
           sc = audio_file_enter(file, &sc_ref);
           if (sc == NULL)
                   return EIO;
   
         switch (AUDIODEV(dev)) {          switch (AUDIODEV(dev)) {
         case SOUND_DEVICE:          case SOUND_DEVICE:
         case AUDIO_DEVICE:          case AUDIO_DEVICE:
Line 1719  audiokqfilter(struct file *fp, struct kn
Line 1888  audiokqfilter(struct file *fp, struct kn
                 break;                  break;
         }          }
   
           audio_file_exit(sc, &sc_ref);
         return error;          return error;
 }  }
   
Line 1727  audiommap(struct file *fp, off_t *offp, 
Line 1897  audiommap(struct file *fp, off_t *offp, 
         int *advicep, struct uvm_object **uobjp, int *maxprotp)          int *advicep, struct uvm_object **uobjp, int *maxprotp)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
           struct psref sc_ref;
         audio_file_t *file;          audio_file_t *file;
         dev_t dev;          dev_t dev;
         int error;          int error;
   
         KASSERT(fp->f_audioctx);          KASSERT(fp->f_audioctx);
         file = fp->f_audioctx;          file = fp->f_audioctx;
         sc = file->sc;  
         dev = file->dev;          dev = file->dev;
   
           sc = audio_file_enter(file, &sc_ref);
           if (sc == NULL)
                   return EIO;
   
         mutex_enter(sc->sc_lock);          mutex_enter(sc->sc_lock);
         device_active(sc->sc_dev, DVA_SYSTEM); /* XXXJDM */          device_active(sc->sc_dev, DVA_SYSTEM); /* XXXJDM */
         mutex_exit(sc->sc_lock);          mutex_exit(sc->sc_lock);
Line 1753  audiommap(struct file *fp, off_t *offp, 
Line 1927  audiommap(struct file *fp, off_t *offp, 
                 break;                  break;
         }          }
   
           audio_file_exit(sc, &sc_ref);
         return error;          return error;
 }  }
   
Line 1775  audiobellopen(dev_t dev, audio_file_t **
Line 1950  audiobellopen(dev_t dev, audio_file_t **
         if (sc == NULL || sc->hw_if == NULL)          if (sc == NULL || sc->hw_if == NULL)
                 return ENXIO;                  return ENXIO;
   
         error = audio_enter_exclusive(sc);          error = audio_exlock_enter(sc);
         if (error)          if (error)
                 return error;                  return error;
   
         device_active(sc->sc_dev, DVA_SYSTEM);          device_active(sc->sc_dev, DVA_SYSTEM);
         error = audio_open(dev, sc, FWRITE, 0, curlwp, filep);          error = audio_open(dev, sc, FWRITE, 0, curlwp, filep);
   
         audio_exit_exclusive(sc);          audio_exlock_exit(sc);
         return error;          return error;
 }  }
   
Line 1791  int
Line 1966  int
 audiobellclose(audio_file_t *file)  audiobellclose(audio_file_t *file)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
           struct psref sc_ref;
         int error;          int error;
   
         sc = file->sc;          sc = audio_file_enter(file, &sc_ref);
           if (sc == NULL)
                   return EIO;
   
         device_active(sc->sc_dev, DVA_SYSTEM);  
         error = audio_close(sc, file);          error = audio_close(sc, file);
   
         /*          audio_file_exit(sc, &sc_ref);
          * Since file has already been destructed,  
          * audio_file_release() is not necessary.  
          */  
   
           KASSERT(file->ptrack);
           audio_track_destroy(file->ptrack);
           KASSERT(file->rtrack == NULL);
           kmem_free(file, sizeof(*file));
         return error;          return error;
 }  }
   
Line 1811  int
Line 1989  int
 audiobellsetrate(audio_file_t *file, u_int sample_rate)  audiobellsetrate(audio_file_t *file, u_int sample_rate)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
           struct psref sc_ref;
         struct audio_info ai;          struct audio_info ai;
         int error;          int error;
   
         sc = file->sc;          sc = audio_file_enter(file, &sc_ref);
           if (sc == NULL)
                   return EIO;
   
         AUDIO_INITINFO(&ai);          AUDIO_INITINFO(&ai);
         ai.play.sample_rate = sample_rate;          ai.play.sample_rate = sample_rate;
   
         error = audio_enter_exclusive(sc);          error = audio_exlock_enter(sc);
         if (error)          if (error)
                 return error;                  goto done;
         error = audio_file_setinfo(sc, file, &ai);          error = audio_file_setinfo(sc, file, &ai);
         audio_exit_exclusive(sc);          audio_exlock_exit(sc);
   
   done:
           audio_file_exit(sc, &sc_ref);
         return error;          return error;
 }  }
   
Line 1833  int
Line 2016  int
 audiobellwrite(audio_file_t *file, struct uio *uio)  audiobellwrite(audio_file_t *file, struct uio *uio)
 {  {
         struct audio_softc *sc;          struct audio_softc *sc;
           struct psref sc_ref;
         int error;          int error;
   
         sc = file->sc;          sc = audio_file_enter(file, &sc_ref);
           if (sc == NULL)
                   return EIO;
   
         error = audio_write(sc, uio, 0, file);          error = audio_write(sc, uio, 0, file);
   
           audio_file_exit(sc, &sc_ref);
         return error;          return error;
 }  }
   
Line 1844  audiobellwrite(audio_file_t *file, struc
Line 2033  audiobellwrite(audio_file_t *file, struc
 /*  /*
  * Audio driver   * Audio driver
  */   */
   
   /*
    * Must be called with sc_exlock held and without sc_lock held.
    */
 int  int
 audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,  audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
         struct lwp *l, audio_file_t **bellfile)          struct lwp *l, audio_file_t **bellfile)
Line 1856  audio_open(dev_t dev, struct audio_softc
Line 2049  audio_open(dev_t dev, struct audio_softc
         int fd;          int fd;
         int error;          int error;
   
         KASSERT(mutex_owned(sc->sc_lock));  
         KASSERT(sc->sc_exlock);          KASSERT(sc->sc_exlock);
   
         TRACE(1, "%sdev=%s flags=0x%x po=%d ro=%d",          TRACE(1, "%sdev=%s flags=0x%x po=%d ro=%d",
Line 1978  audio_open(dev_t dev, struct audio_softc
Line 2170  audio_open(dev_t dev, struct audio_softc
                                         hwflags |= FREAD;                                          hwflags |= FREAD;
                         }                          }
   
                           mutex_enter(sc->sc_lock);
                         mutex_enter(sc->sc_intr_lock);                          mutex_enter(sc->sc_intr_lock);
                         error = sc->hw_if->open(sc->hw_hdl, hwflags);                          error = sc->hw_if->open(sc->hw_hdl, hwflags);
                         mutex_exit(sc->sc_intr_lock);                          mutex_exit(sc->sc_intr_lock);
                           mutex_exit(sc->sc_lock);
                         if (error)                          if (error)
                                 goto bad2;                                  goto bad2;
                 }                  }
Line 1997  audio_open(dev_t dev, struct audio_softc
Line 2191  audio_open(dev_t dev, struct audio_softc
                                 } else {                                  } else {
                                         on = 0;                                          on = 0;
                                 }                                  }
                                   mutex_enter(sc->sc_lock);
                                 mutex_enter(sc->sc_intr_lock);                                  mutex_enter(sc->sc_intr_lock);
                                 error = sc->hw_if->speaker_ctl(sc->hw_hdl, on);                                  error = sc->hw_if->speaker_ctl(sc->hw_hdl, on);
                                 mutex_exit(sc->sc_intr_lock);                                  mutex_exit(sc->sc_intr_lock);
                                   mutex_exit(sc->sc_lock);
                                 if (error)                                  if (error)
                                         goto bad3;                                          goto bad3;
                         }                          }
Line 2016  audio_open(dev_t dev, struct audio_softc
Line 2212  audio_open(dev_t dev, struct audio_softc
         if (af->ptrack && sc->sc_popens == 0) {          if (af->ptrack && sc->sc_popens == 0) {
                 if (sc->hw_if->init_output) {                  if (sc->hw_if->init_output) {
                         hwbuf = &sc->sc_pmixer->hwbuf;                          hwbuf = &sc->sc_pmixer->hwbuf;
                           mutex_enter(sc->sc_lock);
                         mutex_enter(sc->sc_intr_lock);                          mutex_enter(sc->sc_intr_lock);
                         error = sc->hw_if->init_output(sc->hw_hdl,                          error = sc->hw_if->init_output(sc->hw_hdl,
                             hwbuf->mem,                              hwbuf->mem,
                             hwbuf->capacity *                              hwbuf->capacity *
                             hwbuf->fmt.channels * hwbuf->fmt.stride / NBBY);                              hwbuf->fmt.channels * hwbuf->fmt.stride / NBBY);
                         mutex_exit(sc->sc_intr_lock);                          mutex_exit(sc->sc_intr_lock);
                           mutex_exit(sc->sc_lock);
                         if (error)                          if (error)
                                 goto bad3;                                  goto bad3;
                 }                  }
         }          }
         /* Call init_input if this is the first recording open. */          /*
            * Call init_input and start rmixer, if this is the first recording
            * open.  See pause consideration notes.
            */
         if (af->rtrack && sc->sc_ropens == 0) {          if (af->rtrack && sc->sc_ropens == 0) {
                 if (sc->hw_if->init_input) {                  if (sc->hw_if->init_input) {
                         hwbuf = &sc->sc_rmixer->hwbuf;                          hwbuf = &sc->sc_rmixer->hwbuf;
                           mutex_enter(sc->sc_lock);
                         mutex_enter(sc->sc_intr_lock);                          mutex_enter(sc->sc_intr_lock);
                         error = sc->hw_if->init_input(sc->hw_hdl,                          error = sc->hw_if->init_input(sc->hw_hdl,
                             hwbuf->mem,                              hwbuf->mem,
                             hwbuf->capacity *                              hwbuf->capacity *
                             hwbuf->fmt.channels * hwbuf->fmt.stride / NBBY);                              hwbuf->fmt.channels * hwbuf->fmt.stride / NBBY);
                         mutex_exit(sc->sc_intr_lock);                          mutex_exit(sc->sc_intr_lock);
                           mutex_exit(sc->sc_lock);
                         if (error)                          if (error)
                                 goto bad3;                                  goto bad3;
                 }                  }
   
                   mutex_enter(sc->sc_lock);
                   audio_rmixer_start(sc);
                   mutex_exit(sc->sc_lock);
         }          }
   
         if (bellfile == NULL) {          if (bellfile == NULL) {
Line 2051  audio_open(dev_t dev, struct audio_softc
Line 2258  audio_open(dev_t dev, struct audio_softc
          * Count up finally.           * Count up finally.
          * Don't fail from here.           * Don't fail from here.
          */           */
           mutex_enter(sc->sc_lock);
         if (af->ptrack)          if (af->ptrack)
                 sc->sc_popens++;                  sc->sc_popens++;
         if (af->rtrack)          if (af->rtrack)
Line 2058  audio_open(dev_t dev, struct audio_softc
Line 2266  audio_open(dev_t dev, struct audio_softc
         mutex_enter(sc->sc_intr_lock);          mutex_enter(sc->sc_intr_lock);
         SLIST_INSERT_HEAD(&sc->sc_files, af, entry);          SLIST_INSERT_HEAD(&sc->sc_files, af, entry);
         mutex_exit(sc->sc_intr_lock);          mutex_exit(sc->sc_intr_lock);
           mutex_exit(sc->sc_lock);
   
         if (bellfile) {          if (bellfile) {
                 *bellfile = af;                  *bellfile = af;
         } else {          } else {
                 error = fd_clone(fp, fd, flags, &audio_fileops, af);                  error = fd_clone(fp, fd, flags, &audio_fileops, af);
                 KASSERT(error == EMOVEFD);                  KASSERTMSG(error == EMOVEFD, "error=%d", error);
         }          }
   
         TRACEF(3, af, "done");          TRACEF(3, af, "done");
Line 2076  audio_open(dev_t dev, struct audio_softc
Line 2285  audio_open(dev_t dev, struct audio_softc
 bad3:  bad3:
         if (sc->sc_popens + sc->sc_ropens == 0) {          if (sc->sc_popens + sc->sc_ropens == 0) {
                 if (sc->hw_if->close) {                  if (sc->hw_if->close) {
                           mutex_enter(sc->sc_lock);
                         mutex_enter(sc->sc_intr_lock);                          mutex_enter(sc->sc_intr_lock);
                         sc->hw_if->close(sc->hw_hdl);                          sc->hw_if->close(sc->hw_hdl);
                         mutex_exit(sc->sc_intr_lock);                          mutex_exit(sc->sc_intr_lock);
                           mutex_exit(sc->sc_lock);
                 }                  }
         }          }
 bad2:  bad2:
Line 2096  bad1:
Line 2307  bad1:
 }  }
   
 /*  /*
  * Must NOT called with sc_lock nor sc_exlock held.   * Must be called without sc_lock nor sc_exlock held.
  */   */
 int  int
 audio_close(struct audio_softc *sc, audio_file_t *file)  audio_close(struct audio_softc *sc, audio_file_t *file)
 {  {
         audio_track_t *oldtrack;  
           /* Protect entering new fileops to this file */
           atomic_store_relaxed(&file->dying, true);
   
           /*
            * Drain first.
            * It must be done before unlinking(acquiring exlock).
            */
           if (file->ptrack) {
                   mutex_enter(sc->sc_lock);
                   audio_track_drain(sc, file->ptrack);
                   mutex_exit(sc->sc_lock);
           }
   
           return audio_unlink(sc, file);
   }
   
   /*
    * Unlink this file, but not freeing memory here.
    * Must be called without sc_lock nor sc_exlock held.
    */
   int
   audio_unlink(struct audio_softc *sc, audio_file_t *file)
   {
         int error;          int error;
   
         KASSERT(!mutex_owned(sc->sc_lock));          mutex_enter(sc->sc_lock);
   
         TRACEF(1, file, "%spid=%d.%d po=%d ro=%d",          TRACEF(1, file, "%spid=%d.%d po=%d ro=%d",
             (audiodebug >= 3) ? "start " : "",              (audiodebug >= 3) ? "start " : "",
Line 2115  audio_close(struct audio_softc *sc, audi
Line 2349  audio_close(struct audio_softc *sc, audi
             sc->sc_popens, sc->sc_ropens);              sc->sc_popens, sc->sc_ropens);
   
         /*          /*
          * Drain first.           * Acquire exlock to protect counters.
          * It must be done before acquiring exclusive lock.           * Does not use audio_exlock_enter() due to sc_dying.
          */           */
         if (file->ptrack) {          while (__predict_false(sc->sc_exlock != 0)) {
                 mutex_enter(sc->sc_lock);                  error = cv_timedwait_sig(&sc->sc_exlockcv, sc->sc_lock,
                 audio_track_drain(sc, file->ptrack);                      mstohz(AUDIO_TIMEOUT));
                 mutex_exit(sc->sc_lock);                  /* XXX what should I do on error? */
                   if (error == EWOULDBLOCK) {
                           mutex_exit(sc->sc_lock);
                           device_printf(sc->sc_dev,
                               "%s: cv_timedwait_sig failed %d", __func__, error);
                           return error;
                   }
         }          }
           sc->sc_exlock = 1;
   
         /* Then, acquire exclusive lock to protect counters. */          device_active(sc->sc_dev, DVA_SYSTEM);
         /* XXX what should I do when an error occurs? */  
         error = audio_enter_exclusive(sc);          mutex_enter(sc->sc_intr_lock);
         if (error)          SLIST_REMOVE(&sc->sc_files, file, audio_file, entry);
                 return error;          mutex_exit(sc->sc_intr_lock);
   
         if (file->ptrack) {          if (file->ptrack) {
                   TRACET(3, file->ptrack, "dropframes=%" PRIu64,
                       file->ptrack->dropframes);
   
                   KASSERT(sc->sc_popens > 0);
                   sc->sc_popens--;
   
                 /* Call hw halt_output if this is the last playback track. */                  /* Call hw halt_output if this is the last playback track. */
                 if (sc->sc_popens == 1 && sc->sc_pbusy) {                  if (sc->sc_popens == 0 && sc->sc_pbusy) {
                         error = audio_pmixer_halt(sc);                          error = audio_pmixer_halt(sc);
                         if (error) {                          if (error) {
                                 device_printf(sc->sc_dev,                                  device_printf(sc->sc_dev,
                                     "halt_output failed with %d\n", error);                                      "halt_output failed with %d (ignored)\n",
                                       error);
                         }                          }
                 }                  }
   
                 /* Destroy the track. */  
                 oldtrack = file->ptrack;  
                 mutex_enter(sc->sc_intr_lock);  
                 file->ptrack = NULL;  
                 mutex_exit(sc->sc_intr_lock);  
                 TRACET(3, oldtrack, "dropframes=%" PRIu64,  
                     oldtrack->dropframes);  
                 audio_track_destroy(oldtrack);  
   
                 KASSERT(sc->sc_popens > 0);  
                 sc->sc_popens--;  
   
                 /* Restore mixing volume if all tracks are gone. */                  /* Restore mixing volume if all tracks are gone. */
                 if (sc->sc_popens == 0) {                  if (sc->sc_popens == 0) {
                           /* intr_lock is not necessary, but just manners. */
                         mutex_enter(sc->sc_intr_lock);                          mutex_enter(sc->sc_intr_lock);
                         sc->sc_pmixer->volume = 256;                          sc->sc_pmixer->volume = 256;
                         sc->sc_pmixer->voltimer = 0;                          sc->sc_pmixer->voltimer = 0;
Line 2161  audio_close(struct audio_softc *sc, audi
Line 2398  audio_close(struct audio_softc *sc, audi
                 }                  }
         }          }
         if (file->rtrack) {          if (file->rtrack) {
                   TRACET(3, file->rtrack, "dropframes=%" PRIu64,
                       file->rtrack->dropframes);
   
                   KASSERT(sc->sc_ropens > 0);
                   sc->sc_ropens--;
   
                 /* Call hw halt_input if this is the last recording track. */                  /* Call hw halt_input if this is the last recording track. */
                 if (sc->sc_ropens == 1 && sc->sc_rbusy) {                  if (sc->sc_ropens == 0 && sc->sc_rbusy) {
                         error = audio_rmixer_halt(sc);                          error = audio_rmixer_halt(sc);
                         if (error) {                          if (error) {
                                 device_printf(sc->sc_dev,                                  device_printf(sc->sc_dev,
                                     "halt_input failed with %d\n", error);                                      "halt_input failed with %d (ignored)\n",
                                       error);
                         }                          }
                 }                  }
   
                 /* Destroy the track. */  
                 oldtrack = file->rtrack;  
                 mutex_enter(sc->sc_intr_lock);  
                 file->rtrack = NULL;  
                 mutex_exit(sc->sc_intr_lock);  
                 TRACET(3, oldtrack, "dropframes=%" PRIu64,  
                     oldtrack->dropframes);  
                 audio_track_destroy(oldtrack);  
   
                 KASSERT(sc->sc_ropens > 0);  
                 sc->sc_ropens--;  
         }          }
   
         /* Call hw close if this is the last track. */          /* Call hw close if this is the last track. */
Line 2191  audio_close(struct audio_softc *sc, audi
Line 2424  audio_close(struct audio_softc *sc, audi
                         sc->hw_if->close(sc->hw_hdl);                          sc->hw_if->close(sc->hw_hdl);
                         mutex_exit(sc->sc_intr_lock);                          mutex_exit(sc->sc_intr_lock);
                 }                  }
   
                 kauth_cred_free(sc->sc_cred);  
         }          }
   
         mutex_enter(sc->sc_intr_lock);          mutex_exit(sc->sc_lock);
         SLIST_REMOVE(&sc->sc_files, file, audio_file, entry);          if (sc->sc_popens + sc->sc_ropens == 0)
         mutex_exit(sc->sc_intr_lock);                  kauth_cred_free(sc->sc_cred);
   
         TRACE(3, "done");          TRACE(3, "done");
         audio_exit_exclusive(sc);          audio_exlock_exit(sc);
   
         return 0;          return 0;
 }  }
   
   /*
    * Must be called without sc_lock nor sc_exlock held.
    */
 int  int
 audio_read(struct audio_softc *sc, struct uio *uio, int ioflag,  audio_read(struct audio_softc *sc, struct uio *uio, int ioflag,
         audio_file_t *file)          audio_file_t *file)
Line 2213  audio_read(struct audio_softc *sc, struc
Line 2448  audio_read(struct audio_softc *sc, struc
         audio_ring_t *input;          audio_ring_t *input;
         int error;          int error;
   
         KASSERT(!mutex_owned(sc->sc_lock));  
   
         /*          /*
          * On half-duplex hardware, O_RDWR is treated as O_WRONLY.           * On half-duplex hardware, O_RDWR is treated as O_WRONLY.
          * However read() system call itself can be called because it's           * However read() system call itself can be called because it's
Line 2232  audio_read(struct audio_softc *sc, struc
Line 2465  audio_read(struct audio_softc *sc, struc
         TRACET(2, track, "resid=%zd", uio->uio_resid);          TRACET(2, track, "resid=%zd", uio->uio_resid);
   
 #ifdef AUDIO_PM_IDLE  #ifdef AUDIO_PM_IDLE
         mutex_enter(sc->sc_lock);          error = audio_exlock_mutex_enter(sc);
           if (error)
                   return error;
   
         if (device_is_active(&sc->sc_dev) || sc->sc_idle)          if (device_is_active(&sc->sc_dev) || sc->sc_idle)
                 device_active(&sc->sc_dev, DVA_SYSTEM);                  device_active(&sc->sc_dev, DVA_SYSTEM);
         mutex_exit(sc->sc_lock);  
           /* In recording, unlike playback, read() never operates rmixer. */
   
           audio_exlock_mutex_exit(sc);
 #endif  #endif
   
         usrbuf = &track->usrbuf;          usrbuf = &track->usrbuf;
         input = track->input;          input = track->input;
   
         /*  
          * The first read starts rmixer.  
          */  
         error = audio_enter_exclusive(sc);  
         if (error)  
                 return error;  
         if (sc->sc_rbusy == false)  
                 audio_rmixer_start(sc);  
         audio_exit_exclusive(sc);  
   
         error = 0;          error = 0;
   
         while (uio->uio_resid > 0 && error == 0) {          while (uio->uio_resid > 0 && error == 0) {
                 int bytes;                  int bytes;
   
Line 2331  audio_file_clear(struct audio_softc *sc,
Line 2560  audio_file_clear(struct audio_softc *sc,
                 audio_track_clear(sc, file->rtrack);                  audio_track_clear(sc, file->rtrack);
 }  }
   
   /*
    * Must be called without sc_lock nor sc_exlock held.
    */
 int  int
 audio_write(struct audio_softc *sc, struct uio *uio, int ioflag,  audio_write(struct audio_softc *sc, struct uio *uio, int ioflag,
         audio_file_t *file)          audio_file_t *file)
Line 2340  audio_write(struct audio_softc *sc, stru
Line 2572  audio_write(struct audio_softc *sc, stru
         audio_ring_t *outbuf;          audio_ring_t *outbuf;
         int error;          int error;
   
         KASSERT(!mutex_owned(sc->sc_lock));  
   
         track = file->ptrack;          track = file->ptrack;
         KASSERT(track);          KASSERT(track);
   
Line 2358  audio_write(struct audio_softc *sc, stru
Line 2588  audio_write(struct audio_softc *sc, stru
                 return 0;                  return 0;
         }          }
   
           error = audio_exlock_mutex_enter(sc);
           if (error)
                   return error;
   
 #ifdef AUDIO_PM_IDLE  #ifdef AUDIO_PM_IDLE
         mutex_enter(sc->sc_lock);  
         if (device_is_active(&sc->sc_dev) || sc->sc_idle)          if (device_is_active(&sc->sc_dev) || sc->sc_idle)
                 device_active(&sc->sc_dev, DVA_SYSTEM);                  device_active(&sc->sc_dev, DVA_SYSTEM);
         mutex_exit(sc->sc_lock);  
 #endif  #endif
   
         usrbuf = &track->usrbuf;  
         outbuf = &track->outbuf;  
   
         /*          /*
          * The first write starts pmixer.           * The first write starts pmixer.
          */           */
         error = audio_enter_exclusive(sc);  
         if (error)  
                 return error;  
         if (sc->sc_pbusy == false)          if (sc->sc_pbusy == false)
                 audio_pmixer_start(sc, false);                  audio_pmixer_start(sc, false);
         audio_exit_exclusive(sc);          audio_exlock_mutex_exit(sc);
   
           usrbuf = &track->usrbuf;
           outbuf = &track->outbuf;
         track->pstate = AUDIO_STATE_RUNNING;          track->pstate = AUDIO_STATE_RUNNING;
         error = 0;          error = 0;
   
         while (uio->uio_resid > 0 && error == 0) {          while (uio->uio_resid > 0 && error == 0) {
                 int bytes;                  int bytes;
   
Line 2453  abort:
Line 2682  abort:
         return error;          return error;
 }  }
   
   /*
    * Must be called without sc_lock nor sc_exlock held.
    */
 int  int
 audio_ioctl(dev_t dev, struct audio_softc *sc, u_long cmd, void *addr, int flag,  audio_ioctl(dev_t dev, struct audio_softc *sc, u_long cmd, void *addr, int flag,
         struct lwp *l, audio_file_t *file)          struct lwp *l, audio_file_t *file)
Line 2468  audio_ioctl(dev_t dev, struct audio_soft
Line 2700  audio_ioctl(dev_t dev, struct audio_soft
         int index;          int index;
         int error;          int error;
   
         KASSERT(!mutex_owned(sc->sc_lock));  
   
 #if defined(AUDIO_DEBUG)  #if defined(AUDIO_DEBUG)
         const char *ioctlnames[] = {          const char *ioctlnames[] = {
                 " AUDIO_GETINFO",       /* 21 */                  " AUDIO_GETINFO",       /* 21 */
Line 2607  audio_ioctl(dev_t dev, struct audio_soft
Line 2837  audio_ioctl(dev_t dev, struct audio_soft
                 break;                  break;
   
         case AUDIO_SETINFO:          case AUDIO_SETINFO:
                 error = audio_enter_exclusive(sc);                  error = audio_exlock_enter(sc);
                 if (error)                  if (error)
                         break;                          break;
                 error = audio_file_setinfo(sc, file, (struct audio_info *)addr);                  error = audio_file_setinfo(sc, file, (struct audio_info *)addr);
                 if (error) {                  if (error) {
                         audio_exit_exclusive(sc);                          audio_exlock_exit(sc);
                         break;                          break;
                 }                  }
                 /* XXX TODO: update last_ai if /dev/sound ? */                  /* XXX TODO: update last_ai if /dev/sound ? */
                 if (ISDEVSOUND(dev))                  if (ISDEVSOUND(dev))
                         error = audiogetinfo(sc, &sc->sc_ai, 0, file);                          error = audiogetinfo(sc, &sc->sc_ai, 0, file);
                 audio_exit_exclusive(sc);                  audio_exlock_exit(sc);
                 break;                  break;
   
         case AUDIO_GETINFO:          case AUDIO_GETINFO:
                 error = audio_enter_exclusive(sc);                  error = audio_exlock_enter(sc);
                 if (error)                  if (error)
                         break;                          break;
                 error = audiogetinfo(sc, (struct audio_info *)addr, 1, file);                  error = audiogetinfo(sc, (struct audio_info *)addr, 1, file);
                 audio_exit_exclusive(sc);                  audio_exlock_exit(sc);
                 break;                  break;
   
         case AUDIO_GETBUFINFO:          case AUDIO_GETBUFINFO:
                 mutex_enter(sc->sc_lock);                  error = audio_exlock_enter(sc);
                   if (error)
                           break;
                 error = audiogetinfo(sc, (struct audio_info *)addr, 0, file);                  error = audiogetinfo(sc, (struct audio_info *)addr, 0, file);
                 mutex_exit(sc->sc_lock);                  audio_exlock_exit(sc);
                 break;                  break;
   
         case AUDIO_DRAIN:          case AUDIO_DRAIN:
Line 2675  audio_ioctl(dev_t dev, struct audio_soft
Line 2907  audio_ioctl(dev_t dev, struct audio_soft
                  * If HW has full duplex mode and there are two mixers,                   * If HW has full duplex mode and there are two mixers,
                  * it is full duplex.  Otherwise half duplex.                   * it is full duplex.  Otherwise half duplex.
                  */                   */
                 mutex_enter(sc->sc_lock);                  error = audio_exlock_enter(sc);
                   if (error)
                           break;
                 fd = (sc->sc_props & AUDIO_PROP_FULLDUPLEX)                  fd = (sc->sc_props & AUDIO_PROP_FULLDUPLEX)
                     && (sc->sc_pmixer && sc->sc_rmixer);                      && (sc->sc_pmixer && sc->sc_rmixer);
                 mutex_exit(sc->sc_lock);                  audio_exlock_exit(sc);
                 *(int *)addr = fd;                  *(int *)addr = fd;
                 break;                  break;
   
Line 2688  audio_ioctl(dev_t dev, struct audio_soft
Line 2922  audio_ioctl(dev_t dev, struct audio_soft
   
         case AUDIO_QUERYFORMAT:          case AUDIO_QUERYFORMAT:
                 query = (audio_format_query_t *)addr;                  query = (audio_format_query_t *)addr;
                 if (sc->hw_if->query_format) {                  mutex_enter(sc->sc_lock);
                         mutex_enter(sc->sc_lock);                  error = sc->hw_if->query_format(sc->hw_hdl, query);
                         error = sc->hw_if->query_format(sc->hw_hdl, query);                  mutex_exit(sc->sc_lock);
                         mutex_exit(sc->sc_lock);                  /* Hide internal infomations */
                         /* Hide internal infomations */                  query->fmt.driver_data = NULL;
                         query->fmt.driver_data = NULL;  
                 } else {  
                         error = ENODEV;  
                 }  
                 break;                  break;
   
         case AUDIO_GETFORMAT:          case AUDIO_GETFORMAT:
                   error = audio_exlock_enter(sc);
                   if (error)
                           break;
                 audio_mixers_get_format(sc, (struct audio_info *)addr);                  audio_mixers_get_format(sc, (struct audio_info *)addr);
                   audio_exlock_exit(sc);
                 break;                  break;
   
         case AUDIO_SETFORMAT:          case AUDIO_SETFORMAT:
                 mutex_enter(sc->sc_lock);                  error = audio_exlock_enter(sc);
                 audio_mixers_get_format(sc, &ai);                  audio_mixers_get_format(sc, &ai);
                 error = audio_mixers_set_format(sc, (struct audio_info *)addr);                  error = audio_mixers_set_format(sc, (struct audio_info *)addr);
                 if (error) {                  if (error) {
                         /* Rollback */                          /* Rollback */
                         audio_mixers_set_format(sc, &ai);                          audio_mixers_set_format(sc, &ai);
                 }                  }
                 mutex_exit(sc->sc_lock);                  audio_exlock_exit(sc);
                 break;                  break;
   
         case AUDIO_SETFD:          case AUDIO_SETFD:
Line 2722  audio_ioctl(dev_t dev, struct audio_soft
Line 2956  audio_ioctl(dev_t dev, struct audio_soft
   
         default:          default:
                 if (sc->hw_if->dev_ioctl) {                  if (sc->hw_if->dev_ioctl) {
                         error = audio_enter_exclusive(sc);                          mutex_enter(sc->sc_lock);
                         if (error)  
                                 break;  
                         error = sc->hw_if->dev_ioctl(sc->hw_hdl,                          error = sc->hw_if->dev_ioctl(sc->hw_hdl,
                             cmd, addr, flag, l);                              cmd, addr, flag, l);
                         audio_exit_exclusive(sc);                          mutex_exit(sc->sc_lock);
                 } else {                  } else {
                         TRACEF(2, file, "unknown ioctl");                          TRACEF(2, file, "unknown ioctl");
                         error = EINVAL;                          error = EINVAL;
Line 2761  audio_track_readablebytes(const audio_tr
Line 2993  audio_track_readablebytes(const audio_tr
         return bytes;          return bytes;
 }  }
   
   /*
    * Must be called without sc_lock nor sc_exlock held.
    */
 int  int
 audio_poll(struct audio_softc *sc, int events, struct lwp *l,  audio_poll(struct audio_softc *sc, int events, struct lwp *l,
         audio_file_t *file)          audio_file_t *file)
Line 2770  audio_poll(struct audio_softc *sc, int e
Line 3005  audio_poll(struct audio_softc *sc, int e
         bool in_is_valid;          bool in_is_valid;
         bool out_is_valid;          bool out_is_valid;
   
         KASSERT(!mutex_owned(sc->sc_lock));  
   
 #if defined(AUDIO_DEBUG)  #if defined(AUDIO_DEBUG)
 #define POLLEV_BITMAP "\177\020" \  #define POLLEV_BITMAP "\177\020" \
             "b\10WRBAND\0" \              "b\10WRBAND\0" \
Line 2919  filt_audiowrite_event(struct knote *kn, 
Line 3152  filt_audiowrite_event(struct knote *kn, 
         return (track->usrbuf.used < track->usrbuf_usedlow);          return (track->usrbuf.used < track->usrbuf_usedlow);
 }  }
   
   /*
    * Must be called without sc_lock nor sc_exlock held.
    */
 int  int
 audio_kqfilter(struct audio_softc *sc, audio_file_t *file, struct knote *kn)  audio_kqfilter(struct audio_softc *sc, audio_file_t *file, struct knote *kn)
 {  {
         struct klist *klist;          struct klist *klist;
   
         KASSERT(!mutex_owned(sc->sc_lock));  
   
         TRACEF(3, file, "kn=%p kn_filter=%x", kn, (int)kn->kn_filter);          TRACEF(3, file, "kn=%p kn_filter=%x", kn, (int)kn->kn_filter);
   
           mutex_enter(sc->sc_lock);
         switch (kn->kn_filter) {          switch (kn->kn_filter) {
         case EVFILT_READ:          case EVFILT_READ:
                 klist = &sc->sc_rsel.sel_klist;                  klist = &sc->sc_rsel.sel_klist;
Line 2940  audio_kqfilter(struct audio_softc *sc, a
Line 3175  audio_kqfilter(struct audio_softc *sc, a
                 break;                  break;
   
         default:          default:
                   mutex_exit(sc->sc_lock);
                 return EINVAL;                  return EINVAL;
         }          }
   
         kn->kn_hook = file;          kn->kn_hook = file;
   
         mutex_enter(sc->sc_lock);  
         SLIST_INSERT_HEAD(klist, kn, kn_selnext);          SLIST_INSERT_HEAD(klist, kn, kn_selnext);
         mutex_exit(sc->sc_lock);          mutex_exit(sc->sc_lock);
   
         return 0;          return 0;
 }  }
   
   /*
    * Must be called without sc_lock nor sc_exlock held.
    */
 int  int
 audio_mmap(struct audio_softc *sc, off_t *offp, size_t len, int prot,  audio_mmap(struct audio_softc *sc, off_t *offp, size_t len, int prot,
         int *flagsp, int *advicep, struct uvm_object **uobjp, int *maxprotp,          int *flagsp, int *advicep, struct uvm_object **uobjp, int *maxprotp,
Line 2961  audio_mmap(struct audio_softc *sc, off_t
Line 3199  audio_mmap(struct audio_softc *sc, off_t
         vsize_t vsize;          vsize_t vsize;
         int error;          int error;
   
         KASSERT(!mutex_owned(sc->sc_lock));  
   
         TRACEF(2, file, "off=%lld, prot=%d", (long long)(*offp), prot);          TRACEF(2, file, "off=%lld, prot=%d", (long long)(*offp), prot);
   
         if (*offp < 0)          if (*offp < 0)
Line 3005  audio_mmap(struct audio_softc *sc, off_t
Line 3241  audio_mmap(struct audio_softc *sc, off_t
                 track->mmapped = true;                  track->mmapped = true;
   
                 if (!track->is_pause) {                  if (!track->is_pause) {
                         error = audio_enter_exclusive(sc);                          error = audio_exlock_mutex_enter(sc);
                         if (error)                          if (error)
                                 return error;                                  return error;
                         if (sc->sc_pbusy == false)                          if (sc->sc_pbusy == false)
                                 audio_pmixer_start(sc, true);                                  audio_pmixer_start(sc, true);
                         audio_exit_exclusive(sc);                          audio_exlock_mutex_exit(sc);
                 }                  }
                 /* XXX mmapping record buffer is not supported */                  /* XXX mmapping record buffer is not supported */
         }          }
Line 3029  audio_mmap(struct audio_softc *sc, off_t
Line 3265  audio_mmap(struct audio_softc *sc, off_t
 /*  /*
  * /dev/audioctl has to be able to open at any time without interference   * /dev/audioctl has to be able to open at any time without interference
  * with any /dev/audio or /dev/sound.   * with any /dev/audio or /dev/sound.
    * Must be called with sc_exlock held and without sc_lock held.
  */   */
 static int  static int
 audioctl_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,  audioctl_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
Line 3039  audioctl_open(dev_t dev, struct audio_so
Line 3276  audioctl_open(dev_t dev, struct audio_so
         int fd;          int fd;
         int error;          int error;
   
         KASSERT(mutex_owned(sc->sc_lock));  
         KASSERT(sc->sc_exlock);          KASSERT(sc->sc_exlock);
   
         TRACE(1, "");          TRACE(1, "");
Line 3055  audioctl_open(dev_t dev, struct audio_so
Line 3291  audioctl_open(dev_t dev, struct audio_so
         /* Not necessary to insert sc_files. */          /* Not necessary to insert sc_files. */
   
         error = fd_clone(fp, fd, flags, &audio_fileops, af);          error = fd_clone(fp, fd, flags, &audio_fileops, af);
         KASSERT(error == EMOVEFD);          KASSERTMSG(error == EMOVEFD, "error=%d", error);
   
         return error;          return error;
 }  }
   
 /*  /*
  * Reallocate 'memblock' with specified 'bytes' if 'bytes' > 0.  
  * Or free 'memblock' and return NULL if 'byte' is zero.  
  */  
 static void *  
 audio_realloc(void *memblock, size_t bytes)  
 {  
   
         if (memblock != NULL) {  
                 if (bytes != 0) {  
                         return kern_realloc(memblock, bytes, M_NOWAIT);  
                 } else {  
                         kern_free(memblock);  
                         return NULL;  
                 }  
         } else {  
                 if (bytes != 0) {  
                         return kern_malloc(bytes, M_NOWAIT);  
                 } else {  
                         return NULL;  
                 }  
         }  
 }  
   
 /*  
  * Free 'mem' if available, and initialize the pointer.   * Free 'mem' if available, and initialize the pointer.
  * For this reason, this is implemented as macro.   * For this reason, this is implemented as macro.
  */   */
Line 3096  audio_realloc(void *memblock, size_t byt
Line 3308  audio_realloc(void *memblock, size_t byt
 } while (0)  } while (0)
   
 /*  /*
    * (Re)allocate 'memblock' with specified 'bytes'.
    * bytes must not be 0.
    * This function never returns NULL.
    */
   static void *
   audio_realloc(void *memblock, size_t bytes)
   {
   
           KASSERT(bytes != 0);
           audio_free(memblock);
           return kern_malloc(bytes, M_WAITOK);
   }
   
   /*
  * (Re)allocate usrbuf with 'newbufsize' bytes.   * (Re)allocate usrbuf with 'newbufsize' bytes.
  * Use this function for usrbuf because only usrbuf can be mmapped.   * Use this function for usrbuf because only usrbuf can be mmapped.
  * If successful, it updates track->usrbuf.mem, track->usrbuf.capacity and   * If successful, it updates track->usrbuf.mem, track->usrbuf.capacity and
Line 3210  audio_track_chvol(audio_filter_arg_t *ar
Line 3436  audio_track_chvol(audio_filter_arg_t *ar
         u_int channels;          u_int channels;
   
         DIAGNOSTIC_filter_arg(arg);          DIAGNOSTIC_filter_arg(arg);
         KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);          KASSERTMSG(arg->srcfmt->channels == arg->dstfmt->channels,
               "arg->srcfmt->channels=%d, arg->dstfmt->channels=%d",
               arg->srcfmt->channels, arg->dstfmt->channels);
         KASSERT(arg->context != NULL);          KASSERT(arg->context != NULL);
         KASSERT(arg->srcfmt->channels <= AUDIO_MAX_CHANNELS);          KASSERTMSG(arg->srcfmt->channels <= AUDIO_MAX_CHANNELS,
               "arg->srcfmt->channels=%d", arg->srcfmt->channels);
   
         s = arg->src;          s = arg->src;
         d = arg->dst;          d = arg->dst;
Line 3370  audio_track_freq_up(audio_filter_arg_t *
Line 3599  audio_track_freq_up(audio_filter_arg_t *
         DIAGNOSTIC_ring(dst);          DIAGNOSTIC_ring(dst);
         DIAGNOSTIC_ring(src);          DIAGNOSTIC_ring(src);
         KASSERT(src->used > 0);          KASSERT(src->used > 0);
         KASSERT(src->fmt.channels == dst->fmt.channels);          KASSERTMSG(src->fmt.channels == dst->fmt.channels,
         KASSERT(src->head % track->mixer->frames_per_block == 0);              "src->fmt.channels=%d dst->fmt.channels=%d",
               src->fmt.channels, dst->fmt.channels);
           KASSERTMSG(src->head % track->mixer->frames_per_block == 0,
               "src->head=%d track->mixer->frames_per_block=%d",
               src->head, track->mixer->frames_per_block);
   
         s = arg->src;          s = arg->src;
         d = arg->dst;          d = arg->dst;
Line 3496  audio_track_freq_down(audio_filter_arg_t
Line 3729  audio_track_freq_down(audio_filter_arg_t
         DIAGNOSTIC_ring(dst);          DIAGNOSTIC_ring(dst);
         DIAGNOSTIC_ring(src);          DIAGNOSTIC_ring(src);
         KASSERT(src->used > 0);          KASSERT(src->used > 0);
         KASSERT(src->fmt.channels == dst->fmt.channels);          KASSERTMSG(src->fmt.channels == dst->fmt.channels,
               "src->fmt.channels=%d dst->fmt.channels=%d",
               src->fmt.channels, dst->fmt.channels);
         KASSERTMSG(src->head % track->mixer->frames_per_block == 0,          KASSERTMSG(src->head % track->mixer->frames_per_block == 0,
             "src->head=%d fpb=%d",              "src->head=%d track->mixer->frames_per_block=%d",
             src->head, track->mixer->frames_per_block);              src->head, track->mixer->frames_per_block);
   
         s0 = arg->src;          s0 = arg->src;
Line 3531  audio_track_freq_down(audio_filter_arg_t
Line 3766  audio_track_freq_down(audio_filter_arg_t
   
 /*  /*
  * Creates track and returns it.   * Creates track and returns it.
    * Must be called without sc_lock held.
  */   */
 audio_track_t *  audio_track_t *
 audio_track_create(struct audio_softc *sc, audio_trackmixer_t *mixer)  audio_track_create(struct audio_softc *sc, audio_trackmixer_t *mixer)
Line 3660  abort:
Line 3896  abort:
 static int  static int
 audio_track_init_codec(audio_track_t *track, audio_ring_t **last_dstp)  audio_track_init_codec(audio_track_t *track, audio_ring_t **last_dstp)
 {  {
         struct audio_softc *sc;  
         audio_ring_t *last_dst;          audio_ring_t *last_dst;
         audio_ring_t *srcbuf;          audio_ring_t *srcbuf;
         audio_format2_t *srcfmt;          audio_format2_t *srcfmt;
Line 3671  audio_track_init_codec(audio_track_t *tr
Line 3906  audio_track_init_codec(audio_track_t *tr
   
         KASSERT(track);          KASSERT(track);
   
         sc = track->mixer->sc;  
         last_dst = *last_dstp;          last_dst = *last_dstp;
         dstfmt = &last_dst->fmt;          dstfmt = &last_dst->fmt;
         srcfmt = &track->inputfmt;          srcfmt = &track->inputfmt;
Line 3700  audio_track_init_codec(audio_track_t *tr
Line 3934  audio_track_init_codec(audio_track_t *tr
                 srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt);                  srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt);
                 len = auring_bytelen(srcbuf);                  len = auring_bytelen(srcbuf);
                 srcbuf->mem = audio_realloc(srcbuf->mem, len);                  srcbuf->mem = audio_realloc(srcbuf->mem, len);
                 if (srcbuf->mem == NULL) {  
                         device_printf(sc->sc_dev, "%s: malloc(%d) failed\n",  
                             __func__, len);  
                         error = ENOMEM;  
                         goto abort;  
                 }  
   
                 arg = &track->codec.arg;                  arg = &track->codec.arg;
                 arg->srcfmt = &srcbuf->fmt;                  arg->srcfmt = &srcbuf->fmt;
Line 3731  abort:
Line 3959  abort:
 static int  static int
 audio_track_init_chvol(audio_track_t *track, audio_ring_t **last_dstp)  audio_track_init_chvol(audio_track_t *track, audio_ring_t **last_dstp)
 {  {
         struct audio_softc *sc;  
         audio_ring_t *last_dst;          audio_ring_t *last_dst;
         audio_ring_t *srcbuf;          audio_ring_t *srcbuf;
         audio_format2_t *srcfmt;          audio_format2_t *srcfmt;
Line 3742  audio_track_init_chvol(audio_track_t *tr
Line 3969  audio_track_init_chvol(audio_track_t *tr
   
         KASSERT(track);          KASSERT(track);
   
         sc = track->mixer->sc;  
         last_dst = *last_dstp;          last_dst = *last_dstp;
         dstfmt = &last_dst->fmt;          dstfmt = &last_dst->fmt;
         srcfmt = &track->inputfmt;          srcfmt = &track->inputfmt;
Line 3770  audio_track_init_chvol(audio_track_t *tr
Line 3996  audio_track_init_chvol(audio_track_t *tr
                 srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt);                  srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt);
                 len = auring_bytelen(srcbuf);                  len = auring_bytelen(srcbuf);
                 srcbuf->mem = audio_realloc(srcbuf->mem, len);                  srcbuf->mem = audio_realloc(srcbuf->mem, len);
                 if (srcbuf->mem == NULL) {  
                         device_printf(sc->sc_dev, "%s: malloc(%d) failed\n",  
                             __func__, len);  
                         error = ENOMEM;  
                         goto abort;  
                 }  
   
                 arg = &track->chvol.arg;                  arg = &track->chvol.arg;
                 arg->srcfmt = &srcbuf->fmt;                  arg->srcfmt = &srcbuf->fmt;
Line 3786  audio_track_init_chvol(audio_track_t *tr
Line 4006  audio_track_init_chvol(audio_track_t *tr
                 return 0;                  return 0;
         }          }
   
 abort:  
         track->chvol.filter = NULL;          track->chvol.filter = NULL;
         audio_free(srcbuf->mem);          audio_free(srcbuf->mem);
         return error;          return error;
Line 3801  abort:
Line 4020  abort:
 static int  static int
 audio_track_init_chmix(audio_track_t *track, audio_ring_t **last_dstp)  audio_track_init_chmix(audio_track_t *track, audio_ring_t **last_dstp)
 {  {
         struct audio_softc *sc;  
         audio_ring_t *last_dst;          audio_ring_t *last_dst;
         audio_ring_t *srcbuf;          audio_ring_t *srcbuf;
         audio_format2_t *srcfmt;          audio_format2_t *srcfmt;
Line 3814  audio_track_init_chmix(audio_track_t *tr
Line 4032  audio_track_init_chmix(audio_track_t *tr
   
         KASSERT(track);          KASSERT(track);
   
         sc = track->mixer->sc;  
         last_dst = *last_dstp;          last_dst = *last_dstp;
         dstfmt = &last_dst->fmt;          dstfmt = &last_dst->fmt;
         srcfmt = &track->inputfmt;          srcfmt = &track->inputfmt;
Line 3845  audio_track_init_chmix(audio_track_t *tr
Line 4062  audio_track_init_chmix(audio_track_t *tr
                 srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt);                  srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt);
                 len = auring_bytelen(srcbuf);                  len = auring_bytelen(srcbuf);
                 srcbuf->mem = audio_realloc(srcbuf->mem, len);                  srcbuf->mem = audio_realloc(srcbuf->mem, len);
                 if (srcbuf->mem == NULL) {  
                         device_printf(sc->sc_dev, "%s: malloc(%d) failed\n",  
                             __func__, len);  
                         error = ENOMEM;  
                         goto abort;  
                 }  
   
                 arg = &track->chmix.arg;                  arg = &track->chmix.arg;
                 arg->srcfmt = &srcbuf->fmt;                  arg->srcfmt = &srcbuf->fmt;
Line 3861  audio_track_init_chmix(audio_track_t *tr
Line 4072  audio_track_init_chmix(audio_track_t *tr
                 return 0;                  return 0;
         }          }
   
 abort:  
         track->chmix.filter = NULL;          track->chmix.filter = NULL;
         audio_free(srcbuf->mem);          audio_free(srcbuf->mem);
         return error;          return error;
Line 3876  abort:
Line 4086  abort:
 static int  static int
 audio_track_init_freq(audio_track_t *track, audio_ring_t **last_dstp)  audio_track_init_freq(audio_track_t *track, audio_ring_t **last_dstp)
 {  {
         struct audio_softc *sc;  
         audio_ring_t *last_dst;          audio_ring_t *last_dst;
         audio_ring_t *srcbuf;          audio_ring_t *srcbuf;
         audio_format2_t *srcfmt;          audio_format2_t *srcfmt;
Line 3891  audio_track_init_freq(audio_track_t *tra
Line 4100  audio_track_init_freq(audio_track_t *tra
   
         KASSERT(track);          KASSERT(track);
   
         sc = track->mixer->sc;  
         last_dst = *last_dstp;          last_dst = *last_dstp;
         dstfmt = &last_dst->fmt;          dstfmt = &last_dst->fmt;
         srcfmt = &track->inputfmt;          srcfmt = &track->inputfmt;
Line 3930  audio_track_init_freq(audio_track_t *tra
Line 4138  audio_track_init_freq(audio_track_t *tra
                 srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt);                  srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt);
                 len = auring_bytelen(srcbuf);                  len = auring_bytelen(srcbuf);
                 srcbuf->mem = audio_realloc(srcbuf->mem, len);                  srcbuf->mem = audio_realloc(srcbuf->mem, len);
                 if (srcbuf->mem == NULL) {  
                         device_printf(sc->sc_dev, "%s: malloc(%d) failed\n",  
                             __func__, len);  
                         error = ENOMEM;  
                         goto abort;  
                 }  
   
                 arg = &track->freq.arg;                  arg = &track->freq.arg;
                 arg->srcfmt = &srcbuf->fmt;                  arg->srcfmt = &srcbuf->fmt;
Line 3946  audio_track_init_freq(audio_track_t *tra
Line 4148  audio_track_init_freq(audio_track_t *tra
                 return 0;                  return 0;
         }          }
   
 abort:  
         track->freq.filter = NULL;          track->freq.filter = NULL;
         audio_free(srcbuf->mem);          audio_free(srcbuf->mem);
         return error;          return error;
Line 4128  audio_track_set_format(audio_track_t *tr
Line 4329  audio_track_set_format(audio_track_t *tr
                     frame_per_block(track->mixer, &track->input->fmt);                      frame_per_block(track->mixer, &track->input->fmt);
                 len = auring_bytelen(track->input);                  len = auring_bytelen(track->input);
                 track->input->mem = audio_realloc(track->input->mem, len);                  track->input->mem = audio_realloc(track->input->mem, len);
                 if (track->input->mem == NULL) {  
                         device_printf(sc->sc_dev, "malloc input(%d) failed\n",  
                             len);  
                         error = ENOMEM;  
                         goto error;  
                 }  
         }          }
   
         /*          /*
Line 4230  audio_append_silence(audio_track_t *trac
Line 4425  audio_append_silence(audio_track_t *trac
   
         n = (ring->capacity - ring->used) % fpb;          n = (ring->capacity - ring->used) % fpb;
   
         KASSERT(auring_get_contig_free(ring) >= n);          KASSERTMSG(auring_get_contig_free(ring) >= n,
               "auring_get_contig_free(ring)=%d n=%d",
               auring_get_contig_free(ring), n);
   
         memset(auring_tailptr_aint(ring), 0,          memset(auring_tailptr_aint(ring), 0,
             n * ring->fmt.channels * sizeof(aint_t));              n * ring->fmt.channels * sizeof(aint_t));
Line 4263  audio_apply_stage(audio_track_t *track, 
Line 4460  audio_apply_stage(audio_track_t *track, 
         dstcount = auring_get_contig_free(stage->dst);          dstcount = auring_get_contig_free(stage->dst);
   
         if (isfreq) {          if (isfreq) {
                 KASSERTMSG(srccount > 0, "freq but srccount == %d", srccount);                  KASSERTMSG(srccount > 0, "freq but srccount=%d", srccount);
                 count = uimin(dstcount, track->mixer->frames_per_block);                  count = uimin(dstcount, track->mixer->frames_per_block);
         } else {          } else {
                 count = uimin(srccount, dstcount);                  count = uimin(srccount, dstcount);
Line 4348  audio_track_play(audio_track_t *track)
Line 4545  audio_track_play(audio_track_t *track)
                 int bytes2;                  int bytes2;
   
                 bytes1 = auring_get_contig_used(usrbuf);                  bytes1 = auring_get_contig_used(usrbuf);
                 KASSERT(bytes1 % framesize == 0);                  KASSERTMSG(bytes1 % framesize == 0,
                       "bytes1=%d framesize=%d", bytes1, framesize);
                 memcpy((uint8_t *)input->mem + auring_tail(input) * framesize,                  memcpy((uint8_t *)input->mem + auring_tail(input) * framesize,
                     (uint8_t *)usrbuf->mem + usrbuf->head,                      (uint8_t *)usrbuf->mem + usrbuf->head,
                     bytes1);                      bytes1);
Line 4510  audio_track_record(audio_track_t *track)
Line 4708  audio_track_record(audio_track_t *track)
                 int bytes1;                  int bytes1;
                 int bytes2;                  int bytes2;
   
                 bytes1 = auring_get_contig_used(usrbuf);                  bytes1 = auring_get_contig_free(usrbuf);
                 KASSERT(bytes1 % framesize == 0);                  KASSERTMSG(bytes1 % framesize == 0,
                       "bytes1=%d framesize=%d", bytes1, framesize);
                 memcpy((uint8_t *)usrbuf->mem + auring_tail(usrbuf),                  memcpy((uint8_t *)usrbuf->mem + auring_tail(usrbuf),
                     (uint8_t *)outbuf->mem + outbuf->head * framesize,                      (uint8_t *)outbuf->mem + outbuf->head * framesize,
                     bytes1);                      bytes1);
Line 4540  audio_track_record(audio_track_t *track)
Line 4739  audio_track_record(audio_track_t *track)
   
 /*  /*
  * Calcurate blktime [msec] from mixer(.hwbuf.fmt).   * Calcurate blktime [msec] from mixer(.hwbuf.fmt).
  * Must be called with sc_lock held.   * Must be called with sc_exlock held.
  */   */
 static u_int  static u_int
 audio_mixer_calc_blktime(struct audio_softc *sc, audio_trackmixer_t *mixer)  audio_mixer_calc_blktime(struct audio_softc *sc, audio_trackmixer_t *mixer)
Line 4549  audio_mixer_calc_blktime(struct audio_so
Line 4748  audio_mixer_calc_blktime(struct audio_so
         u_int blktime;          u_int blktime;
         u_int frames_per_block;          u_int frames_per_block;
   
         KASSERT(mutex_owned(sc->sc_lock));          KASSERT(sc->sc_exlock);
   
         fmt = &mixer->hwbuf.fmt;          fmt = &mixer->hwbuf.fmt;
         blktime = sc->sc_blk_ms;          blktime = sc->sc_blk_ms;
Line 4577  audio_mixer_calc_blktime(struct audio_so
Line 4776  audio_mixer_calc_blktime(struct audio_so
  * Set AUMODE_PLAY to the 'mode' for playback or AUMODE_RECORD for recording.   * Set AUMODE_PLAY to the 'mode' for playback or AUMODE_RECORD for recording.
  * sc->sc_[pr]mixer (corresponding to the 'mode') must be zero-filled.   * sc->sc_[pr]mixer (corresponding to the 'mode') must be zero-filled.
  * This function returns 0 on sucessful.  Otherwise returns errno.   * This function returns 0 on sucessful.  Otherwise returns errno.
  * Must be called with sc_lock held.   * Must be called with sc_exlock held and without sc_lock held.
  */   */
 static int  static int
 audio_mixer_init(struct audio_softc *sc, int mode,  audio_mixer_init(struct audio_softc *sc, int mode,
         const audio_format2_t *hwfmt, const audio_filter_reg_t *reg)          const audio_format2_t *hwfmt, const audio_filter_reg_t *reg)
 {  {
         char codecbuf[64];          char codecbuf[64];
           char blkdmsbuf[8];
         audio_trackmixer_t *mixer;          audio_trackmixer_t *mixer;
         void (*softint_handler)(void *);          void (*softint_handler)(void *);
         int len;          int len;
Line 4592  audio_mixer_init(struct audio_softc *sc,
Line 4792  audio_mixer_init(struct audio_softc *sc,
         size_t bufsize;          size_t bufsize;
         int hwblks;          int hwblks;
         int blkms;          int blkms;
           int blkdms;
         int error;          int error;
   
         KASSERT(hwfmt != NULL);          KASSERT(hwfmt != NULL);
         KASSERT(reg != NULL);          KASSERT(reg != NULL);
         KASSERT(mutex_owned(sc->sc_lock));          KASSERT(sc->sc_exlock);
   
         error = 0;          error = 0;
         if (mode == AUMODE_PLAY)          if (mode == AUMODE_PLAY)
Line 4619  audio_mixer_init(struct audio_softc *sc,
Line 4820  audio_mixer_init(struct audio_softc *sc,
         if (sc->hw_if->round_blocksize) {          if (sc->hw_if->round_blocksize) {
                 int rounded;                  int rounded;
                 audio_params_t p = format2_to_params(&mixer->hwbuf.fmt);                  audio_params_t p = format2_to_params(&mixer->hwbuf.fmt);
                   mutex_enter(sc->sc_lock);
                 rounded = sc->hw_if->round_blocksize(sc->hw_hdl, blksize,                  rounded = sc->hw_if->round_blocksize(sc->hw_hdl, blksize,
                     mode, &p);                      mode, &p);
                 TRACE(2, "round_blocksize %d -> %d", blksize, rounded);                  mutex_exit(sc->sc_lock);
                   TRACE(1, "round_blocksize %d -> %d", blksize, rounded);
                 if (rounded != blksize) {                  if (rounded != blksize) {
                         if ((rounded * NBBY) % (mixer->hwbuf.fmt.stride *                          if ((rounded * NBBY) % (mixer->hwbuf.fmt.stride *
                             mixer->hwbuf.fmt.channels) != 0) {                              mixer->hwbuf.fmt.channels) != 0) {
                                 device_printf(sc->sc_dev,                                  device_printf(sc->sc_dev,
                                     "blksize not configured %d -> %d\n",                                      "round_blocksize must return blocksize "
                                     blksize, rounded);                                      "divisible by framesize: "
                                       "blksize=%d rounded=%d "
                                       "stride=%ubit channels=%u\n",
                                       blksize, rounded,
                                       mixer->hwbuf.fmt.stride,
                                       mixer->hwbuf.fmt.channels);
                                 return EINVAL;                                  return EINVAL;
                         }                          }
                         /* Recalculation */                          /* Recalculation */
Line 4644  audio_mixer_init(struct audio_softc *sc,
Line 4852  audio_mixer_init(struct audio_softc *sc,
         bufsize = frametobyte(&mixer->hwbuf.fmt, capacity);          bufsize = frametobyte(&mixer->hwbuf.fmt, capacity);
         if (sc->hw_if->round_buffersize) {          if (sc->hw_if->round_buffersize) {
                 size_t rounded;                  size_t rounded;
                   mutex_enter(sc->sc_lock);
                 rounded = sc->hw_if->round_buffersize(sc->hw_hdl, mode,                  rounded = sc->hw_if->round_buffersize(sc->hw_hdl, mode,
                     bufsize);                      bufsize);
                 TRACE(2, "round_buffersize %zd -> %zd", bufsize, rounded);                  mutex_exit(sc->sc_lock);
                   TRACE(1, "round_buffersize %zd -> %zd", bufsize, rounded);
                 if (rounded < bufsize) {                  if (rounded < bufsize) {
                         /* buffersize needs NBLKHW blocks at least. */                          /* buffersize needs NBLKHW blocks at least. */
                         device_printf(sc->sc_dev,                          device_printf(sc->sc_dev,
Line 4669  audio_mixer_init(struct audio_softc *sc,
Line 4879  audio_mixer_init(struct audio_softc *sc,
                         capacity = mixer->frames_per_block * hwblks;                          capacity = mixer->frames_per_block * hwblks;
                 }                  }
         }          }
         TRACE(2, "buffersize for %s = %zu",          TRACE(1, "buffersize for %s = %zu",
             (mode == AUMODE_PLAY) ? "playback" : "recording",              (mode == AUMODE_PLAY) ? "playback" : "recording",
             bufsize);              bufsize);
         mixer->hwbuf.capacity = capacity;          mixer->hwbuf.capacity = capacity;
   
         /*  
          * XXX need to release sc_lock for compatibility?  
          */  
         if (sc->hw_if->allocm) {          if (sc->hw_if->allocm) {
                   /* sc_lock is not necessary for allocm */
                 mixer->hwbuf.mem = sc->hw_if->allocm(sc->hw_hdl, mode, bufsize);                  mixer->hwbuf.mem = sc->hw_if->allocm(sc->hw_hdl, mode, bufsize);
                 if (mixer->hwbuf.mem == NULL) {                  if (mixer->hwbuf.mem == NULL) {
                         device_printf(sc->sc_dev, "%s: allocm(%zu) failed\n",                          device_printf(sc->sc_dev, "%s: allocm(%zu) failed\n",
Line 4728  audio_mixer_init(struct audio_softc *sc,
Line 4936  audio_mixer_init(struct audio_softc *sc,
                 len = mixer->frames_per_block * mixer->mixfmt.channels *                  len = mixer->frames_per_block * mixer->mixfmt.channels *
                     mixer->mixfmt.stride / NBBY;                      mixer->mixfmt.stride / NBBY;
                 mixer->mixsample = audio_realloc(mixer->mixsample, len);                  mixer->mixsample = audio_realloc(mixer->mixsample, len);
                 if (mixer->mixsample == NULL) {  
                         device_printf(sc->sc_dev,  
                             "%s: malloc mixsample(%d) failed\n",  
                             __func__, len);  
                         error = ENOMEM;  
                         goto abort;  
                 }  
         } else {          } else {
                 /* No mixing buffer for recording */                  /* No mixing buffer for recording */
         }          }
Line 4771  audio_mixer_init(struct audio_softc *sc,
Line 4972  audio_mixer_init(struct audio_softc *sc,
                     mixer->hwbuf.fmt.precision);                      mixer->hwbuf.fmt.precision);
         }          }
         blkms = mixer->blktime_n * 1000 / mixer->blktime_d;          blkms = mixer->blktime_n * 1000 / mixer->blktime_d;
         aprint_normal_dev(sc->sc_dev, "%s:%d%s %dch %dHz, blk %dms for %s\n",          blkdms = (mixer->blktime_n * 10000 / mixer->blktime_d) % 10;
           blkdmsbuf[0] = '\0';
           if (blkdms != 0) {
                   snprintf(blkdmsbuf, sizeof(blkdmsbuf), ".%1d", blkdms);
           }
           aprint_normal_dev(sc->sc_dev,
               "%s:%d%s %dch %dHz, blk %d bytes (%d%sms) for %s\n",
             audio_encoding_name(mixer->track_fmt.encoding),              audio_encoding_name(mixer->track_fmt.encoding),
             mixer->track_fmt.precision,              mixer->track_fmt.precision,
             codecbuf,              codecbuf,
             mixer->track_fmt.channels,              mixer->track_fmt.channels,
             mixer->track_fmt.sample_rate,              mixer->track_fmt.sample_rate,
             blkms,              blksize,
               blkms, blkdmsbuf,
             (mode == AUMODE_PLAY) ? "playback" : "recording");              (mode == AUMODE_PLAY) ? "playback" : "recording");
   
         return 0;          return 0;
Line 4790  abort:
Line 4998  abort:
 /*  /*
  * Releases all resources of 'mixer'.   * Releases all resources of 'mixer'.
  * Note that it does not release the memory area of 'mixer' itself.   * Note that it does not release the memory area of 'mixer' itself.
  * Must be called with sc_lock held.   * Must be called with sc_exlock held and without sc_lock held.
  */   */
 static void  static void
 audio_mixer_destroy(struct audio_softc *sc, audio_trackmixer_t *mixer)  audio_mixer_destroy(struct audio_softc *sc, audio_trackmixer_t *mixer)
 {  {
         int bufsize;          int bufsize;
   
         KASSERT(mutex_owned(sc->sc_lock));          KASSERT(sc->sc_exlock == 1);
   
         bufsize = frametobyte(&mixer->hwbuf.fmt, mixer->hwbuf.capacity);          bufsize = frametobyte(&mixer->hwbuf.fmt, mixer->hwbuf.capacity);
   
         if (mixer->hwbuf.mem != NULL) {          if (mixer->hwbuf.mem != NULL) {
                 if (sc->hw_if->freem) {                  if (sc->hw_if->freem) {
                           /* sc_lock is not necessary for freem */
                         sc->hw_if->freem(sc->hw_hdl, mixer->hwbuf.mem, bufsize);                          sc->hw_if->freem(sc->hw_hdl, mixer->hwbuf.mem, bufsize);
                 } else {                  } else {
                         kmem_free(mixer->hwbuf.mem, bufsize);                          kmem_free(mixer->hwbuf.mem, bufsize);
Line 4914  audio_pmixer_process(struct audio_softc 
Line 5123  audio_pmixer_process(struct audio_softc 
         mixer = sc->sc_pmixer;          mixer = sc->sc_pmixer;
   
         frame_count = mixer->frames_per_block;          frame_count = mixer->frames_per_block;
         KASSERT(auring_get_contig_free(&mixer->hwbuf) >= frame_count);          KASSERTMSG(auring_get_contig_free(&mixer->hwbuf) >= frame_count,
               "auring_get_contig_free()=%d frame_count=%d",
               auring_get_contig_free(&mixer->hwbuf), frame_count);
         sample_count = frame_count * mixer->mixfmt.channels;          sample_count = frame_count * mixer->mixfmt.channels;
   
         mixer->mixseq++;          mixer->mixseq++;
Line 5205  audio_pmixer_output(struct audio_softc *
Line 5416  audio_pmixer_output(struct audio_softc *
         TRACE(4, "pbusy=%d hwbuf=%d/%d/%d",          TRACE(4, "pbusy=%d hwbuf=%d/%d/%d",
             sc->sc_pbusy,              sc->sc_pbusy,
             mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity);              mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity);
         KASSERT(mixer->hwbuf.used >= mixer->frames_per_block);          KASSERTMSG(mixer->hwbuf.used >= mixer->frames_per_block,
               "mixer->hwbuf.used=%d mixer->frames_per_block=%d",
               mixer->hwbuf.used, mixer->frames_per_block);
   
         blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block);          blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block);
   
Line 5256  audio_pintr(void *arg)
Line 5469  audio_pintr(void *arg)
   
         if (sc->sc_dying)          if (sc->sc_dying)
                 return;                  return;
 #if defined(DIAGNOSTIC)  
         if (sc->sc_pbusy == false) {          if (sc->sc_pbusy == false) {
                 device_printf(sc->sc_dev, "stray interrupt\n");  #if defined(DIAGNOSTIC)
                   device_printf(sc->sc_dev,
                       "DIAGNOSTIC: %s raised stray interrupt\n",
                       device_xname(sc->hw_dev));
   #endif
                 return;                  return;
         }          }
 #endif  
   
         mixer = sc->sc_pmixer;          mixer = sc->sc_pmixer;
         mixer->hw_complete_counter += mixer->frames_per_block;          mixer->hw_complete_counter += mixer->frames_per_block;
Line 5448  audio_rmixer_process(struct audio_softc 
Line 5663  audio_rmixer_process(struct audio_softc 
                             input->head, input->used, input->capacity);                              input->head, input->used, input->capacity);
                         auring_take(input, drops);                          auring_take(input, drops);
                 }                  }
                 KASSERT(input->used % mixer->frames_per_block == 0);                  KASSERTMSG(input->used % mixer->frames_per_block == 0,
                       "input->used=%d mixer->frames_per_block=%d",
                       input->used, mixer->frames_per_block);
   
                 memcpy(auring_tailptr_aint(input),                  memcpy(auring_tailptr_aint(input),
                     auring_headptr_aint(mixersrc),                      auring_headptr_aint(mixersrc),
Line 5527  audio_rintr(void *arg)
Line 5744  audio_rintr(void *arg)
   
         if (sc->sc_dying)          if (sc->sc_dying)
                 return;                  return;
 #if defined(DIAGNOSTIC)  
         if (sc->sc_rbusy == false) {          if (sc->sc_rbusy == false) {
                 device_printf(sc->sc_dev, "stray interrupt\n");  #if defined(DIAGNOSTIC)
                   device_printf(sc->sc_dev,
                       "DIAGNOSTIC: %s raised stray interrupt\n",
                       device_xname(sc->hw_dev));
   #endif
                 return;                  return;
         }          }
 #endif  
   
         mixer = sc->sc_rmixer;          mixer = sc->sc_rmixer;
         mixer->hw_complete_counter += mixer->frames_per_block;          mixer->hw_complete_counter += mixer->frames_per_block;
Line 5730  audio_track_drain(struct audio_softc *sc
Line 5949  audio_track_drain(struct audio_softc *sc
 }  }
   
 /*  /*
    * Send signal to process.
    * This is intended to be called only from audio_softintr_{rd,wr}.
    * Must be called without sc_intr_lock held.
    */
   static inline void
   audio_psignal(struct audio_softc *sc, pid_t pid, int signum)
   {
           proc_t *p;
   
           KASSERT(pid != 0);
   
           /*
            * psignal() must be called without spin lock held.
            */
   
           mutex_enter(proc_lock);
           p = proc_find(pid);
           if (p)
                   psignal(p, signum);
           mutex_exit(proc_lock);
   }
   
   /*
  * This is software interrupt handler for record.   * This is software interrupt handler for record.
  * It is called from recording hardware interrupt everytime.   * It is called from recording hardware interrupt everytime.
  * It does:   * It does:
Line 5747  audio_softintr_rd(void *cookie)
Line 5989  audio_softintr_rd(void *cookie)
 {  {
         struct audio_softc *sc = cookie;          struct audio_softc *sc = cookie;
         audio_file_t *f;          audio_file_t *f;
         proc_t *p;  
         pid_t pid;          pid_t pid;
   
         mutex_enter(sc->sc_lock);          mutex_enter(sc->sc_lock);
         mutex_enter(sc->sc_intr_lock);  
   
         SLIST_FOREACH(f, &sc->sc_files, entry) {          SLIST_FOREACH(f, &sc->sc_files, entry) {
                 audio_track_t *track = f->rtrack;                  audio_track_t *track = f->rtrack;
Line 5767  audio_softintr_rd(void *cookie)
Line 6007  audio_softintr_rd(void *cookie)
                 pid = f->async_audio;                  pid = f->async_audio;
                 if (pid != 0) {                  if (pid != 0) {
                         TRACEF(4, f, "sending SIGIO %d", pid);                          TRACEF(4, f, "sending SIGIO %d", pid);
                         mutex_enter(proc_lock);                          audio_psignal(sc, pid, SIGIO);
                         if ((p = proc_find(pid)) != NULL)  
                                 psignal(p, SIGIO);  
                         mutex_exit(proc_lock);  
                 }                  }
         }          }
         mutex_exit(sc->sc_intr_lock);  
   
         /* Notify that data has arrived. */          /* Notify that data has arrived. */
         selnotify(&sc->sc_rsel, 0, NOTE_SUBMIT);          selnotify(&sc->sc_rsel, 0, NOTE_SUBMIT);
Line 5799  audio_softintr_wr(void *cookie)
Line 6035  audio_softintr_wr(void *cookie)
         struct audio_softc *sc = cookie;          struct audio_softc *sc = cookie;
         audio_file_t *f;          audio_file_t *f;
         bool found;          bool found;
         proc_t *p;  
         pid_t pid;          pid_t pid;
   
         TRACE(4, "called");          TRACE(4, "called");
         found = false;          found = false;
   
         mutex_enter(sc->sc_lock);          mutex_enter(sc->sc_lock);
         mutex_enter(sc->sc_intr_lock);  
   
         SLIST_FOREACH(f, &sc->sc_files, entry) {          SLIST_FOREACH(f, &sc->sc_files, entry) {
                 audio_track_t *track = f->ptrack;                  audio_track_t *track = f->ptrack;
Line 5826  audio_softintr_wr(void *cookie)
Line 6060  audio_softintr_wr(void *cookie)
                  */                   */
                 if (track->usrbuf.used <= track->usrbuf_usedlow &&                  if (track->usrbuf.used <= track->usrbuf_usedlow &&
                     !track->is_pause) {                      !track->is_pause) {
                           /* For selnotify */
                         found = true;                          found = true;
                           /* For SIGIO */
                         pid = f->async_audio;                          pid = f->async_audio;
                         if (pid != 0) {                          if (pid != 0) {
                                 TRACEF(4, f, "sending SIGIO %d", pid);                                  TRACEF(4, f, "sending SIGIO %d", pid);
                                 mutex_enter(proc_lock);                                  audio_psignal(sc, pid, SIGIO);
                                 if ((p = proc_find(pid)) != NULL)  
                                         psignal(p, SIGIO);  
                                 mutex_exit(proc_lock);  
                         }                          }
                 }                  }
         }          }
         mutex_exit(sc->sc_intr_lock);  
   
         /*          /*
          * Notify for select/poll when someone become writable.           * Notify for select/poll when someone become writable.
Line 5941  audio_check_params(audio_format2_t *p)
Line 6173  audio_check_params(audio_format2_t *p)
  * phwfmt and rhwfmt indicate the hardware format.  pfil and rfil indicate   * phwfmt and rhwfmt indicate the hardware format.  pfil and rfil indicate
  * the filter registration information.  These four must not be NULL.   * the filter registration information.  These four must not be NULL.
  * If successful returns 0.  Otherwise returns errno.   * If successful returns 0.  Otherwise returns errno.
  * Must be called with sc_lock held.   * Must be called with sc_exlock held and without sc_lock held.
  * Must not be called if there are any tracks.   * Must not be called if there are any tracks.
  * Caller should check that the initialization succeed by whether   * Caller should check that the initialization succeed by whether
  * sc_[pr]mixer is not NULL.   * sc_[pr]mixer is not NULL.
Line 5957  audio_mixers_init(struct audio_softc *sc
Line 6189  audio_mixers_init(struct audio_softc *sc
         KASSERT(rhwfmt != NULL);          KASSERT(rhwfmt != NULL);
         KASSERT(pfil != NULL);          KASSERT(pfil != NULL);
         KASSERT(rfil != NULL);          KASSERT(rfil != NULL);
         KASSERT(mutex_owned(sc->sc_lock));          KASSERT(sc->sc_exlock);
   
         if ((mode & AUMODE_PLAY)) {          if ((mode & AUMODE_PLAY)) {
                 if (sc->sc_pmixer == NULL) {                  if (sc->sc_pmixer == NULL) {
Line 6044  audio_select_freq(const struct audio_for
Line 6276  audio_select_freq(const struct audio_for
 }  }
   
 /*  /*
  * Probe playback and/or recording format (depending on *modep).  
  * *modep is an in-out parameter.  It indicates the direction to configure  
  * as an argument, and the direction configured is written back as out  
  * parameter.  
  * If successful, probed hardware format is stored into *phwfmt, *rhwfmt  
  * depending on *modep, and return 0.  Otherwise it returns errno.  
  * Must be called with sc_lock held.  
  */  
 static int  
 audio_hw_probe(struct audio_softc *sc, int is_indep, int *modep,  
         audio_format2_t *phwfmt, audio_format2_t *rhwfmt)  
 {  
         audio_format2_t fmt;  
         int mode;  
         int error = 0;  
   
         KASSERT(mutex_owned(sc->sc_lock));  
   
         mode = *modep;  
         KASSERTMSG((mode & (AUMODE_PLAY | AUMODE_RECORD)) != 0,  
             "invalid mode = %x", mode);  
   
         if (is_indep) {  
                 int errorp = 0, errorr = 0;  
   
                 /* On independent devices, probe separately. */  
                 if ((mode & AUMODE_PLAY) != 0) {  
                         errorp = audio_hw_probe_fmt(sc, phwfmt, AUMODE_PLAY);  
                         if (errorp)  
                                 mode &= ~AUMODE_PLAY;  
                 }  
                 if ((mode & AUMODE_RECORD) != 0) {  
                         errorr = audio_hw_probe_fmt(sc, rhwfmt, AUMODE_RECORD);  
                         if (errorr)  
                                 mode &= ~AUMODE_RECORD;  
                 }  
   
                 /* Return error if both play and record probes failed. */  
                 if (errorp && errorr)  
                         error = errorp;  
         } else {  
                 /* On non independent devices, probe simultaneously. */  
                 error = audio_hw_probe_fmt(sc, &fmt, mode);  
                 if (error) {  
                         mode = 0;  
                 } else {  
                         *phwfmt = fmt;  
                         *rhwfmt = fmt;  
                 }  
         }  
   
         *modep = mode;  
         return error;  
 }  
   
 /*  
  * Choose the most preferred hardware format.   * Choose the most preferred hardware format.
  * If successful, it will store the chosen format into *cand and return 0.   * If successful, it will store the chosen format into *cand and return 0.
  * Otherwise, return errno.   * Otherwise, return errno.
  * Must be called with sc_lock held.   * Must be called without sc_lock held.
  */   */
 static int  static int
 audio_hw_probe_fmt(struct audio_softc *sc, audio_format2_t *cand, int mode)  audio_hw_probe(struct audio_softc *sc, audio_format2_t *cand, int mode)
 {  {
         audio_format_query_t query;          audio_format_query_t query;
         int cand_score;          int cand_score;
Line 6114  audio_hw_probe_fmt(struct audio_softc *s
Line 6290  audio_hw_probe_fmt(struct audio_softc *s
         int i;          int i;
         int error;          int error;
   
         KASSERT(mutex_owned(sc->sc_lock));  
   
         /*          /*
          * Score each formats and choose the highest one.           * Score each formats and choose the highest one.
          *           *
Line 6130  audio_hw_probe_fmt(struct audio_softc *s
Line 6304  audio_hw_probe_fmt(struct audio_softc *s
                 memset(&query, 0, sizeof(query));                  memset(&query, 0, sizeof(query));
                 query.index = i;                  query.index = i;
   
                   mutex_enter(sc->sc_lock);
                 error = sc->hw_if->query_format(sc->hw_hdl, &query);                  error = sc->hw_if->query_format(sc->hw_hdl, &query);
                   mutex_exit(sc->sc_lock);
                 if (error == EINVAL)                  if (error == EINVAL)
                         break;                          break;
                 if (error)                  if (error)
Line 6218  audio_hw_probe_fmt(struct audio_softc *s
Line 6394  audio_hw_probe_fmt(struct audio_softc *s
  * Validate fmt with query_format.   * Validate fmt with query_format.
  * If fmt is included in the result of query_format, returns 0.   * If fmt is included in the result of query_format, returns 0.
  * Otherwise returns EINVAL.   * Otherwise returns EINVAL.
  * Must be called with sc_lock held.   * Must be called without sc_lock held.
  */   */
 static int  static int
 audio_hw_validate_format(struct audio_softc *sc, int mode,  audio_hw_validate_format(struct audio_softc *sc, int mode,
Line 6230  audio_hw_validate_format(struct audio_so
Line 6406  audio_hw_validate_format(struct audio_so
         int error;          int error;
         int j;          int j;
   
         KASSERT(mutex_owned(sc->sc_lock));  
   
         /*  
          * If query_format is not supported by hardware driver,  
          * a rough check instead will be performed.  
          * XXX This will gone in the future.  
          */  
         if (sc->hw_if->query_format == NULL) {  
                 if (fmt->encoding != AUDIO_ENCODING_SLINEAR_NE)  
                         return EINVAL;  
                 if (fmt->precision != AUDIO_INTERNAL_BITS)  
                         return EINVAL;  
                 if (fmt->stride != AUDIO_INTERNAL_BITS)  
                         return EINVAL;  
                 return 0;  
         }  
   
         for (index = 0; ; index++) {          for (index = 0; ; index++) {
                 query.index = index;                  query.index = index;
                   mutex_enter(sc->sc_lock);
                 error = sc->hw_if->query_format(sc->hw_hdl, &query);                  error = sc->hw_if->query_format(sc->hw_hdl, &query);
                   mutex_exit(sc->sc_lock);
                 if (error == EINVAL)                  if (error == EINVAL)
                         break;                          break;
                 if (error)                  if (error)
Line 6306  audio_hw_validate_format(struct audio_so
Line 6467  audio_hw_validate_format(struct audio_so
  * All other fields in ai are ignored.   * All other fields in ai are ignored.
  * If successful returns 0.  Otherwise returns errno.   * If successful returns 0.  Otherwise returns errno.
  * This function does not roll back even if it fails.   * This function does not roll back even if it fails.
  * Must be called with sc_lock held.   * Must be called with sc_exlock held and without sc_lock held.
  */   */
 static int  static int
 audio_mixers_set_format(struct audio_softc *sc, const struct audio_info *ai)  audio_mixers_set_format(struct audio_softc *sc, const struct audio_info *ai)
Line 6318  audio_mixers_set_format(struct audio_sof
Line 6479  audio_mixers_set_format(struct audio_sof
         int mode;          int mode;
         int error;          int error;
   
         KASSERT(mutex_owned(sc->sc_lock));          KASSERT(sc->sc_exlock);
   
         /*          /*
          * Even when setting either one of playback and recording,           * Even when setting either one of playback and recording,
Line 6406  audio_mixers_set_format(struct audio_sof
Line 6567  audio_mixers_set_format(struct audio_sof
         if (error)          if (error)
                 return error;                  return error;
   
           /*
            * Reinitialize the sticky parameters for /dev/sound.
            * If the number of the hardware channels becomes less than the number
            * of channels that sticky parameters remember, subsequent /dev/sound
            * open will fail.  To prevent this, reinitialize the sticky
            * parameters whenever the hardware format is changed.
            */
           sc->sc_sound_pparams = params_to_format2(&audio_default);
           sc->sc_sound_rparams = params_to_format2(&audio_default);
           sc->sc_sound_ppause = false;
           sc->sc_sound_rpause = false;
   
         return 0;          return 0;
 }  }
   
 /*  /*
  * Store current mixers format into *ai.   * Store current mixers format into *ai.
    * Must be called with sc_exlock held.
  */   */
 static void  static void
 audio_mixers_get_format(struct audio_softc *sc, struct audio_info *ai)  audio_mixers_get_format(struct audio_softc *sc, struct audio_info *ai)
 {  {
   
           KASSERT(sc->sc_exlock);
   
         /*          /*
          * There is no stride information in audio_info but it doesn't matter.           * There is no stride information in audio_info but it doesn't matter.
          * trackmixer always treats stride and precision as the same.           * trackmixer always treats stride and precision as the same.
Line 6517  audio_mixers_get_format(struct audio_sof
Line 6694  audio_mixers_get_format(struct audio_sof
 /*  /*
  * Pause consideration:   * Pause consideration:
  *   *
  * The introduction of these two behavior makes pause/unpause operation   * Pausing/unpausing never affect [pr]mixer.  This single rule makes
  * simple.   * operation simple.  Note that playback and recording are asymmetric.
  * 1. The first read/write access of the first track makes mixer start.   *
  * 2. A pause of the last track doesn't make mixer stop.   * For playback,
    *  1. Any playback open doesn't start pmixer regardless of initial pause
    *     state of this track.
    *  2. The first write access among playback tracks only starts pmixer
    *     regardless of this track's pause state.
    *  3. Even a pause of the last playback track doesn't stop pmixer.
    *  4. The last close of all playback tracks only stops pmixer.
    *
    * For recording,
    *  1. The first recording open only starts rmixer regardless of initial
    *     pause state of this track.
    *  2. Even a pause of the last track doesn't stop rmixer.
    *  3. The last close of all recording tracks only stops rmixer.
  */   */
   
 /*  /*
  * Set both track's parameters within a file depending on ai.   * Set both track's parameters within a file depending on ai.
  * Update sc_sound_[pr]* if set.   * Update sc_sound_[pr]* if set.
  * Must be called with sc_lock and sc_exlock held.   * Must be called with sc_exlock held and without sc_lock held.
  */   */
 static int  static int
 audio_file_setinfo(struct audio_softc *sc, audio_file_t *file,  audio_file_setinfo(struct audio_softc *sc, audio_file_t *file,
Line 6546  audio_file_setinfo(struct audio_softc *s
Line 6735  audio_file_setinfo(struct audio_softc *s
         audio_format2_t saved_rfmt;          audio_format2_t saved_rfmt;
         int error;          int error;
   
         KASSERT(mutex_owned(sc->sc_lock));  
         KASSERT(sc->sc_exlock);          KASSERT(sc->sc_exlock);
   
         pi = &ai->play;          pi = &ai->play;
Line 6627  audio_file_setinfo(struct audio_softc *s
Line 6815  audio_file_setinfo(struct audio_softc *s
         memset(&saved_pfmt, 0, sizeof(saved_pfmt));          memset(&saved_pfmt, 0, sizeof(saved_pfmt));
         memset(&saved_rfmt, 0, sizeof(saved_rfmt));          memset(&saved_rfmt, 0, sizeof(saved_rfmt));
   
         /* Set default value and save current parameters */          /*
            * Set default value and save current parameters.
            * For backward compatibility, use sticky parameters for nonexistent
            * track.
            */
         if (ptrack) {          if (ptrack) {
                 pfmt = ptrack->usrbuf.fmt;                  pfmt = ptrack->usrbuf.fmt;
                 saved_pfmt = ptrack->usrbuf.fmt;                  saved_pfmt = ptrack->usrbuf.fmt;
                 saved_ai.play.pause = ptrack->is_pause;                  saved_ai.play.pause = ptrack->is_pause;
           } else {
                   pfmt = sc->sc_sound_pparams;
         }          }
         if (rtrack) {          if (rtrack) {
                 rfmt = rtrack->usrbuf.fmt;                  rfmt = rtrack->usrbuf.fmt;
                 saved_rfmt = rtrack->usrbuf.fmt;                  saved_rfmt = rtrack->usrbuf.fmt;
                 saved_ai.record.pause = rtrack->is_pause;                  saved_ai.record.pause = rtrack->is_pause;
           } else {
                   rfmt = sc->sc_sound_rparams;
         }          }
         saved_ai.mode = file->mode;          saved_ai.mode = file->mode;
   
         /* Overwrite if specified */          /*
            * Overwrite if specified.
            */
         mode = file->mode;          mode = file->mode;
         if (SPECIFIED(ai->mode)) {          if (SPECIFIED(ai->mode)) {
                 /*                  /*
Line 6659  audio_file_setinfo(struct audio_softc *s
Line 6857  audio_file_setinfo(struct audio_softc *s
                 }                  }
         }          }
   
         if (ptrack) {          pchanges = audio_track_setinfo_check(ptrack, &pfmt, pi);
                 pchanges = audio_track_setinfo_check(&pfmt, pi);          if (pchanges == -1) {
                 if (pchanges == -1) {  
 #if defined(AUDIO_DEBUG)  #if defined(AUDIO_DEBUG)
                         char fmtbuf[64];                  TRACEF(1, file, "check play.params failed: "
                         audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &pfmt);                      "%s %ubit %uch %uHz",
                         TRACET(1, ptrack, "check play.params failed: %s",                      audio_encoding_name(pi->encoding),
                             fmtbuf);                      pi->precision,
                       pi->channels,
                       pi->sample_rate);
 #endif  #endif
                         return EINVAL;                  return EINVAL;
                 }  
                 if (SPECIFIED(ai->mode))  
                         pchanges = 1;  
         }          }
         if (rtrack) {  
                 rchanges = audio_track_setinfo_check(&rfmt, ri);          rchanges = audio_track_setinfo_check(rtrack, &rfmt, ri);
                 if (rchanges == -1) {          if (rchanges == -1) {
 #if defined(AUDIO_DEBUG)  #if defined(AUDIO_DEBUG)
                         char fmtbuf[64];                  TRACEF(1, file, "check record.params failed: "
                         audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &rfmt);                      "%s %ubit %uch %uHz",
                         TRACET(1, rtrack, "check record.params failed: %s",                      audio_encoding_name(ri->encoding),
                             fmtbuf);                      ri->precision,
                       ri->channels,
                       ri->sample_rate);
 #endif  #endif
                         return EINVAL;                  return EINVAL;
                 }          }
                 if (SPECIFIED(ai->mode))  
                         rchanges = 1;          if (SPECIFIED(ai->mode)) {
                   pchanges = 1;
                   rchanges = 1;
         }          }
   
         /*          /*
Line 6695  audio_file_setinfo(struct audio_softc *s
Line 6895  audio_file_setinfo(struct audio_softc *s
         if (pchanges || rchanges) {          if (pchanges || rchanges) {
                 audio_file_clear(sc, file);                  audio_file_clear(sc, file);
 #if defined(AUDIO_DEBUG)  #if defined(AUDIO_DEBUG)
                   char nbuf[16];
                 char fmtbuf[64];                  char fmtbuf[64];
                 if (pchanges) {                  if (pchanges) {
                           if (ptrack) {
                                   snprintf(nbuf, sizeof(nbuf), "%d", ptrack->id);
                           } else {
                                   snprintf(nbuf, sizeof(nbuf), "-");
                           }
                         audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &pfmt);                          audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &pfmt);
                         DPRINTF(1, "audio track#%d play mode: %s\n",                          DPRINTF(1, "audio track#%s play mode: %s\n",
                             ptrack->id, fmtbuf);                              nbuf, fmtbuf);
                 }                  }
                 if (rchanges) {                  if (rchanges) {
                           if (rtrack) {
                                   snprintf(nbuf, sizeof(nbuf), "%d", rtrack->id);
                           } else {
                                   snprintf(nbuf, sizeof(nbuf), "-");
                           }
                         audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &rfmt);                          audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &rfmt);
                         DPRINTF(1, "audio track#%d rec  mode: %s\n",                          DPRINTF(1, "audio track#%s rec  mode: %s\n",
                             rtrack->id, fmtbuf);                              nbuf, fmtbuf);
                 }                  }
 #endif  #endif
         }          }
   
         /* Set mixer parameters */          /* Set mixer parameters */
           mutex_enter(sc->sc_lock);
         error = audio_hw_setinfo(sc, ai, &saved_ai);          error = audio_hw_setinfo(sc, ai, &saved_ai);
           mutex_exit(sc->sc_lock);
         if (error)          if (error)
                 goto abort1;                  goto abort1;
   
         /* Set to track and update sticky parameters */          /*
            * Set to track and update sticky parameters.
            */
         error = 0;          error = 0;
         file->mode = mode;          file->mode = mode;
         if (ptrack) {  
                 if (SPECIFIED_CH(pi->pause)) {          if (SPECIFIED_CH(pi->pause)) {
                   if (ptrack)
                         ptrack->is_pause = pi->pause;                          ptrack->is_pause = pi->pause;
                         sc->sc_sound_ppause = pi->pause;                  sc->sc_sound_ppause = pi->pause;
                 }          }
                 if (pchanges) {          if (pchanges) {
                   if (ptrack) {
                         audio_track_lock_enter(ptrack);                          audio_track_lock_enter(ptrack);
                         error = audio_track_set_format(ptrack, &pfmt);                          error = audio_track_set_format(ptrack, &pfmt);
                         audio_track_lock_exit(ptrack);                          audio_track_lock_exit(ptrack);
Line 6730  audio_file_setinfo(struct audio_softc *s
Line 6947  audio_file_setinfo(struct audio_softc *s
                                 TRACET(1, ptrack, "set play.params failed");                                  TRACET(1, ptrack, "set play.params failed");
                                 goto abort2;                                  goto abort2;
                         }                          }
                         sc->sc_sound_pparams = pfmt;  
                 }                  }
                 /* Change water marks after initializing the buffers. */                  sc->sc_sound_pparams = pfmt;
                 if (SPECIFIED(ai->hiwat) || SPECIFIED(ai->lowat))          }
           /* Change water marks after initializing the buffers. */
           if (SPECIFIED(ai->hiwat) || SPECIFIED(ai->lowat)) {
                   if (ptrack)
                         audio_track_setinfo_water(ptrack, ai);                          audio_track_setinfo_water(ptrack, ai);
         }          }
         if (rtrack) {  
                 if (SPECIFIED_CH(ri->pause)) {          if (SPECIFIED_CH(ri->pause)) {
                   if (rtrack)
                         rtrack->is_pause = ri->pause;                          rtrack->is_pause = ri->pause;
                         sc->sc_sound_rpause = ri->pause;                  sc->sc_sound_rpause = ri->pause;
                 }          }
                 if (rchanges) {          if (rchanges) {
                   if (rtrack) {
                         audio_track_lock_enter(rtrack);                          audio_track_lock_enter(rtrack);
                         error = audio_track_set_format(rtrack, &rfmt);                          error = audio_track_set_format(rtrack, &rfmt);
                         audio_track_lock_exit(rtrack);                          audio_track_lock_exit(rtrack);
Line 6749  audio_file_setinfo(struct audio_softc *s
Line 6970  audio_file_setinfo(struct audio_softc *s
                                 TRACET(1, rtrack, "set record.params failed");                                  TRACET(1, rtrack, "set record.params failed");
                                 goto abort3;                                  goto abort3;
                         }                          }
                         sc->sc_sound_rparams = rfmt;  
                 }                  }
                   sc->sc_sound_rparams = rfmt;
         }          }
   
         return 0;          return 0;
Line 6763  abort3:
Line 6984  abort3:
                 audio_track_set_format(rtrack, &saved_rfmt);                  audio_track_set_format(rtrack, &saved_rfmt);
                 audio_track_lock_exit(rtrack);                  audio_track_lock_exit(rtrack);
         }          }
           sc->sc_sound_rpause = saved_ai.record.pause;
           sc->sc_sound_rparams = saved_rfmt;
 abort2:  abort2:
         if (ptrack && error != ENOMEM) {          if (ptrack && error != ENOMEM) {
                 ptrack->is_pause = saved_ai.play.pause;                  ptrack->is_pause = saved_ai.play.pause;
                 audio_track_lock_enter(ptrack);                  audio_track_lock_enter(ptrack);
                 audio_track_set_format(ptrack, &saved_pfmt);                  audio_track_set_format(ptrack, &saved_pfmt);
                 audio_track_lock_exit(ptrack);                  audio_track_lock_exit(ptrack);
                 sc->sc_sound_pparams = saved_pfmt;  
                 sc->sc_sound_ppause = saved_ai.play.pause;  
         }          }
           sc->sc_sound_ppause = saved_ai.play.pause;
           sc->sc_sound_pparams = saved_pfmt;
         file->mode = saved_ai.mode;          file->mode = saved_ai.mode;
 abort1:  abort1:
           mutex_enter(sc->sc_lock);
         audio_hw_setinfo(sc, &saved_ai, NULL);          audio_hw_setinfo(sc, &saved_ai, NULL);
           mutex_exit(sc->sc_lock);
   
         return error;          return error;
 }  }
   
 /*  /*
  * Write SPECIFIED() parameters within info back to fmt.   * Write SPECIFIED() parameters within info back to fmt.
    * Note that track can be NULL here.
  * Return value of 1 indicates that fmt is modified.   * Return value of 1 indicates that fmt is modified.
  * Return value of 0 indicates that fmt is not modified.   * Return value of 0 indicates that fmt is not modified.
  * Return value of -1 indicates that error EINVAL has occurred.   * Return value of -1 indicates that error EINVAL has occurred.
  */   */
 static int  static int
 audio_track_setinfo_check(audio_format2_t *fmt, const struct audio_prinfo *info)  audio_track_setinfo_check(audio_track_t *track,
           audio_format2_t *fmt, const struct audio_prinfo *info)
 {  {
           const audio_format2_t *hwfmt;
         int changes;          int changes;
   
         changes = 0;          changes = 0;
Line 6810  audio_track_setinfo_check(audio_format2_
Line 7038  audio_track_setinfo_check(audio_format2_
                 changes = 1;                  changes = 1;
         }          }
         if (SPECIFIED(info->channels)) {          if (SPECIFIED(info->channels)) {
                   /*
                    * We can convert between monaural and stereo each other.
                    * We can reduce than the number of channels that the hardware
                    * supports.
                    */
                   if (info->channels > 2) {
                           if (track) {
                                   hwfmt = &track->mixer->hwbuf.fmt;
                                   if (info->channels > hwfmt->channels)
                                           return -1;
                           } else {
                                   /*
                                    * This should never happen.
                                    * If track == NULL, channels should be <= 2.
                                    */
                                   return -1;
                           }
                   }
                 fmt->channels = info->channels;                  fmt->channels = info->channels;
                 changes = 1;                  changes = 1;
         }          }
Line 6864  audio_track_setinfo_water(audio_track_t 
Line 7110  audio_track_setinfo_water(audio_track_t 
  * The parameters handled here are *.port, *.gain, *.balance and monitor_gain.   * The parameters handled here are *.port, *.gain, *.balance and monitor_gain.
  * If oldai is specified, previous parameters are stored.   * If oldai is specified, previous parameters are stored.
  * This function itself does not roll back if error occurred.   * This function itself does not roll back if error occurred.
  * Must be called with sc_lock and sc_exlock held.   * Must be called with sc_lock && sc_exlock held.
  */   */
 static int  static int
 audio_hw_setinfo(struct audio_softc *sc, const struct audio_info *newai,  audio_hw_setinfo(struct audio_softc *sc, const struct audio_info *newai,
Line 7014  abort:
Line 7260  abort:
  * - pfil, rfil will be filled with filter information specified by the   * - pfil, rfil will be filled with filter information specified by the
  *   hardware driver.   *   hardware driver.
  * and then returns 0.  Otherwise returns errno.   * and then returns 0.  Otherwise returns errno.
  * Must be called with sc_lock held.   * Must be called without sc_lock held.
  */   */
 static int  static int
 audio_hw_set_format(struct audio_softc *sc, int setmode,  audio_hw_set_format(struct audio_softc *sc, int setmode,
Line 7024  audio_hw_set_format(struct audio_softc *
Line 7270  audio_hw_set_format(struct audio_softc *
         audio_params_t pp, rp;          audio_params_t pp, rp;
         int error;          int error;
   
         KASSERT(mutex_owned(sc->sc_lock));  
         KASSERT(phwfmt != NULL);          KASSERT(phwfmt != NULL);
         KASSERT(rhwfmt != NULL);          KASSERT(rhwfmt != NULL);
   
         pp = format2_to_params(phwfmt);          pp = format2_to_params(phwfmt);
         rp = format2_to_params(rhwfmt);          rp = format2_to_params(rhwfmt);
   
           mutex_enter(sc->sc_lock);
         error = sc->hw_if->set_format(sc->hw_hdl, setmode,          error = sc->hw_if->set_format(sc->hw_hdl, setmode,
             &pp, &rp, pfil, rfil);              &pp, &rp, pfil, rfil);
         if (error) {          if (error) {
                   mutex_exit(sc->sc_lock);
                 device_printf(sc->sc_dev,                  device_printf(sc->sc_dev,
                     "set_format failed with %d\n", error);                      "set_format failed with %d\n", error);
                 return error;                  return error;
Line 7042  audio_hw_set_format(struct audio_softc *
Line 7289  audio_hw_set_format(struct audio_softc *
         if (sc->hw_if->commit_settings) {          if (sc->hw_if->commit_settings) {
                 error = sc->hw_if->commit_settings(sc->hw_hdl);                  error = sc->hw_if->commit_settings(sc->hw_hdl);
                 if (error) {                  if (error) {
                           mutex_exit(sc->sc_lock);
                         device_printf(sc->sc_dev,                          device_printf(sc->sc_dev,
                             "commit_settings failed with %d\n", error);                              "commit_settings failed with %d\n", error);
                         return error;                          return error;
                 }                  }
         }          }
           mutex_exit(sc->sc_lock);
   
         return 0;          return 0;
 }  }
Line 7054  audio_hw_set_format(struct audio_softc *
Line 7303  audio_hw_set_format(struct audio_softc *
 /*  /*
  * Fill audio_info structure.  If need_mixerinfo is true, it will also   * Fill audio_info structure.  If need_mixerinfo is true, it will also
  * fill the hardware mixer information.   * fill the hardware mixer information.
  * Must be called with sc_lock held.   * Must be called with sc_exlock held and without sc_lock held.
  * Must be called with sc_exlock held, in addition, if need_mixerinfo is  
  * true.  
  */   */
 static int  static int
 audiogetinfo(struct audio_softc *sc, struct audio_info *ai, int need_mixerinfo,  audiogetinfo(struct audio_softc *sc, struct audio_info *ai, int need_mixerinfo,
Line 7068  audiogetinfo(struct audio_softc *sc, str
Line 7315  audiogetinfo(struct audio_softc *sc, str
         audio_track_t *rtrack;          audio_track_t *rtrack;
         int gain;          int gain;
   
         KASSERT(mutex_owned(sc->sc_lock));          KASSERT(sc->sc_exlock);
   
         ri = &ai->record;          ri = &ai->record;
         pi = &ai->play;          pi = &ai->play;
Line 7082  audiogetinfo(struct audio_softc *sc, str
Line 7329  audiogetinfo(struct audio_softc *sc, str
                 pi->channels    = ptrack->usrbuf.fmt.channels;                  pi->channels    = ptrack->usrbuf.fmt.channels;
                 pi->precision   = ptrack->usrbuf.fmt.precision;                  pi->precision   = ptrack->usrbuf.fmt.precision;
                 pi->encoding    = ptrack->usrbuf.fmt.encoding;                  pi->encoding    = ptrack->usrbuf.fmt.encoding;
                   pi->pause       = ptrack->is_pause;
         } else {          } else {
                 /* Set default parameters if the track is not available. */                  /* Use sticky parameters if the track is not available. */
                 if (ISDEVAUDIO(file->dev)) {                  pi->sample_rate = sc->sc_sound_pparams.sample_rate;
                         pi->sample_rate = audio_default.sample_rate;                  pi->channels    = sc->sc_sound_pparams.channels;
                         pi->channels    = audio_default.channels;                  pi->precision   = sc->sc_sound_pparams.precision;
                         pi->precision   = audio_default.precision;                  pi->encoding    = sc->sc_sound_pparams.encoding;
                         pi->encoding    = audio_default.encoding;                  pi->pause       = sc->sc_sound_ppause;
                 } else {  
                         pi->sample_rate = sc->sc_sound_pparams.sample_rate;  
                         pi->channels    = sc->sc_sound_pparams.channels;  
                         pi->precision   = sc->sc_sound_pparams.precision;  
                         pi->encoding    = sc->sc_sound_pparams.encoding;  
                 }  
         }          }
         if (rtrack) {          if (rtrack) {
                 ri->sample_rate = rtrack->usrbuf.fmt.sample_rate;                  ri->sample_rate = rtrack->usrbuf.fmt.sample_rate;
                 ri->channels    = rtrack->usrbuf.fmt.channels;                  ri->channels    = rtrack->usrbuf.fmt.channels;
                 ri->precision   = rtrack->usrbuf.fmt.precision;                  ri->precision   = rtrack->usrbuf.fmt.precision;
                 ri->encoding    = rtrack->usrbuf.fmt.encoding;                  ri->encoding    = rtrack->usrbuf.fmt.encoding;
                   ri->pause       = rtrack->is_pause;
         } else {          } else {
                 /* Set default parameters if the track is not available. */                  /* Use sticky parameters if the track is not available. */
                 if (ISDEVAUDIO(file->dev)) {                  ri->sample_rate = sc->sc_sound_rparams.sample_rate;
                         ri->sample_rate = audio_default.sample_rate;                  ri->channels    = sc->sc_sound_rparams.channels;
                         ri->channels    = audio_default.channels;                  ri->precision   = sc->sc_sound_rparams.precision;
                         ri->precision   = audio_default.precision;                  ri->encoding    = sc->sc_sound_rparams.encoding;
                         ri->encoding    = audio_default.encoding;                  ri->pause       = sc->sc_sound_rpause;
                 } else {  
                         ri->sample_rate = sc->sc_sound_rparams.sample_rate;  
                         ri->channels    = sc->sc_sound_rparams.channels;  
                         ri->precision   = sc->sc_sound_rparams.precision;  
                         ri->encoding    = sc->sc_sound_rparams.encoding;  
                 }  
         }          }
   
         if (ptrack) {          if (ptrack) {
                 pi->seek = ptrack->usrbuf.used;                  pi->seek = ptrack->usrbuf.used;
                 pi->samples = ptrack->usrbuf_stamp;                  pi->samples = ptrack->usrbuf_stamp;
                 pi->eof = ptrack->eofcounter;                  pi->eof = ptrack->eofcounter;
                 pi->pause = ptrack->is_pause;  
                 pi->error = (ptrack->dropframes != 0) ? 1 : 0;                  pi->error = (ptrack->dropframes != 0) ? 1 : 0;
                 pi->waiting = 0;                /* open never hangs */  
                 pi->open = 1;                  pi->open = 1;
                 pi->active = sc->sc_pbusy;  
                 pi->buffer_size = ptrack->usrbuf.capacity;                  pi->buffer_size = ptrack->usrbuf.capacity;
         }          }
           pi->waiting = 0;                /* open never hangs */
           pi->active = sc->sc_pbusy;
   
         if (rtrack) {          if (rtrack) {
                 ri->seek = rtrack->usrbuf.used;                  ri->seek = rtrack->usrbuf.used;
                 ri->samples = rtrack->usrbuf_stamp;                  ri->samples = rtrack->usrbuf_stamp;
                 ri->eof = 0;                  ri->eof = 0;
                 ri->pause = rtrack->is_pause;  
                 ri->error = (rtrack->dropframes != 0) ? 1 : 0;                  ri->error = (rtrack->dropframes != 0) ? 1 : 0;
                 ri->waiting = 0;                /* open never hangs */  
                 ri->open = 1;                  ri->open = 1;
                 ri->active = sc->sc_rbusy;  
                 ri->buffer_size = rtrack->usrbuf.capacity;                  ri->buffer_size = rtrack->usrbuf.capacity;
         }          }
           ri->waiting = 0;                /* open never hangs */
           ri->active = sc->sc_rbusy;
   
         /*          /*
          * XXX There may be different number of channels between playback           * XXX There may be different number of channels between playback
Line 7157  audiogetinfo(struct audio_softc *sc, str
Line 7393  audiogetinfo(struct audio_softc *sc, str
         }          }
         ai->mode = file->mode;          ai->mode = file->mode;
   
           /*
            * For backward compatibility, we have to pad these five fields
            * a fake non-zero value even if there are no tracks.
            */
           if (ptrack == NULL)
                   pi->buffer_size = 65536;
           if (rtrack == NULL)
                   ri->buffer_size = 65536;
           if (ptrack == NULL && rtrack == NULL) {
                   ai->blocksize = 2048;
                   ai->hiwat = ai->play.buffer_size / ai->blocksize;
                   ai->lowat = ai->hiwat * 3 / 4;
           }
   
         if (need_mixerinfo) {          if (need_mixerinfo) {
                 KASSERT(sc->sc_exlock);                  mutex_enter(sc->sc_lock);
   
                 pi->port = au_get_port(sc, &sc->sc_outports);                  pi->port = au_get_port(sc, &sc->sc_outports);
                 ri->port = au_get_port(sc, &sc->sc_inports);                  ri->port = au_get_port(sc, &sc->sc_inports);
Line 7174  audiogetinfo(struct audio_softc *sc, str
Line 7424  audiogetinfo(struct audio_softc *sc, str
                         if (gain != -1)                          if (gain != -1)
                                 ai->monitor_gain = gain;                                  ai->monitor_gain = gain;
                 }                  }
                   mutex_exit(sc->sc_lock);
         }          }
   
         return 0;          return 0;
Line 7312  audio_sysctl_blk_ms(SYSCTLFN_ARGS)
Line 7563  audio_sysctl_blk_ms(SYSCTLFN_ARGS)
         node = *rnode;          node = *rnode;
         sc = node.sysctl_data;          sc = node.sysctl_data;
   
         mutex_enter(sc->sc_lock);          error = audio_exlock_enter(sc);
           if (error)
                   return error;
   
         old_blk_ms = sc->sc_blk_ms;          old_blk_ms = sc->sc_blk_ms;
         t = old_blk_ms;          t = old_blk_ms;
Line 7359  audio_sysctl_blk_ms(SYSCTLFN_ARGS)
Line 7612  audio_sysctl_blk_ms(SYSCTLFN_ARGS)
         }          }
         error = 0;          error = 0;
 abort:  abort:
         mutex_exit(sc->sc_lock);          audio_exlock_exit(sc);
         return error;          return error;
 }  }
   
Line 7377  audio_sysctl_multiuser(SYSCTLFN_ARGS)
Line 7630  audio_sysctl_multiuser(SYSCTLFN_ARGS)
         node = *rnode;          node = *rnode;
         sc = node.sysctl_data;          sc = node.sysctl_data;
   
         mutex_enter(sc->sc_lock);          error = audio_exlock_enter(sc);
           if (error)
                   return error;
   
         t = sc->sc_multiuser;          t = sc->sc_multiuser;
         node.sysctl_data = &t;          node.sysctl_data = &t;
Line 7388  audio_sysctl_multiuser(SYSCTLFN_ARGS)
Line 7643  audio_sysctl_multiuser(SYSCTLFN_ARGS)
         sc->sc_multiuser = t;          sc->sc_multiuser = t;
         error = 0;          error = 0;
 abort:  abort:
         mutex_exit(sc->sc_lock);          audio_exlock_exit(sc);
         return error;          return error;
 }  }
   
Line 7468  audio_suspend(device_t dv, const pmf_qua
Line 7723  audio_suspend(device_t dv, const pmf_qua
         struct audio_softc *sc = device_private(dv);          struct audio_softc *sc = device_private(dv);
         int error;          int error;
   
         error = audio_enter_exclusive(sc);          error = audio_exlock_mutex_enter(sc);
         if (error)          if (error)
                 return error;                  return error;
         audio_mixer_capture(sc);          audio_mixer_capture(sc);
Line 7486  audio_suspend(device_t dv, const pmf_qua
Line 7741  audio_suspend(device_t dv, const pmf_qua
 #ifdef AUDIO_PM_IDLE  #ifdef AUDIO_PM_IDLE
         callout_halt(&sc->sc_idle_counter, sc->sc_lock);          callout_halt(&sc->sc_idle_counter, sc->sc_lock);
 #endif  #endif
         audio_exit_exclusive(sc);          audio_exlock_mutex_exit(sc);
   
         return true;          return true;
 }  }
Line 7498  audio_resume(device_t dv, const pmf_qual
Line 7753  audio_resume(device_t dv, const pmf_qual
         struct audio_info ai;          struct audio_info ai;
         int error;          int error;
   
         error = audio_enter_exclusive(sc);          error = audio_exlock_mutex_enter(sc);
         if (error)          if (error)
                 return error;                  return error;
   
Line 7512  audio_resume(device_t dv, const pmf_qual
Line 7767  audio_resume(device_t dv, const pmf_qual
         if (sc->sc_rbusy)          if (sc->sc_rbusy)
                 audio_rmixer_start(sc);                  audio_rmixer_start(sc);
   
         audio_exit_exclusive(sc);          audio_exlock_mutex_exit(sc);
   
         return true;          return true;
 }  }
Line 7551  audio_print_format2(const char *s, const
Line 7806  audio_print_format2(const char *s, const
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
 void  void
 audio_diagnostic_format2(const char *func, const audio_format2_t *fmt)  audio_diagnostic_format2(const char *where, const audio_format2_t *fmt)
 {  {
   
         KASSERTMSG(fmt, "%s: fmt == NULL", func);          KASSERTMSG(fmt, "called from %s", where);
   
         /* XXX MSM6258 vs(4) only has 4bit stride format. */          /* XXX MSM6258 vs(4) only has 4bit stride format. */
         if (fmt->encoding == AUDIO_ENCODING_ADPCM) {          if (fmt->encoding == AUDIO_ENCODING_ADPCM) {
                 KASSERTMSG(fmt->stride == 4 || fmt->stride == 8,                  KASSERTMSG(fmt->stride == 4 || fmt->stride == 8,
                     "%s: stride(%d) is invalid", func, fmt->stride);                      "called from %s: fmt->stride=%d", where, fmt->stride);
         } else {          } else {
                 KASSERTMSG(fmt->stride % NBBY == 0,                  KASSERTMSG(fmt->stride % NBBY == 0,
                     "%s: stride(%d) is invalid", func, fmt->stride);                      "called from %s: fmt->stride=%d", where, fmt->stride);
         }          }
         KASSERTMSG(fmt->precision <= fmt->stride,          KASSERTMSG(fmt->precision <= fmt->stride,
             "%s: precision(%d) <= stride(%d)",              "called from %s: fmt->precision=%d fmt->stride=%d",
             func, fmt->precision, fmt->stride);              where, fmt->precision, fmt->stride);
         KASSERTMSG(1 <= fmt->channels && fmt->channels <= AUDIO_MAX_CHANNELS,          KASSERTMSG(1 <= fmt->channels && fmt->channels <= AUDIO_MAX_CHANNELS,
             "%s: channels(%d) is out of range",              "called from %s: fmt->channels=%d", where, fmt->channels);
             func, fmt->channels);  
   
         /* XXX No check for encodings? */          /* XXX No check for encodings? */
 }  }
   
 void  void
 audio_diagnostic_filter_arg(const char *func, const audio_filter_arg_t *arg)  audio_diagnostic_filter_arg(const char *where, const audio_filter_arg_t *arg)
 {  {
   
         KASSERT(arg != NULL);          KASSERT(arg != NULL);
         KASSERT(arg->src != NULL);          KASSERT(arg->src != NULL);
         KASSERT(arg->dst != NULL);          KASSERT(arg->dst != NULL);
         DIAGNOSTIC_format2(arg->srcfmt);          audio_diagnostic_format2(where, arg->srcfmt);
         DIAGNOSTIC_format2(arg->dstfmt);          audio_diagnostic_format2(where, arg->dstfmt);
         KASSERTMSG(arg->count > 0,          KASSERT(arg->count > 0);
             "%s: count(%d) is out of range", func, arg->count);  
 }  }
   
 void  void
 audio_diagnostic_ring(const char *func, const audio_ring_t *ring)  audio_diagnostic_ring(const char *where, const audio_ring_t *ring)
 {  {
   
         KASSERTMSG(ring, "%s: ring == NULL", func);          KASSERTMSG(ring, "called from %s", where);
         DIAGNOSTIC_format2(&ring->fmt);          audio_diagnostic_format2(where, &ring->fmt);
         KASSERTMSG(0 <= ring->capacity && ring->capacity < INT_MAX / 2,          KASSERTMSG(0 <= ring->capacity && ring->capacity < INT_MAX / 2,
             "%s: capacity(%d) is out of range", func, ring->capacity);              "called from %s: ring->capacity=%d", where, ring->capacity);
         KASSERTMSG(0 <= ring->used && ring->used <= ring->capacity,          KASSERTMSG(0 <= ring->used && ring->used <= ring->capacity,
             "%s: used(%d) is out of range (capacity:%d)",              "called from %s: ring->used=%d ring->capacity=%d",
             func, ring->used, ring->capacity);              where, ring->used, ring->capacity);
         if (ring->capacity == 0) {          if (ring->capacity == 0) {
                 KASSERTMSG(ring->mem == NULL,                  KASSERTMSG(ring->mem == NULL,
                     "%s: capacity == 0 but mem != NULL", func);                      "called from %s: capacity == 0 but mem != NULL", where);
         } else {          } else {
                 KASSERTMSG(ring->mem != NULL,                  KASSERTMSG(ring->mem != NULL,
                     "%s: capacity != 0 but mem == NULL", func);                      "called from %s: capacity != 0 but mem == NULL", where);
                 KASSERTMSG(0 <= ring->head && ring->head < ring->capacity,                  KASSERTMSG(0 <= ring->head && ring->head < ring->capacity,
                     "%s: head(%d) is out of range (capacity:%d)",                      "called from %s: ring->head=%d ring->capacity=%d",
                     func, ring->head, ring->capacity);                      where, ring->head, ring->capacity);
         }          }
 }  }
 #endif /* DIAGNOSTIC */  #endif /* DIAGNOSTIC */
Line 7615  audio_diagnostic_ring(const char *func, 
Line 7868  audio_diagnostic_ring(const char *func, 
 /*  /*
  * Mixer driver   * Mixer driver
  */   */
   
   /*
    * Must be called without sc_lock held.
    */
 int  int
 mixer_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,  mixer_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
         struct lwp *l)          struct lwp *l)
Line 7623  mixer_open(dev_t dev, struct audio_softc
Line 7880  mixer_open(dev_t dev, struct audio_softc
         audio_file_t *af;          audio_file_t *af;
         int error, fd;          int error, fd;
   
         KASSERT(mutex_owned(sc->sc_lock));  
   
         TRACE(1, "flags=0x%x", flags);          TRACE(1, "flags=0x%x", flags);
   
         error = fd_allocfile(&fp, &fd);          error = fd_allocfile(&fp, &fd);
Line 7642  mixer_open(dev_t dev, struct audio_softc
Line 7897  mixer_open(dev_t dev, struct audio_softc
 }  }
   
 /*  /*
    * Add a process to those to be signalled on mixer activity.
    * If the process has already been added, do nothing.
    * Must be called with sc_exlock held and without sc_lock held.
    */
   static void
   mixer_async_add(struct audio_softc *sc, pid_t pid)
   {
           int i;
   
           KASSERT(sc->sc_exlock);
   
           /* If already exists, returns without doing anything. */
           for (i = 0; i < sc->sc_am_used; i++) {
                   if (sc->sc_am[i] == pid)
                           return;
           }
   
           /* Extend array if necessary. */
           if (sc->sc_am_used >= sc->sc_am_capacity) {
                   sc->sc_am_capacity += AM_CAPACITY;
                   sc->sc_am = kern_realloc(sc->sc_am,
                       sc->sc_am_capacity * sizeof(pid_t), M_WAITOK);
                   TRACE(2, "realloc am_capacity=%d", sc->sc_am_capacity);
           }
   
           TRACE(2, "am[%d]=%d", sc->sc_am_used, (int)pid);
           sc->sc_am[sc->sc_am_used++] = pid;
   }
   
   /*
  * Remove a process from those to be signalled on mixer activity.   * Remove a process from those to be signalled on mixer activity.
  * Must be called with sc_lock held.   * If the process has not been added, do nothing.
    * Must be called with sc_exlock held and without sc_lock held.
  */   */
 static void  static void
 mixer_remove(struct audio_softc *sc)  mixer_async_remove(struct audio_softc *sc, pid_t pid)
 {  {
         struct mixer_asyncs **pm, *m;          int i;
         pid_t pid;  
   
         KASSERT(mutex_owned(sc->sc_lock));          KASSERT(sc->sc_exlock);
   
         pid = curproc->p_pid;          for (i = 0; i < sc->sc_am_used; i++) {
         for (pm = &sc->sc_async_mixer; *pm; pm = &(*pm)->next) {                  if (sc->sc_am[i] == pid) {
                 if ((*pm)->pid == pid) {                          sc->sc_am[i] = sc->sc_am[--sc->sc_am_used];
                         m = *pm;                          TRACE(2, "am[%d](%d) removed, used=%d",
                         *pm = m->next;                              i, (int)pid, sc->sc_am_used);
                         kmem_free(m, sizeof(*m));  
                           /* Empty array if no longer necessary. */
                           if (sc->sc_am_used == 0) {
                                   kern_free(sc->sc_am);
                                   sc->sc_am = NULL;
                                   sc->sc_am_capacity = 0;
                                   TRACE(2, "released");
                           }
                         return;                          return;
                 }                  }
         }          }
Line 7666  mixer_remove(struct audio_softc *sc)
Line 7958  mixer_remove(struct audio_softc *sc)
   
 /*  /*
  * Signal all processes waiting for the mixer.   * Signal all processes waiting for the mixer.
  * Must be called with sc_lock held.   * Must be called with sc_exlock held.
  */   */
 static void  static void
 mixer_signal(struct audio_softc *sc)  mixer_signal(struct audio_softc *sc)
 {  {
         struct mixer_asyncs *m;  
         proc_t *p;          proc_t *p;
           int i;
   
           KASSERT(sc->sc_exlock);
   
         for (m = sc->sc_async_mixer; m; m = m->next) {          for (i = 0; i < sc->sc_am_used; i++) {
                 mutex_enter(proc_lock);                  mutex_enter(proc_lock);
                 if ((p = proc_find(m->pid)) != NULL)                  p = proc_find(sc->sc_am[i]);
                   if (p)
                         psignal(p, SIGIO);                          psignal(p, SIGIO);
                 mutex_exit(proc_lock);                  mutex_exit(proc_lock);
         }          }
Line 7688  mixer_signal(struct audio_softc *sc)
Line 7983  mixer_signal(struct audio_softc *sc)
 int  int
 mixer_close(struct audio_softc *sc, audio_file_t *file)  mixer_close(struct audio_softc *sc, audio_file_t *file)
 {  {
           int error;
   
         mutex_enter(sc->sc_lock);          error = audio_exlock_enter(sc);
           if (error)
                   return error;
         TRACE(1, "");          TRACE(1, "");
         mixer_remove(sc);          mixer_async_remove(sc, curproc->p_pid);
         mutex_exit(sc->sc_lock);          audio_exlock_exit(sc);
   
         return 0;          return 0;
 }  }
   
   /*
    * Must be called without sc_lock nor sc_exlock held.
    */
 int  int
 mixer_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,  mixer_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
         struct lwp *l)          struct lwp *l)
 {  {
         struct mixer_asyncs *ma;  
         mixer_devinfo_t *mi;          mixer_devinfo_t *mi;
         mixer_ctrl_t *mc;          mixer_ctrl_t *mc;
         int error;          int error;
   
         KASSERT(!mutex_owned(sc->sc_lock));  
   
         TRACE(2, "(%lu,'%c',%lu)",          TRACE(2, "(%lu,'%c',%lu)",
             IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd & 0xff);              IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd & 0xff);
         error = EINVAL;          error = EINVAL;
Line 7721  mixer_ioctl(struct audio_softc *sc, u_lo
Line 8019  mixer_ioctl(struct audio_softc *sc, u_lo
   
         switch (cmd) {          switch (cmd) {
         case FIOASYNC:          case FIOASYNC:
                   error = audio_exlock_enter(sc);
                   if (error)
                           break;
                 if (*(int *)addr) {                  if (*(int *)addr) {
                         ma = kmem_alloc(sizeof(struct mixer_asyncs), KM_SLEEP);                          mixer_async_add(sc, curproc->p_pid);
                 } else {                  } else {
                         ma = NULL;                          mixer_async_remove(sc, curproc->p_pid);
                 }  
                 mixer_remove(sc);       /* remove old entry */  
                 if (ma != NULL) {  
                         ma->next = sc->sc_async_mixer;  
                         ma->pid = curproc->p_pid;  
                         sc->sc_async_mixer = ma;  
                 }                  }
                 error = 0;                  audio_exlock_exit(sc);
                 break;                  break;
   
         case AUDIO_GETDEV:          case AUDIO_GETDEV:
                 TRACE(2, "AUDIO_GETDEV");                  TRACE(2, "AUDIO_GETDEV");
                 error = audio_enter_exclusive(sc);                  mutex_enter(sc->sc_lock);
                 if (error)  
                         break;  
                 error = sc->hw_if->getdev(sc->hw_hdl, (audio_device_t *)addr);                  error = sc->hw_if->getdev(sc->hw_hdl, (audio_device_t *)addr);
                 audio_exit_exclusive(sc);                  mutex_exit(sc->sc_lock);
                 break;                  break;
   
         case AUDIO_MIXER_DEVINFO:          case AUDIO_MIXER_DEVINFO:
Line 7758  mixer_ioctl(struct audio_softc *sc, u_lo
Line 8051  mixer_ioctl(struct audio_softc *sc, u_lo
                 TRACE(2, "AUDIO_MIXER_READ");                  TRACE(2, "AUDIO_MIXER_READ");
                 mc = (mixer_ctrl_t *)addr;                  mc = (mixer_ctrl_t *)addr;
   
                 error = audio_enter_exclusive(sc);                  error = audio_exlock_mutex_enter(sc);
                 if (error)                  if (error)
                         break;                          break;
                 if (device_is_active(sc->hw_dev))                  if (device_is_active(sc->hw_dev))
Line 7771  mixer_ioctl(struct audio_softc *sc, u_lo
Line 8064  mixer_ioctl(struct audio_softc *sc, u_lo
                             sizeof(mixer_ctrl_t));                              sizeof(mixer_ctrl_t));
                         error = 0;                          error = 0;
                 }                  }
                 audio_exit_exclusive(sc);                  audio_exlock_mutex_exit(sc);
                 break;                  break;
   
         case AUDIO_MIXER_WRITE:          case AUDIO_MIXER_WRITE:
                 TRACE(2, "AUDIO_MIXER_WRITE");                  TRACE(2, "AUDIO_MIXER_WRITE");
                 error = audio_enter_exclusive(sc);                  error = audio_exlock_mutex_enter(sc);
                 if (error)                  if (error)
                         break;                          break;
                 error = audio_set_port(sc, (mixer_ctrl_t *)addr);                  error = audio_set_port(sc, (mixer_ctrl_t *)addr);
                 if (error) {                  if (error) {
                         audio_exit_exclusive(sc);                          audio_exlock_mutex_exit(sc);
                         break;                          break;
                 }                  }
   
                 if (sc->hw_if->commit_settings) {                  if (sc->hw_if->commit_settings) {
                         error = sc->hw_if->commit_settings(sc->hw_hdl);                          error = sc->hw_if->commit_settings(sc->hw_hdl);
                         if (error) {                          if (error) {
                                 audio_exit_exclusive(sc);                                  audio_exlock_mutex_exit(sc);
                                 break;                                  break;
                         }                          }
                 }                  }
                   mutex_exit(sc->sc_lock);
                 mixer_signal(sc);                  mixer_signal(sc);
                 audio_exit_exclusive(sc);                  audio_exlock_exit(sc);
                 break;                  break;
   
         default:          default:
                 if (sc->hw_if->dev_ioctl) {                  if (sc->hw_if->dev_ioctl) {
                         error = audio_enter_exclusive(sc);                          mutex_enter(sc->sc_lock);
                         if (error)  
                                 break;  
                         error = sc->hw_if->dev_ioctl(sc->hw_hdl,                          error = sc->hw_if->dev_ioctl(sc->hw_hdl,
                             cmd, addr, flag, l);                              cmd, addr, flag, l);
                         audio_exit_exclusive(sc);                          mutex_exit(sc->sc_lock);
                 } else                  } else
                         error = EINVAL;                          error = EINVAL;
                 break;                  break;
Line 8324  audio_volume_down(device_t dv)
Line 8616  audio_volume_down(device_t dv)
         u_int gain;          u_int gain;
         u_char balance;          u_char balance;
   
         if (audio_enter_exclusive(sc) != 0)          if (audio_exlock_mutex_enter(sc) != 0)
                 return;                  return;
         if (sc->sc_outports.index == -1 && sc->sc_outports.master != -1) {          if (sc->sc_outports.index == -1 && sc->sc_outports.master != -1) {
                 mi.index = sc->sc_outports.master;                  mi.index = sc->sc_outports.master;
Line 8337  audio_volume_down(device_t dv)
Line 8629  audio_volume_down(device_t dv)
                         au_set_gain(sc, &sc->sc_outports, newgain, balance);                          au_set_gain(sc, &sc->sc_outports, newgain, balance);
                 }                  }
         }          }
         audio_exit_exclusive(sc);          audio_exlock_mutex_exit(sc);
 }  }
   
 static void  static void
Line 8348  audio_volume_up(device_t dv)
Line 8640  audio_volume_up(device_t dv)
         u_int gain, newgain;          u_int gain, newgain;
         u_char balance;          u_char balance;
   
         if (audio_enter_exclusive(sc) != 0)          if (audio_exlock_mutex_enter(sc) != 0)
                 return;                  return;
         if (sc->sc_outports.index == -1 && sc->sc_outports.master != -1) {          if (sc->sc_outports.index == -1 && sc->sc_outports.master != -1) {
                 mi.index = sc->sc_outports.master;                  mi.index = sc->sc_outports.master;
Line 8361  audio_volume_up(device_t dv)
Line 8653  audio_volume_up(device_t dv)
                         au_set_gain(sc, &sc->sc_outports, newgain, balance);                          au_set_gain(sc, &sc->sc_outports, newgain, balance);
                 }                  }
         }          }
         audio_exit_exclusive(sc);          audio_exlock_mutex_exit(sc);
 }  }
   
 static void  static void
Line 8371  audio_volume_toggle(device_t dv)
Line 8663  audio_volume_toggle(device_t dv)
         u_int gain, newgain;          u_int gain, newgain;
         u_char balance;          u_char balance;
   
         if (audio_enter_exclusive(sc) != 0)          if (audio_exlock_mutex_enter(sc) != 0)
                 return;                  return;
         au_get_gain(sc, &sc->sc_outports, &gain, &balance);          au_get_gain(sc, &sc->sc_outports, &gain, &balance);
         if (gain != 0) {          if (gain != 0) {
Line 8380  audio_volume_toggle(device_t dv)
Line 8672  audio_volume_toggle(device_t dv)
         } else          } else
                 newgain = sc->sc_lastgain;                  newgain = sc->sc_lastgain;
         au_set_gain(sc, &sc->sc_outports, newgain, balance);          au_set_gain(sc, &sc->sc_outports, newgain, balance);
         audio_exit_exclusive(sc);          audio_exlock_mutex_exit(sc);
 }  }
   
   /*
    * Must be called with sc_lock held.
    */
 static int  static int
 audio_query_devinfo(struct audio_softc *sc, mixer_devinfo_t *di)  audio_query_devinfo(struct audio_softc *sc, mixer_devinfo_t *di)
 {  {
Line 8449  audio_modcmd(modcmd_t cmd, void *arg)
Line 8744  audio_modcmd(modcmd_t cmd, void *arg)
 {  {
         int error = 0;          int error = 0;
   
 #ifdef _MODULE  
         switch (cmd) {          switch (cmd) {
         case MODULE_CMD_INIT:          case MODULE_CMD_INIT:
                   /* XXX interrupt level? */
                   audio_psref_class = psref_class_create("audio", IPL_SOFTSERIAL);
   #ifdef _MODULE
                 error = devsw_attach(audio_cd.cd_name, NULL, &audio_bmajor,                  error = devsw_attach(audio_cd.cd_name, NULL, &audio_bmajor,
                     &audio_cdevsw, &audio_cmajor);                      &audio_cdevsw, &audio_cmajor);
                 if (error)                  if (error)
Line 8462  audio_modcmd(modcmd_t cmd, void *arg)
Line 8759  audio_modcmd(modcmd_t cmd, void *arg)
                 if (error) {                  if (error) {
                         devsw_detach(NULL, &audio_cdevsw);                          devsw_detach(NULL, &audio_cdevsw);
                 }                  }
   #endif
                 break;                  break;
         case MODULE_CMD_FINI:          case MODULE_CMD_FINI:
   #ifdef _MODULE
                 devsw_detach(NULL, &audio_cdevsw);                  devsw_detach(NULL, &audio_cdevsw);
                 error = config_fini_component(cfdriver_ioconf_audio,                  error = config_fini_component(cfdriver_ioconf_audio,
                    cfattach_ioconf_audio, cfdata_ioconf_audio);                     cfattach_ioconf_audio, cfdata_ioconf_audio);
                 if (error)                  if (error)
                         devsw_attach(audio_cd.cd_name, NULL, &audio_bmajor,                          devsw_attach(audio_cd.cd_name, NULL, &audio_bmajor,
                             &audio_cdevsw, &audio_cmajor);                              &audio_cdevsw, &audio_cmajor);
   #endif
                   psref_class_destroy(audio_psref_class);
                 break;                  break;
         default:          default:
                 error = ENOTTY;                  error = ENOTTY;
                 break;                  break;
         }          }
 #endif  
   
         return error;          return error;
 }  }

Legend:
Removed from v.1.28  
changed lines
  Added in v.1.28.2.14

CVSweb <webmaster@jp.NetBSD.org>