Commit 7d177fdd authored by Jaroslav Kysela's avatar Jaroslav Kysela

[ALSA] MPU-401 PnP support

Documentation,MPU401 UART
Replace the ACPI PnP code with generic PnP calls.
Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
parent 2da0e44a
......@@ -853,10 +853,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
port - port number or -1 (disable)
irq - IRQ number or -1 (disable)
acpipnp - ACPI PnP detection - 0 = disable, 1 = enable (default)
pnp - PnP detection - 0 = disable, 1 = enable (default)
Module supports multiple devices (max 8) and ACPI PnP. If PnP is not
used (or ACPI not enabled), port and irq must be specified.
Module supports multiple devices (max 8) and PnP.
Module snd-mtpav
----------------
......
/*
* Driver for generic MPU-401 boards (UART mode only)
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
*
* ACPI PnP Copyright (c) 2004 by Clemens Ladisch <clemens@ladisch.de>
* based on 8250_acpi.c
* Copyright (c) 2002-2003 Matthew Wilcox for Hewlett-Packard
* Copyright (C) 2004 Hewlett-Packard Co
* Bjorn Helgaas <bjorn.helgaas@hp.com>
* Copyright (c) 2004 by Castet Matthieu <castet.matthieu@free.fr>
*
*
* This program is free software; you can redistribute it and/or modify
......@@ -27,27 +22,21 @@
#include <sound/driver.h>
#include <linux/init.h>
#ifdef CONFIG_ACPI_BUS
#include <linux/acpi.h>
#endif
#include <linux/pnp.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/mpu401.h>
#include <sound/initval.h>
#ifdef CONFIG_ACPI_BUS
#define USE_ACPI_PNP
#endif
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("MPU-401 UART");
MODULE_LICENSE("GPL");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* exclude the first card */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
#ifdef USE_ACPI_PNP
static int acpipnp[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
#ifdef CONFIG_PNP
static int pnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
#endif
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* MPU-401 port number */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* MPU-401 IRQ */
......@@ -58,79 +47,61 @@ module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for MPU-401 device.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable MPU-401 device.");
#ifdef USE_ACPI_PNP
module_param_array(acpipnp, bool, NULL, 0444);
MODULE_PARM_DESC(acpipnp, "ACPI PnP detection for MPU-401 device.");
#ifdef CONFIG_PNP
module_param_array(pnp, bool, NULL, 0444);
MODULE_PARM_DESC(pnp, "PnP detection for MPU-401 device.");
#endif
module_param_array(port, long, NULL, 0444);
MODULE_PARM_DESC(port, "Port # for MPU-401 device.");
module_param_array(irq, int, NULL, 0444);
MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device.");
#ifndef CONFIG_ACPI_BUS
struct acpi_device;
#endif
static snd_card_t *snd_mpu401_legacy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
static int cards;
#ifdef USE_ACPI_PNP
#ifdef CONFIG_PNP
static int acpi_driver_registered;
#define IO_EXTENT 2
struct mpu401_resources {
unsigned long port;
int irq;
static struct pnp_device_id snd_mpu401_pnpids[] = {
{ .id = "PNPb006" },
{ .id = "" }
};
static acpi_status __devinit snd_mpu401_acpi_resource(struct acpi_resource *res,
void *data)
{
struct mpu401_resources *resources = (struct mpu401_resources *)data;
if (res->id == ACPI_RSTYPE_IRQ) {
if (res->data.irq.number_of_interrupts > 0) {
resources->irq = acpi_register_gsi(res->data.irq.interrupts[0],
res->data.irq.edge_level,
res->data.irq.active_high_low);
}
} else if (res->id == ACPI_RSTYPE_IO) {
if (res->data.io.range_length >= 2) {
resources->port = res->data.io.min_base_address;
}
}
return AE_OK;
}
MODULE_DEVICE_TABLE(pnp, snd_mpu401_pnpids);
static int __devinit snd_mpu401_acpi_pnp(int dev, struct acpi_device *device)
static int __init snd_mpu401_pnp(int dev, struct pnp_dev *device,
const struct pnp_device_id *id)
{
struct mpu401_resources res;
acpi_status status;
res.port = SNDRV_AUTO_PORT;
res.irq = SNDRV_AUTO_IRQ;
status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
snd_mpu401_acpi_resource, &res);
if (ACPI_FAILURE(status))
if (!pnp_port_valid(device, 0) ||
pnp_port_flags(device, 0) & IORESOURCE_DISABLED) {
snd_printk(KERN_ERR "no PnP port\n");
return -ENODEV;
if (res.port == SNDRV_AUTO_PORT || res.irq == SNDRV_AUTO_IRQ) {
snd_printk(KERN_ERR "no port or irq in %s _CRS\n",
acpi_device_bid(device));
}
if (pnp_port_len(device, 0) < IO_EXTENT) {
snd_printk(KERN_ERR "PnP port length is %ld, expected %d\n",
pnp_port_len(device, 0), IO_EXTENT);
return -ENODEV;
}
port[dev] = res.port;
irq[dev] = res.irq;
port[dev] = pnp_port_start(device, 0);
if (!pnp_irq_valid(device, 0) ||
pnp_irq_flags(device, 0) & IORESOURCE_DISABLED) {
snd_printk(KERN_WARNING "no PnP irq, using polling\n");
irq[dev] = -1;
} else {
irq[dev] = pnp_irq(device, 0);
}
return 0;
}
#endif
#endif /* USE_ACPI_PNP */
static int __devinit snd_card_mpu401_probe(int dev, struct acpi_device *device)
static int __devinit snd_card_mpu401_probe(int dev, struct pnp_dev *device,
const struct pnp_device_id *pnp_id)
{
snd_card_t *card;
int err;
#ifdef USE_ACPI_PNP
#ifdef CONFIG_PNP
if (!device) {
#endif
if (port[dev] == SNDRV_AUTO_PORT) {
......@@ -138,33 +109,30 @@ static int __devinit snd_card_mpu401_probe(int dev, struct acpi_device *device)
return -EINVAL;
}
if (irq[dev] == SNDRV_AUTO_IRQ) {
snd_printk(KERN_ERR "specify or disable IRQ port\n");
snd_printk(KERN_ERR "specify or disable IRQ\n");
return -EINVAL;
}
#ifdef USE_ACPI_PNP
#ifdef CONFIG_PNP
} else {
if ((err = snd_mpu401_pnp(dev, device, pnp_id)) < 0)
return err;
}
#endif
#ifdef USE_ACPI_PNP
if (device && (err = snd_mpu401_acpi_pnp(dev, device)) < 0)
return err;
#endif
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
strcpy(card->driver, "MPU-401 UART");
strcpy(card->shortname, card->driver);
sprintf(card->longname, "%s at 0x%lx, ", card->shortname, port[dev]);
sprintf(card->longname, "%s at %#lx, ", card->shortname, port[dev]);
if (irq[dev] >= 0) {
sprintf(card->longname + strlen(card->longname), "IRQ %d", irq[dev]);
sprintf(card->longname + strlen(card->longname), "irq %d", irq[dev]);
} else {
strcat(card->longname, "polled");
}
#ifdef USE_ACPI_PNP
#ifdef CONFIG_PNP
if (device) {
strcat(card->longname, ", ACPI id ");
strlcat(card->longname, acpi_device_bid(device), sizeof(card->longname));
snd_card_set_dev(card, &device->dev);
}
#endif
if (snd_mpu401_uart_new(card, 0,
......@@ -179,27 +147,26 @@ static int __devinit snd_card_mpu401_probe(int dev, struct acpi_device *device)
snd_card_free(card);
return err;
}
#ifdef USE_ACPI_PNP
#ifdef CONFIG_PNP
if (device)
acpi_driver_data(device) = card;
pnp_set_drvdata(device, card);
else
#endif
snd_mpu401_legacy_cards[dev] = card;
++cards;
return 0;
}
#ifdef USE_ACPI_PNP
static int __devinit snd_mpu401_acpi_add(struct acpi_device *device)
#ifdef CONFIG_PNP
static int __devinit snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev,
const struct pnp_device_id *id)
{
static int dev;
int err;
for ( ; dev < SNDRV_CARDS; ++dev) {
if (!enable[dev] || !acpipnp[dev])
if (!enable[dev] || !pnp[dev])
continue;
err = snd_card_mpu401_probe(dev, device);
err = snd_card_mpu401_probe(dev, pnp_dev, id);
if (err < 0)
return err;
++dev;
......@@ -208,59 +175,45 @@ static int __devinit snd_mpu401_acpi_add(struct acpi_device *device)
return -ENODEV;
}
static int __devexit snd_mpu401_acpi_remove(struct acpi_device *device,
int type)
static void __devexit snd_mpu401_pnp_remove(struct pnp_dev *dev)
{
snd_card_t *card;
if (!device)
return -EINVAL;
card = (snd_card_t *)acpi_driver_data(device);
if (!card)
return -EINVAL;
snd_card_t *card = (snd_card_t *) pnp_get_drvdata(dev);
snd_card_disconnect(card);
snd_card_free_in_thread(card);
acpi_driver_data(device) = NULL;
return 0;
}
static struct acpi_driver snd_mpu401_acpi_driver = {
.name = "MPU-401 Driver",
.class = "mpu401",
.ids = "PNPB006",
.ops = {
.add = snd_mpu401_acpi_add,
.remove = __devexit_p(snd_mpu401_acpi_remove),
},
static struct pnp_driver snd_mpu401_pnp_driver = {
.name = "mpu401",
.id_table = snd_mpu401_pnpids,
.probe = snd_mpu401_pnp_probe,
.remove = __devexit_p(snd_mpu401_pnp_remove),
};
#endif /* USE_ACPI_PNP */
#endif
static int __init alsa_card_mpu401_init(void)
{
int dev;
int dev, devices = 0;
#ifdef USE_ACPI_PNP
if (acpi_bus_register_driver(&snd_mpu401_acpi_driver) >= 0)
acpi_driver_registered = 1;
#endif
for (dev = 0; dev < SNDRV_CARDS; dev++) {
if (!enable[dev])
continue;
#ifdef USE_ACPI_PNP
if (acpipnp[dev] && acpi_driver_registered)
#ifdef CONFIG_PNP
if (pnp[dev])
continue;
#endif
snd_card_mpu401_probe(dev, NULL);
if (snd_card_mpu401_probe(dev, NULL, NULL) >= 0)
devices++;
}
if (!cards) {
#ifdef CONFIG_PNP
devices += pnp_register_driver(&snd_mpu401_pnp_driver);
#endif
if (!devices) {
#ifdef MODULE
printk(KERN_ERR "MPU-401 device not found or device busy\n");
#endif
#ifdef USE_ACPI_PNP
if (acpi_driver_registered)
acpi_bus_unregister_driver(&snd_mpu401_acpi_driver);
#ifdef CONFIG_PNP
pnp_unregister_driver(&snd_mpu401_pnp_driver);
#endif
return -ENODEV;
}
......@@ -271,9 +224,8 @@ static void __exit alsa_card_mpu401_exit(void)
{
int idx;
#ifdef USE_ACPI_PNP
if (acpi_driver_registered)
acpi_bus_unregister_driver(&snd_mpu401_acpi_driver);
#ifdef CONFIG_PNP
pnp_unregister_driver(&snd_mpu401_pnp_driver);
#endif
for (idx = 0; idx < SNDRV_CARDS; idx++)
snd_card_free(snd_mpu401_legacy_cards[idx]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment