/* * sound/oss/sb_audio.c * * Audio routines for Sound Blaster compatible cards. * * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * * Changes * Alan Cox : Formatting and clean ups * * Status * Mostly working. Weird uart bug causing irq storms * * Daniel J. Rodriksson: Changes to make sb16 work full duplex. * Maybe other 16 bit cards in this code could behave * the same. * Chris Rankin: Use spinlocks instead of CLI/STI */ #include <linux/spinlock.h> #include "sound_config.h" #include "sb_mixer.h" #include "sb.h" #include "sb_ess.h" int sb_audio_open(int dev, int mode) { sb_devc *devc = audio_devs[dev]->devc; unsigned long flags; if (devc == NULL) { printk(KERN_ERR "Sound Blaster: incomplete initialization.\n"); return -ENXIO; } if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ) { if (mode == OPEN_READ) return -EPERM; } spin_lock_irqsave(&devc->lock, flags); if (devc->opened) { spin_unlock_irqrestore(&devc->lock, flags); return -EBUSY; } if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex) { if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit")) { spin_unlock_irqrestore(&devc->lock, flags); return -EBUSY; } } devc->opened = mode; spin_unlock_irqrestore(&devc->lock, flags); devc->irq_mode = IMODE_NONE; devc->irq_mode_16 = IMODE_NONE; devc->fullduplex = devc->duplex && ((mode & OPEN_READ) && (mode & OPEN_WRITE)); sb_dsp_reset(devc); /* At first glance this check isn't enough, some ESS chips might not * have a RECLEV. However if they don't common_mixer_set will refuse * cause devc->iomap has no register mapping for RECLEV */ if (devc->model == MDL_ESS) ess_mixer_reload (devc, SOUND_MIXER_RECLEV); /* The ALS007 seems to require that the DSP be removed from the output */ /* in order for recording to be activated properly. This is done by */ /* setting the appropriate bits of the output control register 4ch to */ /* zero. This code assumes that the output control registers are not */ /* used anywhere else and therefore the DSP bits are *always* ON for */ /* output and OFF for sampling. */ if (devc->submodel == SUBMDL_ALS007) { if (mode & OPEN_READ) sb_setmixer(devc,ALS007_OUTPUT_CTRL2, sb_getmixer(devc,ALS007_OUTPUT_CTRL2) & 0xf9); else sb_setmixer(devc,ALS007_OUTPUT_CTRL2, sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06); } return 0; } void sb_audio_close(int dev) { sb_devc *devc = audio_devs[dev]->devc; /* fix things if mmap turned off fullduplex */ if(devc->duplex && !devc->fullduplex && (devc->opened & OPEN_READ) && (devc->opened & OPEN_WRITE)) swap(audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_in); audio_devs[dev]->dmap_out->dma = devc->dma8; audio_devs[dev]->dmap_in->dma = ( devc->duplex ) ? devc->dma16 : devc->dma8; if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex) sound_close_dma(devc->dma16); /* For ALS007, turn DSP output back on if closing the device for read */ if ((devc->submodel == SUBMDL_ALS007) && (devc->opened & OPEN_READ)) { sb_setmixer(devc,ALS007_OUTPUT_CTRL2, sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06); } devc->opened = 0; } static void sb_set_output_parms(int dev, unsigned long buf, int nr_bytes, int intrflag) { sb_devc *devc = audio_devs[dev]->devc; if (!devc->fullduplex || devc->bits == AFMT_S16_LE) { devc->trg_buf = buf; devc->trg_bytes = nr_bytes; devc->trg_intrflag = intrflag; devc->irq_mode = IMODE_OUTPUT; } else { devc->trg_buf_16 = buf; devc->trg_bytes_16 = nr_bytes; devc->trg_intrflag_16 = intrflag; devc->irq_mode_16 = IMODE_OUTPUT; } } static void sb_set_input_parms(int<style> @media only all and (prefers-color-scheme: dark) { .highlight .hll { background-color: #49483e } .highlight .c { color: #75715e } /* Comment */ .highlight .err { color: #960050; background-color: #1e0010 } /* Error */ .highlight .k { color: #66d9ef } /* Keyword */ .highlight .l { color: #ae81ff } /* Literal */ .highlight .n { color: #f8f8f2 } /* Name */ .highlight .o { color: #f92672 } /* Operator */ .highlight .p { color: #f8f8f2 } /* Punctuation */ .highlight .ch { color: #75715e } /* Comment.Hashbang */ .highlight .cm { color: #75715e } /* Comment.Multiline */ .highlight .cp { color: #75715e } /* Comment.Preproc */ .highlight .cpf { color: #75715e } /* Comment.PreprocFile */ .highlight .c1 { color: #75715e } /* Comment.Single */ .highlight .cs { color: #75715e } /* Comment.Special */ .highlight .gd { color: #f92672 } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gi { color: #a6e22e } /* Generic.Inserted */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #75715e } /* Generic.Subheading */ .highlight .kc { color: #66d9ef } /* Keyword.Constant */ .highlight .kd { color: #66d9ef } /* Keyword.Declaration */ .highlight .kn { color: #f92672 } /* Keyword.Namespace */ .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ .highlight .kt { color: #66d9ef } /* Keyword.Type */ .highlight .ld { color: #e6db74 } /* Literal.Date */ .highlight .m { color: #ae81ff } /* Literal.Number */ .highlight .s { color: #e6db74 } /* Literal.String */ .highlight .na { color: #a6e22e } /* Name.Attribute */ .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ .highlight .nc { color: #a6e22e } /* Name.Class */ .highlight .no { color: #66d9ef } /* Name.Constant */ .highlight .nd { color: #a6e22e } /* Name.Decorator */ .highlight .ni { color: #f8f8f2 } /* Name.Entity */ .highlight .ne { color: #a6e22e } /* Name.Exception */ .highlight .nf { color: #a6e22e } /* Name.Function */ .highlight .nl { color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ } </style><div class="highlight"><pre><span></span><span class="nt">resource_registry</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">OS::TripleO::Services::MistralEngine</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">../../docker/services/mistral-engine.yaml</span> <span class="l l-Scalar l-Scalar-Plain">OS::TripleO::Services::MistralApi</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">../../docker/services/mistral-api.yaml</span> <span class="l l-Scalar l-Scalar-Plain">OS::TripleO::Services::MistralExecutor</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">../../docker/services/mistral-executor.yaml</span> </pre></div> </code></pre></td></tr></table> </div> <!-- class=content --> <div id="lfcollabprojects-footer"> <div class="gray-diagonal"> <div class="footer-inner"> <p> © 2015 <a href="https://opnfv.org/">Open Platform for NFV Project, Inc</a>., a Linux Foundation Collaborative Project. All Rights Reserved. </p> <p> Open Platform for NFV and OPNFV are trademarks of the Open Platform for NFV Project, Inc. </p> <p> Linux Foundation is a registered trademark of The Linux Foundation. Linux is a registered <a href="http://www.linuxfoundation.org/programs/legal/trademark" title="Linux Mark Institute" >trademark</a > of Linus Torvalds. </p> <p> Please see our <a href="https://opnfv.org/about/bylaws-and-policies/terms-use" >terms of use</a >, <a href="https://opnfv.org/about/bylaws-and-policies/trademarks" >trademark policy</a >, and <a href="https://opnfv.org/about/bylaws-and-policies/privacy-policy" >privacy policy</a >. </p> </div> </div> </div> </div> <!-- id=cgit --> </body> </html> , unsigned int bits) { sb_devc *devc = audio_devs[dev]->devc; if (bits != 0) { if (bits == AFMT_U8 || bits == AFMT_S16_LE) devc->bits = bits; else devc->bits = AFMT_U8; } return devc->bits; } static int sb16_audio_prepare_for_input(int dev, int bsize, int bcount) { sb_devc *devc = audio_devs[dev]->devc; if (!devc->fullduplex) { audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma = devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; } else if (devc->bits == AFMT_S16_LE) { audio_devs[dev]->dmap_out->dma = devc->dma8; audio_devs[dev]->dmap_in->dma = devc->dma16; } else { audio_devs[dev]->dmap_out->dma = devc->dma16; audio_devs[dev]->dmap_in->dma = devc->dma8; } devc->trigger_bits = 0; return 0; } static int sb16_audio_prepare_for_output(int dev, int bsize, int bcount) { sb_devc *devc = audio_devs[dev]->devc; if (!devc->fullduplex) { audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma = devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; } else if (devc->bits == AFMT_S16_LE) { audio_devs[dev]->dmap_out->dma = devc->dma8; audio_devs[dev]->dmap_in->dma = devc->dma16; } else { audio_devs[dev]->dmap_out->dma = devc->dma16; audio_devs[dev]->dmap_in->dma = devc->dma8; } devc->trigger_bits = 0; return 0; } static void sb16_audio_output_block(int dev, unsigned long buf, int count, int intrflag) { unsigned long flags, cnt; sb_devc *devc = audio_devs[dev]->devc; unsigned long bits; if (!devc->fullduplex || devc->bits == AFMT_S16_LE) { devc->irq_mode = IMODE_OUTPUT; devc->intr_active = 1; } else { devc->irq_mode_16 = IMODE_OUTPUT; devc->intr_active_16 = 1; } /* save value */ spin_lock_irqsave(&devc->lock, flags); bits = devc->bits; if (devc->fullduplex) devc->bits = (devc->bits == AFMT_S16_LE) ? AFMT_U8 : AFMT_S16_LE; spin_unlock_irqrestore(&devc->lock, flags); cnt = count; if (devc->bits == AFMT_S16_LE) cnt >>= 1; cnt--; spin_lock_irqsave(&devc->lock, flags); /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ sb_dsp_command(devc, 0x41); sb_dsp_command(devc, (unsigned char) ((devc->speed >> 8) & 0xff)); sb_dsp_command(devc, (unsigned char) (devc->speed & 0xff)); sb_dsp_command(devc, (devc->bits == AFMT_S16_LE ? 0xb6 : 0xc6)); sb_dsp_command(devc, ((devc->channels == 2 ? 0x20 : 0) + (devc->bits == AFMT_S16_LE ? 0x10 : 0))); sb_dsp_command(devc, (unsigned char) (cnt & 0xff)); sb_dsp_command(devc, (unsigned char) (cnt >> 8)); /* restore real value after all programming */ devc->bits = bits; spin_unlock_irqrestore(&devc->lock, flags); } /* * This fails on the Cyrix MediaGX. If you don't have the DMA enabled * before the first sample arrives it locks up. However even if you * do enable the DMA in time you just get DMA timeouts and missing * interrupts and stuff, so for now I've not bothered fixing this either. */ static void sb16_audio_start_input(int dev, unsigned long buf, int count, int intrflag) { unsigned long flags, cnt; sb_devc *devc = audio_devs[dev]->devc; if (!devc->fullduplex || devc->bits != AFMT_S16_LE) { devc->irq_mode = IMODE_INPUT; devc->intr_active = 1; } else { devc->irq_mode_16 = IMODE_INPUT; devc->intr_active_16 = 1; } cnt = count; if (devc->bits == AFMT_S16_LE) cnt >>= 1; cnt--; spin_lock_irqsave(&devc->lock, flags); /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ sb_dsp_command(devc, 0x42); sb_dsp_command(devc, (unsigned char) ((devc->speed >> 8) & 0xff)); sb_dsp_command(devc, (unsigned char) (devc->speed & 0xff)); sb_dsp_command(devc, (devc->bits == AFMT_S16_LE ? 0xbe : 0xce)); sb_dsp_command(devc, ((devc->channels == 2 ? 0x20 : 0) + (devc->bits == AFMT_S16_LE ? 0x10 : 0))); sb_dsp_command(devc, (unsigned char) (cnt & 0xff)); sb_dsp_command(devc, (unsigned char) (cnt >> 8)); spin_unlock_irqrestore(&devc->lock, flags); } static void sb16_audio_trigger(int dev, int bits) { sb_devc *devc = audio_devs[dev]->devc; int bits_16 = bits & devc->irq_mode_16; bits &= devc->irq_mode; if (!bits && !bits_16) sb_dsp_command(devc, 0xd0); /* Halt DMA */ else { if (bits) { switch (devc->irq_mode) { case IMODE_INPUT: sb16_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, devc->trg_intrflag); break; case IMODE_OUTPUT: sb16_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, devc->trg_intrflag); break; } } if (bits_16) { switch (devc->irq_mode_16) { case IMODE_INPUT: sb16_audio_start_input(dev, devc->trg_buf_16, devc->trg_bytes_16, devc->trg_intrflag_16); break; case IMODE_OUTPUT: sb16_audio_output_block(dev, devc->trg_buf_16, devc->trg_bytes_16, devc->trg_intrflag_16); break; } } } devc->trigger_bits = bits | bits_16; } static unsigned char lbuf8[2048]; static signed short *lbuf16 = (signed short *)lbuf8; #define LBUFCOPYSIZE 1024 static void sb16_copy_from_user(int dev, char *localbuf, int localoffs, const char __user *userbuf, int useroffs, int max_in, int max_out, int *used, int *returned, int len) { sb_devc *devc = audio_devs[dev]->devc; int i, c, p, locallen; unsigned char *buf8; signed short *buf16; /* if not duplex no conversion */ if (!devc->fullduplex) { if (copy_from_user(localbuf + localoffs, userbuf + useroffs, len)) return; *used = len; *returned = len; } else if (devc->bits == AFMT_S16_LE) { /* 16 -> 8 */ /* max_in >> 1, max number of samples in ( 16 bits ) */ /* max_out, max number of samples out ( 8 bits ) */ /* len, number of samples that will be taken ( 16 bits )*/ /* c, count of samples remaining in buffer ( 16 bits )*/ /* p, count of samples already processed ( 16 bits )*/ len = ( (max_in >> 1) > max_out) ? max_out : (max_in >> 1); c = len; p = 0; buf8 = (unsigned char *)(localbuf + localoffs); while (c) { locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); /* << 1 in order to get 16 bit samples */ if (copy_from_user(lbuf16, userbuf + useroffs + (p << 1), locallen << 1)) return; for (i = 0; i < locallen; i++) { buf8[p+i] = ~((lbuf16[i] >> 8) & 0xff) ^ 0x80; } c -= locallen; p += locallen; } /* used = ( samples * 16 bits size ) */ *used = max_in > ( max_out << 1) ? (max_out << 1) : max_in; /* returned = ( samples * 8 bits size ) */ *returned = len; } else { /* 8 -> 16 */ /* max_in, max number of samples in ( 8 bits ) */ /* max_out >> 1, max number of samples out ( 16 bits ) */ /* len, number of samples that will be taken ( 8 bits )*/ /* c, count of samples remaining in buffer ( 8 bits )*/ /* p, count of samples already processed ( 8 bits )*/ len = max_in > (max_out >> 1) ? (max_out >> 1) : max_in; c = len; p = 0; buf16 = (signed short *)(localbuf + localoffs); while (c) { locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); if (copy_from_user(lbuf8, userbuf+useroffs + p, locallen)) return; for (i = 0; i < locallen; i++) { buf16[p+i] = (~lbuf8[i] ^ 0x80) << 8; } c -= locallen; p += locallen; } /* used = ( samples * 8 bits size ) */ *used = len; /* returned = ( samples * 16 bits size ) */ *returned = len << 1; } } static void sb16_audio_mmap(int dev) { sb_devc *devc = audio_devs[dev]->devc; devc->fullduplex = 0; } static struct audio_driver sb1_audio_driver = /* SB1.x */ { .owner = THIS_MODULE, .open = sb_audio_open, .close = sb_audio_close, .output_block = sb_set_output_parms, .start_input = sb_set_input_parms, .prepare_for_input = sb1_audio_prepare_for_input, .prepare_for_output = sb1_audio_prepare_for_output, .halt_io = sb1_audio_halt_xfer, .trigger = sb1_audio_trigger, .set_speed = sb1_audio_set_speed, .set_bits = sb1_audio_set_bits, .set_channels = sb1_audio_set_channels }; static struct audio_driver sb20_audio_driver = /* SB2.0 */ { .owner = THIS_MODULE, .open = sb_audio_open, .close = sb_audio_close, .output_block = sb_set_output_parms, .start_input = sb_set_input_parms, .prepare_for_input = sb1_audio_prepare_for_input, .prepare_for_output = sb1_audio_prepare_for_output, .halt_io = sb1_audio_halt_xfer, .trigger = sb20_audio_trigger, .set_speed = sb1_audio_set_speed, .set_bits = sb1_audio_set_bits, .set_channels = sb1_audio_set_channels }; static struct audio_driver sb201_audio_driver = /* SB2.01 */ { .owner = THIS_MODULE, .open = sb_audio_open, .close = sb_audio_close, .output_block = sb_set_output_parms, .start_input = sb_set_input_parms, .prepare_for_input = sb1_audio_prepare_for_input, .prepare_for_output = sb1_audio_prepare_for_output, .halt_io = sb1_audio_halt_xfer, .trigger = sb20_audio_trigger, .set_speed = sb201_audio_set_speed, .set_bits = sb1_audio_set_bits, .set_channels = sb1_audio_set_channels }; static struct audio_driver sbpro_audio_driver = /* SB Pro */ { .owner = THIS_MODULE, .open = sb_audio_open, .close = sb_audio_close, .output_block = sb_set_output_parms, .start_input = sb_set_input_parms, .prepare_for_input = sbpro_audio_prepare_for_input, .prepare_for_output = sbpro_audio_prepare_for_output, .halt_io = sb1_audio_halt_xfer, .trigger = sb20_audio_trigger, .set_speed = sbpro_audio_set_speed, .set_bits = sb1_audio_set_bits, .set_channels = sbpro_audio_set_channels }; static struct audio_driver jazz16_audio_driver = /* Jazz16 and SM Wave */ { .owner = THIS_MODULE, .open = sb_audio_open, .close = sb_audio_close, .output_block = sb_set_output_parms, .start_input = sb_set_input_parms, .prepare_for_input = sbpro_audio_prepare_for_input, .prepare_for_output = sbpro_audio_prepare_for_output, .halt_io = sb1_audio_halt_xfer, .trigger = sb20_audio_trigger, .set_speed = jazz16_audio_set_speed, .set_bits = sb16_audio_set_bits, .set_channels = sbpro_audio_set_channels }; static struct audio_driver sb16_audio_driver = /* SB16 */ { .owner = THIS_MODULE, .open = sb_audio_open, .close = sb_audio_close, .output_block = sb_set_output_parms, .start_input = sb_set_input_parms, .prepare_for_input = sb16_audio_prepare_for_input, .prepare_for_output = sb16_audio_prepare_for_output, .halt_io = sb1_audio_halt_xfer, .copy_user = sb16_copy_from_user, .trigger = sb16_audio_trigger, .set_speed = sb16_audio_set_speed, .set_bits = sb16_audio_set_bits, .set_channels = sbpro_audio_set_channels, .mmap = sb16_audio_mmap }; void sb_audio_init(sb_devc * devc, char *name, struct module *owner) { int audio_flags = 0; int format_mask = AFMT_U8; struct audio_driver *driver = &sb1_audio_driver; switch (devc->model) { case MDL_SB1: /* SB1.0 or SB 1.5 */ DDB(printk("Will use standard SB1.x driver\n")); audio_flags = DMA_HARDSTOP; break; case MDL_SB2: DDB(printk("Will use SB2.0 driver\n")); audio_flags = DMA_AUTOMODE; driver = &sb20_audio_driver; break; case MDL_SB201: DDB(printk("Will use SB2.01 (high speed) driver\n")); audio_flags = DMA_AUTOMODE; driver = &sb201_audio_driver; break; case MDL_JAZZ: case MDL_SMW: DDB(printk("Will use Jazz16 driver\n")); audio_flags = DMA_AUTOMODE; format_mask |= AFMT_S16_LE; driver = &jazz16_audio_driver; break; case MDL_ESS: DDB(printk("Will use ESS ES688/1688 driver\n")); driver = ess_audio_init (devc, &audio_flags, &format_mask); break; case MDL_SB16: DDB(printk("Will use SB16 driver\n")); audio_flags = DMA_AUTOMODE; format_mask |= AFMT_S16_LE; if (devc->dma8 != devc->dma16 && devc->dma16 != -1) { audio_flags |= DMA_DUPLEX; devc->duplex = 1; } driver = &sb16_audio_driver; break; default: DDB(printk("Will use SB Pro driver\n")); audio_flags = DMA_AUTOMODE; driver = &sbpro_audio_driver; } if (owner) driver->owner = owner; if ((devc->dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name,driver, sizeof(struct audio_driver), audio_flags, format_mask, devc, devc->dma8, devc->duplex ? devc->dma16 : devc->dma8)) < 0) { printk(KERN_ERR "Sound Blaster: unable to install audio.\n"); return; } audio_devs[devc->dev]->mixer_dev = devc->my_mixerdev; audio_devs[devc->dev]->min_fragment = 5; }