[alsa-devel] [PATCH] Turtle Beach Multisound Classic/Pinnacle driver (2nd rev)
Takashi Iwai
tiwai at suse.de
Thu Jan 22 11:03:53 CET 2009
At Thu, 22 Jan 2009 10:32:08 +0100,
Krzysztof Helt wrote:
>
> diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
> index 660beb4..2d6ce32 100644
> --- a/sound/isa/Kconfig
> +++ b/sound/isa/Kconfig
> @@ -411,5 +411,36 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL
> you need to install the firmware files from the
> alsa-firmware package.
>
> +config SND_MSND_PINNACLE
> + tristate "Turtle Beach MultiSound Pinnacle/Fiji driver"
> + depends on X86
Better to add depends on EXPERIMENTAL at this stage.
> +config SND_MSND_CLASSIC
> + tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
> + depends on X86
Ditto.
> diff --git a/sound/isa/msnd/Makefile b/sound/isa/msnd/Makefile
> new file mode 100644
> index 0000000..41f278f
> --- /dev/null
> +++ b/sound/isa/msnd/Makefile
> @@ -0,0 +1,10 @@
> +
> +snd-msnd-pinnacle-objs := msnd_pinnacle.o msnd_pinnacle_mixer.o \
> + msnd.o msnd_midi.o
> +snd-msnd-classic-objs := msnd_classic.o msnd_pinnacle_mixer.o \
> + msnd.o msnd_midi.o
> +
> +# Toplevel Module Dependency
> +obj-$(CONFIG_SND_MSND_PINNACLE) += snd-msnd-pinnacle.o
> +obj-$(CONFIG_SND_MSND_CLASSIC) += snd-msnd-classic.o
Well, this won't work if both modules are loaded the same time...
Put the common codes into a library module such as snd-msnd-lib.
In this case, you can't use ifdef MSND_CLASSIC in the library module.
It must be checked dynamically.
Or, a typical workaround (e.g. for echoaudio or au88x0) is to include
all sources into one piece and make all functions static.
> --- /dev/null
> +++ b/sound/isa/msnd/msnd.c
(snip)
> +int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dev->lock, flags);
> + if (snd_msnd_wait_HC0(dev) == 0) {
> + outb(cmd, dev->io + HP_CVR);
> + spin_unlock_irqrestore(&dev->lock, flags);
> + return 0;
> + }
> + spin_unlock_irqrestore(&dev->lock, flags);
> +
> + snd_printd(LOGNAME ": Send DSP command timeout\n");
Put a proper KERN_* prefix.
> +int snd_msnd_send_word(struct snd_msnd *dev, unsigned char high,
> + unsigned char mid, unsigned char low)
> +{
> + unsigned int io = dev->io;
> +
> + if (snd_msnd_wait_TXDE(dev) == 0) {
> + outb(high, io + HP_TXH);
> + outb(mid, io + HP_TXM);
> + outb(low, io + HP_TXL);
> + return 0;
> + }
> +
> + snd_printd(LOGNAME ": Send host word timeout\n");
Ditto.
> +int snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len)
> +{
> + int i;
> +
> + if (len % 3 != 0) {
> + snd_printk(LOGNAME ": Upload host data not multiple of 3!\n");
Ditto.
> + return -EINVAL;
> + }
> +
> + for (i = 0; i < len; i += 3)
> + if (snd_msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]))
> + return -EIO;
> +
> + inb(dev->io + HP_RXL);
> + inb(dev->io + HP_CVR);
> +
> + return 0;
> +}
> +
> +int snd_msnd_enable_irq(struct snd_msnd *dev)
> +{
> + unsigned long flags;
> +
> + if (dev->irq_ref++)
> + return 0;
> +
> + snd_printd(LOGNAME ": Enabling IRQ\n");
I guess it's annoying to print at each time?
snd_printdd() would be a better choice if it's only for really verbose
debugging, as CONFIG_SND_DEBUG=y on most distros.
> + spin_lock_irqsave(&dev->lock, flags);
> + if (snd_msnd_wait_TXDE(dev) == 0) {
> + outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
> + if (dev->type == msndClassic)
> + outb(dev->irqid, dev->io + HP_IRQM);
> +
> + outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
> + outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
> + enable_irq(dev->irq);
> + snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff,
> + dev->dspq_buff_size);
> + spin_unlock_irqrestore(&dev->lock, flags);
> + return 0;
> + }
> + spin_unlock_irqrestore(&dev->lock, flags);
> +
> + snd_printd(LOGNAME ": Enable IRQ failed\n");
This is an error message. Should use a proper KERN_* prefix.
Ditto for snd_msnd_disable_irq().
> --- /dev/null
> +++ b/sound/isa/msnd/msnd.h
> @@ -0,0 +1,293 @@
(snip)
> +/* Generic FIFO * /
> +typedef struct {
> + size_t n, len;
> + char *data;
> + int head, tail;
> +} msnd_fifo; */
^^
What?
> +struct snd_msnd {
> + void *mappedbase;
Use __iomem annotation.
> + /* Motorola 56k DSP SMA */
> + void *SMA;
> + void *DAPQ;
> + void *DARQ;
> + void *MODQ;
> + void *MIDQ;
> + void *DSPQ;
I guess __iomem annotation is needed for these, too.
> --- /dev/null
> +++ b/sound/isa/msnd/msnd_classic.h
> @@ -0,0 +1,159 @@
(snip)
> +#ifdef HAVE_DSPCODEH
Do we ever have this config? Otherwise let's rip off.
> +# include "msndperm.c"
> +# include "msndinit.c"
> +# define PERMCODE msndperm
> +# define INITCODE msndinit
> +# define PERMCODESIZE sizeof(msndperm)
> +# define INITCODESIZE sizeof(msndinit)
> +#else
> +# ifndef CONFIG_MSNDCLAS_INIT_FILE
> +# define CONFIG_MSNDCLAS_INIT_FILE "turtlebeach/msndinit.bin"
> +# endif
> +# ifndef CONFIG_MSNDCLAS_PERM_FILE
> +# define CONFIG_MSNDCLAS_PERM_FILE "turtlebeach/msndperm.bin"
> +# endif
These configs are in sound/oss/Kconfig. You should add the same
config (but a different name) into ALSA side, too.
> --- /dev/null
> +++ b/sound/isa/msnd/msnd_midi.c
> --- /dev/null
> +++ b/sound/isa/msnd/msnd_pinnacle.c
> +#ifdef CONFIG_MSNDCLAS_HAVE_BOOT
> +# define HAVE_DSPCODEH
> +#endif
Ah, ok here it is. This config is also in sound/oss/Kconfig...
> +static int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
> +{
(snip)
> + / * Read data from the head (unprotected bank 1 access okay
> + since this is only called inside an interrupt) * /
> + outb(HPBLKSEL_1, chip->io + HP_BLKS);
> + if ((n = msnd_fifo_write(
> + &chip->DARF,
> + (char *)(chip->base + bank * DAR_BUFF_SIZE),
> + size, 0)) <= 0) {
> + outb(HPBLKSEL_0, chip->io + HP_BLKS);
> + return n;
> + }
> + outb(HPBLKSEL_0, chip->io + HP_BLKS);
> + */
Avoid nested comments...
> +irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
Missing static?
> +static struct snd_pcm_hardware snd_msnd_playback = {
> + .info = SNDRV_PCM_INFO_MMAP |
> + SNDRV_PCM_INFO_INTERLEAVED |
> + SNDRV_PCM_INFO_MMAP_VALID,
> + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
> + .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
> + .rate_min = 8000,
> + .rate_max = 48000,
(snip)
> +static unsigned int rates[] = {
> + 8000, 11025, 16000, 22050, 32000, 44100, 48000
> +};
> +
> +static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
> + .count = ARRAY_SIZE(rates),
> + .list = rates,
> + .mask = 0,
> +};
These are all standard sample rates, so you don't need the extra
hw_constraint code. Just set SNDRV_PCM_RATE_XXX into rates flags
properly.
> +int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm)
Missing static?
thanks,
Takashi
More information about the Alsa-devel
mailing list