[alsa-devel] [PATCH] PnP: Protocol for Media Vision Jazz16 sound cards
From: Rask Ingemann Lambertsen rask@sygehus.dk
- Add code to detect and PnP protocol to manage Media Vision Jazz16 sound cards.
Tested with a Jazz16 based sound card and Linux 2.6.20.6.
Signed-off-by: Rask Ingemann Lambertsen rask@sygehus.dk ---
This patch depends on the patch "ALSA: Support Media Vision Jazz16 chips" because the patched include/sound/sb.h is needed.
drivers/pnp/Kconfig | 12 drivers/pnp/Makefile | 1 drivers/pnp/jazz16pnp.c | 591 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 604 insertions(+)
Main changes since the last patch: Request just one DMA channel (1, 3, 5 or 7). Request port 0x388-0x38b for the OPL3 alias to avoid conflicts. Use the recommended resources from the manual for the preferred option. More SB port bases: 0x210, 0x230 and 0x250.
diff -rup linux-2.6.20.6-clean/drivers/pnp/Kconfig linux-2.6.20.6-ril/drivers/pnp/Kconfig --- linux-2.6.20.6-clean/drivers/pnp/Kconfig 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20.6-ril/drivers/pnp/Kconfig 2007-04-07 20:10:35.000000000 +0200 @@ -37,5 +37,17 @@ source "drivers/pnp/pnpbios/Kconfig"
source "drivers/pnp/pnpacpi/Kconfig"
+# +# Jazz16 Plug and Play configuration +# +config JAZZ16PNP + bool "Jazz16 sound card Plug and Play support" + depends on PNP && ISA + help + Say Y here if you would like support for automatic configuration + of I/O ports, DMA channels and IRQ lines of Jazz16 sound cards. + + Say Y if you have such a card. Otherwise, say N. + endmenu
diff -rup linux-2.6.20.6-clean/drivers/pnp/Makefile linux-2.6.20.6-ril/drivers/pnp/Makefile --- linux-2.6.20.6-clean/drivers/pnp/Makefile 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20.6-ril/drivers/pnp/Makefile 2007-04-07 20:10:35.000000000 +0200 @@ -7,3 +7,4 @@ obj-y := core.o card.o driver.o resourc obj-$(CONFIG_PNPACPI) += pnpacpi/ obj-$(CONFIG_PNPBIOS) += pnpbios/ obj-$(CONFIG_ISAPNP) += isapnp/ +obj-$(CONFIG_JAZZ16PNP) += jazz16pnp.o --- /dev/null 2007-04-11 19:30:17.320748640 +0200 +++ linux-2.6.20.6-ril/drivers/pnp/jazz16pnp.c 2007-04-11 21:41:39.000000000 +0200 @@ -0,0 +1,591 @@ +/* + * Media Vision Jazz16 Plug & Play support. + * + * Copyright (c) 2007 Rask Ingemann Lambertsen rask@sygehus.dk + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver manages two devices: + * + * Device 0: The game port. + * Device 1: The SoundBlaster look-alike part. + * + * Sources: + * sound/oss/sb_common.c + * sys/dev/isa/sbdsp.c (OpenBSD) + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/pnp.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/sb.h> + +MODULE_AUTHOR("Rask Ingemann Lambertsen rask@sygehus.dk"); +MODULE_DESCRIPTION("Jazz16 Plug & Play support"); +MODULE_LICENSE("GPL"); + +int jazz16pnp_disable = false; /* Disable Jazz16 PnP. */ +module_param_named(disable, jazz16pnp_disable, bool, false); +MODULE_PARM_DESC(disable, "Jazz16 Plug & Play disable switch"); + +int jazz16pnp_verbose = false; /* Verbosity level. */ +module_param_named(verbose, jazz16pnp_verbose, bool, false); +MODULE_PARM_DESC(verbose, "Jazz16 Plug & Play verbosity level"); + +#define PFX "jazz16pnp: " +#define PFX_DEBUG KERN_DEBUG PFX +#define PFX_INFO KERN_INFO PFX +#define PFX_WARN KERN_WARNING PFX + +/* Jazz16 configuration. */ +#define SB_JAZZ16_CONFIG_PORT 0x201 +#define SB_JAZZ16_WAKEUP 0xaf +#define SB_JAZZ16_SET_PORTS 0x50 +#define SB_JAZZ16_SET_DMAINTR 0xFB + +extern void *pnp_alloc(long size); +extern void pnp_free_option(struct pnp_option *option); + +static struct pnp_dev *jazz16_gameport_dev = NULL; +static struct pnp_dev *jazz16_sb_dev = NULL; +static struct resource *jazz16pnp_fm_res = NULL; + +static uint jazz16_sb_port = 0, jazz16_sb_irq = 0; +static uint jazz16_sb_dma1 = 0, jazz16_sb_dma2 = 0; +static uint jazz16_mpu401_port = 0, jazz16_mpu401_irq = 0; + +static uint jazz16pnp_count = 0; + +static struct pnp_protocol jazz16pnp_protocol; + +static bool __init jazz16pnp_easy_option(struct pnp_dev *dev, uint pri, + struct pnp_port *port, uint nports, + struct pnp_irq *irq, uint nirqs, + struct pnp_dma *dma, uint ndmas) +{ + struct pnp_option *opt; + struct pnp_port *new_port; + struct pnp_irq *new_irq; + struct pnp_dma *new_dma; + uint i; + + switch (pri) { + case PNP_RES_PRIORITY_PREFERRED: + case PNP_RES_PRIORITY_ACCEPTABLE: + case PNP_RES_PRIORITY_FUNCTIONAL: + opt = pnp_register_dependent_option(dev, pri); + break; + + default: + opt = pnp_register_independent_option(dev); + break; + } + if (!opt) + return false; + + for (i = 0; i < nports; i ++) { + new_port = pnp_alloc(sizeof(*new_port)); + if (!new_port) + goto out_no_mem; + memcpy(new_port, &port[i], sizeof(*new_port)); + pnp_register_port_resource(opt, new_port); + } + for (i = 0; i < nirqs; i ++) { + new_irq = pnp_alloc(sizeof(*new_irq)); + if (!new_irq) + goto out_no_mem; + memcpy(new_irq, &irq[i], sizeof(*new_irq)); + pnp_register_irq_resource(opt, new_irq); + } + for (i = 0; i < ndmas; i ++) { + new_dma = pnp_alloc(sizeof(*new_dma)); + if (!new_dma) + goto out_no_mem; + memcpy(new_dma, &dma[i], sizeof(*new_dma)); + pnp_register_dma_resource(opt, new_dma); + } + return true; + +out_no_mem: + return false; +} + +static struct pnp_port jazz16pnp_game_ports[] __initdata = { + { .min = SB_JAZZ16_CONFIG_PORT, + .max = SB_JAZZ16_CONFIG_PORT, + .size = 1, .align = 0, + .flags = PNP_PORT_FLAG_FIXED, }, +}; + +static int __init jazz16pnp_add_gameport(void) +{ + struct pnp_dev *dev; + struct pnp_id *dev_id; + + if (!(dev = pnp_alloc(sizeof(*dev)))) + goto out_no_dev; + if (!(dev_id = pnp_alloc(sizeof(*dev_id)))) + goto out_no_id; + if (!jazz16pnp_easy_option(dev, PNP_RES_PRIORITY_INVALID, + jazz16pnp_game_ports, 1, + NULL, 0, NULL, 0)) + goto out_no_option; + + dev->protocol = &jazz16pnp_protocol; + dev->capabilities = PNP_READ; + dev->active = 1; + dev->number = 0; + + pnp_init_resource_table(&dev->res); + dev->res.port_resource[0].start = SB_JAZZ16_CONFIG_PORT; + dev->res.port_resource[0].end = SB_JAZZ16_CONFIG_PORT; + dev->res.port_resource[0].flags = IORESOURCE_IO; + + memcpy(dev_id->id, "PNPb02f", PNP_ID_LEN); + pnp_add_id(dev_id, dev); + + jazz16_gameport_dev = dev; + pnp_add_device(dev); + return 0; + +out_no_option: + if (dev->independent) + pnp_free_option(dev->independent); + kfree(dev_id); +out_no_id: + kfree(dev); +out_no_dev: + return -ENOMEM; +}; + +static struct pnp_port jazz16pnp_pref_ports[] __initdata = { + { .min = 0x220, .max = 0x220, .align = 0x00, .size = 0x10 }, + { .min = 0x330, .max = 0x330, .align = 0x00, .size = 0x02 }, + { .min = 0x388, .max = 0x388, .align = 0x00, .size = 0x04 }, +}; + +static struct pnp_port jazz16pnp_ports[] __initdata = { + { .min = 0x210, .max = 0x260, .align = 0x10, .size = 0x10 }, + { .min = 0x300, .max = 0x330, .align = 0x10, .size = 0x02 }, + { .min = 0x388, .max = 0x388, .align = 0x00, .size = 0x04 }, +}; + +static struct pnp_irq jazz16pnp_pref_irqs[] __initdata = { + { .map[0] = (1 << 5), + .flags = IORESOURCE_IRQ_HIGHEDGE }, + { .map[0] = (1 << 9), + .flags = IORESOURCE_IRQ_HIGHEDGE }, +}; + +static struct pnp_irq jazz16pnp_irqs[] __initdata = { + { .map[0] = (1 << 3) | (1 << 5) | (1 << 7) | + (1 << 9) | (1 << 10) | (1 << 15), + .flags = IORESOURCE_IRQ_HIGHEDGE }, + { .map[0] = (1 << 3) | (1 << 5) | (1 << 7) | + (1 << 9) | (1 << 10) | (1 << 15), + .flags = IORESOURCE_IRQ_HIGHEDGE }, +}; + +static struct pnp_dma jazz16pnp_pref_dmas[] __initdata = { + { .map = (1 << 1), .flags = IORESOURCE_DMA_8BIT, }, +}; + +static struct pnp_dma jazz16pnp_dmas[] __initdata = { + { .map = (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7), + .flags = IORESOURCE_DMA_8AND16BIT, }, +}; + +static int __init jazz16pnp_add_sb(void) +{ + struct pnp_dev *sbdev; + struct pnp_id *sbid; + + if (!(sbdev = pnp_alloc(sizeof(*sbdev)))) + goto out_no_sbdev; + if (!(sbid = pnp_alloc(sizeof(*sbid)))) + goto out_no_sbid; + + if (!jazz16pnp_easy_option(sbdev, PNP_RES_PRIORITY_PREFERRED, + jazz16pnp_pref_ports, 3, + jazz16pnp_pref_irqs, 2, + jazz16pnp_pref_dmas, 1)) + goto out_no_sboption; + if (!jazz16pnp_easy_option(sbdev, PNP_RES_PRIORITY_ACCEPTABLE, + jazz16pnp_ports, 3, + jazz16pnp_irqs, 2, + jazz16pnp_dmas, 1)) + goto out_no_sboption; + if (!jazz16pnp_easy_option(sbdev, PNP_RES_PRIORITY_ACCEPTABLE, + jazz16pnp_ports, 3, + jazz16pnp_irqs, 1, + jazz16pnp_dmas, 1)) + goto out_no_sboption; + memcpy(sbid->id, "PNPb00f", PNP_ID_LEN); + pnp_add_id(sbid, sbdev); + + pnp_init_resource_table(&sbdev->res); + sbdev->capabilities = PNP_READ | PNP_WRITE | PNP_CONFIGURABLE | PNP_DISABLE; + sbdev->protocol = &jazz16pnp_protocol; + sbdev->number = 1; + + jazz16_sb_dev = sbdev; + pnp_add_device(sbdev); + return 0; + +out_no_sboption: + if (sbdev->dependent) + pnp_free_option(sbdev->dependent); + kfree(sbid); +out_no_sbid: + kfree(sbdev); +out_no_sbdev: + return -ENOMEM; +} + +/* Configure the SB and MPU ports. Passing 0 for sbport disables the Jazz16. */ +static void jazz16_port_setup(const uint sbport, const uint mpuport) +{ + u8 config; + + switch (sbport) { + case 0x210: + case 0x220: + case 0x230: + case 0x240: + case 0x250: + case 0x260: + config = sbport & 0x70; + jazz16_sb_port = sbport; + break; + + default: + config = 0; + jazz16_sb_port = 0; + break; + } + + switch (mpuport) { + case 0x300: + case 0x310: + case 0x320: + case 0x330: + config |= (mpuport >> 4) & 0x07; + jazz16_mpu401_port = mpuport; + break; + + default: + if (jazz16_sb_port) + BUG(); + } + if (jazz16pnp_verbose) + printk(PFX_DEBUG "Setting SB port = %#x, MPU port = %#x.\n", + jazz16_sb_port, jazz16_mpu401_port); + outb(SB_JAZZ16_WAKEUP, SB_JAZZ16_CONFIG_PORT); + outb(SB_JAZZ16_SET_PORTS, SB_JAZZ16_CONFIG_PORT); + outb(config, SB_JAZZ16_CONFIG_PORT); +} + +static u8 jazz16_irq_config(uint irq) +{ + switch (irq) { + case 3: return 3; + case 5: return 1; + case 7: return 4; + case 9: return 2; + case 10: return 5; + case 15: return 6; + default: return 0; + } +} + +static u8 jazz16_dma_config(uint dma) +{ + switch (dma) { + case 1: return 1; + case 3: return 2; + case 5: return 3; + case 7: return 4; + default: return 0; + } +} + +/* The my_sbdsp_xxx functions were ripped from sound/isa/sb/sb_common.c. */ +#define BUSY_LOOPS 100000 + +static int my_sbdsp_command(unsigned int base, unsigned char val) +{ + int i; + for (i = BUSY_LOOPS; i; i--) + if ((inb(SBP1(base, STATUS)) & 0x80) == 0) { + outb(val, SBP1(base, COMMAND)); + return 1; + } + return 0; +} + +static int my_sbdsp_get_byte(unsigned int base) +{ + int val; + int i; + for (i = BUSY_LOOPS; i; i--) { + if (inb(SBP1(base, DATA_AVAIL)) & 0x80) { + val = inb(SBP1(base, READ)); + return val; + } + } + return -ENODEV; +} + +static int my_sbdsp_reset(unsigned int base) +{ + int i; + + outb(1, SBP1(base, RESET)); + udelay(10); + outb(0, SBP1(base, RESET)); + udelay(30); + for (i = BUSY_LOOPS; i; i--) + if (inb(SBP1(base, DATA_AVAIL)) & 0x80) { + if (inb(SBP1(base, READ)) == 0xaa) + return 0; + else + break; + } + return -ENODEV; +} + +static int jazz16_irq_dma_setup(unsigned int base, uint sbirq, uint mpuirq, uint dma8, uint dma16) +{ + u8 dma_config, irq_config; + + if (jazz16pnp_verbose) + printk(PFX_DEBUG "Setting SB irq %u, dma %u&%u, MPU irq %u.\n", + sbirq, dma8, dma16, mpuirq); + irq_config = jazz16_irq_config(sbirq) | jazz16_irq_config(mpuirq) << 4; + dma_config = jazz16_dma_config(dma8) | jazz16_dma_config(dma16) << 4; + if (!my_sbdsp_command(base, SB_JAZZ16_SET_DMAINTR)) + return 0; + + if (!my_sbdsp_command(base, dma_config)) + return 0; + jazz16_sb_dma1 = dma8; + jazz16_sb_dma2 = dma16; + + if (!my_sbdsp_command(base, irq_config)) + return 0; + jazz16_sb_irq = sbirq; + jazz16_mpu401_irq = mpuirq; + return 1; +} + +static int jazz16pnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table *res) +{ + pnp_init_resource_table(res); + if (dev == jazz16_gameport_dev) { + res->port_resource[0].start = res->port_resource[0].end = SB_JAZZ16_CONFIG_PORT; + res->port_resource[0].flags = IORESOURCE_IO; + } else if (dev == jazz16_sb_dev) { + if (!jazz16_sb_port) + return 0; + res->port_resource[0].start = jazz16_sb_port; + res->port_resource[0].end = jazz16_sb_port + 0x10 - 1; + res->port_resource[0].flags = IORESOURCE_IO; + + res->irq_resource[0].start = jazz16_sb_irq; + res->irq_resource[0].end = jazz16_sb_irq; + res->irq_resource[0].flags = IORESOURCE_IRQ; + if (jazz16_mpu401_irq) { + res->irq_resource[1].start = jazz16_mpu401_irq; + res->irq_resource[1].end = jazz16_mpu401_irq; + res->irq_resource[1].flags = IORESOURCE_IRQ; + } + + res->dma_resource[0].start = jazz16_sb_dma1; + res->dma_resource[0].end = jazz16_sb_dma1; + res->dma_resource[0].flags = IORESOURCE_DMA; + if (jazz16_sb_dma2 != jazz16_sb_dma1) { + res->dma_resource[1].start = jazz16_sb_dma2; + res->dma_resource[1].end = jazz16_sb_dma2; + res->dma_resource[1].flags = IORESOURCE_DMA; + } + res->port_resource[1].start = jazz16_mpu401_port; + res->port_resource[1].end = jazz16_mpu401_port + 2 - 1; + res->port_resource[1].flags = IORESOURCE_IO; + } else + return -EINVAL; + return 0; +} + +/* Disables the device if supported. */ +static int jazz16pnp_disable_resources(struct pnp_dev *dev) +{ + if (dev == jazz16_gameport_dev) { + return -ENOSYS; + } else if (dev == jazz16_sb_dev) { + if (jazz16_sb_port) + jazz16_irq_dma_setup(jazz16_sb_port, 0, 0, 0, 0); + jazz16_port_setup(0, 0); + if (jazz16pnp_fm_res) { + release_resource(jazz16pnp_fm_res); + jazz16pnp_fm_res = NULL; + } + dev->active = false; + return 0; + } else { + return -EINVAL; + } +} + +#define PNP_RES_IS_SET(res,type,TYPE,i) \ + (((res)->type##_resource[i].flags & (IORESOURCE_##TYPE | IORESOURCE_UNSET)) \ + == IORESOURCE_##TYPE) + +static int jazz16pnp_set_resources(struct pnp_dev *dev, struct pnp_resource_table *res) +{ + unsigned int sbirq, mpuirq, dma1, dma2; + + if (dev == jazz16_gameport_dev) + return -ENOSYS; + + else if (dev == jazz16_sb_dev) { + if (PNP_RES_IS_SET(res, dma, DMA, 0)) + dma1 = res->dma_resource[0].start; + else + return -EINVAL; + if (PNP_RES_IS_SET(res, dma, DMA, 1)) + dma2 = res->dma_resource[1].start; + else + dma2 = dma1; /* "half duplex" operation. */ + if (PNP_RES_IS_SET(res, irq, IRQ, 0)) + sbirq = res->irq_resource[0].start; + else + return -EINVAL; + if (PNP_RES_IS_SET(res, irq, IRQ, 1)) + mpuirq = res->irq_resource[1].start; + else + mpuirq = 0; /* MPU-401 driver supports this. */ + if (! PNP_RES_IS_SET(res, port, IO, 0)) + return -EINVAL; + if (! PNP_RES_IS_SET(res, port, IO, 1)) + return -EINVAL; + + /* Block the OPL3 alias to avoid conflicts. */ + jazz16pnp_fm_res = request_region(0x388, 4, "SoundBlaster FM"); + /* Avoid setting the mpu port after setting the sb port + because doing so will glitch the mpu port from the + previous one to the new one. */ + jazz16_port_setup(res->port_resource[0].start, + res->port_resource[1].start); + jazz16_irq_dma_setup(jazz16_sb_port, sbirq, mpuirq, dma1, dma2); + dev->active = true; + return 0; + } else + return -EINVAL; +} +#undef PNP_RES_IS_SET + +static struct pnp_protocol jazz16pnp_protocol = { + .name = "Jazz16 PnP", + .get = jazz16pnp_get_resources, + .set = jazz16pnp_set_resources, + .disable = jazz16pnp_disable_resources, +}; + +static uint __init jazz16_check(unsigned int base) +{ + if (my_sbdsp_reset(base)) + return 0; + if (!(my_sbdsp_command(base, SB_DSP_GET_JAZZ_VERSION))) + return 0; + return SB_VERSION_IS_JAZZ16(my_sbdsp_get_byte(base)); +} + +static int __init jazz16pnp_init(void) +{ + int err = 0; + unsigned int base, mpubase; + + if (jazz16pnp_disable == 1) { + printk(PFX_INFO "Jazz16 Plug & Play support disabled.\n"); + return 0; + } + if (!request_region(SB_JAZZ16_CONFIG_PORT, 1, "Jazz16 PnP probe")) + return -EBUSY; + + for (mpubase = 0x300; mpubase <= 0x330; mpubase += 0x10) + if (request_region(mpubase, 2, "Jazz16 PnP probe")) + break; + if (mpubase > 0x330) + goto out_no_mpubase; + + if (jazz16pnp_verbose) + printk(PFX_DEBUG "Scanning for Jazz16 cards...\n"); + + for (base = 0x260; base >= 0x210; base -= 0x10) { + if (!request_region(base, 16, "Jazz16 PnP probe")) + continue; + if (jazz16pnp_verbose) + printk(PFX_DEBUG "Probing at %#x (with MPU at %#x).\n", + base, mpubase); + jazz16_port_setup(base, mpubase); + if (jazz16_check(base)) + jazz16pnp_count++; + jazz16_irq_dma_setup(base, 0, 0, 0, 0); + jazz16_port_setup(0, 0); + release_region(base, 16); + if (jazz16pnp_count) + break; + } + if (base < 0x210) + goto out_no_sbbase; + if (!jazz16pnp_count) { + err = -ENODEV; + goto out_no_devices; + } + if (pnp_register_protocol(&jazz16pnp_protocol) < 0) + err = -ENOMEM; + else { + if (jazz16pnp_add_gameport()) + printk(PFX_WARN "Failed to add game port.\n"); + if (jazz16pnp_add_sb()) + printk(PFX_WARN "Failed to add SB port.\n"); + err = 0; + } +out_no_devices: + printk(PFX_INFO "%u Jazz16 card%s detected.\n", jazz16pnp_count, + jazz16pnp_count == 1 ? "" : "s"); +out_no_sbbase: + release_region(mpubase, 2); +out_no_mpubase: + release_region(SB_JAZZ16_CONFIG_PORT, 1); + return err; +} +module_init(jazz16pnp_init); + +static void __exit jazz16pnp_exit(void) +{ + pnp_unregister_protocol(&jazz16pnp_protocol); +} +module_exit(jazz16pnp_exit);
At Thu, 12 Apr 2007 21:55:23 +0200, Rask Ingemann Lambertsen wrote:
From: Rask Ingemann Lambertsen rask@sygehus.dk
- Add code to detect and PnP protocol to manage Media Vision Jazz16 sound cards.
Tested with a Jazz16 based sound card and Linux 2.6.20.6.
Signed-off-by: Rask Ingemann Lambertsen rask@sygehus.dk
Acked-by: Takashi Iwai tiwai@suse.de
Adam, could you review it?
Thanks,
Takashi
This patch depends on the patch "ALSA: Support Media Vision Jazz16 chips" because the patched include/sound/sb.h is needed.
drivers/pnp/Kconfig | 12 drivers/pnp/Makefile | 1 drivers/pnp/jazz16pnp.c | 591 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 604 insertions(+)
Main changes since the last patch: Request just one DMA channel (1, 3, 5 or 7). Request port 0x388-0x38b for the OPL3 alias to avoid conflicts. Use the recommended resources from the manual for the preferred option. More SB port bases: 0x210, 0x230 and 0x250.
diff -rup linux-2.6.20.6-clean/drivers/pnp/Kconfig linux-2.6.20.6-ril/drivers/pnp/Kconfig --- linux-2.6.20.6-clean/drivers/pnp/Kconfig 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20.6-ril/drivers/pnp/Kconfig 2007-04-07 20:10:35.000000000 +0200 @@ -37,5 +37,17 @@ source "drivers/pnp/pnpbios/Kconfig"
source "drivers/pnp/pnpacpi/Kconfig"
+# +# Jazz16 Plug and Play configuration +# +config JAZZ16PNP
- bool "Jazz16 sound card Plug and Play support"
- depends on PNP && ISA
- help
Say Y here if you would like support for automatic configuration
of I/O ports, DMA channels and IRQ lines of Jazz16 sound cards.
Say Y if you have such a card. Otherwise, say N.
endmenu
diff -rup linux-2.6.20.6-clean/drivers/pnp/Makefile linux-2.6.20.6-ril/drivers/pnp/Makefile --- linux-2.6.20.6-clean/drivers/pnp/Makefile 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20.6-ril/drivers/pnp/Makefile 2007-04-07 20:10:35.000000000 +0200 @@ -7,3 +7,4 @@ obj-y := core.o card.o driver.o resourc obj-$(CONFIG_PNPACPI) += pnpacpi/ obj-$(CONFIG_PNPBIOS) += pnpbios/ obj-$(CONFIG_ISAPNP) += isapnp/ +obj-$(CONFIG_JAZZ16PNP) += jazz16pnp.o --- /dev/null 2007-04-11 19:30:17.320748640 +0200 +++ linux-2.6.20.6-ril/drivers/pnp/jazz16pnp.c 2007-04-11 21:41:39.000000000 +0200 @@ -0,0 +1,591 @@ +/*
- Media Vision Jazz16 Plug & Play support.
- Copyright (c) 2007 Rask Ingemann Lambertsen rask@sygehus.dk
- 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- This driver manages two devices:
- Device 0: The game port.
- Device 1: The SoundBlaster look-alike part.
- Sources:
- sound/oss/sb_common.c
- sys/dev/isa/sbdsp.c (OpenBSD)
- */
+#include <linux/types.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/pnp.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/sb.h>
+MODULE_AUTHOR("Rask Ingemann Lambertsen rask@sygehus.dk"); +MODULE_DESCRIPTION("Jazz16 Plug & Play support"); +MODULE_LICENSE("GPL");
+int jazz16pnp_disable = false; /* Disable Jazz16 PnP. */ +module_param_named(disable, jazz16pnp_disable, bool, false); +MODULE_PARM_DESC(disable, "Jazz16 Plug & Play disable switch");
+int jazz16pnp_verbose = false; /* Verbosity level. */ +module_param_named(verbose, jazz16pnp_verbose, bool, false); +MODULE_PARM_DESC(verbose, "Jazz16 Plug & Play verbosity level");
+#define PFX "jazz16pnp: " +#define PFX_DEBUG KERN_DEBUG PFX +#define PFX_INFO KERN_INFO PFX +#define PFX_WARN KERN_WARNING PFX
+/* Jazz16 configuration. */ +#define SB_JAZZ16_CONFIG_PORT 0x201 +#define SB_JAZZ16_WAKEUP 0xaf +#define SB_JAZZ16_SET_PORTS 0x50 +#define SB_JAZZ16_SET_DMAINTR 0xFB
+extern void *pnp_alloc(long size); +extern void pnp_free_option(struct pnp_option *option);
+static struct pnp_dev *jazz16_gameport_dev = NULL; +static struct pnp_dev *jazz16_sb_dev = NULL; +static struct resource *jazz16pnp_fm_res = NULL;
+static uint jazz16_sb_port = 0, jazz16_sb_irq = 0; +static uint jazz16_sb_dma1 = 0, jazz16_sb_dma2 = 0; +static uint jazz16_mpu401_port = 0, jazz16_mpu401_irq = 0;
+static uint jazz16pnp_count = 0;
+static struct pnp_protocol jazz16pnp_protocol;
+static bool __init jazz16pnp_easy_option(struct pnp_dev *dev, uint pri,
struct pnp_port *port, uint nports,
struct pnp_irq *irq, uint nirqs,
struct pnp_dma *dma, uint ndmas)
+{
- struct pnp_option *opt;
- struct pnp_port *new_port;
- struct pnp_irq *new_irq;
- struct pnp_dma *new_dma;
- uint i;
- switch (pri) {
- case PNP_RES_PRIORITY_PREFERRED:
- case PNP_RES_PRIORITY_ACCEPTABLE:
- case PNP_RES_PRIORITY_FUNCTIONAL:
opt = pnp_register_dependent_option(dev, pri);
break;
- default:
opt = pnp_register_independent_option(dev);
break;
- }
- if (!opt)
return false;
- for (i = 0; i < nports; i ++) {
new_port = pnp_alloc(sizeof(*new_port));
if (!new_port)
goto out_no_mem;
memcpy(new_port, &port[i], sizeof(*new_port));
pnp_register_port_resource(opt, new_port);
- }
- for (i = 0; i < nirqs; i ++) {
new_irq = pnp_alloc(sizeof(*new_irq));
if (!new_irq)
goto out_no_mem;
memcpy(new_irq, &irq[i], sizeof(*new_irq));
pnp_register_irq_resource(opt, new_irq);
- }
- for (i = 0; i < ndmas; i ++) {
new_dma = pnp_alloc(sizeof(*new_dma));
if (!new_dma)
goto out_no_mem;
memcpy(new_dma, &dma[i], sizeof(*new_dma));
pnp_register_dma_resource(opt, new_dma);
- }
- return true;
+out_no_mem:
- return false;
+}
+static struct pnp_port jazz16pnp_game_ports[] __initdata = {
- { .min = SB_JAZZ16_CONFIG_PORT,
.max = SB_JAZZ16_CONFIG_PORT,
.size = 1, .align = 0,
.flags = PNP_PORT_FLAG_FIXED, },
+};
+static int __init jazz16pnp_add_gameport(void) +{
- struct pnp_dev *dev;
- struct pnp_id *dev_id;
- if (!(dev = pnp_alloc(sizeof(*dev))))
goto out_no_dev;
- if (!(dev_id = pnp_alloc(sizeof(*dev_id))))
goto out_no_id;
- if (!jazz16pnp_easy_option(dev, PNP_RES_PRIORITY_INVALID,
jazz16pnp_game_ports, 1,
NULL, 0, NULL, 0))
goto out_no_option;
- dev->protocol = &jazz16pnp_protocol;
- dev->capabilities = PNP_READ;
- dev->active = 1;
- dev->number = 0;
- pnp_init_resource_table(&dev->res);
- dev->res.port_resource[0].start = SB_JAZZ16_CONFIG_PORT;
- dev->res.port_resource[0].end = SB_JAZZ16_CONFIG_PORT;
- dev->res.port_resource[0].flags = IORESOURCE_IO;
- memcpy(dev_id->id, "PNPb02f", PNP_ID_LEN);
- pnp_add_id(dev_id, dev);
- jazz16_gameport_dev = dev;
- pnp_add_device(dev);
- return 0;
+out_no_option:
- if (dev->independent)
pnp_free_option(dev->independent);
- kfree(dev_id);
+out_no_id:
- kfree(dev);
+out_no_dev:
- return -ENOMEM;
+};
+static struct pnp_port jazz16pnp_pref_ports[] __initdata = {
- { .min = 0x220, .max = 0x220, .align = 0x00, .size = 0x10 },
- { .min = 0x330, .max = 0x330, .align = 0x00, .size = 0x02 },
- { .min = 0x388, .max = 0x388, .align = 0x00, .size = 0x04 },
+};
+static struct pnp_port jazz16pnp_ports[] __initdata = {
- { .min = 0x210, .max = 0x260, .align = 0x10, .size = 0x10 },
- { .min = 0x300, .max = 0x330, .align = 0x10, .size = 0x02 },
- { .min = 0x388, .max = 0x388, .align = 0x00, .size = 0x04 },
+};
+static struct pnp_irq jazz16pnp_pref_irqs[] __initdata = {
- { .map[0] = (1 << 5),
.flags = IORESOURCE_IRQ_HIGHEDGE },
- { .map[0] = (1 << 9),
.flags = IORESOURCE_IRQ_HIGHEDGE },
+};
+static struct pnp_irq jazz16pnp_irqs[] __initdata = {
- { .map[0] = (1 << 3) | (1 << 5) | (1 << 7) |
(1 << 9) | (1 << 10) | (1 << 15),
.flags = IORESOURCE_IRQ_HIGHEDGE },
- { .map[0] = (1 << 3) | (1 << 5) | (1 << 7) |
(1 << 9) | (1 << 10) | (1 << 15),
.flags = IORESOURCE_IRQ_HIGHEDGE },
+};
+static struct pnp_dma jazz16pnp_pref_dmas[] __initdata = {
- { .map = (1 << 1), .flags = IORESOURCE_DMA_8BIT, },
+};
+static struct pnp_dma jazz16pnp_dmas[] __initdata = {
- { .map = (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7),
.flags = IORESOURCE_DMA_8AND16BIT, },
+};
+static int __init jazz16pnp_add_sb(void) +{
- struct pnp_dev *sbdev;
- struct pnp_id *sbid;
- if (!(sbdev = pnp_alloc(sizeof(*sbdev))))
goto out_no_sbdev;
- if (!(sbid = pnp_alloc(sizeof(*sbid))))
goto out_no_sbid;
- if (!jazz16pnp_easy_option(sbdev, PNP_RES_PRIORITY_PREFERRED,
jazz16pnp_pref_ports, 3,
jazz16pnp_pref_irqs, 2,
jazz16pnp_pref_dmas, 1))
goto out_no_sboption;
- if (!jazz16pnp_easy_option(sbdev, PNP_RES_PRIORITY_ACCEPTABLE,
jazz16pnp_ports, 3,
jazz16pnp_irqs, 2,
jazz16pnp_dmas, 1))
goto out_no_sboption;
- if (!jazz16pnp_easy_option(sbdev, PNP_RES_PRIORITY_ACCEPTABLE,
jazz16pnp_ports, 3,
jazz16pnp_irqs, 1,
jazz16pnp_dmas, 1))
goto out_no_sboption;
- memcpy(sbid->id, "PNPb00f", PNP_ID_LEN);
- pnp_add_id(sbid, sbdev);
- pnp_init_resource_table(&sbdev->res);
- sbdev->capabilities = PNP_READ | PNP_WRITE | PNP_CONFIGURABLE | PNP_DISABLE;
- sbdev->protocol = &jazz16pnp_protocol;
- sbdev->number = 1;
- jazz16_sb_dev = sbdev;
- pnp_add_device(sbdev);
- return 0;
+out_no_sboption:
- if (sbdev->dependent)
pnp_free_option(sbdev->dependent);
- kfree(sbid);
+out_no_sbid:
- kfree(sbdev);
+out_no_sbdev:
- return -ENOMEM;
+}
+/* Configure the SB and MPU ports. Passing 0 for sbport disables the Jazz16. */ +static void jazz16_port_setup(const uint sbport, const uint mpuport) +{
- u8 config;
- switch (sbport) {
- case 0x210:
- case 0x220:
- case 0x230:
- case 0x240:
- case 0x250:
- case 0x260:
config = sbport & 0x70;
jazz16_sb_port = sbport;
break;
- default:
config = 0;
jazz16_sb_port = 0;
break;
- }
- switch (mpuport) {
- case 0x300:
- case 0x310:
- case 0x320:
- case 0x330:
config |= (mpuport >> 4) & 0x07;
jazz16_mpu401_port = mpuport;
break;
- default:
if (jazz16_sb_port)
BUG();
- }
- if (jazz16pnp_verbose)
printk(PFX_DEBUG "Setting SB port = %#x, MPU port = %#x.\n",
jazz16_sb_port, jazz16_mpu401_port);
- outb(SB_JAZZ16_WAKEUP, SB_JAZZ16_CONFIG_PORT);
- outb(SB_JAZZ16_SET_PORTS, SB_JAZZ16_CONFIG_PORT);
- outb(config, SB_JAZZ16_CONFIG_PORT);
+}
+static u8 jazz16_irq_config(uint irq) +{
- switch (irq) {
- case 3: return 3;
- case 5: return 1;
- case 7: return 4;
- case 9: return 2;
- case 10: return 5;
- case 15: return 6;
- default: return 0;
- }
+}
+static u8 jazz16_dma_config(uint dma) +{
- switch (dma) {
- case 1: return 1;
- case 3: return 2;
- case 5: return 3;
- case 7: return 4;
- default: return 0;
- }
+}
+/* The my_sbdsp_xxx functions were ripped from sound/isa/sb/sb_common.c. */ +#define BUSY_LOOPS 100000
+static int my_sbdsp_command(unsigned int base, unsigned char val) +{
- int i;
- for (i = BUSY_LOOPS; i; i--)
if ((inb(SBP1(base, STATUS)) & 0x80) == 0) {
outb(val, SBP1(base, COMMAND));
return 1;
}
- return 0;
+}
+static int my_sbdsp_get_byte(unsigned int base) +{
- int val;
- int i;
- for (i = BUSY_LOOPS; i; i--) {
if (inb(SBP1(base, DATA_AVAIL)) & 0x80) {
val = inb(SBP1(base, READ));
return val;
}
- }
- return -ENODEV;
+}
+static int my_sbdsp_reset(unsigned int base) +{
- int i;
- outb(1, SBP1(base, RESET));
- udelay(10);
- outb(0, SBP1(base, RESET));
- udelay(30);
- for (i = BUSY_LOOPS; i; i--)
if (inb(SBP1(base, DATA_AVAIL)) & 0x80) {
if (inb(SBP1(base, READ)) == 0xaa)
return 0;
else
break;
}
- return -ENODEV;
+}
+static int jazz16_irq_dma_setup(unsigned int base, uint sbirq, uint mpuirq, uint dma8, uint dma16) +{
- u8 dma_config, irq_config;
- if (jazz16pnp_verbose)
printk(PFX_DEBUG "Setting SB irq %u, dma %u&%u, MPU irq %u.\n",
sbirq, dma8, dma16, mpuirq);
- irq_config = jazz16_irq_config(sbirq) | jazz16_irq_config(mpuirq) << 4;
- dma_config = jazz16_dma_config(dma8) | jazz16_dma_config(dma16) << 4;
- if (!my_sbdsp_command(base, SB_JAZZ16_SET_DMAINTR))
return 0;
- if (!my_sbdsp_command(base, dma_config))
return 0;
- jazz16_sb_dma1 = dma8;
- jazz16_sb_dma2 = dma16;
- if (!my_sbdsp_command(base, irq_config))
return 0;
- jazz16_sb_irq = sbirq;
- jazz16_mpu401_irq = mpuirq;
- return 1;
+}
+static int jazz16pnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table *res) +{
- pnp_init_resource_table(res);
- if (dev == jazz16_gameport_dev) {
res->port_resource[0].start = res->port_resource[0].end = SB_JAZZ16_CONFIG_PORT;
res->port_resource[0].flags = IORESOURCE_IO;
- } else if (dev == jazz16_sb_dev) {
if (!jazz16_sb_port)
return 0;
res->port_resource[0].start = jazz16_sb_port;
res->port_resource[0].end = jazz16_sb_port + 0x10 - 1;
res->port_resource[0].flags = IORESOURCE_IO;
res->irq_resource[0].start = jazz16_sb_irq;
res->irq_resource[0].end = jazz16_sb_irq;
res->irq_resource[0].flags = IORESOURCE_IRQ;
if (jazz16_mpu401_irq) {
res->irq_resource[1].start = jazz16_mpu401_irq;
res->irq_resource[1].end = jazz16_mpu401_irq;
res->irq_resource[1].flags = IORESOURCE_IRQ;
}
res->dma_resource[0].start = jazz16_sb_dma1;
res->dma_resource[0].end = jazz16_sb_dma1;
res->dma_resource[0].flags = IORESOURCE_DMA;
if (jazz16_sb_dma2 != jazz16_sb_dma1) {
res->dma_resource[1].start = jazz16_sb_dma2;
res->dma_resource[1].end = jazz16_sb_dma2;
res->dma_resource[1].flags = IORESOURCE_DMA;
}
res->port_resource[1].start = jazz16_mpu401_port;
res->port_resource[1].end = jazz16_mpu401_port + 2 - 1;
res->port_resource[1].flags = IORESOURCE_IO;
- } else
return -EINVAL;
- return 0;
+}
+/* Disables the device if supported. */ +static int jazz16pnp_disable_resources(struct pnp_dev *dev) +{
- if (dev == jazz16_gameport_dev) {
return -ENOSYS;
- } else if (dev == jazz16_sb_dev) {
if (jazz16_sb_port)
jazz16_irq_dma_setup(jazz16_sb_port, 0, 0, 0, 0);
jazz16_port_setup(0, 0);
if (jazz16pnp_fm_res) {
release_resource(jazz16pnp_fm_res);
jazz16pnp_fm_res = NULL;
}
dev->active = false;
return 0;
- } else {
return -EINVAL;
- }
+}
+#define PNP_RES_IS_SET(res,type,TYPE,i) \
- (((res)->type##_resource[i].flags & (IORESOURCE_##TYPE | IORESOURCE_UNSET)) \
- == IORESOURCE_##TYPE)
+static int jazz16pnp_set_resources(struct pnp_dev *dev, struct pnp_resource_table *res) +{
- unsigned int sbirq, mpuirq, dma1, dma2;
- if (dev == jazz16_gameport_dev)
return -ENOSYS;
- else if (dev == jazz16_sb_dev) {
if (PNP_RES_IS_SET(res, dma, DMA, 0))
dma1 = res->dma_resource[0].start;
else
return -EINVAL;
if (PNP_RES_IS_SET(res, dma, DMA, 1))
dma2 = res->dma_resource[1].start;
else
dma2 = dma1; /* "half duplex" operation. */
if (PNP_RES_IS_SET(res, irq, IRQ, 0))
sbirq = res->irq_resource[0].start;
else
return -EINVAL;
if (PNP_RES_IS_SET(res, irq, IRQ, 1))
mpuirq = res->irq_resource[1].start;
else
mpuirq = 0; /* MPU-401 driver supports this. */
if (! PNP_RES_IS_SET(res, port, IO, 0))
return -EINVAL;
if (! PNP_RES_IS_SET(res, port, IO, 1))
return -EINVAL;
/* Block the OPL3 alias to avoid conflicts. */
jazz16pnp_fm_res = request_region(0x388, 4, "SoundBlaster FM");
/* Avoid setting the mpu port after setting the sb port
because doing so will glitch the mpu port from the
previous one to the new one. */
jazz16_port_setup(res->port_resource[0].start,
res->port_resource[1].start);
jazz16_irq_dma_setup(jazz16_sb_port, sbirq, mpuirq, dma1, dma2);
dev->active = true;
return 0;
- } else
return -EINVAL;
+} +#undef PNP_RES_IS_SET
+static struct pnp_protocol jazz16pnp_protocol = {
- .name = "Jazz16 PnP",
- .get = jazz16pnp_get_resources,
- .set = jazz16pnp_set_resources,
- .disable = jazz16pnp_disable_resources,
+};
+static uint __init jazz16_check(unsigned int base) +{
- if (my_sbdsp_reset(base))
return 0;
- if (!(my_sbdsp_command(base, SB_DSP_GET_JAZZ_VERSION)))
return 0;
- return SB_VERSION_IS_JAZZ16(my_sbdsp_get_byte(base));
+}
+static int __init jazz16pnp_init(void) +{
- int err = 0;
- unsigned int base, mpubase;
- if (jazz16pnp_disable == 1) {
printk(PFX_INFO "Jazz16 Plug & Play support disabled.\n");
return 0;
- }
- if (!request_region(SB_JAZZ16_CONFIG_PORT, 1, "Jazz16 PnP probe"))
return -EBUSY;
- for (mpubase = 0x300; mpubase <= 0x330; mpubase += 0x10)
if (request_region(mpubase, 2, "Jazz16 PnP probe"))
break;
- if (mpubase > 0x330)
goto out_no_mpubase;
- if (jazz16pnp_verbose)
printk(PFX_DEBUG "Scanning for Jazz16 cards...\n");
- for (base = 0x260; base >= 0x210; base -= 0x10) {
if (!request_region(base, 16, "Jazz16 PnP probe"))
continue;
if (jazz16pnp_verbose)
printk(PFX_DEBUG "Probing at %#x (with MPU at %#x).\n",
base, mpubase);
jazz16_port_setup(base, mpubase);
if (jazz16_check(base))
jazz16pnp_count++;
jazz16_irq_dma_setup(base, 0, 0, 0, 0);
jazz16_port_setup(0, 0);
release_region(base, 16);
if (jazz16pnp_count)
break;
- }
- if (base < 0x210)
goto out_no_sbbase;
- if (!jazz16pnp_count) {
err = -ENODEV;
goto out_no_devices;
- }
- if (pnp_register_protocol(&jazz16pnp_protocol) < 0)
err = -ENOMEM;
- else {
if (jazz16pnp_add_gameport())
printk(PFX_WARN "Failed to add game port.\n");
if (jazz16pnp_add_sb())
printk(PFX_WARN "Failed to add SB port.\n");
err = 0;
- }
+out_no_devices:
- printk(PFX_INFO "%u Jazz16 card%s detected.\n", jazz16pnp_count,
jazz16pnp_count == 1 ? "" : "s");
+out_no_sbbase:
- release_region(mpubase, 2);
+out_no_mpubase:
- release_region(SB_JAZZ16_CONFIG_PORT, 1);
- return err;
+} +module_init(jazz16pnp_init);
+static void __exit jazz16pnp_exit(void) +{
- pnp_unregister_protocol(&jazz16pnp_protocol);
+} +module_exit(jazz16pnp_exit);
-- Rask Ingemann Lambertsen _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On 04/12/2007 09:55 PM, Rask Ingemann Lambertsen wrote:
- Add code to detect and PnP protocol to manage Media Vision Jazz16 sound cards.
Tested with a Jazz16 based sound card and Linux 2.6.20.6.
Just got around to giving this a spin again and unfortunately the preffered options code isn't working for me:
rene@5bt1:~$ cat /sys/bus/pnp/devices/02:01/options Dependent: 01 - Priority preferred port 0x220-0x220, align 0x0, size 0x10, 10-bit address decoding port 0x330-0x330, align 0x0, size 0x2, 10-bit address decoding port 0x388-0x388, align 0x0, size 0x4, 10-bit address decoding irq 5 High-Edge irq 2/9 High-Edge dma 1 8-bit compatible Dependent: 02 - Priority acceptable port 0x210-0x260, align 0xf, size 0x10, 10-bit address decoding port 0x300-0x330, align 0xf, size 0x2, 10-bit address decoding port 0x388-0x388, align 0x0, size 0x4, 10-bit address decoding irq 3,5,7,2/9,10,15 High-Edge irq 3,5,7,2/9,10,15 High-Edge dma 1,3,5,7 8-bit&16-bit compatible Dependent: 03 - Priority acceptable port 0x210-0x260, align 0xf, size 0x10, 10-bit address decoding port 0x300-0x330, align 0xf, size 0x2, 10-bit address decoding port 0x388-0x388, align 0x0, size 0x4, 10-bit address decoding irq 3,5,7,2/9,10,15 High-Edge dma 1,3,5,7 8-bit&16-bit compatible rene@5bt1:~$ cat /sys/bus/pnp/devices/02:01/resources state = disabled rene@5bt1:~$ su -c "modprobe snd-jazz16" rene@5bt1:~$ cat /sys/bus/pnp/devices/02:01/resources state = active io 0x210-0x21f io 0x300-0x301 io 0x388-0x38b irq 5 irq 7 dma 1
Ports 210 and 300 are first from the acceptables, not the preferreds and the irq 7 is also not preffered for MPU. Yes, ports 220, 330 and irq 9 are free.
Looking back through what I sent earlier, I see I sent you a wrong patch then so I'm not sure anymore what I tested and I don't have time to look at it now. Thought I'd let you know though.
Rene.
On Fri, Apr 20, 2007 at 07:27:25PM +0200, Rene Herman wrote:
Just got around to giving this a spin again and unfortunately the preffered options code isn't working for me:
rene@5bt1:~$ cat /sys/bus/pnp/devices/02:01/options Dependent: 01 - Priority preferred port 0x220-0x220, align 0x0, size 0x10, 10-bit address decoding port 0x330-0x330, align 0x0, size 0x2, 10-bit address decoding port 0x388-0x388, align 0x0, size 0x4, 10-bit address decoding irq 5 High-Edge irq 2/9 High-Edge dma 1 8-bit compatible
Do you have a PCI device like this one? /sbin/lspci -v:
00:07.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 01) Flags: medium devsel, IRQ 9
I don't know who to blame, but I know of no way of moving that device off of IRQ 9. It may also just be a bug in the PCI code, because lspci -v -b gives:
00:07.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 01) Flags: medium devsel
I.e. no IRQ as seen from the bus.
On 04/20/2007 10:00 PM, Rask Ingemann Lambertsen wrote:
On Fri, Apr 20, 2007 at 07:27:25PM +0200, Rene Herman wrote:
Just got around to giving this a spin again and unfortunately the preffered options code isn't working for me:
Do you have a PCI device like this one? /sbin/lspci -v:
00:07.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 01) Flags: medium devsel, IRQ 9
Mmm, yes, I do. Was on an Intel 430VX chipset with a PIIX3 last time and on a 430TX with the PIIX4 this time.
I don't know who to blame, but I know of no way of moving that device off of IRQ 9.
Indeed; it seems to be a well-known problem.
The Intel 430TX and 440BX (which also uses the PIIX4 if I'm not mistaken) were hugely popular chipsets in the later generation of boards that still had ISA slots and given that noone will deperately want the MPU-401 IRQ assigned; how would you feel about the attached? Just adds the preffered options minus the MPU IRQ as the first acceptable. Works for me...
I ran the driver through a complete test again. Playback, capture (from line, CD and mic), the OPL3 synth and MPU-401 out- and input (both with and without the MPU-401 IRQ) and all work fine. Feel free to add my signed-off to the ALSA part.
As to the PnP part; other than that IRQ9 thing everything also working fine and if you think the attached is ugly; I don't much care. I still have the possible objection with the BIOS maybe needing to know about the card anyway so it can route the IRQ to ISA (and the slight discomfort about Jazz16 code in drivers/pnp). But next iteration can be final.
If Adam still isn't commenting by then, let's just feed it through Andrew Morton and LKML.
Rene.
commit ff9c54ec792041f6f7f45d5abceb5af47a71a2f7 Author: Rene Herman rene.herman@gmail.com Date: Sat Apr 21 09:07:44 2007 +0200
IRQ 9 is unavailable on PIIX4 boards -- the MPU-401 UART can do without an IRQ as well...
diff --git a/drivers/pnp/jazz16pnp.c b/drivers/pnp/jazz16pnp.c index b71381b..020b6bb 100644 --- a/drivers/pnp/jazz16pnp.c +++ b/drivers/pnp/jazz16pnp.c @@ -233,6 +233,11 @@ static int __init jazz16pnp_add_sb(void) jazz16pnp_pref_dmas, 1)) goto out_no_sboption; if (!jazz16pnp_easy_option(sbdev, PNP_RES_PRIORITY_ACCEPTABLE, + jazz16pnp_pref_ports, 3, + jazz16pnp_pref_irqs, 1, + jazz16pnp_pref_dmas, 1)) + goto out_no_sboption; + if (!jazz16pnp_easy_option(sbdev, PNP_RES_PRIORITY_ACCEPTABLE, jazz16pnp_ports, 3, jazz16pnp_irqs, 2, jazz16pnp_dmas, 1))
On Sun, Apr 22, 2007 at 06:27:44PM +0200, Rene Herman wrote:
The Intel 430TX and 440BX (which also uses the PIIX4 if I'm not mistaken) were hugely popular chipsets in the later generation of boards that still had ISA slots and given that noone will deperately want the MPU-401 IRQ assigned; how would you feel about the attached? Just adds the preffered options minus the MPU IRQ as the first acceptable. Works for me...
Fine with me. Maybe the MPU IRQ should be omitted alltogether? You tell me.
Thanks for the testing you've done.
As to the PnP part; other than that IRQ9 thing everything also working fine
Aren't you having problems loading the module after a resource allocation failure? I find that I need this additional patch to be able to retry:
--- linux-2.6.20.6-clean/drivers/pnp/driver.c 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20.6-ril/drivers/pnp/driver.c 2007-04-15 10:10:35.000000000 +0200 @@ -96,13 +96,13 @@ if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) { error = pnp_activate_dev(pnp_dev); if (error < 0) - return error; + goto fail; } } else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE) == PNP_DRIVER_RES_DISABLE) { error = pnp_disable_dev(pnp_dev); if (error < 0) - return error; + goto fail; } error = 0; if (pnp_drv->probe) {
Without it, the device stays attached to the driver. What happens is
pnp_attach_device (device, driver); error = pnp_activate_dev(device); if (error < 0) return error; ... fail: pnp_detach_device (device, driver); return error;
On 04/23/2007 08:52 PM, Rask Ingemann Lambertsen wrote:
On Sun, Apr 22, 2007 at 06:27:44PM +0200, Rene Herman wrote:
The Intel 430TX and 440BX (which also uses the PIIX4 if I'm not mistaken) were hugely popular chipsets in the later generation of boards that still had ISA slots and given that noone will deperately want the MPU-401 IRQ assigned; how would you feel about the attached? Just adds the preffered options minus the MPU IRQ as the first acceptable. Works for me...
Fine with me. Maybe the MPU IRQ should be omitted alltogether? You tell me.
"Using the hardware to its fullest potential" should probably be called the preferred option. I mean, what's the fun of playing with this old hardware if we're not going to use it fully? :)
So as submitted (or nothing at all but if we suppose the driver will be seeing practical use, guarding against that PIIX4 seems best) is nicest I feel.
Aren't you having problems loading the module after a resource allocation failure? I find that I need this additional patch to be able to retry:
I've had to remove the jazz16 again for a bit and I haven't tested an allocation failure yet. That looks to be an "obvious fix" though. Now all we need is a PnP maintainer...
Rene.
At Thu, 26 Apr 2007 14:55:03 +0200, Rene Herman wrote:
Aren't you having problems loading the module after a resource allocation failure? I find that I need this additional patch to be able to retry:
I've had to remove the jazz16 again for a bit and I haven't tested an allocation failure yet. That looks to be an "obvious fix" though. Now all we need is a PnP maintainer...
I'd suggest to post LKML once, then. If you get no negative feedback, let's try to push together with ALSA patch.
Takashi
On 04/26/2007 03:00 PM, Takashi Iwai wrote:
I've had to remove the jazz16 again for a bit and I haven't tested an allocation failure yet. That looks to be an "obvious fix" though. Now all we need is a PnP maintainer...
I'd suggest to post LKML once, then. If you get no negative feedback, let's try to push together with ALSA patch.
I have one other email address for Adam Belay (added to CC). Let's see if that one's active...
Rene.
participants (3)
-
Rask Ingemann Lambertsen
-
Rene Herman
-
Takashi Iwai