diff options
author | Ondrej Zary <linux@rainbow-software.org> | 2006-07-31 06:51:57 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-09-23 04:39:46 -0400 |
commit | 1c3985580445ef9225c1ea7714d6d963f7626eeb (patch) | |
tree | b3cbc142be479ff13593239c3db6ee132d1d167c | |
parent | f3302a59cf6961712658db63b66ea5902c17d5e1 (diff) |
[ALSA] es18xx - Add PnP BIOS support
This patch adds PnP BIOS support to es18xx driver. It allows ESS ES18xx sound
chips integrated in some notebooks (such as DTK FortisPro TOP-5A) that don't
appear as ISA cards (they aren't recognized by ISA PnP, only by PnP BIOS)
to 'just work' automatically.
Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
-rw-r--r-- | sound/isa/es18xx.c | 219 |
1 files changed, 157 insertions, 62 deletions
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 34998de9968c..85818200333f 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c | |||
@@ -2038,7 +2038,80 @@ MODULE_PARM_DESC(dma2, "DMA 2 # for ES18xx driver."); | |||
2038 | static struct platform_device *platform_devices[SNDRV_CARDS]; | 2038 | static struct platform_device *platform_devices[SNDRV_CARDS]; |
2039 | 2039 | ||
2040 | #ifdef CONFIG_PNP | 2040 | #ifdef CONFIG_PNP |
2041 | static int pnp_registered; | 2041 | static int pnp_registered, pnpc_registered; |
2042 | |||
2043 | static struct pnp_device_id snd_audiodrive_pnpbiosids[] = { | ||
2044 | { .id = "ESS1869" }, | ||
2045 | { .id = "" } /* end */ | ||
2046 | }; | ||
2047 | |||
2048 | MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids); | ||
2049 | |||
2050 | /* PnP main device initialization */ | ||
2051 | static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev, | ||
2052 | struct pnp_resource_table *cfg) | ||
2053 | { | ||
2054 | int err; | ||
2055 | |||
2056 | pnp_init_resource_table(cfg); | ||
2057 | if (port[dev] != SNDRV_AUTO_PORT) | ||
2058 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
2059 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
2060 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
2061 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2062 | pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2); | ||
2063 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
2064 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
2065 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
2066 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
2067 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
2068 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
2069 | if (pnp_device_is_isapnp(pdev)) { | ||
2070 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
2071 | if (err < 0) | ||
2072 | snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n"); | ||
2073 | } | ||
2074 | err = pnp_activate_dev(pdev); | ||
2075 | if (err < 0) { | ||
2076 | snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n"); | ||
2077 | return -EBUSY; | ||
2078 | } | ||
2079 | /* ok. hack using Vendor-Defined Card-Level registers */ | ||
2080 | /* skip csn and logdev initialization - already done in isapnp_configure */ | ||
2081 | if (pnp_device_is_isapnp(pdev)) { | ||
2082 | isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev)); | ||
2083 | isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */ | ||
2084 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2085 | isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */ | ||
2086 | isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */ | ||
2087 | isapnp_cfg_end(); | ||
2088 | } | ||
2089 | port[dev] = pnp_port_start(pdev, 0); | ||
2090 | fm_port[dev] = pnp_port_start(pdev, 1); | ||
2091 | mpu_port[dev] = pnp_port_start(pdev, 2); | ||
2092 | dma1[dev] = pnp_dma(pdev, 0); | ||
2093 | dma2[dev] = pnp_dma(pdev, 1); | ||
2094 | irq[dev] = pnp_irq(pdev, 0); | ||
2095 | snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]); | ||
2096 | snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]); | ||
2097 | return 0; | ||
2098 | } | ||
2099 | |||
2100 | static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, | ||
2101 | struct pnp_dev *pdev) | ||
2102 | { | ||
2103 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
2104 | |||
2105 | if (!cfg) | ||
2106 | return -ENOMEM; | ||
2107 | acard->dev = pdev; | ||
2108 | if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) { | ||
2109 | kfree(cfg); | ||
2110 | return -EBUSY; | ||
2111 | } | ||
2112 | kfree(cfg); | ||
2113 | return 0; | ||
2114 | } | ||
2042 | 2115 | ||
2043 | static struct pnp_card_device_id snd_audiodrive_pnpids[] = { | 2116 | static struct pnp_card_device_id snd_audiodrive_pnpids[] = { |
2044 | /* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */ | 2117 | /* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */ |
@@ -2061,13 +2134,11 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = { | |||
2061 | 2134 | ||
2062 | MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids); | 2135 | MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids); |
2063 | 2136 | ||
2064 | static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, | 2137 | static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, |
2065 | struct pnp_card_link *card, | 2138 | struct pnp_card_link *card, |
2066 | const struct pnp_card_device_id *id) | 2139 | const struct pnp_card_device_id *id) |
2067 | { | 2140 | { |
2068 | struct pnp_dev *pdev; | ||
2069 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | 2141 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); |
2070 | int err; | ||
2071 | 2142 | ||
2072 | if (!cfg) | 2143 | if (!cfg) |
2073 | return -ENOMEM; | 2144 | return -ENOMEM; |
@@ -2082,58 +2153,16 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, | |||
2082 | return -EBUSY; | 2153 | return -EBUSY; |
2083 | } | 2154 | } |
2084 | /* Control port initialization */ | 2155 | /* Control port initialization */ |
2085 | err = pnp_activate_dev(acard->devc); | 2156 | if (pnp_activate_dev(acard->devc) < 0) { |
2086 | if (err < 0) { | ||
2087 | snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); | 2157 | snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); |
2088 | kfree(cfg); | ||
2089 | return -EAGAIN; | 2158 | return -EAGAIN; |
2090 | } | 2159 | } |
2091 | snd_printdd("pnp: port=0x%llx\n", | 2160 | snd_printdd("pnp: port=0x%llx\n", |
2092 | (unsigned long long)pnp_port_start(acard->devc, 0)); | 2161 | (unsigned long long)pnp_port_start(acard->devc, 0)); |
2093 | /* PnP initialization */ | 2162 | if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) { |
2094 | pdev = acard->dev; | ||
2095 | pnp_init_resource_table(cfg); | ||
2096 | if (port[dev] != SNDRV_AUTO_PORT) | ||
2097 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
2098 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
2099 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
2100 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2101 | pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2); | ||
2102 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
2103 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
2104 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
2105 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
2106 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
2107 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
2108 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
2109 | if (err < 0) | ||
2110 | snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n"); | ||
2111 | err = pnp_activate_dev(pdev); | ||
2112 | if (err < 0) { | ||
2113 | snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n"); | ||
2114 | kfree(cfg); | 2163 | kfree(cfg); |
2115 | return -EBUSY; | 2164 | return -EBUSY; |
2116 | } | 2165 | } |
2117 | /* ok. hack using Vendor-Defined Card-Level registers */ | ||
2118 | /* skip csn and logdev initialization - already done in isapnp_configure */ | ||
2119 | if (pnp_device_is_isapnp(pdev)) { | ||
2120 | isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev)); | ||
2121 | isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */ | ||
2122 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2123 | isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */ | ||
2124 | isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */ | ||
2125 | isapnp_cfg_end(); | ||
2126 | } else { | ||
2127 | snd_printk(KERN_ERR PFX "unable to install ISA PnP hack, expect malfunction\n"); | ||
2128 | } | ||
2129 | port[dev] = pnp_port_start(pdev, 0); | ||
2130 | fm_port[dev] = pnp_port_start(pdev, 1); | ||
2131 | mpu_port[dev] = pnp_port_start(pdev, 2); | ||
2132 | dma1[dev] = pnp_dma(pdev, 0); | ||
2133 | dma2[dev] = pnp_dma(pdev, 1); | ||
2134 | irq[dev] = pnp_irq(pdev, 0); | ||
2135 | snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]); | ||
2136 | snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]); | ||
2137 | kfree(cfg); | 2166 | kfree(cfg); |
2138 | return 0; | 2167 | return 0; |
2139 | } | 2168 | } |
@@ -2302,7 +2331,69 @@ static struct platform_driver snd_es18xx_nonpnp_driver = { | |||
2302 | #ifdef CONFIG_PNP | 2331 | #ifdef CONFIG_PNP |
2303 | static unsigned int __devinitdata es18xx_pnp_devices; | 2332 | static unsigned int __devinitdata es18xx_pnp_devices; |
2304 | 2333 | ||
2305 | static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | 2334 | static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev, |
2335 | const struct pnp_device_id *id) | ||
2336 | { | ||
2337 | static int dev; | ||
2338 | int err; | ||
2339 | struct snd_card *card; | ||
2340 | |||
2341 | if (pnp_device_is_isapnp(pdev)) | ||
2342 | return -ENOENT; /* we have another procedure - card */ | ||
2343 | for (; dev < SNDRV_CARDS; dev++) { | ||
2344 | if (enable[dev] && isapnp[dev]) | ||
2345 | break; | ||
2346 | } | ||
2347 | if (dev >= SNDRV_CARDS) | ||
2348 | return -ENODEV; | ||
2349 | |||
2350 | card = snd_es18xx_card_new(dev); | ||
2351 | if (! card) | ||
2352 | return -ENOMEM; | ||
2353 | if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) { | ||
2354 | snd_card_free(card); | ||
2355 | return err; | ||
2356 | } | ||
2357 | snd_card_set_dev(card, &pdev->dev); | ||
2358 | if ((err = snd_audiodrive_probe(card, dev)) < 0) { | ||
2359 | snd_card_free(card); | ||
2360 | return err; | ||
2361 | } | ||
2362 | pnp_set_drvdata(pdev, card); | ||
2363 | dev++; | ||
2364 | es18xx_pnp_devices++; | ||
2365 | return 0; | ||
2366 | } | ||
2367 | |||
2368 | static void __devexit snd_audiodrive_pnp_remove(struct pnp_dev * pdev) | ||
2369 | { | ||
2370 | snd_card_free(pnp_get_drvdata(pdev)); | ||
2371 | pnp_set_drvdata(pdev, NULL); | ||
2372 | } | ||
2373 | |||
2374 | #ifdef CONFIG_PM | ||
2375 | static int snd_audiodrive_pnp_suspend(struct pnp_dev *pdev, pm_message_t state) | ||
2376 | { | ||
2377 | return snd_es18xx_suspend(pnp_get_drvdata(pdev), state); | ||
2378 | } | ||
2379 | static int snd_audiodrive_pnp_resume(struct pnp_dev *pdev) | ||
2380 | { | ||
2381 | return snd_es18xx_resume(pnp_get_drvdata(pdev)); | ||
2382 | } | ||
2383 | #endif | ||
2384 | |||
2385 | static struct pnp_driver es18xx_pnp_driver = { | ||
2386 | .name = "es18xx-pnpbios", | ||
2387 | .id_table = snd_audiodrive_pnpbiosids, | ||
2388 | .probe = snd_audiodrive_pnp_detect, | ||
2389 | .remove = __devexit_p(snd_audiodrive_pnp_remove), | ||
2390 | #ifdef CONFIG_PM | ||
2391 | .suspend = snd_audiodrive_pnp_suspend, | ||
2392 | .resume = snd_audiodrive_pnp_resume, | ||
2393 | #endif | ||
2394 | }; | ||
2395 | |||
2396 | static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard, | ||
2306 | const struct pnp_card_device_id *pid) | 2397 | const struct pnp_card_device_id *pid) |
2307 | { | 2398 | { |
2308 | static int dev; | 2399 | static int dev; |
@@ -2320,7 +2411,7 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | |||
2320 | if (! card) | 2411 | if (! card) |
2321 | return -ENOMEM; | 2412 | return -ENOMEM; |
2322 | 2413 | ||
2323 | if ((res = snd_audiodrive_pnp(dev, card->private_data, pcard, pid)) < 0) { | 2414 | if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) { |
2324 | snd_card_free(card); | 2415 | snd_card_free(card); |
2325 | return res; | 2416 | return res; |
2326 | } | 2417 | } |
@@ -2336,19 +2427,19 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | |||
2336 | return 0; | 2427 | return 0; |
2337 | } | 2428 | } |
2338 | 2429 | ||
2339 | static void __devexit snd_audiodrive_pnp_remove(struct pnp_card_link * pcard) | 2430 | static void __devexit snd_audiodrive_pnpc_remove(struct pnp_card_link * pcard) |
2340 | { | 2431 | { |
2341 | snd_card_free(pnp_get_card_drvdata(pcard)); | 2432 | snd_card_free(pnp_get_card_drvdata(pcard)); |
2342 | pnp_set_card_drvdata(pcard, NULL); | 2433 | pnp_set_card_drvdata(pcard, NULL); |
2343 | } | 2434 | } |
2344 | 2435 | ||
2345 | #ifdef CONFIG_PM | 2436 | #ifdef CONFIG_PM |
2346 | static int snd_audiodrive_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) | 2437 | static int snd_audiodrive_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state) |
2347 | { | 2438 | { |
2348 | return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state); | 2439 | return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state); |
2349 | } | 2440 | } |
2350 | 2441 | ||
2351 | static int snd_audiodrive_pnp_resume(struct pnp_card_link *pcard) | 2442 | static int snd_audiodrive_pnpc_resume(struct pnp_card_link *pcard) |
2352 | { | 2443 | { |
2353 | return snd_es18xx_resume(pnp_get_card_drvdata(pcard)); | 2444 | return snd_es18xx_resume(pnp_get_card_drvdata(pcard)); |
2354 | } | 2445 | } |
@@ -2359,11 +2450,11 @@ static struct pnp_card_driver es18xx_pnpc_driver = { | |||
2359 | .flags = PNP_DRIVER_RES_DISABLE, | 2450 | .flags = PNP_DRIVER_RES_DISABLE, |
2360 | .name = "es18xx", | 2451 | .name = "es18xx", |
2361 | .id_table = snd_audiodrive_pnpids, | 2452 | .id_table = snd_audiodrive_pnpids, |
2362 | .probe = snd_audiodrive_pnp_detect, | 2453 | .probe = snd_audiodrive_pnpc_detect, |
2363 | .remove = __devexit_p(snd_audiodrive_pnp_remove), | 2454 | .remove = __devexit_p(snd_audiodrive_pnpc_remove), |
2364 | #ifdef CONFIG_PM | 2455 | #ifdef CONFIG_PM |
2365 | .suspend = snd_audiodrive_pnp_suspend, | 2456 | .suspend = snd_audiodrive_pnpc_suspend, |
2366 | .resume = snd_audiodrive_pnp_resume, | 2457 | .resume = snd_audiodrive_pnpc_resume, |
2367 | #endif | 2458 | #endif |
2368 | }; | 2459 | }; |
2369 | #endif /* CONFIG_PNP */ | 2460 | #endif /* CONFIG_PNP */ |
@@ -2373,8 +2464,10 @@ static void __init_or_module snd_es18xx_unregister_all(void) | |||
2373 | int i; | 2464 | int i; |
2374 | 2465 | ||
2375 | #ifdef CONFIG_PNP | 2466 | #ifdef CONFIG_PNP |
2376 | if (pnp_registered) | 2467 | if (pnpc_registered) |
2377 | pnp_unregister_card_driver(&es18xx_pnpc_driver); | 2468 | pnp_unregister_card_driver(&es18xx_pnpc_driver); |
2469 | if (pnp_registered) | ||
2470 | pnp_unregister_driver(&es18xx_pnp_driver); | ||
2378 | #endif | 2471 | #endif |
2379 | for (i = 0; i < ARRAY_SIZE(platform_devices); ++i) | 2472 | for (i = 0; i < ARRAY_SIZE(platform_devices); ++i) |
2380 | platform_device_unregister(platform_devices[i]); | 2473 | platform_device_unregister(platform_devices[i]); |
@@ -2405,11 +2498,13 @@ static int __init alsa_card_es18xx_init(void) | |||
2405 | } | 2498 | } |
2406 | 2499 | ||
2407 | #ifdef CONFIG_PNP | 2500 | #ifdef CONFIG_PNP |
2408 | err = pnp_register_card_driver(&es18xx_pnpc_driver); | 2501 | err = pnp_register_driver(&es18xx_pnp_driver); |
2409 | if (!err) { | 2502 | if (!err) |
2410 | pnp_registered = 1; | 2503 | pnp_registered = 1; |
2411 | cards += es18xx_pnp_devices; | 2504 | err = pnp_register_card_driver(&es18xx_pnpc_driver); |
2412 | } | 2505 | if (!err) |
2506 | pnpc_registered = 1; | ||
2507 | cards += es18xx_pnp_devices; | ||
2413 | #endif | 2508 | #endif |
2414 | 2509 | ||
2415 | if(!cards) { | 2510 | if(!cards) { |