Commit b21c3168 authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA CVS update - Clemens Ladisch <clemens@ladisch.de>

Documentation,MPU401 UART
integrate MPU-401 ACPI PnP from alsa-driver
parent bcd243ff
...@@ -755,8 +755,10 @@ Module parameters ...@@ -755,8 +755,10 @@ Module parameters
port - port number or -1 (disable) port - port number or -1 (disable)
irq - IRQ number or -1 (disable) irq - IRQ number or -1 (disable)
acpipnp - ACPI PnP detection - 0 = disable, 1 = enable (default)
Module supports multiple devices (max 8). 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 snd-mtpav Module snd-mtpav
---------------- ----------------
......
...@@ -2,6 +2,12 @@ ...@@ -2,6 +2,12 @@
* Driver for generic MPU-401 boards (UART mode only) * Driver for generic MPU-401 boards (UART mode only)
* Copyright (c) by Jaroslav Kysela <perex@suse.cz> * 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>
*
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -21,14 +27,17 @@ ...@@ -21,14 +27,17 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/wait.h> #ifdef CONFIG_ACPI_BUS
#include <linux/sched.h> #include <acpi/acpi_bus.h>
#include <linux/slab.h> #endif
#include <sound/core.h> #include <sound/core.h>
#include <sound/mpu401.h> #include <sound/mpu401.h>
#define SNDRV_GET_ID #define SNDRV_GET_ID
#include <sound/initval.h> #include <sound/initval.h>
#include <linux/delay.h>
#ifdef CONFIG_ACPI_BUS
#define USE_ACPI_PNP
#endif
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("MPU-401 UART"); MODULE_DESCRIPTION("MPU-401 UART");
...@@ -38,6 +47,9 @@ MODULE_CLASSES("{sound}"); ...@@ -38,6 +47,9 @@ MODULE_CLASSES("{sound}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable 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 };
#endif
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* MPU-401 port number */ static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* MPU-401 port number */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* MPU-401 IRQ */ static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* MPU-401 IRQ */
#ifdef CONFIG_X86_PC9800 #ifdef CONFIG_X86_PC9800
...@@ -53,6 +65,11 @@ MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); ...@@ -53,6 +65,11 @@ MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(enable, "Enable MPU-401 device."); MODULE_PARM_DESC(enable, "Enable MPU-401 device.");
MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
#ifdef USE_ACPI_PNP
MODULE_PARM(acpipnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(acpipnp, "ACPI PnP detection for MPU-401 device.");
MODULE_PARM_SYNTAX(acpipnp, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
#endif
MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
MODULE_PARM_DESC(port, "Port # for MPU-401 device."); MODULE_PARM_DESC(port, "Port # for MPU-401 device.");
MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
...@@ -65,25 +82,107 @@ MODULE_PARM_DESC(pc98ii, "Roland MPU-PC98II support."); ...@@ -65,25 +82,107 @@ MODULE_PARM_DESC(pc98ii, "Roland MPU-PC98II support.");
MODULE_PARM_SYNTAX(pc98ii, SNDRV_BOOLEAN_FALSE_DESC); MODULE_PARM_SYNTAX(pc98ii, SNDRV_BOOLEAN_FALSE_DESC);
#endif #endif
static snd_card_t *snd_mpu401_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; #ifndef CONFIG_ACPI_BUS
struct acpi_device;
#endif
static snd_card_t *snd_mpu401_legacy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
#ifdef USE_ACPI_PNP
struct mpu401_resources {
unsigned long port;
int irq;
};
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) {
#ifdef CONFIG_IA64
resources->irq = acpi_register_irq(res->data.irq.interrupts[0],
res->data.irq.active_high_low,
res->data.irq.edge_level);
#else
resources->irq = res->data.irq.interrupts[0];
#endif
}
} 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;
}
static int __devinit snd_mpu401_acpi_pnp(int dev, struct acpi_device *device)
{
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))
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));
return -ENODEV;
}
port[dev] = res.port;
irq[dev] = res.irq;
return 0;
}
#endif /* USE_ACPI_PNP */
static int __init snd_card_mpu401_probe(int dev) static int __devinit snd_card_mpu401_probe(int dev, struct acpi_device *device)
{ {
snd_card_t *card; snd_card_t *card;
int err; int err;
#ifdef USE_ACPI_PNP
if (!device) {
#endif
if (port[dev] == SNDRV_AUTO_PORT) { if (port[dev] == SNDRV_AUTO_PORT) {
snd_printk("specify port\n"); snd_printk(KERN_ERR "specify port\n");
return -EINVAL; return -EINVAL;
} }
if (irq[dev] == SNDRV_AUTO_IRQ) { if (irq[dev] == SNDRV_AUTO_IRQ) {
snd_printk("specify or disable IRQ port\n"); snd_printk(KERN_ERR "specify or disable IRQ port\n");
return -EINVAL; return -EINVAL;
} }
#ifdef USE_ACPI_PNP
}
#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); card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL) if (card == NULL)
return -ENOMEM; return -ENOMEM;
strcpy(card->driver, "MPU-401 UART");
strcpy(card->shortname, card->driver);
sprintf(card->longname, "%s at 0x%lx, ", card->shortname, port[dev]);
if (irq[dev] >= 0) {
sprintf(card->longname + strlen(card->longname), "IRQ %d", irq[dev]);
} else {
strcat(card->longname, "polled");
}
#ifdef USE_ACPI_PNP
if (device) {
strcat(card->longname, ", bus id ");
strlcat(card->longname, acpi_device_bid(device), sizeof(card->longname));
}
#endif
if (snd_mpu401_uart_new(card, 0, if (snd_mpu401_uart_new(card, 0,
#ifdef CONFIG_X86_PC9800 #ifdef CONFIG_X86_PC9800
pc98ii[dev] ? MPU401_HW_PC98II : pc98ii[dev] ? MPU401_HW_PC98II :
...@@ -95,22 +194,67 @@ static int __init snd_card_mpu401_probe(int dev) ...@@ -95,22 +194,67 @@ static int __init snd_card_mpu401_probe(int dev)
snd_card_free(card); snd_card_free(card);
return -ENODEV; return -ENODEV;
} }
strcpy(card->driver, "MPU-401 UART");
strcpy(card->shortname, card->driver);
sprintf(card->longname, "%s at 0x%lx, ", card->shortname, port[dev]);
if (irq[dev] >= 0) {
sprintf(card->longname + strlen(card->longname), "IRQ %d", irq[dev]);
} else {
strcat(card->longname, "polled");
}
if ((err = snd_card_register(card)) < 0) { if ((err = snd_card_register(card)) < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
} }
snd_mpu401_cards[dev] = card; #ifdef USE_ACPI_PNP
if (device)
acpi_driver_data(device) = card;
else
#endif
snd_mpu401_legacy_cards[dev] = card;
return 0;
}
#ifdef USE_ACPI_PNP
static int __devinit snd_mpu401_acpi_add(struct acpi_device *device)
{
static int dev;
int err;
for ( ; dev < SNDRV_CARDS; ++dev) {
if (!enable[dev] || !acpipnp[dev])
continue;
err = snd_card_mpu401_probe(dev, device);
if (err < 0)
return err;
++dev;
return 0;
}
return -ENODEV;
}
static int __devexit snd_mpu401_acpi_remove(struct acpi_device *device,
int type)
{
snd_card_t *card;
if (!device)
return -EINVAL;
card = (snd_card_t *)acpi_driver_data(device);
if (!card)
return -EINVAL;
snd_card_disconnect(card);
snd_card_free_in_thread(card);
acpi_driver_data(device) = NULL;
return 0; 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),
},
};
#endif /* USE_ACPI_PNP */
static int __init alsa_card_mpu401_init(void) static int __init alsa_card_mpu401_init(void)
{ {
int dev, cards = 0; int dev, cards = 0;
...@@ -118,12 +262,24 @@ static int __init alsa_card_mpu401_init(void) ...@@ -118,12 +262,24 @@ static int __init alsa_card_mpu401_init(void)
for (dev = 0; dev < SNDRV_CARDS; dev++) { for (dev = 0; dev < SNDRV_CARDS; dev++) {
if (!enable[dev]) if (!enable[dev])
continue; continue;
if (snd_card_mpu401_probe(dev) >= 0) #ifdef USE_ACPI_PNP
if (acpipnp[dev] && !acpi_disabled)
continue;
#endif
if (snd_card_mpu401_probe(dev, NULL) >= 0)
cards++; cards++;
} }
#ifdef USE_ACPI_PNP
if (!acpi_disabled)
cards += acpi_bus_register_driver(&snd_mpu401_acpi_driver);
#endif
if (!cards) { if (!cards) {
#ifdef MODULE #ifdef MODULE
printk(KERN_ERR "MPU-401 device not found or device busy\n"); printk(KERN_ERR "MPU-401 device not found or device busy\n");
#endif
#ifdef USE_ACPI_PNP
if (!acpi_disabled)
acpi_bus_unregister_driver(&snd_mpu401_acpi_driver);
#endif #endif
return -ENODEV; return -ENODEV;
} }
...@@ -134,8 +290,12 @@ static void __exit alsa_card_mpu401_exit(void) ...@@ -134,8 +290,12 @@ static void __exit alsa_card_mpu401_exit(void)
{ {
int idx; int idx;
#ifdef USE_ACPI_PNP
if (!acpi_disabled)
acpi_bus_unregister_driver(&snd_mpu401_acpi_driver);
#endif
for (idx = 0; idx < SNDRV_CARDS; idx++) for (idx = 0; idx < SNDRV_CARDS; idx++)
snd_card_free(snd_mpu401_cards[idx]); snd_card_free(snd_mpu401_legacy_cards[idx]);
} }
module_init(alsa_card_mpu401_init) module_init(alsa_card_mpu401_init)
...@@ -143,22 +303,28 @@ module_exit(alsa_card_mpu401_exit) ...@@ -143,22 +303,28 @@ module_exit(alsa_card_mpu401_exit)
#ifndef MODULE #ifndef MODULE
/* format is: snd-mpu401=enable,index,id,port,irq */ /* format is: snd-mpu401=enable,index,id,acpipnp[,pc98ii],port,irq */
static int __init alsa_card_mpu401_setup(char *str) static int __init alsa_card_mpu401_setup(char *str)
{ {
static unsigned __initdata nr_dev = 0; static unsigned __initdata nr_dev = 0;
int __attribute__ ((__unused__)) pnp = INT_MAX;
if (nr_dev >= SNDRV_CARDS) if (nr_dev >= SNDRV_CARDS)
return 0; return 0;
(void)(get_option(&str,&enable[nr_dev]) == 2 && (void)(get_option(&str,&enable[nr_dev]) == 2 &&
get_option(&str,&index[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 &&
get_id(&str,&id[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 &&
get_option(&str,&pnp) == 2 &&
#ifdef CONFIG_X86_PC9800 #ifdef CONFIG_X86_PC9800
get_option(&str,&pc98ii[nr_dev]) == 2 && get_option(&str,&pc98ii[nr_dev]) == 2 &&
#endif #endif
get_option_long(&str,&port[nr_dev]) == 2 && get_option_long(&str,&port[nr_dev]) == 2 &&
get_option(&str,&irq[nr_dev]) == 2); get_option(&str,&irq[nr_dev]) == 2);
#ifdef USE_ACPI_PNP
if (pnp != INT_MAX)
acpipnp[nr_dev] = pnp;
#endif
nr_dev++; nr_dev++;
return 1; return 1;
} }
......
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