All of lore.kernel.org
 help / color / mirror / Atom feed
* mpu401_pnp
@ 2004-08-31 20:50 castet.matthieu
  2005-02-07  8:46 ` mpu401_pnp Clemens Ladisch
  0 siblings, 1 reply; 11+ messages in thread
From: castet.matthieu @ 2004-08-31 20:50 UTC (permalink / raw)
  To: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 677 bytes --]


Hello,

I send you a mpu401 modules that support pnpbios.
I don't add it to the mpu401 because it would add too much define.
I am not a specialist in Kconfig edit, so for testing on my comptuter, I only
remplace traditionnal mpu401 with mpu401_pnp.

Also I clear the function that create the mpu (snd_card_mpu401_add), and I think
you could re-use it for acpi_pnp insted of adding define.

As you can see, because of a bug in pnpbios code, sometime it doesn't find a
irq, so it add a litle hack waiting the bug is fix in the kernel.

With that, an some script (hotplug for example), the mpu401 is automatiquely
detected(at least on my i810 chipset).

Matthieu

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mpu401_pnp.c --]
[-- Type: text/x-csrc; name="mpu401_pnp.c", Size: 5575 bytes --]

/*
 *  Driver for generic MPU-401 boards (UART mode only)
 *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
 *
 *  Copyright (c) 2004 by Castet Matthieu <castet.matthieu@free.fr>
 *  portd on mpu401.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
 *   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
 *
 */

#include <sound/driver.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/mpu401.h>
#include <sound/initval.h>
#include <linux/pnp.h>


MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("MPU-401 UART");
MODULE_LICENSE("GPL");
MODULE_CLASSES("{sound}");

static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
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 boot_devs;

module_param_array(index, int, boot_devs, 0444);
MODULE_PARM_DESC(index, "Index value for MPU-401 device.");
MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
module_param_array(id, charp, boot_devs, 0444);
MODULE_PARM_DESC(id, "ID string for MPU-401 device.");
MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
module_param_array(enable, bool, boot_devs, 0444);
MODULE_PARM_DESC(enable, "Enable MPU-401 device.");
MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);

#define IO_EXTENT 2

#define BROKEN_PNPBIOS

static int snd_card_mpu401_add(int dev, snd_card_t **pcard, long port, int irq, char * optional_description) 
{
	int err;
	snd_card_t *card;

	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);
	if (irq >= 0) {
		sprintf(card->longname + strlen(card->longname), "IRQ %d", irq);
	} else {
		strcat(card->longname, "polled");
	}
	if (optional_description)
		strlcat(card->longname, optional_description, sizeof(card->longname));

	if (snd_mpu401_uart_new(card, 0,
				MPU401_HW_MPU401,
				port, 0,
				irq, irq >= 0 ? SA_INTERRUPT : 0, NULL) < 0) {
		printk(KERN_ERR "MPU401 not detected at 0x%lx\n", port);
		snd_card_free(card);
		return -ENODEV;
	}
	if ((err = snd_card_register(card)) < 0) {
		snd_card_free(card);
		return err;
	}
	*pcard = card;
	return 0;
}

static struct pnp_device_id pnp_devids[] = {
	{ .id = "PNPb006", .driver_data = 0 },
	{ .id = "", },
};

MODULE_DEVICE_TABLE(pnp, pnp_devids);

static int __devinit snd_card_mpu401_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did) {
	long port;
	int irq;
	snd_card_t *card = NULL;
	int ret;
	
	static int card_dev = 0;

	if (card_dev >= SNDRV_CARDS)
		return -ENODEV;

	if (!enable[card_dev]) {
		card_dev++;
		return -ENOENT;
	}

#ifdef BROKEN_PNPBIOS
retry:
#endif
	if (!pnp_port_valid(dev, 0) ||
			pnp_port_flags(dev,0) & IORESOURCE_DISABLED) {
		printk(KERN_WARNING "No io port !\n");
		return -ENODEV;
	}
	if (pnp_port_len(dev, 0) < IO_EXTENT) {
		printk(KERN_WARNING "io port len : %ld (expected : %d) !\n",
				pnp_port_len(dev, 0), 
				IO_EXTENT);
		return -ENODEV;
	}
	port = pnp_port_start(dev,0);

	if (!pnp_irq_valid(dev,0)||
			pnp_irq_flags(dev,0) & IORESOURCE_DISABLED) {
#ifdef BROKEN_PNPBIOS
		//XXX parser bug
		static int retry = 0;
		if (dev->dependent && !retry) {
			dev->active = 0;
			printk(KERN_WARNING "broken pnpbios retry : %d!\n",pnp_assign_resources(dev, 2));
			dev->active = 1;
			retry = 1;
			goto retry;
		}
#endif
		printk(KERN_WARNING "No irq !\n");
		irq = -1;
	}
	else {
		irq = pnp_irq(dev,0);
	}

	printk(KERN_INFO "snd_card_mpu401 pnpbios :"
		"%s port 0x%03lx, irq=%d\n",
		pnp_dev_name(dev), port, irq);
	
	//XXX pnp_dev_name(pnp_dev) give me a empty string ...
	/*
	strcat(option, ", ");
	strlcat(option, pnp_dev_name(pnp_dev), sizeof(card->longname));
	*/
	ret = snd_card_mpu401_add(card_dev, &card, port, irq, NULL); 
	if (ret >= 0)
		pnp_set_drvdata(dev, card);

	return ret;
}

static void snd_card_mpu401_pnp_remove(struct pnp_dev *dev) {
	snd_card_t *card = (snd_card_t *)pnp_get_drvdata(dev);
	if (!card) {
		BUG();
		return;
	}

	snd_card_disconnect(card);
	snd_card_free_in_thread(card);
}
	
static struct pnp_driver snd_mpu401_pnp_driver = {
	.name           = "mpu401",
	.id_table       = pnp_devids,
	.probe          = snd_card_mpu401_pnp_probe,
	.remove		= snd_card_mpu401_pnp_remove,
};

static int __init alsa_card_mpu401_init(void)
{
	int ret = pnp_register_driver(&snd_mpu401_pnp_driver);
	if (ret == 0) {
		pnp_unregister_driver(&snd_mpu401_pnp_driver);
	}
		
	if (ret <= 0) {
		return -ENODEV;
	}

	return 0;
}

static void __exit alsa_card_mpu401_exit(void)
{
	pnp_unregister_driver(&snd_mpu401_pnp_driver);
}

module_init(alsa_card_mpu401_init)
module_exit(alsa_card_mpu401_exit)

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2005-02-11 10:00 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-08-31 20:50 mpu401_pnp castet.matthieu
2005-02-07  8:46 ` mpu401_pnp Clemens Ladisch
2005-02-07 10:40   ` mpu401_pnp castet.matthieu
2005-02-07 12:10   ` mpu401_pnp matthieu castet
2005-02-07 12:59   ` mpu401_pnp matthieu castet
2005-02-07 15:54     ` mpu401_pnp Clemens Ladisch
2005-02-07 19:13       ` mpu401_pnp matthieu castet
2005-02-07 19:23       ` mpu401_pnp matthieu castet
2005-02-09 16:46         ` mpu401_pnp Clemens Ladisch
2005-02-09 14:17       ` mpu401_pnp matthieu castet
2005-02-11 10:00     ` mpu401_pnp Clemens Ladisch

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.