summaryrefslogtreecommitdiffstats
path: root/sound/oss/skeleton.c
blob: 8fea783dd0cba505a8b85969f56727f25bffa941 (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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/*
 *	PCI sound skeleton example
 *
 *	(c) 1998 Red Hat Software
 *
 *	This software may be used and distributed according to the 
 *	terms of the GNU General Public License, incorporated herein by 
 *	reference.
 *
 *	This example is designed to be built in the linux/drivers/sound
 *	directory as part of a kernel build. The example is modular only
 *	drop me a note once you have a working modular driver and want
 *	to integrate it with the main code.
 *		-- Alan <alan@redhat.com>
 *
 *	This is a first draft. Please report any errors, corrections or
 *	improvements to me.
 */

#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/pci.h>

#include <asm/io.h>

#include "sound_config.h"

/*
 *	Define our PCI vendor ID here
 */
 
#ifndef PCI_VENDOR_MYIDENT
#define PCI_VENDOR_MYIDENT			0x125D

/*
 *	PCI identity for the card.
 */
 
#define PCI_DEVICE_ID_MYIDENT_MYCARD1		0x1969
#endif

#define CARD_NAME	"ExampleWave 3D Pro Ultra ThingyWotsit"

#define MAX_CARDS	8

/*
 *	Each address_info object holds the information about one of
 *	our card resources. In this case the MSS emulation of our
 *	ficticious card. Its used to manage and attach things.
 */
 
static struct address_info	mss_data[MAX_CARDS];
static int 			cards;

/*
 *	Install the actual card. This is an example
 */

static int mycard_install(struct pci_dev *pcidev)
{
	int iobase;
	int mssbase;
	int mpubase;
	u8 x;
	u16 w;
	u32 v;
	int i;
	int dma;

	/*
	 *	Our imaginary code has its I/O on PCI address 0, a
	 *	MSS on PCI address 1 and an MPU on address 2
	 *
	 *	For the example we will only initialise the MSS
	 */
	 	
	iobase = pci_resource_start(pcidev, 0);
	mssbase = pci_resource_start(pcidev, 1);
	mpubase = pci_resource_start(pcidev, 2);
	
	/*
	 *	Reset the board
	 */
	 
	/*
	 *	Wait for completion. udelay() waits in microseconds
	 */
	 
	udelay(100);
	
	/*
	 *	Ok card ready. Begin setup proper. You might for example
	 *	load the firmware here
	 */
	
	dma = card_specific_magic(ioaddr);
	
	/*
	 *	Turn on legacy mode (example), There are also byte and
	 *	dword (32bit) PCI configuration function calls
	 */

	pci_read_config_word(pcidev, 0x40, &w);
	w&=~(1<<15);			/* legacy decode on */
	w|=(1<<14);			/* Reserved write as 1 in this case */
	w|=(1<<3)|(1<<1)|(1<<0);	/* SB on , FM on, MPU on */
	pci_write_config_word(pcidev, 0x40, w);
	
	/*
	 *	Let the user know we found his toy.
	 */
	 
	printk(KERN_INFO "Programmed "CARD_NAME" at 0x%X to legacy mode.\n",
		iobase);
		
	/*
	 *	Now set it up the description of the card
	 */
	 
	mss_data[cards].io_base = mssbase;
	mss_data[cards].irq = pcidev->irq;
	mss_data[cards].dma = dma;
	
	/*
	 *	Check there is an MSS present
	 */

	if(ad1848_detect(mssbase, NULL, mss_data[cards].osp)==0)
		return 0;
		
	/*
	 *	Initialize it
	 */
	 
	mss_data[cards].slots[3] = ad1848_init("MyCard MSS 16bit", 
			mssbase,
			mss_data[cards].irq,
			mss_data[cards].dma,
			mss_data[cards].dma,
			0,
			0,
			THIS_MODULE);

	cards++;	
	return 1;
}


/*
 * 	This loop walks the PCI configuration database and finds where
 *	the sound cards are.
 */
 
int init_mycard(void)
{
	struct pci_dev *pcidev=NULL;
	int count=0;
		
	while((pcidev = pci_find_device(PCI_VENDOR_MYIDENT, PCI_DEVICE_ID_MYIDENT_MYCARD1, pcidev))!=NULL)
	{
		if (pci_enable_device(pcidev))
			continue;
		count+=mycard_install(pcidev);
		if(count)
			return 0;
		if(count==MAX_CARDS)
			break;
	}
	
	if(count==0)
		return -ENODEV;
	return 0;
}

/*
 *	This function is called when the user or kernel loads the 
 *	module into memory.
 */


int init_module(void)
{
	if(init_mycard()<0)
	{
		printk(KERN_ERR "No "CARD_NAME" cards found.\n");
		return -ENODEV;
	}

	return 0;
}

/*
 *	This is called when it is removed. It will only be removed 
 *	when its use count is 0.
 */
 
void cleanup_module(void)
{
	for(i=0;i< cards; i++)
	{
		/*
		 *	Free attached resources
		 */
		 
		ad1848_unload(mss_data[i].io_base,
			      mss_data[i].irq,
			      mss_data[i].dma,
			      mss_data[i].dma,
			      0);
		/*
		 *	And disconnect the device from the kernel
		 */
		sound_unload_audiodevice(mss_data[i].slots[3]);
	}
}