123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862 |
- /*
- * $Id: saa7134-oss.c,v 1.17 2005/06/28 23:41:47 mkrufky Exp $
- *
- * device driver for philips saa7134 based TV cards
- * oss dsp interface
- *
- * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #include <linux/init.h>
- #include <linux/list.h>
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/soundcard.h>
- #include "saa7134-reg.h"
- #include "saa7134.h"
- /* ------------------------------------------------------------------ */
- static unsigned int oss_debug = 0;
- module_param(oss_debug, int, 0644);
- MODULE_PARM_DESC(oss_debug,"enable debug messages [oss]");
- static unsigned int oss_rate = 0;
- module_param(oss_rate, int, 0444);
- MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)");
- #define dprintk(fmt, arg...) if (oss_debug) \
- printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
- /* ------------------------------------------------------------------ */
- static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
- {
- if (blksize < 0x100)
- blksize = 0x100;
- if (blksize > 0x10000)
- blksize = 0x10000;
- if (blocks < 2)
- blocks = 2;
- if ((blksize * blocks) > 1024*1024)
- blocks = 1024*1024 / blksize;
- dev->oss.blocks = blocks;
- dev->oss.blksize = blksize;
- dev->oss.bufsize = blksize * blocks;
- dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
- blocks,blksize,blksize * blocks / 1024);
- return 0;
- }
- static int dsp_buffer_init(struct saa7134_dev *dev)
- {
- int err;
- if (!dev->oss.bufsize)
- BUG();
- videobuf_dma_init(&dev->oss.dma);
- err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE,
- (dev->oss.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
- if (0 != err)
- return err;
- return 0;
- }
- static int dsp_buffer_free(struct saa7134_dev *dev)
- {
- if (!dev->oss.blksize)
- BUG();
- videobuf_dma_free(&dev->oss.dma);
- dev->oss.blocks = 0;
- dev->oss.blksize = 0;
- dev->oss.bufsize = 0;
- return 0;
- }
- static void dsp_dma_start(struct saa7134_dev *dev)
- {
- dev->oss.dma_blk = 0;
- dev->oss.dma_running = 1;
- saa7134_set_dmabits(dev);
- }
- static void dsp_dma_stop(struct saa7134_dev *dev)
- {
- dev->oss.dma_blk = -1;
- dev->oss.dma_running = 0;
- saa7134_set_dmabits(dev);
- }
- static int dsp_rec_start(struct saa7134_dev *dev)
- {
- int err, bswap, sign;
- u32 fmt, control;
- unsigned long flags;
- /* prepare buffer */
- if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma)))
- return err;
- if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->oss.pt)))
- goto fail1;
- if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->oss.pt,
- dev->oss.dma.sglist,
- dev->oss.dma.sglen,
- 0)))
- goto fail2;
- /* sample format */
- switch (dev->oss.afmt) {
- case AFMT_U8:
- case AFMT_S8: fmt = 0x00; break;
- case AFMT_U16_LE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_S16_BE: fmt = 0x01; break;
- default:
- err = -EINVAL;
- goto fail2;
- }
- switch (dev->oss.afmt) {
- case AFMT_S8:
- case AFMT_S16_LE:
- case AFMT_S16_BE: sign = 1; break;
- default: sign = 0; break;
- }
- switch (dev->oss.afmt) {
- case AFMT_U16_BE:
- case AFMT_S16_BE: bswap = 1; break;
- default: bswap = 0; break;
- }
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- if (1 == dev->oss.channels)
- fmt |= (1 << 3);
- if (2 == dev->oss.channels)
- fmt |= (3 << 3);
- if (sign)
- fmt |= 0x04;
- fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
- saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->oss.blksize - 1) & 0x0000ff));
- saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->oss.blksize - 1) & 0x00ff00) >> 8);
- saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->oss.blksize - 1) & 0xff0000) >> 16);
- saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
- break;
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- if (1 == dev->oss.channels)
- fmt |= (1 << 4);
- if (2 == dev->oss.channels)
- fmt |= (2 << 4);
- if (!sign)
- fmt |= 0x04;
- saa_writel(0x588 >> 2, dev->oss.blksize -4);
- saa_writel(0x58c >> 2, 0x543210 | (fmt << 24));
- break;
- }
- dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n",
- dev->oss.afmt, dev->oss.channels, fmt,
- bswap ? 'b' : '-');
- /* dma: setup channel 6 (= AUDIO) */
- control = SAA7134_RS_CONTROL_BURST_16 |
- SAA7134_RS_CONTROL_ME |
- (dev->oss.pt.dma >> 12);
- if (bswap)
- control |= SAA7134_RS_CONTROL_BSWAP;
- saa_writel(SAA7134_RS_BA1(6),0);
- saa_writel(SAA7134_RS_BA2(6),dev->oss.blksize);
- saa_writel(SAA7134_RS_PITCH(6),0);
- saa_writel(SAA7134_RS_CONTROL(6),control);
- /* start dma */
- dev->oss.recording_on = 1;
- spin_lock_irqsave(&dev->slock,flags);
- dsp_dma_start(dev);
- spin_unlock_irqrestore(&dev->slock,flags);
- return 0;
- fail2:
- saa7134_pgtable_free(dev->pci,&dev->oss.pt);
- fail1:
- videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
- return err;
- }
- static int dsp_rec_stop(struct saa7134_dev *dev)
- {
- unsigned long flags;
- dprintk("rec_stop dma_blk=%d\n",dev->oss.dma_blk);
- /* stop dma */
- dev->oss.recording_on = 0;
- spin_lock_irqsave(&dev->slock,flags);
- dsp_dma_stop(dev);
- spin_unlock_irqrestore(&dev->slock,flags);
- /* unlock buffer */
- saa7134_pgtable_free(dev->pci,&dev->oss.pt);
- videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
- return 0;
- }
- /* ------------------------------------------------------------------ */
- static int dsp_open(struct inode *inode, struct file *file)
- {
- int minor = iminor(inode);
- struct saa7134_dev *h,*dev = NULL;
- struct list_head *list;
- int err;
- list_for_each(list,&saa7134_devlist) {
- h = list_entry(list, struct saa7134_dev, devlist);
- if (h->oss.minor_dsp == minor)
- dev = h;
- }
- if (NULL == dev)
- return -ENODEV;
- down(&dev->oss.lock);
- err = -EBUSY;
- if (dev->oss.users_dsp)
- goto fail1;
- dev->oss.users_dsp++;
- file->private_data = dev;
- dev->oss.afmt = AFMT_U8;
- dev->oss.channels = 1;
- dev->oss.read_count = 0;
- dev->oss.read_offset = 0;
- dsp_buffer_conf(dev,PAGE_SIZE,64);
- err = dsp_buffer_init(dev);
- if (0 != err)
- goto fail2;
- up(&dev->oss.lock);
- return 0;
- fail2:
- dev->oss.users_dsp--;
- fail1:
- up(&dev->oss.lock);
- return err;
- }
- static int dsp_release(struct inode *inode, struct file *file)
- {
- struct saa7134_dev *dev = file->private_data;
- down(&dev->oss.lock);
- if (dev->oss.recording_on)
- dsp_rec_stop(dev);
- dsp_buffer_free(dev);
- dev->oss.users_dsp--;
- file->private_data = NULL;
- up(&dev->oss.lock);
- return 0;
- }
- static ssize_t dsp_read(struct file *file, char __user *buffer,
- size_t count, loff_t *ppos)
- {
- struct saa7134_dev *dev = file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- unsigned int bytes;
- unsigned long flags;
- int err,ret = 0;
- add_wait_queue(&dev->oss.wq, &wait);
- down(&dev->oss.lock);
- while (count > 0) {
- /* wait for data if needed */
- if (0 == dev->oss.read_count) {
- if (!dev->oss.recording_on) {
- err = dsp_rec_start(dev);
- if (err < 0) {
- if (0 == ret)
- ret = err;
- break;
- }
- }
- if (dev->oss.recording_on &&
- !dev->oss.dma_running) {
- /* recover from overruns */
- spin_lock_irqsave(&dev->slock,flags);
- dsp_dma_start(dev);
- spin_unlock_irqrestore(&dev->slock,flags);
- }
- if (file->f_flags & O_NONBLOCK) {
- if (0 == ret)
- ret = -EAGAIN;
- break;
- }
- up(&dev->oss.lock);
- set_current_state(TASK_INTERRUPTIBLE);
- if (0 == dev->oss.read_count)
- schedule();
- set_current_state(TASK_RUNNING);
- down(&dev->oss.lock);
- if (signal_pending(current)) {
- if (0 == ret)
- ret = -EINTR;
- break;
- }
- }
- /* copy data to userspace */
- bytes = count;
- if (bytes > dev->oss.read_count)
- bytes = dev->oss.read_count;
- if (bytes > dev->oss.bufsize - dev->oss.read_offset)
- bytes = dev->oss.bufsize - dev->oss.read_offset;
- if (copy_to_user(buffer + ret,
- dev->oss.dma.vmalloc + dev->oss.read_offset,
- bytes)) {
- if (0 == ret)
- ret = -EFAULT;
- break;
- }
- ret += bytes;
- count -= bytes;
- dev->oss.read_count -= bytes;
- dev->oss.read_offset += bytes;
- if (dev->oss.read_offset == dev->oss.bufsize)
- dev->oss.read_offset = 0;
- }
- up(&dev->oss.lock);
- remove_wait_queue(&dev->oss.wq, &wait);
- return ret;
- }
- static ssize_t dsp_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *ppos)
- {
- return -EINVAL;
- }
- static int dsp_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
- {
- struct saa7134_dev *dev = file->private_data;
- void __user *argp = (void __user *) arg;
- int __user *p = argp;
- int val = 0;
- if (oss_debug > 1)
- saa7134_print_ioctl(dev->name,cmd);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
- case SNDCTL_DSP_GETCAPS:
- return 0;
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- /* fall through */
- case SOUND_PCM_READ_RATE:
- return put_user(dev->oss.rate, p);
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- down(&dev->oss.lock);
- dev->oss.channels = val ? 2 : 1;
- if (dev->oss.recording_on) {
- dsp_rec_stop(dev);
- dsp_rec_start(dev);
- }
- up(&dev->oss.lock);
- return put_user(dev->oss.channels-1, p);
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2)
- return -EINVAL;
- down(&dev->oss.lock);
- dev->oss.channels = val;
- if (dev->oss.recording_on) {
- dsp_rec_stop(dev);
- dsp_rec_start(dev);
- }
- up(&dev->oss.lock);
- /* fall through */
- case SOUND_PCM_READ_CHANNELS:
- return put_user(dev->oss.channels, p);
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_U8 | AFMT_S8 |
- AFMT_U16_LE | AFMT_U16_BE |
- AFMT_S16_LE | AFMT_S16_BE, p);
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
- if (get_user(val, p))
- return -EFAULT;
- switch (val) {
- case AFMT_QUERY:
- /* nothing to do */
- break;
- case AFMT_U8:
- case AFMT_S8:
- case AFMT_U16_LE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_S16_BE:
- down(&dev->oss.lock);
- dev->oss.afmt = val;
- if (dev->oss.recording_on) {
- dsp_rec_stop(dev);
- dsp_rec_start(dev);
- }
- up(&dev->oss.lock);
- return put_user(dev->oss.afmt, p);
- default:
- return -EINVAL;
- }
- case SOUND_PCM_READ_BITS:
- switch (dev->oss.afmt) {
- case AFMT_U8:
- case AFMT_S8:
- return put_user(8, p);
- case AFMT_U16_LE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_S16_BE:
- return put_user(16, p);
- default:
- return -EINVAL;
- }
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
- case SNDCTL_DSP_RESET:
- down(&dev->oss.lock);
- if (dev->oss.recording_on)
- dsp_rec_stop(dev);
- up(&dev->oss.lock);
- return 0;
- case SNDCTL_DSP_GETBLKSIZE:
- return put_user(dev->oss.blksize, p);
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- if (dev->oss.recording_on)
- return -EBUSY;
- dsp_buffer_free(dev);
- /* used to be arg >> 16 instead of val >> 16; fixed */
- dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff);
- dsp_buffer_init(dev);
- return 0;
- case SNDCTL_DSP_SYNC:
- /* NOP */
- return 0;
- case SNDCTL_DSP_GETISPACE:
- {
- audio_buf_info info;
- info.fragsize = dev->oss.blksize;
- info.fragstotal = dev->oss.blocks;
- info.bytes = dev->oss.read_count;
- info.fragments = info.bytes / info.fragsize;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- default:
- return -EINVAL;
- }
- }
- static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
- {
- struct saa7134_dev *dev = file->private_data;
- unsigned int mask = 0;
- poll_wait(file, &dev->oss.wq, wait);
- if (0 == dev->oss.read_count) {
- down(&dev->oss.lock);
- if (!dev->oss.recording_on)
- dsp_rec_start(dev);
- up(&dev->oss.lock);
- } else
- mask |= (POLLIN | POLLRDNORM);
- return mask;
- }
- struct file_operations saa7134_dsp_fops = {
- .owner = THIS_MODULE,
- .open = dsp_open,
- .release = dsp_release,
- .read = dsp_read,
- .write = dsp_write,
- .ioctl = dsp_ioctl,
- .poll = dsp_poll,
- .llseek = no_llseek,
- };
- /* ------------------------------------------------------------------ */
- static int
- mixer_recsrc_7134(struct saa7134_dev *dev)
- {
- int analog_io,rate;
- switch (dev->oss.input) {
- case TV:
- saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
- saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00);
- break;
- case LINE1:
- case LINE2:
- case LINE2_LEFT:
- analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08;
- rate = (32000 == dev->oss.rate) ? 0x01 : 0x03;
- saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io);
- saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
- saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate);
- break;
- }
- return 0;
- }
- static int
- mixer_recsrc_7133(struct saa7134_dev *dev)
- {
- u32 anabar, xbarin;
- xbarin = 0x03; // adc
- anabar = 0;
- switch (dev->oss.input) {
- case TV:
- xbarin = 0; // Demodulator
- anabar = 2; // DACs
- break;
- case LINE1:
- anabar = 0; // aux1, aux1
- break;
- case LINE2:
- case LINE2_LEFT:
- anabar = 9; // aux2, aux2
- break;
- }
- /* output xbar always main channel */
- saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10);
- saa_dsp_writel(dev, 0x464 >> 2, xbarin);
- saa_writel(0x594 >> 2, anabar);
- return 0;
- }
- static int
- mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
- {
- static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
- dev->oss.count++;
- dev->oss.input = src;
- dprintk("mixer input = %s\n",iname[dev->oss.input]);
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- mixer_recsrc_7134(dev);
- break;
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- mixer_recsrc_7133(dev);
- break;
- }
- return 0;
- }
- static int
- mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level)
- {
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- switch (src) {
- case TV:
- /* nothing */
- break;
- case LINE1:
- saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10,
- (100 == level) ? 0x00 : 0x10);
- break;
- case LINE2:
- case LINE2_LEFT:
- saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20,
- (100 == level) ? 0x00 : 0x20);
- break;
- }
- break;
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- /* nothing */
- break;
- }
- return 0;
- }
- /* ------------------------------------------------------------------ */
- static int mixer_open(struct inode *inode, struct file *file)
- {
- int minor = iminor(inode);
- struct saa7134_dev *h,*dev = NULL;
- struct list_head *list;
- list_for_each(list,&saa7134_devlist) {
- h = list_entry(list, struct saa7134_dev, devlist);
- if (h->oss.minor_mixer == minor)
- dev = h;
- }
- if (NULL == dev)
- return -ENODEV;
- file->private_data = dev;
- return 0;
- }
- static int mixer_release(struct inode *inode, struct file *file)
- {
- file->private_data = NULL;
- return 0;
- }
- static int mixer_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
- {
- struct saa7134_dev *dev = file->private_data;
- enum saa7134_audio_in input;
- int val,ret;
- void __user *argp = (void __user *) arg;
- int __user *p = argp;
- if (oss_debug > 1)
- saa7134_print_ioctl(dev->name,cmd);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
- case SOUND_MIXER_INFO:
- {
- mixer_info info;
- memset(&info,0,sizeof(info));
- strlcpy(info.id, "TV audio", sizeof(info.id));
- strlcpy(info.name, dev->name, sizeof(info.name));
- info.modify_counter = dev->oss.count;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- case SOUND_OLD_MIXER_INFO:
- {
- _old_mixer_info info;
- memset(&info,0,sizeof(info));
- strlcpy(info.id, "TV audio", sizeof(info.id));
- strlcpy(info.name, dev->name, sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- case MIXER_READ(SOUND_MIXER_CAPS):
- return put_user(SOUND_CAP_EXCL_INPUT, p);
- case MIXER_READ(SOUND_MIXER_STEREODEVS):
- return put_user(0, p);
- case MIXER_READ(SOUND_MIXER_RECMASK):
- case MIXER_READ(SOUND_MIXER_DEVMASK):
- val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2;
- if (32000 == dev->oss.rate)
- val |= SOUND_MASK_VIDEO;
- return put_user(val, p);
- case MIXER_WRITE(SOUND_MIXER_RECSRC):
- if (get_user(val, p))
- return -EFAULT;
- input = dev->oss.input;
- if (32000 == dev->oss.rate &&
- val & SOUND_MASK_VIDEO && dev->oss.input != TV)
- input = TV;
- if (val & SOUND_MASK_LINE1 && dev->oss.input != LINE1)
- input = LINE1;
- if (val & SOUND_MASK_LINE2 && dev->oss.input != LINE2)
- input = LINE2;
- if (input != dev->oss.input)
- mixer_recsrc(dev,input);
- /* fall throuth */
- case MIXER_READ(SOUND_MIXER_RECSRC):
- switch (dev->oss.input) {
- case TV: ret = SOUND_MASK_VIDEO; break;
- case LINE1: ret = SOUND_MASK_LINE1; break;
- case LINE2: ret = SOUND_MASK_LINE2; break;
- default: ret = 0;
- }
- return put_user(ret, p);
- case MIXER_WRITE(SOUND_MIXER_VIDEO):
- case MIXER_READ(SOUND_MIXER_VIDEO):
- if (32000 != dev->oss.rate)
- return -EINVAL;
- return put_user(100 | 100 << 8, p);
- case MIXER_WRITE(SOUND_MIXER_LINE1):
- if (get_user(val, p))
- return -EFAULT;
- val &= 0xff;
- val = (val <= 50) ? 50 : 100;
- dev->oss.line1 = val;
- mixer_level(dev,LINE1,dev->oss.line1);
- /* fall throuth */
- case MIXER_READ(SOUND_MIXER_LINE1):
- return put_user(dev->oss.line1 | dev->oss.line1 << 8, p);
- case MIXER_WRITE(SOUND_MIXER_LINE2):
- if (get_user(val, p))
- return -EFAULT;
- val &= 0xff;
- val = (val <= 50) ? 50 : 100;
- dev->oss.line2 = val;
- mixer_level(dev,LINE2,dev->oss.line2);
- /* fall throuth */
- case MIXER_READ(SOUND_MIXER_LINE2):
- return put_user(dev->oss.line2 | dev->oss.line2 << 8, p);
- default:
- return -EINVAL;
- }
- }
- struct file_operations saa7134_mixer_fops = {
- .owner = THIS_MODULE,
- .open = mixer_open,
- .release = mixer_release,
- .ioctl = mixer_ioctl,
- .llseek = no_llseek,
- };
- /* ------------------------------------------------------------------ */
- int saa7134_oss_init1(struct saa7134_dev *dev)
- {
- /* general */
- init_MUTEX(&dev->oss.lock);
- init_waitqueue_head(&dev->oss.wq);
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- saa_writel(0x588 >> 2, 0x00000fff);
- saa_writel(0x58c >> 2, 0x00543210);
- saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb);
- break;
- }
- /* dsp */
- dev->oss.rate = 32000;
- if (oss_rate)
- dev->oss.rate = oss_rate;
- dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000;
- /* mixer */
- dev->oss.line1 = 50;
- dev->oss.line2 = 50;
- mixer_level(dev,LINE1,dev->oss.line1);
- mixer_level(dev,LINE2,dev->oss.line2);
- mixer_recsrc(dev, (dev->oss.rate == 32000) ? TV : LINE2);
- return 0;
- }
- int saa7134_oss_fini(struct saa7134_dev *dev)
- {
- /* nothing */
- return 0;
- }
- void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
- {
- int next_blk, reg = 0;
- spin_lock(&dev->slock);
- if (UNSET == dev->oss.dma_blk) {
- dprintk("irq: recording stopped\n");
- goto done;
- }
- if (0 != (status & 0x0f000000))
- dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
- if (0 == (status & 0x10000000)) {
- /* odd */
- if (0 == (dev->oss.dma_blk & 0x01))
- reg = SAA7134_RS_BA1(6);
- } else {
- /* even */
- if (1 == (dev->oss.dma_blk & 0x01))
- reg = SAA7134_RS_BA2(6);
- }
- if (0 == reg) {
- dprintk("irq: field oops [%s]\n",
- (status & 0x10000000) ? "even" : "odd");
- goto done;
- }
- if (dev->oss.read_count >= dev->oss.blksize * (dev->oss.blocks-2)) {
- dprintk("irq: overrun [full=%d/%d]\n",dev->oss.read_count,
- dev->oss.bufsize);
- dsp_dma_stop(dev);
- goto done;
- }
- /* next block addr */
- next_blk = (dev->oss.dma_blk + 2) % dev->oss.blocks;
- saa_writel(reg,next_blk * dev->oss.blksize);
- if (oss_debug > 2)
- dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
- (status & 0x10000000) ? "even" : "odd ", next_blk,
- next_blk * dev->oss.blksize);
- /* update status & wake waiting readers */
- dev->oss.dma_blk = (dev->oss.dma_blk + 1) % dev->oss.blocks;
- dev->oss.read_count += dev->oss.blksize;
- wake_up(&dev->oss.wq);
- done:
- spin_unlock(&dev->slock);
- }
- /* ----------------------------------------------------------- */
- /*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
|