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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/sound/usb/uaudio_pcm.c

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

    1 /* $FreeBSD: releng/5.2/sys/dev/sound/usb/uaudio_pcm.c 117126 2003-07-01 15:52:06Z scottl $ */
    2 
    3 /*
    4  * Copyright (c) 2000-2002 Hiroyuki Aizu <aizu@navi.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 
   29 #include <sys/soundcard.h>
   30 #include <dev/sound/pcm/sound.h>
   31 #include <dev/sound/chip.h>
   32 
   33 #include <dev/sound/usb/uaudio.h>
   34 
   35 #include "mixer_if.h"
   36 
   37 struct ua_info;
   38 
   39 struct ua_chinfo {
   40         struct ua_info *parent;
   41         struct pcm_channel *channel;
   42         struct snd_dbuf *buffer;
   43         int dir, hwch;
   44         u_int32_t fmt, spd, blksz;      /* XXXXX */
   45 };
   46 
   47 struct ua_info {
   48         device_t sc_dev;
   49         struct ua_chinfo pch, rch;
   50         bus_dma_tag_t   parent_dmat;
   51 };
   52 
   53 static u_int32_t ua_playfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
   54 
   55 static struct pcmchan_caps ua_playcaps = {8000, 48000, ua_playfmt, 0};
   56 
   57 static u_int32_t ua_recfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
   58 
   59 static struct pcmchan_caps ua_reccaps = {8000, 48000, ua_recfmt, 0};
   60 
   61 #define UAUDIO_PCM_BUFF_SIZE    16*1024
   62 
   63 /************************************************************/
   64 static void *
   65 ua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
   66 {
   67         device_t pa_dev;
   68         u_char *buf,*end;
   69 
   70         struct ua_info *sc = devinfo;
   71         struct ua_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
   72 
   73         ch->parent = sc;
   74         ch->channel = c;
   75         ch->buffer = b;
   76 
   77         pa_dev = device_get_parent(sc->sc_dev);
   78         /* Create ua_playfmt[] & ua_recfmt[] */
   79         uaudio_query_formats(pa_dev, (u_int32_t *)&ua_playfmt, (u_int32_t *)&ua_recfmt);
   80         if (ua_playfmt[0] == 0) {
   81                 printf("%s channel supported format list invalid\n", dir == PCMDIR_PLAY? "play" : "record");
   82                 return NULL;
   83         }
   84 
   85         /* allocate PCM side DMA buffer */
   86         if (sndbuf_alloc(ch->buffer, sc->parent_dmat, UAUDIO_PCM_BUFF_SIZE) != 0) {
   87             return NULL;
   88         }
   89 
   90         buf = end = sndbuf_getbuf(b);
   91         end += sndbuf_getsize(b);
   92         uaudio_chan_set_param_pcm_dma_buff(pa_dev, buf, end, ch->channel);
   93 
   94         ch->dir = dir;
   95 #ifndef NO_RECORDING
   96         ch->hwch = 1;
   97         if (dir == PCMDIR_PLAY)
   98                 ch->hwch = 2;
   99 #else
  100         ch->hwch = 2;
  101 #endif
  102 
  103         return ch;
  104 }
  105 
  106 static int
  107 ua_chan_setformat(kobj_t obj, void *data, u_int32_t format)
  108 {
  109         device_t pa_dev;
  110         struct ua_info *ua;
  111 
  112         struct ua_chinfo *ch = data;
  113 
  114         ua = ch->parent;
  115         pa_dev = device_get_parent(ua->sc_dev);
  116         uaudio_chan_set_param_format(pa_dev, format);
  117 
  118         ch->fmt = format;
  119         return 0;
  120 }
  121 
  122 static int
  123 ua_chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
  124 {
  125         device_t pa_dev;
  126         struct ua_info *ua;
  127 
  128         struct ua_chinfo *ch = data;
  129         ch->spd = speed;
  130 
  131         ua = ch->parent;
  132         pa_dev = device_get_parent(ua->sc_dev);
  133         uaudio_chan_set_param_speed(pa_dev, speed);
  134 
  135         return ch->spd;
  136 }
  137 
  138 static int
  139 ua_chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
  140 {
  141         device_t pa_dev;
  142         struct ua_info *ua;
  143         struct ua_chinfo *ch = data;
  144         /* ch->blksz = blocksize; */
  145         if (blocksize) {
  146                 ch->blksz = blocksize;
  147         } else {
  148                 ch->blksz = UAUDIO_PCM_BUFF_SIZE/2;
  149         }
  150 
  151         /* XXXXX */
  152         ua = ch->parent;
  153         pa_dev = device_get_parent(ua->sc_dev);
  154         uaudio_chan_set_param_blocksize(pa_dev, blocksize);
  155 
  156         return ch->blksz;
  157 }
  158 
  159 static int
  160 ua_chan_trigger(kobj_t obj, void *data, int go)
  161 {
  162         device_t pa_dev;
  163         struct ua_info *ua;
  164         struct ua_chinfo *ch = data;
  165 
  166         if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
  167                 return 0;
  168 
  169         ua = ch->parent;
  170         pa_dev = device_get_parent(ua->sc_dev);
  171 
  172         /* XXXXX */
  173         if (ch->dir == PCMDIR_PLAY) {
  174                 if (go == PCMTRIG_START) {
  175                         uaudio_trigger_output(pa_dev);
  176                 } else {
  177                         uaudio_halt_out_dma(pa_dev);
  178                 }
  179         } else {
  180 #ifndef NO_RECORDING
  181                 if (go == PCMTRIG_START)
  182                         uaudio_trigger_input(pa_dev);
  183                 else
  184                         uaudio_halt_in_dma(pa_dev);
  185 #endif
  186         }
  187 
  188         return 0;
  189 }
  190 
  191 static int
  192 ua_chan_getptr(kobj_t obj, void *data)
  193 {
  194         device_t pa_dev;
  195         struct ua_info *ua;
  196         struct ua_chinfo *ch = data;
  197 
  198         ua = ch->parent;
  199         pa_dev = device_get_parent(ua->sc_dev);
  200 
  201         return uaudio_chan_getptr(pa_dev);
  202 }
  203 
  204 static struct pcmchan_caps *
  205 ua_chan_getcaps(kobj_t obj, void *data)
  206 {
  207         struct ua_chinfo *ch = data;
  208 
  209         return (ch->dir == PCMDIR_PLAY) ? &ua_playcaps : & ua_reccaps;
  210 }
  211 
  212 static kobj_method_t ua_chan_methods[] = {
  213         KOBJMETHOD(channel_init,                ua_chan_init),
  214         KOBJMETHOD(channel_setformat,           ua_chan_setformat),
  215         KOBJMETHOD(channel_setspeed,            ua_chan_setspeed),
  216         KOBJMETHOD(channel_setblocksize,        ua_chan_setblocksize),
  217         KOBJMETHOD(channel_trigger,             ua_chan_trigger),
  218         KOBJMETHOD(channel_getptr,              ua_chan_getptr),
  219         KOBJMETHOD(channel_getcaps,             ua_chan_getcaps),
  220         { 0, 0 }
  221 };
  222 
  223 CHANNEL_DECLARE(ua_chan);
  224 
  225 /************************************************************/
  226 static int
  227 ua_mixer_init(struct snd_mixer *m)
  228 {
  229         u_int32_t mask;
  230         device_t pa_dev;
  231         struct ua_info *ua = mix_getdevinfo(m);
  232 
  233         pa_dev = device_get_parent(ua->sc_dev);
  234 
  235         mask = uaudio_query_mix_info(pa_dev);
  236         mix_setdevs(m,  mask);
  237 
  238         return 0;
  239 }
  240 
  241 static int
  242 ua_mixer_set(struct snd_mixer *m, unsigned type, unsigned left, unsigned right)
  243 {
  244         device_t pa_dev;
  245         struct ua_info *ua = mix_getdevinfo(m);
  246 
  247         pa_dev = device_get_parent(ua->sc_dev);
  248         uaudio_mixer_set(pa_dev, type, left, right);
  249 
  250         return left | (right << 8);
  251 }
  252 
  253 static int
  254 ua_mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
  255 {
  256         return src;
  257 }
  258 
  259 static kobj_method_t ua_mixer_methods[] = {
  260         KOBJMETHOD(mixer_init,          ua_mixer_init),
  261         KOBJMETHOD(mixer_set,           ua_mixer_set),
  262         KOBJMETHOD(mixer_setrecsrc,     ua_mixer_setrecsrc),
  263 
  264         { 0, 0 }
  265 };
  266 MIXER_DECLARE(ua_mixer);
  267 /************************************************************/
  268 
  269 
  270 static int
  271 ua_probe(device_t dev)
  272 {
  273         char *s;
  274         struct sndcard_func *func;
  275 
  276         /* The parent device has already been probed. */
  277 
  278         func = device_get_ivars(dev);
  279         if (func == NULL || func->func != SCF_PCM)
  280                 return (ENXIO);
  281 
  282         s = "USB Audio";
  283 
  284         device_set_desc(dev, s);
  285         return 0;
  286 }
  287 
  288 static int
  289 ua_attach(device_t dev)
  290 {
  291         struct ua_info *ua;
  292         char status[SND_STATUSLEN];
  293         unsigned int bufsz;
  294 
  295         ua = (struct ua_info *)malloc(sizeof *ua, M_DEVBUF, M_NOWAIT);
  296         if (!ua)
  297                 return ENXIO;
  298         bzero(ua, sizeof *ua);
  299 
  300         ua->sc_dev = dev;
  301 
  302         bufsz = pcm_getbuffersize(dev, 4096, UAUDIO_PCM_BUFF_SIZE, 65536);
  303 
  304         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
  305                                 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
  306                                 /*highaddr*/BUS_SPACE_MAXADDR,
  307                                 /*filter*/NULL, /*filterarg*/NULL,
  308                                 /*maxsize*/bufsz, /*nsegments*/1,
  309                                 /*maxsegz*/0x3fff, /*flags*/0,
  310                                 /*lockfunc*/busdma_lock_mutex,
  311                                 /*lockarg*/&Giant,
  312                                 &ua->parent_dmat) != 0) {
  313                 device_printf(dev, "unable to create dma tag\n");
  314                 goto bad;
  315         }
  316 
  317         if (mixer_init(dev, &ua_mixer_class, ua)) {
  318                 return(ENXIO);
  319         }
  320 
  321         snprintf(status, SND_STATUSLEN, "at addr ?");
  322 
  323         if (pcm_register(dev, ua, 1, 0)) {
  324                 return(ENXIO);
  325         }
  326 
  327         pcm_addchan(dev, PCMDIR_PLAY, &ua_chan_class, ua);
  328 #ifndef NO_RECORDING
  329         pcm_addchan(dev, PCMDIR_REC, &ua_chan_class, ua);
  330 #endif
  331         pcm_setstatus(dev, status);
  332 
  333         return 0;
  334 bad:
  335         if (ua->parent_dmat)
  336                 bus_dma_tag_destroy(ua->parent_dmat);
  337         free(ua, M_DEVBUF);
  338 
  339         return ENXIO;
  340 }
  341 
  342 static int
  343 ua_detach(device_t dev)
  344 {
  345         int r;
  346         struct ua_info *sc;
  347 
  348         r = pcm_unregister(dev);
  349         if (r)
  350                 return r;
  351 
  352         sc = pcm_getdevinfo(dev);
  353         bus_dma_tag_destroy(sc->parent_dmat);
  354         free(sc, M_DEVBUF);
  355 
  356         return 0;
  357 }
  358 
  359 /************************************************************/
  360 
  361 static device_method_t ua_pcm_methods[] = {
  362         /* Device interface */
  363         DEVMETHOD(device_probe,         ua_probe),
  364         DEVMETHOD(device_attach,        ua_attach),
  365         DEVMETHOD(device_detach,        ua_detach),
  366 
  367         { 0, 0 }
  368 };
  369 
  370 static driver_t ua_pcm_driver = {
  371         "pcm",
  372         ua_pcm_methods,
  373         PCM_SOFTC_SIZE,
  374 };
  375 
  376 static devclass_t pcm_devclass;
  377 
  378 DRIVER_MODULE(ua_pcm, uaudio, ua_pcm_driver, pcm_devclass, 0, 0);
  379 MODULE_DEPEND(ua_pcm, uaudio, 1, 1, 1);
  380 MODULE_DEPEND(ua_pcm, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
  381 MODULE_VERSION(ua_pcm, 1);

Cache object: b69d78202d76933ad4fcd1747b92b8f4


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


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