comparison src/audio/nto/SDL_nto_audio.c @ 2049:5f6550e5184f

Merged SDL-ryan-multiple-audio-device branch r2803:2871 into the trunk.
author Ryan C. Gordon <icculus@icculus.org>
date Tue, 17 Oct 2006 09:15:21 +0000
parents cff63f857ff3
children 866052b01ee5
comparison
equal deleted inserted replaced
2048:6067c7f9a672 2049:5f6550e5184f
67 {"Sound Blaster Live!", QSA_MMAP_WORKAROUND}, 67 {"Sound Blaster Live!", QSA_MMAP_WORKAROUND},
68 {"Vortex 8820", QSA_MMAP_WORKAROUND}, 68 {"Vortex 8820", QSA_MMAP_WORKAROUND},
69 {"Vortex 8830", QSA_MMAP_WORKAROUND}, 69 {"Vortex 8830", QSA_MMAP_WORKAROUND},
70 }; 70 };
71 71
72 /* Audio driver functions */ 72
73 static void NTO_ThreadInit(_THIS); 73 static inline void
74 static int NTO_OpenAudio(_THIS, SDL_AudioSpec * spec); 74 NTO_SetError(const char *fn, int rval)
75 static void NTO_WaitAudio(_THIS); 75 {
76 static void NTO_PlayAudio(_THIS); 76 SDL_SetError("NTO: %s failed: %s", fn, snd_strerror(rval));
77 static Uint8 *NTO_GetAudioBuf(_THIS); 77 }
78 static void NTO_CloseAudio(_THIS); 78
79 79
80 /* card names check to apply the workarounds */ 80 /* card names check to apply the workarounds */
81 static int 81 static int
82 NTO_CheckBuggyCards(_THIS, unsigned long checkfor) 82 NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
83 { 83 {
84 char scardname[33]; 84 char scardname[33];
85 int it; 85 int it;
86 86
87 if (snd_card_get_name(cardno, scardname, 32) < 0) { 87 if (snd_card_get_name(this->hidden->cardno, scardname, 32) < 0) {
88 return 0; 88 return 0;
89 } 89 }
90 90
91 for (it = 0; it < QSA_WA_CARDS; it++) { 91 for (it = 0; it < QSA_WA_CARDS; it++) {
92 if (SDL_strcmp(buggycards[it].cardname, scardname) == 0) { 92 if (SDL_strcmp(buggycards[it].cardname, scardname) == 0) {
100 } 100 }
101 101
102 static void 102 static void
103 NTO_ThreadInit(_THIS) 103 NTO_ThreadInit(_THIS)
104 { 104 {
105 int status;
106 struct sched_param param; 105 struct sched_param param;
106 int status = SchedGet(0, 0, &param);
107 107
108 /* increasing default 10 priority to 25 to avoid jerky sound */ 108 /* increasing default 10 priority to 25 to avoid jerky sound */
109 status = SchedGet(0, 0, &param);
110 param.sched_priority = param.sched_curpriority + 15; 109 param.sched_priority = param.sched_curpriority + 15;
111 status = SchedSet(0, 0, SCHED_NOCHANGE, &param); 110 status = SchedSet(0, 0, SCHED_NOCHANGE, &param);
112 } 111 }
113 112
114 /* PCM transfer channel parameters initialize function */ 113 /* PCM transfer channel parameters initialize function */
128 cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE; 127 cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
129 cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN; 128 cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
130 cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX; 129 cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
131 } 130 }
132 131
133 static int
134 NTO_AudioAvailable(void)
135 {
136 /* See if we can open a nonblocking channel.
137 Return value '1' means we can.
138 Return value '0' means we cannot. */
139
140 int available;
141 int rval;
142 snd_pcm_t *handle;
143
144 available = 0;
145 handle = NULL;
146
147 rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
148
149 if (rval >= 0) {
150 available = 1;
151
152 if ((rval = snd_pcm_close(handle)) < 0) {
153 SDL_SetError
154 ("NTO_AudioAvailable(): snd_pcm_close failed: %s\n",
155 snd_strerror(rval));
156 available = 0;
157 }
158 } else {
159 SDL_SetError
160 ("NTO_AudioAvailable(): there are no available audio devices.\n");
161 }
162
163 return (available);
164 }
165
166 static void
167 NTO_DeleteAudioDevice(SDL_AudioDevice * device)
168 {
169 if ((device) && (device->hidden)) {
170 SDL_free(device->hidden);
171 }
172 if (device) {
173 SDL_free(device);
174 }
175 }
176
177 static SDL_AudioDevice *
178 NTO_CreateAudioDevice(int devindex)
179 {
180 SDL_AudioDevice *this;
181
182 /* Initialize all variables that we clean on shutdown */
183 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
184 if (this) {
185 SDL_memset(this, 0, sizeof(SDL_AudioDevice));
186 this->hidden = (struct SDL_PrivateAudioData *)
187 SDL_malloc(sizeof(struct SDL_PrivateAudioData));
188 }
189 if ((this == NULL) || (this->hidden == NULL)) {
190 SDL_OutOfMemory();
191 if (this) {
192 SDL_free(this);
193 }
194 return (0);
195 }
196 SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
197 audio_handle = NULL;
198
199 /* Set the function pointers */
200 this->ThreadInit = NTO_ThreadInit;
201 this->OpenAudio = NTO_OpenAudio;
202 this->WaitAudio = NTO_WaitAudio;
203 this->PlayAudio = NTO_PlayAudio;
204 this->GetAudioBuf = NTO_GetAudioBuf;
205 this->CloseAudio = NTO_CloseAudio;
206
207 this->free = NTO_DeleteAudioDevice;
208
209 return this;
210 }
211
212 AudioBootStrap QNXNTOAUDIO_bootstrap = {
213 DRIVER_NAME, "QNX6 QSA-NTO Audio",
214 NTO_AudioAvailable,
215 NTO_CreateAudioDevice
216 };
217 132
218 /* This function waits until it is possible to write a full sound buffer */ 133 /* This function waits until it is possible to write a full sound buffer */
219 static void 134 static void
220 NTO_WaitAudio(_THIS) 135 NTO_WaitDevice(_THIS)
221 { 136 {
222 fd_set wfds; 137 fd_set wfds;
223 int selectret; 138 int selectret;
224 139
225 FD_ZERO(&wfds); 140 FD_ZERO(&wfds);
226 FD_SET(audio_fd, &wfds); 141 FD_SET(this->hidden->audio_fd, &wfds);
227 142
228 do { 143 do {
229 selectret = select(audio_fd + 1, NULL, &wfds, NULL, NULL); 144 selectret = select(this->hidden->audio_fd+1, NULL, &wfds, NULL, NULL);
230 switch (selectret) { 145 switch (selectret) {
231 case -1: 146 case -1:
232 case 0: 147 case 0:
233 SDL_SetError("NTO_WaitAudio(): select() failed: %s\n", 148 SDL_SetError("NTO: select() failed: %s\n", strerror(errno));
234 strerror(errno));
235 return; 149 return;
236 default: 150 default:
237 if (FD_ISSET(audio_fd, &wfds)) { 151 if (FD_ISSET(this->hidden->audio_fd, &wfds)) {
238 return; 152 return;
239 } 153 }
240 break; 154 break;
241 } 155 }
242 } 156 }
243 while (1); 157 while (1);
244 } 158 }
245 159
246 static void 160 static void
247 NTO_PlayAudio(_THIS) 161 NTO_PlayDevice(_THIS)
248 { 162 {
163 snd_pcm_channel_status_t cstatus;
249 int written, rval; 164 int written, rval;
250 int towrite; 165 int towrite;
251 void *pcmbuffer; 166 void *pcmbuffer;
252 167
253 if (!this->enabled) { 168 if ((!this->enabled) || (!this->hidden)) {
254 return; 169 return;
255 } 170 }
256 171
257 towrite = this->spec.size; 172 towrite = this->spec.size;
258 pcmbuffer = pcm_buf; 173 pcmbuffer = this->hidden->pcm_buf;
259 174
260 /* Write the audio data, checking for EAGAIN (buffer full) and underrun */ 175 /* Write the audio data, checking for EAGAIN (buffer full) and underrun */
261 do { 176 do {
262 written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite); 177 written = snd_pcm_plugin_write(this->hidden->audio_handle,
178 pcmbuffer, towrite);
263 if (written != towrite) { 179 if (written != towrite) {
264 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { 180 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
265 /* Let a little CPU time go by and try to write again */ 181 /* Let a little CPU time go by and try to write again */
266 SDL_Delay(1); 182 SDL_Delay(1);
267 /* if we wrote some data */ 183 /* if we wrote some data */
268 towrite -= written; 184 towrite -= written;
269 pcmbuffer += written * this->spec.channels; 185 pcmbuffer += written * this->spec.channels;
270 continue; 186 continue;
271 } else { 187 } else if ((errno == EINVAL) || (errno == EIO)) {
272 if ((errno == EINVAL) || (errno == EIO)) { 188 SDL_memset(&cstatus, 0, sizeof (cstatus));
273 SDL_memset(&cstatus, 0, sizeof(cstatus)); 189 cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
274 cstatus.channel = SND_PCM_CHANNEL_PLAYBACK; 190 rval = snd_pcm_plugin_status(this->hidden->audio_handle,
275 if ((rval = 191 &cstatus);
276 snd_pcm_plugin_status(audio_handle, &cstatus)) < 0) { 192 if (rval < 0) {
277 SDL_SetError 193 NTO_SetError("snd_pcm_plugin_status", rval);
278 ("NTO_PlayAudio(): snd_pcm_plugin_status failed: %s\n", 194 return;
279 snd_strerror(rval)); 195 }
196
197 if ( (cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
198 (cstatus.status == SND_PCM_STATUS_READY)) {
199 rval = snd_pcm_plugin_prepare(this->hidden->audio_handle,
200 SND_PCM_CHANNEL_PLAYBACK);
201 if (rval < 0) {
202 NTO_SetError("snd_pcm_plugin_prepare", rval);
280 return; 203 return;
281 } 204 }
282 if ((cstatus.status == SND_PCM_STATUS_UNDERRUN)
283 || (cstatus.status == SND_PCM_STATUS_READY)) {
284 if ((rval =
285 snd_pcm_plugin_prepare(audio_handle,
286 SND_PCM_CHANNEL_PLAYBACK))
287 < 0) {
288 SDL_SetError
289 ("NTO_PlayAudio(): snd_pcm_plugin_prepare failed: %s\n",
290 snd_strerror(rval));
291 return;
292 }
293 }
294 continue;
295 } else {
296 return;
297 } 205 }
206 continue;
207 } else {
208 return;
298 } 209 }
299 } else { 210 } else {
300 /* we wrote all remaining data */ 211 /* we wrote all remaining data */
301 towrite -= written; 212 towrite -= written;
302 pcmbuffer += written * this->spec.channels; 213 pcmbuffer += written * this->spec.channels;
306 217
307 /* If we couldn't write, assume fatal error for now */ 218 /* If we couldn't write, assume fatal error for now */
308 if (towrite != 0) { 219 if (towrite != 0) {
309 this->enabled = 0; 220 this->enabled = 0;
310 } 221 }
311
312 return;
313 } 222 }
314 223
315 static Uint8 * 224 static Uint8 *
316 NTO_GetAudioBuf(_THIS) 225 NTO_GetDeviceBuf(_THIS)
317 { 226 {
318 return pcm_buf; 227 return this->hidden->pcm_buf;
319 } 228 }
320 229
321 static void 230 static void
322 NTO_CloseAudio(_THIS) 231 NTO_CloseDevice(_THIS)
323 { 232 {
324 int rval; 233 if (this->hidden != NULL) {
325 234 if (this->hidden->audio_handle != NULL) {
326 this->enabled = 0; 235 snd_pcm_plugin_flush(this->hidden->audio_handle,
327 236 SND_PCM_CHANNEL_PLAYBACK);
328 if (audio_handle != NULL) { 237 snd_pcm_close(this->hidden->audio_handle);
329 if ((rval = 238 this->hidden->audio_handle = NULL;
330 snd_pcm_plugin_flush(audio_handle, 239 }
331 SND_PCM_CHANNEL_PLAYBACK)) < 0) { 240 if (this->hidden->pcm_buf != NULL) {
332 SDL_SetError 241 SDL_FreeAudioMem(this->hidden->pcm_buf);
333 ("NTO_CloseAudio(): snd_pcm_plugin_flush failed: %s\n", 242 this->hidden->pcm_buf = NULL;
334 snd_strerror(rval)); 243 }
335 return; 244 SDL_free(this->hidden);
336 } 245 this->hidden = NULL;
337 if ((rval = snd_pcm_close(audio_handle)) < 0) {
338 SDL_SetError("NTO_CloseAudio(): snd_pcm_close failed: %s\n",
339 snd_strerror(rval));
340 return;
341 }
342 audio_handle = NULL;
343 } 246 }
344 } 247 }
345 248
346 static int 249 static int
347 NTO_OpenAudio(_THIS, SDL_AudioSpec * spec) 250 NTO_OpenDevice(_THIS, const char *devname, int iscapture)
348 { 251 {
349 int rval; 252 int rval = 0;
350 int format; 253 int format = 0;
351 SDL_AudioFormat test_format; 254 SDL_AudioFormat test_format = 0;
352 int found; 255 int found = 0;
353 256 snd_pcm_channel_setup_t csetup;
354 audio_handle = NULL; 257 snd_pcm_channel_params_t cparams;
355 this->enabled = 0; 258
356 259 /* Initialize all variables that we clean on shutdown */
357 if (pcm_buf != NULL) { 260 this->hidden = (struct SDL_PrivateAudioData *)
358 SDL_FreeAudioMem(pcm_buf); 261 SDL_malloc((sizeof *this->hidden));
359 pcm_buf = NULL; 262 if (this->hidden == NULL) {
360 } 263 SDL_OutOfMemory();
264 return 0;
265 }
266 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
361 267
362 /* initialize channel transfer parameters to default */ 268 /* initialize channel transfer parameters to default */
363 NTO_InitAudioParams(&cparams); 269 NTO_InitAudioParams(&cparams);
364 270
365 /* Open the audio device */ 271 /* Open the audio device */
366 rval = 272 rval = snd_pcm_open_preferred(&this->hidden->audio_handle,
367 snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS); 273 &this->hidden->cardno,
274 &this->hidden->deviceno, OPEN_FLAGS);
275
368 if (rval < 0) { 276 if (rval < 0) {
369 SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n", 277 NTO_CloseDevice(this);
370 snd_strerror(rval)); 278 NTO_SetError("snd_pcm_open", rval);
371 return (-1); 279 return 0;
372 } 280 }
373 281
374 if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) { 282 if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) {
375 /* enable count status parameter */ 283 /* enable count status parameter */
376 if ((rval = 284 rval = snd_pcm_plugin_set_disable(this->hidden->audio_handle,
377 snd_pcm_plugin_set_disable(audio_handle, 285 PLUGIN_DISABLE_MMAP);
378 PLUGIN_DISABLE_MMAP)) < 0) { 286 if (rval < 0) {
379 SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n", 287 NTO_CloseDevice(this);
380 snd_strerror(rval)); 288 NTO_SetError("snd_pcm_plugin_set_disable", rval);
381 return (-1); 289 return 0;
382 } 290 }
383 } 291 }
384 292
385 /* Try for a closest match on audio format */ 293 /* Try for a closest match on audio format */
386 format = 0; 294 format = 0;
387 /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */ 295 /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */
388 found = 0; 296 found = 0;
389 297
390 for (test_format = SDL_FirstAudioFormat(spec->format); !found;) { 298 for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) {
391 /* if match found set format to equivalent ALSA format */ 299 /* if match found set format to equivalent ALSA format */
392 switch (test_format) { 300 switch (test_format) {
393 case AUDIO_U8: 301 case AUDIO_U8:
394 format = SND_PCM_SFMT_U8; 302 format = SND_PCM_SFMT_U8;
395 found = 1; 303 found = 1;
439 } 347 }
440 } 348 }
441 349
442 /* assumes test_format not 0 on success */ 350 /* assumes test_format not 0 on success */
443 if (test_format == 0) { 351 if (test_format == 0) {
444 SDL_SetError 352 NTO_CloseDevice(this);
445 ("NTO_OpenAudio(): Couldn't find any hardware audio formats"); 353 SDL_SetError("NTO: Couldn't find any hardware audio formats");
446 return (-1); 354 return 0;
447 } 355 }
448 356
449 spec->format = test_format; 357 this->spec.format = test_format;
450 358
451 /* Set the audio format */ 359 /* Set the audio format */
452 cparams.format.format = format; 360 cparams.format.format = format;
453 361
454 /* Set mono or stereo audio (currently only two channels supported) */ 362 /* Set mono or stereo audio (currently only two channels supported) */
455 cparams.format.voices = spec->channels; 363 cparams.format.voices = this->spec.channels;
456 364
457 /* Set rate */ 365 /* Set rate */
458 cparams.format.rate = spec->freq; 366 cparams.format.rate = this->spec.freq;
459 367
460 /* Setup the transfer parameters according to cparams */ 368 /* Setup the transfer parameters according to cparams */
461 rval = snd_pcm_plugin_params(audio_handle, &cparams); 369 rval = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
462 if (rval < 0) { 370 if (rval < 0) {
463 SDL_SetError 371 NTO_CloseDevice(this);
464 ("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n", 372 NTO_SetError("snd_pcm_channel_params", rval);
465 snd_strerror(rval)); 373 return 0;
466 return (-1);
467 } 374 }
468 375
469 /* Make sure channel is setup right one last time */ 376 /* Make sure channel is setup right one last time */
470 SDL_memset(&csetup, 0x00, sizeof(csetup)); 377 SDL_memset(&csetup, '\0', sizeof (csetup));
471 csetup.channel = SND_PCM_CHANNEL_PLAYBACK; 378 csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
472 if (snd_pcm_plugin_setup(audio_handle, &csetup) < 0) { 379 if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
473 SDL_SetError("NTO_OpenAudio(): Unable to setup playback channel\n"); 380 NTO_CloseDevice(this);
474 return -1; 381 SDL_SetError("NTO: Unable to setup playback channel\n");
475 } 382 return 0;
476 383 }
477 384
478 /* Calculate the final parameters for this audio specification */ 385 /* Calculate the final parameters for this audio specification */
479 SDL_CalculateAudioSpec(spec); 386 SDL_CalculateAudioSpec(&this->spec);
480 387
481 pcm_len = spec->size; 388 this->hidden->pcm_len = this->spec.size;
482 389
483 if (pcm_len == 0) { 390 if (this->hidden->pcm_len == 0) {
484 pcm_len = 391 this->hidden->pcm_len =
485 csetup.buf.block.frag_size * spec->channels * 392 csetup.buf.block.frag_size * this->spec.channels *
486 (snd_pcm_format_width(format) / 8); 393 (snd_pcm_format_width(format) / 8);
487 } 394 }
488 395
489 /* Allocate memory to the audio buffer and initialize with silence (Note that 396 /*
490 buffer size must be a multiple of fragment size, so find closest multiple) 397 * Allocate memory to the audio buffer and initialize with silence
398 * (Note that buffer size must be a multiple of fragment size, so find
399 * closest multiple)
491 */ 400 */
492 pcm_buf = (Uint8 *) SDL_AllocAudioMem(pcm_len); 401 this->hidden->pcm_buf = (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len);
493 if (pcm_buf == NULL) { 402 if (this->hidden->pcm_buf == NULL) {
494 SDL_SetError("NTO_OpenAudio(): pcm buffer allocation failed\n"); 403 NTO_CloseDevice(this);
495 return (-1); 404 SDL_OutOfMemory();
496 } 405 return 0;
497 SDL_memset(pcm_buf, spec->silence, pcm_len); 406 }
407 SDL_memset(this->hidden->pcm_buf,this->spec.silence,this->hidden->pcm_len);
498 408
499 /* get the file descriptor */ 409 /* get the file descriptor */
500 if ((audio_fd = 410 this->hidden->audio_fd = snd_pcm_file_descriptor(this->hidden->audio_handle,
501 snd_pcm_file_descriptor(audio_handle, 411 SND_PCM_CHANNEL_PLAYBACK);
502 SND_PCM_CHANNEL_PLAYBACK)) < 0) { 412 if (this->hidden->audio_fd < 0) {
503 SDL_SetError 413 NTO_CloseDevice(this);
504 ("NTO_OpenAudio(): snd_pcm_file_descriptor failed with error code: %s\n", 414 NTO_SetError("snd_pcm_file_descriptor", rval);
505 snd_strerror(rval)); 415 return 0;
506 return (-1);
507 } 416 }
508 417
509 /* Trigger audio playback */ 418 /* Trigger audio playback */
510 rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK); 419 rval = snd_pcm_plugin_prepare(this->hidden->audio_handle,
420 SND_PCM_CHANNEL_PLAYBACK);
511 if (rval < 0) { 421 if (rval < 0) {
512 SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", 422 NTO_CloseDevice(this);
513 snd_strerror(rval)); 423 NTO_SetError("snd_pcm_plugin_prepare", rval);
514 return (-1); 424 return 0;
515 } 425 }
516
517 this->enabled = 1;
518
519 /* Get the parent process id (we're the parent of the audio thread) */
520 parent = getpid();
521 426
522 /* We're really ready to rock and roll. :-) */ 427 /* We're really ready to rock and roll. :-) */
523 return (0); 428 return 1;
524 } 429 }
430
431
432 static int
433 NTO_Init(SDL_AudioDriverImpl *impl)
434 {
435 /* See if we can open a nonblocking channel. */
436 snd_pcm_t *handle = NULL;
437 int rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
438 if (rval < 0) {
439 SDL_SetError("NTO: couldn't open preferred audio device");
440 return 0;
441 }
442 if ((rval = snd_pcm_close(handle)) < 0) {
443 SDL_SetError("NTO: couldn't close test audio device");
444 return 0;
445 }
446
447 /* Set the function pointers */
448 impl->OpenDevice = NTO_OpenDevice;
449 impl->ThreadInit = NTO_ThreadInit;
450 impl->WaitDevice = NTO_WaitDevice;
451 impl->PlayDevice = NTO_PlayDevice;
452 impl->GetDeviceBuf = NTO_GetDeviceBuf;
453 impl->CloseDevice = NTO_CloseDevice;
454 impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
455
456 return 1;
457 }
458
459 AudioBootStrap QNXNTOAUDIO_bootstrap = {
460 DRIVER_NAME, "QNX6 QSA-NTO Audio", NTO_Init, 0
461 };
525 462
526 /* vi: set ts=4 sw=4 expandtab: */ 463 /* vi: set ts=4 sw=4 expandtab: */