summaryrefslogtreecommitdiffstats
path: root/sound/isa/adlib.c
blob: a253a14e6a45be6ea18e8b982268c855337eefba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * AdLib FM card driver.
 */

#include <sound/driver.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/opl3.h>

#define CRD_NAME "AdLib FM"
#define DRV_NAME "snd_adlib"

MODULE_DESCRIPTION(CRD_NAME);
MODULE_AUTHOR("Rene Herman");
MODULE_LICENSE("GPL");

static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;

module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
module_param_array(port, long, NULL, 0444);
MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");

static struct platform_device *devices[SNDRV_CARDS];

static void snd_adlib_free(struct snd_card *card)
{
	release_and_free_resource(card->private_data);
}

static int __devinit snd_adlib_probe(struct platform_device *device)
{
	struct snd_card *card;
	struct snd_opl3 *opl3;

	int error;
	int i = device->id;

	if (port[i] == SNDRV_AUTO_PORT) {
		snd_printk(KERN_ERR DRV_NAME ": please specify port\n");
		error = -EINVAL;
		goto out0;
	}

	card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
	if (!card) {
		snd_printk(KERN_ERR DRV_NAME ": could not create card\n");
		error = -EINVAL;
		goto out0;
	}

	card->private_data = request_region(port[i], 4, CRD_NAME);
	if (!card->private_data) {
		snd_printk(KERN_ERR DRV_NAME ": could not grab ports\n");
		error = -EBUSY;
		goto out1;
	}
	card->private_free = snd_adlib_free;

	error = snd_opl3_create(card, port[i], port[i] + 2, OPL3_HW_AUTO, 1, &opl3);
	if (error < 0) {
		snd_printk(KERN_ERR DRV_NAME ": could not create OPL\n");
		goto out1;
	}

	error = snd_opl3_hwdep_new(opl3, 0, 0, NULL);
	if (error < 0) {
		snd_printk(KERN_ERR DRV_NAME ": could not create FM\n");
		goto out1;
	}

	strcpy(card->driver, DRV_NAME);
	strcpy(card->shortname, CRD_NAME);
	sprintf(card->longname, CRD_NAME " at %#lx", port[i]);

	snd_card_set_dev(card, &device->dev);

	error = snd_card_register(card);
	if (error < 0) {
		snd_printk(KERN_ERR DRV_NAME ": could not register card\n");
		goto out1;
	}

	platform_set_drvdata(device, card);
	return 0;

out1:	snd_card_free(card);
 out0:	error = -EINVAL; /* FIXME: should be the original error code */
	return error;
}

static int __devexit snd_adlib_remove(struct platform_device *device)
{
	snd_card_free(platform_get_drvdata(device));
	platform_set_drvdata(device, NULL);
	return 0;
}

static struct platform_driver snd_adlib_driver = {
	.probe		= snd_adlib_probe,
	.remove		= __devexit_p(snd_adlib_remove),

	.driver		= {
		.name	= DRV_NAME
	}
};

static int __init alsa_card_adlib_init(void)
{
	int i, cards;

	if (platform_driver_register(&snd_adlib_driver) < 0) {
		snd_printk(KERN_ERR DRV_NAME ": could not register driver\n");
		return -ENODEV;
	}

	for (cards = 0, i = 0; i < SNDRV_CARDS; i++) {
		struct platform_device *device;

		if (!enable[i])
			continue;

		device = platform_device_register_simple(DRV_NAME, i, NULL, 0);
		if (IS_ERR(device))
			continue;

		devices[i] = device;
		cards++;
	}

	if (!cards) {
#ifdef MODULE
		printk(KERN_ERR CRD_NAME " soundcard not found or device busy\n");
#endif
		platform_driver_unregister(&snd_adlib_driver);
		return -ENODEV;
	}
	return 0;
}

static void __exit alsa_card_adlib_exit(void)
{
	int i;

	for (i = 0; i < SNDRV_CARDS; i++)
		platform_device_unregister(devices[i]);
	platform_driver_unregister(&snd_adlib_driver);
}

module_init(alsa_card_adlib_init);
module_exit(alsa_card_adlib_exit);
OpenPOWER on IntegriCloud