]>
Commit | Line | Data |
---|---|---|
95e83f51 JR |
1 | --- Linux/drivers/sound/i810_audio.c Tue Apr 17 18:06:46 2001 |
2 | +++ linux/drivers/sound/i810_audio.c Tue Apr 17 18:14:17 2001 | |
3 | @@ -323,6 +323,10 @@ | |
4 | struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *); | |
5 | struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *); | |
6 | void (*free_pcm_channel)(struct i810_card *, int chan); | |
7 | + | |
8 | + /* We have a *very* long init time possibly, so use this to block */ | |
9 | + /* attempts to open our devices before we are ready (stops oops'es) */ | |
10 | + int initializing; | |
11 | }; | |
12 | ||
13 | static struct i810_card *devs = NULL; | |
14 | @@ -1738,7 +1742,9 @@ | |
15 | ||
16 | /* find an avaiable virtual channel (instance of /dev/dsp) */ | |
17 | while (card != NULL) { | |
18 | - for (i = 0; i < NR_HW_CH; i++) { | |
19 | + for (i = 0; i < 50 && card->initializing; i++) | |
20 | + schedule_timeout(HZ/20); | |
21 | + for (i = 0; i < NR_HW_CH && !card->initializing; i++) { | |
22 | if (card->states[i] == NULL) { | |
23 | state = card->states[i] = (struct i810_state *) | |
24 | kmalloc(sizeof(struct i810_state), GFP_KERNEL); | |
25 | @@ -1885,13 +1887,16 @@ | |
26 | int minor = MINOR(inode->i_rdev); | |
27 | struct i810_card *card = devs; | |
28 | ||
29 | - for (card = devs; card != NULL; card = card->next) | |
30 | - for (i = 0; i < NR_AC97; i++) | |
31 | + for (card = devs; card != NULL; card = card->next) { | |
32 | + for (i = 0; i < 50 && card->initializing; i++) | |
33 | + schedule_timeout(HZ/20); | |
34 | + for (i = 0; i < NR_AC97 && !card->initializing; i++) | |
35 | if (card->ac97_codec[i] != NULL && | |
36 | card->ac97_codec[i]->dev_mixer == minor) { | |
37 | file->private_data = card->ac97_codec[i]; | |
38 | return 0; | |
39 | } | |
40 | + } | |
41 | return -ENODEV; | |
42 | } | |
43 | ||
44 | @@ -2023,6 +2028,75 @@ | |
45 | return num_ac97; | |
46 | } | |
47 | ||
48 | +static void __init i810_configure_clocking (void) | |
49 | +{ | |
50 | + struct i810_card *card; | |
51 | + struct i810_state *state; | |
52 | + struct dmabuf *dmabuf; | |
53 | + unsigned int i, offset, new_offset; | |
54 | + unsigned long flags; | |
55 | + | |
56 | + card = devs; | |
57 | + /* We could try to set the clocking for multiple cards, but can you even have | |
58 | + * more than one i810 in a machine? Besides, clocking is global, so unless | |
59 | + * someone actually thinks more than one i810 in a machine is possible and | |
60 | + * decides to rewrite that little bit, setting the rate for more than one card | |
61 | + * is a waste of time. | |
62 | + */ | |
63 | + if(card != NULL) { | |
64 | + state = card->states[0] = (struct i810_state *) | |
65 | + kmalloc(sizeof(struct i810_state), GFP_KERNEL); | |
66 | + if (state == NULL) | |
67 | + return; | |
68 | + memset(state, 0, sizeof(struct i810_state)); | |
69 | + dmabuf = &state->dmabuf; | |
70 | + | |
71 | + dmabuf->write_channel = card->alloc_pcm_channel(card); | |
72 | + state->virt = 0; | |
73 | + state->card = card; | |
74 | + state->magic = I810_STATE_MAGIC; | |
75 | + init_waitqueue_head(&dmabuf->wait); | |
76 | + init_MUTEX(&state->open_sem); | |
77 | + dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT; | |
78 | + dmabuf->trigger = PCM_ENABLE_OUTPUT; | |
79 | + i810_set_dac_rate(state, 48000); | |
80 | + if(prog_dmabuf(state, 0) != 0) { | |
81 | + goto config_out_nodmabuf; | |
82 | + } | |
83 | + if(dmabuf->dmasize < 16384) { | |
84 | + goto config_out; | |
85 | + } | |
86 | + dmabuf->count = dmabuf->dmasize; | |
87 | + outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI); | |
88 | + save_flags(flags); | |
89 | + cli(); | |
90 | + start_dac(state); | |
91 | + offset = i810_get_dma_addr(state, 0); | |
92 | + mdelay(50); | |
93 | + new_offset = i810_get_dma_addr(state, 0); | |
94 | + stop_dac(state); | |
95 | + outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR); | |
96 | + restore_flags(flags); | |
97 | + i = new_offset - offset; | |
98 | +#ifdef DEBUG | |
99 | + printk("i810_audio: %d bytes in 50 milliseconds\n", i); | |
100 | +#endif | |
101 | + if(i == 0) | |
102 | + goto config_out; | |
103 | + i = i / 4 * 20; | |
104 | + if (i > 48500 || i < 47500) { | |
105 | + clocking = clocking * clocking / i; | |
106 | + printk("i810_audio: setting clocking to %d\n", clocking); | |
107 | + } | |
108 | +config_out: | |
109 | + dealloc_dmabuf(state); | |
110 | +config_out_nodmabuf: | |
111 | + state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num); | |
112 | + kfree(state); | |
113 | + card->states[0] = NULL; | |
114 | + } | |
115 | +} | |
116 | + | |
117 | /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered | |
118 | until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ | |
119 | ||
120 | @@ -2030,21 +2104,21 @@ | |
121 | { | |
122 | struct i810_card *card; | |
123 | ||
124 | - if (pci_enable_device(pci_dev)) | |
125 | - return -EIO; | |
126 | - | |
127 | - if (pci_set_dma_mask(pci_dev, I810_DMA_MASK)) { | |
128 | + if (!pci_dma_supported(pci_dev, I810_DMA_MASK)) { | |
129 | printk(KERN_ERR "intel810: architecture does not support" | |
130 | " 32bit PCI busmaster DMA\n"); | |
131 | return -ENODEV; | |
132 | } | |
133 | ||
134 | + if (pci_enable_device(pci_dev)) | |
135 | + return -EIO; | |
136 | if ((card = kmalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) { | |
137 | printk(KERN_ERR "i810_audio: out of memory\n"); | |
138 | return -ENOMEM; | |
139 | } | |
140 | memset(card, 0, sizeof(*card)); | |
141 | ||
142 | + card->initializing = 1; | |
143 | card->iobase = pci_resource_start (pci_dev, 1); | |
144 | card->ac97base = pci_resource_start (pci_dev, 0); | |
145 | card->pci_dev = pci_dev; | |
146 | @@ -2108,6 +2182,11 @@ | |
147 | return -ENODEV; | |
148 | } | |
149 | pci_dev->driver_data = card; | |
150 | + pci_dev->dma_mask = I810_DMA_MASK; | |
151 | + if(clocking == 48000) { | |
152 | + i810_configure_clocking(); | |
153 | + } | |
154 | + card->initializing = 0; | |
155 | return 0; | |
156 | } | |
157 | ||
158 | @@ -2146,75 +2225,6 @@ | |
159 | remove: i810_remove, | |
160 | }; | |
161 | ||
162 | -static void __init i810_configure_clocking (void) | |
163 | -{ | |
164 | - struct i810_card *card; | |
165 | - struct i810_state *state; | |
166 | - struct dmabuf *dmabuf; | |
167 | - unsigned int i, offset, new_offset; | |
168 | - unsigned long flags; | |
169 | - | |
170 | - card = devs; | |
171 | - /* We could try to set the clocking for multiple cards, but can you even have | |
172 | - * more than one i810 in a machine? Besides, clocking is global, so unless | |
173 | - * someone actually thinks more than one i810 in a machine is possible and | |
174 | - * decides to rewrite that little bit, setting the rate for more than one card | |
175 | - * is a waste of time. | |
176 | - */ | |
177 | - if(card != NULL) { | |
178 | - state = card->states[0] = (struct i810_state *) | |
179 | - kmalloc(sizeof(struct i810_state), GFP_KERNEL); | |
180 | - if (state == NULL) | |
181 | - return; | |
182 | - memset(state, 0, sizeof(struct i810_state)); | |
183 | - dmabuf = &state->dmabuf; | |
184 | - | |
185 | - dmabuf->write_channel = card->alloc_pcm_channel(card); | |
186 | - state->virt = 0; | |
187 | - state->card = card; | |
188 | - state->magic = I810_STATE_MAGIC; | |
189 | - init_waitqueue_head(&dmabuf->wait); | |
190 | - init_MUTEX(&state->open_sem); | |
191 | - dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT; | |
192 | - dmabuf->trigger = PCM_ENABLE_OUTPUT; | |
193 | - i810_set_dac_rate(state, 48000); | |
194 | - if(prog_dmabuf(state, 0) != 0) { | |
195 | - goto config_out_nodmabuf; | |
196 | - } | |
197 | - if(dmabuf->dmasize < 16384) { | |
198 | - goto config_out; | |
199 | - } | |
200 | - dmabuf->count = dmabuf->dmasize; | |
201 | - outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI); | |
202 | - save_flags(flags); | |
203 | - cli(); | |
204 | - start_dac(state); | |
205 | - offset = i810_get_dma_addr(state, 0); | |
206 | - mdelay(50); | |
207 | - new_offset = i810_get_dma_addr(state, 0); | |
208 | - stop_dac(state); | |
209 | - outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR); | |
210 | - restore_flags(flags); | |
211 | - i = new_offset - offset; | |
212 | -#ifdef DEBUG | |
213 | - printk("i810_audio: %d bytes in 50 milliseconds\n", i); | |
214 | -#endif | |
215 | - if(i == 0) | |
216 | - goto config_out; | |
217 | - i = i / 4 * 20; | |
218 | - if (i > 48500 || i < 47500) { | |
219 | - clocking = clocking * clocking / i; | |
220 | - printk("i810_audio: setting clocking to %d\n", clocking); | |
221 | - } | |
222 | -config_out: | |
223 | - dealloc_dmabuf(state); | |
224 | -config_out_nodmabuf: | |
225 | - state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num); | |
226 | - kfree(state); | |
227 | - card->states[0] = NULL; | |
228 | - } | |
229 | -} | |
230 | - | |
231 | static int __init i810_init_module (void) | |
232 | { | |
233 | if (!pci_present()) /* No PCI bus in this machine! */ | |
234 | @@ -2229,9 +2239,6 @@ | |
235 | } | |
236 | if(ftsodell != 0) { | |
237 | printk("i810_audio: ftsodell is now a deprecated option.\n"); | |
238 | - } | |
239 | - if(clocking == 48000) { | |
240 | - i810_configure_clocking(); | |
241 | } | |
242 | return 0; | |
243 | } |