Index: forte.c =================================================================== RCS file: /home/mkp/Repository/forte/forte.c,v retrieving revision 1.51 retrieving revision 1.54 diff -u -r1.51 -r1.54 --- forte.c 26 Aug 2002 18:10:41 -0000 1.51 +++ forte.c 1 Oct 2002 15:03:42 -0000 1.54 @@ -49,11 +49,13 @@ #include #include +#include + #include #include #define DRIVER_NAME "forte" -#define DRIVER_VERSION "$Id: forte.c,v 1.51 2002/08/26 18:10:41 mkp Exp $" +#define DRIVER_VERSION "$Id: forte.c,v 1.54 2002/10/01 15:03:42 mkp Exp $" #define PFX DRIVER_NAME ": " #undef M_DEBUG @@ -64,11 +66,18 @@ #define DPRINTK(args...) #endif -/* Card capabilities */ -#define FORTE_CAPS (DSP_CAP_MMAP | DSP_CAP_TRIGGER) +/* Codec I/F is buggy in 8-bit mode. Force chip to 16-bit only mode. */ +#define FORTE_8BIT_BUGGY /* Supported audio formats */ -#define FORTE_FMTS (AFMT_U8 | AFMT_S16_LE) +#ifdef FORTE_8BIT_BUGGY + #define FORTE_FMTS (AFMT_S16_LE) +#else + #define FORTE_FMTS (AFMT_U8 | AFMT_S16_LE) +#endif + +/* Card capabilities */ +#define FORTE_CAPS (DSP_CAP_MMAP | DSP_CAP_TRIGGER) /* Buffers */ #define FORTE_MIN_FRAG_SIZE 256 @@ -204,6 +213,10 @@ }; +static int channels[] = { 2, 4, 6, }; +static int rates[] = { 5500, 8000, 9600, 11025, 16000, 19200, + 22050, 32000, 38400, 44100, 48000, }; + static struct forte_chip *forte; static int found; @@ -462,49 +475,33 @@ static int forte_channel_rate (struct forte_channel *channel, unsigned int rate) { - int new_rate, ret; + int new_rate; if (!channel || !channel->iobase) return -EINVAL; - if (rate == 0 || channel->rate == rate) { - ret = channel->rate; - goto out; - } - - if (rate > 48000) - rate = 48000; - - if (rate < 5500) - rate = 5500; - - switch (rate) { - case 5500: new_rate = 0; break; - case 8000: new_rate = 1; break; - case 9600: new_rate = 2; break; - case 11025: new_rate = 3; break; - case 16000: new_rate = 4; break; - case 19200: new_rate = 5; break; - case 22050: new_rate = 6; break; - case 32000: new_rate = 7; break; - case 38400: new_rate = 8; break; - case 44100: new_rate = 9; break; - case 48000: new_rate = 10; break; - - default: - DPRINTK ("Unsupported rate: %d", rate); - ret = -EINVAL; - goto out; - } + /* The FM801 only supports a handful of fixed frequencies. + * We find the value closest to what userland requested. + */ + if (rate <= 6250) { rate = 5500; new_rate = 0; } + else if (rate <= 8800) { rate = 8000; new_rate = 1; } + else if (rate <= 10312) { rate = 9600; new_rate = 2; } + else if (rate <= 13512) { rate = 11025; new_rate = 3; } + else if (rate <= 17600) { rate = 16000; new_rate = 4; } + else if (rate <= 20625) { rate = 19200; new_rate = 5; } + else if (rate <= 27025) { rate = 22050; new_rate = 6; } + else if (rate <= 35200) { rate = 32000; new_rate = 7; } + else if (rate <= 41250) { rate = 38400; new_rate = 8; } + else if (rate <= 46050) { rate = 44100; new_rate = 9; } + else { rate = 48000; new_rate = 10; } channel->ctrl &= ~FORTE_RATE_MASK; channel->ctrl |= new_rate << FORTE_RATE_SHIFT; - channel->rate = ret = rate; + channel->rate = rate; - out: DPRINTK ("%s: %s rate = %d\n", __FUNCTION__, channel->name, rate); - return ret; + return rate; } @@ -519,38 +516,32 @@ static int forte_channel_format (struct forte_channel *channel, int format) { - int ret; - if (!channel || !channel->iobase) return -EINVAL; - DPRINTK ("%s: %s format = %d\n", __FUNCTION__, channel->name, format); - switch (format) { case AFMT_QUERY: - ret = channel->format; break; +#ifndef FORTE_8BIT_BUGGY case AFMT_U8: channel->ctrl &= ~FORTE_16BIT; - channel->format = format; - ret = format; + channel->format = AFMT_U8; break; +#endif case AFMT_S16_LE: - channel->ctrl |= FORTE_16BIT; - channel->format = format; - ret = format; - break; - default: - DPRINTK ("Unsupported audio format"); - ret = -EINVAL; + channel->ctrl |= FORTE_16BIT; + channel->format = AFMT_S16_LE; break; } - return ret; + DPRINTK ("%s: %s want %d format, got %d\n", __FUNCTION__, channel->name, + format, channel->format); + + return channel->format; } @@ -669,14 +660,14 @@ channel->buf_pages * PAGE_SIZE, &channel->buf_handle); + if (!channel->buf || !channel->buf_handle) + BUG(); + page = virt_to_page (channel->buf); for (i = 0 ; i < channel->buf_pages ; i++) mem_map_reserve (page++); - if (!channel->buf || !channel->buf_handle) - BUG(); - /* Prep buffer registers */ outw (channel->frag_sz - 1, channel->iobase + FORTE_PLY_COUNT); outl (channel->buf_handle, channel->iobase + FORTE_PLY_BUF1); @@ -777,9 +768,10 @@ init_waitqueue_head (&channel->wait); - /* Defaults: 48kHz, 16-bit, mono */ + /* Defaults: 48kHz, 16-bit, stereo */ + channel->ctrl = inw (channel->iobase + FORTE_PLY_CTRL); forte_channel_reset (channel); - forte_channel_stereo (channel, 0); + forte_channel_stereo (channel, 1); forte_channel_format (channel, AFMT_S16_LE); forte_channel_rate (channel, 48000); forte_channel_buffer (channel, FORTE_DEF_FRAG_SIZE, @@ -829,8 +821,7 @@ forte_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int ival, ret, rval, rd, wr, count; - unsigned long flags; + int ival=0, ret, rval=0, rd, wr, count; struct forte_chip *chip; struct audio_buf_info abi; struct count_info cinfo; @@ -1183,6 +1174,18 @@ return 0; + case SOUND_PCM_READ_RATE: + DPRINTK ("%s: PCM_READ_RATE\n", __FUNCTION__); + return put_user (chip->play.rate, (int *) arg); + + case SOUND_PCM_READ_CHANNELS: + DPRINTK ("%s: PCM_READ_CHANNELS\n", __FUNCTION__); + return put_user (chip->play.stereo, (int *) arg); + + case SOUND_PCM_READ_BITS: + DPRINTK ("%s: PCM_READ_BITS\n", __FUNCTION__); + return put_user (chip->play.format, (int *) arg); + default: DPRINTK ("Unsupported ioctl: %x (%p)\n", cmd, (void *) arg); break; @@ -1200,7 +1203,6 @@ forte_dsp_open (struct inode *inode, struct file *file) { struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */ - struct forte_channel *channel; if (down_interruptible (&chip->open_sem)) { DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__); @@ -1252,7 +1254,6 @@ forte_channel_free (chip, &chip->rec); } - out: up (&chip->open_sem); return ret; @@ -1484,7 +1485,7 @@ { struct forte_chip *chip; struct forte_channel *channel; - unsigned int i = bytes, sz, ret; + unsigned int i = bytes, sz; unsigned long flags; if (ppos != &file->f_pos) @@ -1702,6 +1703,118 @@ /** + * forte_proc_read: + */ + +static int +forte_proc_read (char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i = 0, p_rate, p_chan, r_rate; + unsigned short p_reg, r_reg; + + i += sprintf (page, "ForteMedia FM801 OSS Lite driver\n%s\n\n", + DRIVER_VERSION); + + if (!forte->iobase) + return i; + + p_rate = p_chan = -1; + p_reg = inw (forte->iobase + FORTE_PLY_CTRL); + p_rate = (p_reg >> 8) & 15; + p_chan = (p_reg >> 12) & 3; + + if (p_rate >= 0 || p_rate <= 10) + p_rate = rates[p_rate]; + + if (p_chan >= 0 || p_chan <= 2) + p_chan = channels[p_chan]; + + r_rate = -1; + r_reg = inw (forte->iobase + FORTE_CAP_CTRL); + r_rate = (r_reg >> 8) & 15; + + if (r_rate >= 0 || r_rate <= 10) + r_rate = rates[r_rate]; + + i += sprintf (page + i, + " Playback Capture\n" + "FIFO empty : %-3s %-3s\n" + "Buf1 Last : %-3s %-3s\n" + "Buf2 Last : %-3s %-3s\n" + "Started : %-3s %-3s\n" + "Paused : %-3s %-3s\n" + "Immed Stop : %-3s %-3s\n" + "Rate : %-5d %-5d\n" + "Channels : %-5d -\n" + "16-bit : %-3s %-3s\n" + "Stereo : %-3s %-3s\n", + p_reg & 1<<0 ? "yes" : "no", + r_reg & 1<<0 ? "yes" : "no", + p_reg & 1<<1 ? "yes" : "no", + r_reg & 1<<1 ? "yes" : "no", + p_reg & 1<<2 ? "yes" : "no", + r_reg & 1<<2 ? "yes" : "no", + p_reg & 1<<5 ? "yes" : "no", + r_reg & 1<<5 ? "yes" : "no", + p_reg & 1<<6 ? "yes" : "no", + r_reg & 1<<6 ? "yes" : "no", + p_reg & 1<<7 ? "yes" : "no", + r_reg & 1<<7 ? "yes" : "no", + p_rate, r_rate, + p_chan, + p_reg & 1<<14 ? "yes" : "no", + r_reg & 1<<14 ? "yes" : "no", + p_reg & 1<<15 ? "yes" : "no", + r_reg & 1<<15 ? "yes" : "no"); + + return i; +} + + +/** + * forte_proc_init: + * + * Creates driver info entries in /proc + */ + +static int __init +forte_proc_init (void) +{ + if (!proc_mkdir ("driver/forte", 0)) + return -EIO; + + if (!create_proc_read_entry ("driver/forte/chip", 0, 0, forte_proc_read, forte)) { + remove_proc_entry ("driver/forte", NULL); + return -EIO; + } + + if (!create_proc_read_entry("driver/forte/ac97", 0, 0, ac97_read_proc, forte->ac97)) { + remove_proc_entry ("driver/forte/chip", NULL); + remove_proc_entry ("driver/forte", NULL); + return -EIO; + } + + return 0; +} + + +/** + * forte_proc_remove: + * + * Removes driver info entries in /proc + */ + +static void +forte_proc_remove (void) +{ + remove_proc_entry ("driver/forte/ac97", NULL); + remove_proc_entry ("driver/forte/chip", NULL); + remove_proc_entry ("driver/forte", NULL); +} + + +/** * forte_chip_init: * @chip: Chip instance to initialize * @@ -1793,6 +1906,12 @@ return -1; } + /* Register with /proc */ + if (forte_proc_init()) { + printk (KERN_ERR PFX "couldn't add entries to /proc!\n"); + return -1; + } + return 0; } @@ -1897,6 +2016,7 @@ outw (0x1f1f, chip->iobase + FORTE_FM_VOL); outw (0x1f1f, chip->iobase + FORTE_I2S_VOL); + forte_proc_remove(); free_irq (chip->irq, chip); release_region (chip->iobase, pci_resource_len (pci_dev, 0));