1 /*
2 * Auvia BeOS Driver for Via VT82xx Southbridge audio
3 *
4 * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
5
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Tyler C. Sarna
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the NetBSD
20 * Foundation, Inc. and its contributors.
21 * 4. Neither the name of The NetBSD Foundation nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <KernelExport.h>
39 #include <PCI.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include "auvia.h"
43 #include "debug.h"
44 #include "config.h"
45 #include "util.h"
46 #include "io.h"
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include "ac97.h"
50
51 status_t init_hardware(void);
52 status_t init_driver(void);
53 void uninit_driver(void);
54 const char ** publish_devices(void);
55 device_hooks * find_device(const char *);
56
57 pci_module_info *pci;
58
59 int32 num_cards;
60 auvia_dev cards[NUM_CARDS];
61 int32 num_names;
62 char * names[NUM_CARDS*20+1];
63
64 extern device_hooks multi_hooks;
65
66 /* Auvia Memory management */
67
68 static auvia_mem *
auvia_mem_new(auvia_dev * card,size_t size)69 auvia_mem_new(auvia_dev *card, size_t size)
70 {
71 auvia_mem *mem;
72
73 if ((mem = malloc(sizeof(*mem))) == NULL)
74 return (NULL);
75
76 mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "auvia buffer", true);
77 mem->size = size;
78 if (mem->area < B_OK) {
79 free(mem);
80 return NULL;
81 }
82 return mem;
83 }
84
85
86 static void
auvia_mem_delete(auvia_mem * mem)87 auvia_mem_delete(auvia_mem *mem)
88 {
89 if(mem->area > B_OK)
90 delete_area(mem->area);
91 free(mem);
92 }
93
94
95 static void *
auvia_mem_alloc(auvia_dev * card,size_t size)96 auvia_mem_alloc(auvia_dev *card, size_t size)
97 {
98 auvia_mem *mem;
99
100 mem = auvia_mem_new(card, size);
101 if (mem == NULL)
102 return (NULL);
103
104 LIST_INSERT_HEAD(&(card->mems), mem, next);
105
106 return mem;
107 }
108
109
110 static void
auvia_mem_free(auvia_dev * card,void * ptr)111 auvia_mem_free(auvia_dev *card, void *ptr)
112 {
113 auvia_mem *mem;
114
115 LIST_FOREACH(mem, &card->mems, next) {
116 if (mem->log_base != ptr)
117 continue;
118 LIST_REMOVE(mem, next);
119
120 auvia_mem_delete(mem);
121 break;
122 }
123 }
124
125 /* Auvia stream functions */
126
127 status_t
auvia_stream_set_audioparms(auvia_stream * stream,uint8 channels,uint8 b16,uint32 sample_rate)128 auvia_stream_set_audioparms(auvia_stream *stream, uint8 channels,
129 uint8 b16, uint32 sample_rate)
130 {
131 uint8 sample_size, frame_size;
132 LOG(("auvia_stream_set_audioparms\n"));
133
134 if ((stream->channels == channels) &&
135 (stream->b16 == b16) &&
136 (stream->sample_rate == sample_rate))
137 return B_OK;
138
139 if(stream->buffer)
140 auvia_mem_free(stream->card, stream->buffer->log_base);
141
142 stream->b16 = b16;
143 stream->sample_rate = sample_rate;
144 stream->channels = channels;
145
146 sample_size = stream->b16 + 1;
147 frame_size = sample_size * stream->channels;
148
149 stream->buffer = auvia_mem_alloc(stream->card, stream->bufframes
150 * frame_size * stream->bufcount);
151
152 stream->trigblk = 0; /* This shouldn't be needed */
153 stream->blkmod = stream->bufcount;
154 stream->blksize = stream->bufframes * frame_size;
155
156 return B_OK;
157 }
158
159
160 status_t
auvia_stream_commit_parms(auvia_stream * stream)161 auvia_stream_commit_parms(auvia_stream *stream)
162 {
163 int i;
164 uint32* page;
165 uint32 value;
166 LOG(("auvia_stream_commit_parms\n"));
167
168 page = stream->dmaops_log_base;
169
170 for(i = 0; i < stream->bufcount; i++) {
171 page[2 * i] = stream->buffer->phy_base + i * stream->blksize;
172 page[2 * i + 1] = AUVIA_DMAOP_FLAG | stream->blksize;
173 }
174
175 page[2 * stream->bufcount - 1] &= ~AUVIA_DMAOP_FLAG;
176 page[2 * stream->bufcount - 1] |= AUVIA_DMAOP_EOL;
177
178 auvia_reg_write_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE,
179 stream->dmaops_phy_base);
180
181 if(stream->use & AUVIA_USE_RECORD)
182 auvia_codec_write(&stream->card->config, AC97_PCM_L_R_ADC_RATE,
183 (uint16)stream->sample_rate);
184 else
185 auvia_codec_write(&stream->card->config, AC97_PCM_FRONT_DAC_RATE,
186 (uint16)stream->sample_rate);
187
188 if(IS_8233(&stream->card->config)) {
189 if(stream->base != AUVIA_8233_MP_BASE) {
190 value = auvia_reg_read_32(&stream->card->config, stream->base
191 + AUVIA_8233_RP_RATEFMT);
192 value &= ~(AUVIA_8233_RATEFMT_48K | AUVIA_8233_RATEFMT_STEREO
193 | AUVIA_8233_RATEFMT_16BIT);
194 if(stream->use & AUVIA_USE_PLAY)
195 value |= AUVIA_8233_RATEFMT_48K * (stream->sample_rate / 20)
196 / (48000 / 20);
197 value |= (stream->channels == 2 ? AUVIA_8233_RATEFMT_STEREO : 0)
198 | (stream->b16 ? AUVIA_8233_RATEFMT_16BIT : 0);
199 auvia_reg_write_32(&stream->card->config, stream->base
200 + AUVIA_8233_RP_RATEFMT, value);
201 } else {
202 static const uint32 slottab[7] = {0, 0xff000011, 0xff000021,
203 0xff000521, 0xff004321, 0xff054321, 0xff654321};
204 value = (stream->b16 ? AUVIA_8233_MP_FORMAT_16BIT : AUVIA_8233_MP_FORMAT_8BIT)
205 | ((stream->channels << 4) & AUVIA_8233_MP_FORMAT_CHANNEL_MASK);
206 auvia_reg_write_8(&stream->card->config, stream->base
207 + AUVIA_8233_OFF_MP_FORMAT, value);
208 auvia_reg_write_32(&stream->card->config, stream->base
209 + AUVIA_8233_OFF_MP_STOP, slottab[stream->channels]);
210 }
211 }
212 //auvia_codec_write(&stream->card->config, AC97_SPDIF_CONTROL, (uint16)stream->sample_rate);
213
214 return B_OK;
215 }
216
217
218 status_t
auvia_stream_get_nth_buffer(auvia_stream * stream,uint8 chan,uint8 buf,char ** buffer,size_t * stride)219 auvia_stream_get_nth_buffer(auvia_stream *stream, uint8 chan, uint8 buf,
220 char** buffer, size_t *stride)
221 {
222 uint8 sample_size, frame_size;
223 LOG(("auvia_stream_get_nth_buffer\n"));
224
225 sample_size = stream->b16 + 1;
226 frame_size = sample_size * stream->channels;
227
228 *buffer =(char *)((addr_t)stream->buffer->log_base + (uintptr_t)(buf * stream->bufframes * frame_size))
229 + chan * sample_size;
230 *stride = frame_size;
231
232 return B_OK;
233 }
234
235
236 static uint32
auvia_stream_curaddr(auvia_stream * stream)237 auvia_stream_curaddr(auvia_stream *stream)
238 {
239 uint32 addr;
240 if(IS_8233(&stream->card->config)) {
241 addr = auvia_reg_read_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE);
242 TRACE(("stream_curaddr %p, phy_base %p\n", addr, stream->dmaops_phy_base));
243 return (addr - stream->dmaops_phy_base - 4) / 8;
244 } else {
245 addr = auvia_reg_read_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE);
246 TRACE(("stream_curaddr %p, phy_base %p\n", addr, stream->dmaops_phy_base));
247 return (addr - stream->dmaops_phy_base - 8) / 8;
248 }
249 }
250
251
252 void
auvia_stream_start(auvia_stream * stream,void (* inth)(void *),void * inthparam)253 auvia_stream_start(auvia_stream *stream, void (*inth) (void *), void *inthparam)
254 {
255 LOG(("auvia_stream_start\n"));
256
257 stream->inth = inth;
258 stream->inthparam = inthparam;
259
260 stream->state |= AUVIA_STATE_STARTED;
261
262 if(IS_8233(&stream->card->config)) {
263 if(stream->base != AUVIA_8233_MP_BASE) {
264 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_8233_RP_DXS_LVOL, 0);
265 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_8233_RP_DXS_RVOL, 0);
266 }
267 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_CONTROL,
268 AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART | AUVIA_RPCTRL_STOP
269 | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
270 } else {
271 uint8 regvalue = (stream->channels > 1 ? AUVIA_RPMODE_STEREO : 0)
272 | (stream->b16 == 1 ? AUVIA_RPMODE_16BIT : 0)
273 | AUVIA_RPMODE_INTR_FLAG | AUVIA_RPMODE_INTR_EOL | AUVIA_RPMODE_AUTOSTART;
274 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_MODE, regvalue);
275 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_CONTROL,
276 AUVIA_RPCTRL_START);
277 }
278 }
279
280
281 void
auvia_stream_halt(auvia_stream * stream)282 auvia_stream_halt(auvia_stream *stream)
283 {
284 LOG(("auvia_stream_halt\n"));
285
286 stream->state &= ~AUVIA_STATE_STARTED;
287
288 auvia_reg_write_8(&stream->card->config, stream->base + AUVIA_RP_CONTROL,
289 AUVIA_RPCTRL_TERMINATE);
290 }
291
292
293 auvia_stream *
auvia_stream_new(auvia_dev * card,uint8 use,uint32 bufframes,uint8 bufcount)294 auvia_stream_new(auvia_dev *card, uint8 use, uint32 bufframes, uint8 bufcount)
295 {
296 auvia_stream *stream;
297 cpu_status status;
298 LOG(("auvia_stream_new\n"));
299
300 stream = malloc(sizeof(auvia_stream));
301 if (stream == NULL)
302 return (NULL);
303 stream->card = card;
304 stream->use = use;
305 stream->state = !AUVIA_STATE_STARTED;
306 stream->b16 = 0;
307 stream->sample_rate = 0;
308 stream->channels = 0;
309 stream->bufframes = bufframes;
310 stream->bufcount = bufcount;
311 stream->inth = NULL;
312 stream->inthparam = NULL;
313 stream->buffer = NULL;
314 stream->blksize = 0;
315 stream->trigblk = 0;
316 stream->blkmod = 0;
317
318 if(use & AUVIA_USE_PLAY) {
319 if(IS_8233(&card->config))
320 stream->base = AUVIA_8233_MP_BASE;
321 //stream->base = AUVIA_PLAY_BASE;
322 else
323 stream->base = AUVIA_PLAY_BASE;
324 } else {
325 if(IS_8233(&card->config))
326 stream->base = AUVIA_8233_RECORD_BASE;
327 else
328 stream->base = AUVIA_RECORD_BASE;
329 }
330
331 stream->frames_count = 0;
332 stream->real_time = 0;
333 stream->buffer_cycle = 0;
334 stream->update_needed = false;
335
336 /* allocate memory for our dma ops */
337 stream->dmaops_area = alloc_mem(&stream->dmaops_phy_base, &stream->dmaops_log_base,
338 VIA_TABLE_SIZE, "auvia dmaops", false);
339
340 if (stream->dmaops_area < B_OK) {
341 PRINT(("couldn't allocate memory\n"));
342 free(stream);
343 return NULL;
344 }
345
346 status = lock();
347 LIST_INSERT_HEAD((&card->streams), stream, next);
348 unlock(status);
349
350 return stream;
351 }
352
353
354 void
auvia_stream_delete(auvia_stream * stream)355 auvia_stream_delete(auvia_stream *stream)
356 {
357 cpu_status status;
358 LOG(("auvia_stream_delete\n"));
359
360 auvia_stream_halt(stream);
361
362 auvia_reg_write_32(&stream->card->config, stream->base + AUVIA_RP_DMAOPS_BASE, 0);
363
364 if (stream->dmaops_area > B_OK)
365 delete_area(stream->dmaops_area);
366
367 if(stream->buffer)
368 auvia_mem_free(stream->card, stream->buffer->log_base);
369
370 status = lock();
371 LIST_REMOVE(stream, next);
372 unlock(status);
373
374 free(stream);
375 }
376
377 /* Auvia interrupt */
378
379 static int32
auvia_int(void * arg)380 auvia_int(void *arg)
381 {
382 auvia_dev *card = arg;
383 bool gotone = false;
384 uint32 curblk;
385 auvia_stream *stream;
386
387 if(auvia_reg_read_32(&card->config, AUVIA_SGD_SHADOW)
388 & card->interrupt_mask) {
389
390 LIST_FOREACH(stream, &card->streams, next)
391 if(auvia_reg_read_8(&card->config, stream->base + AUVIA_RP_STAT) & AUVIA_RPSTAT_INTR) {
392 gotone = true;
393 //TRACE(("interrupt\n"));
394
395 curblk = auvia_stream_curaddr(stream);
396 TRACE(("RPSTAT_INTR at trigblk %lu, stream->trigblk %lu\n", curblk, stream->trigblk));
397 if (curblk == stream->trigblk) {
398 //TRACE(("AUVIA_RPSTAT_INTR at trigblk %lu\n", curblk));
399
400 if(stream->inth)
401 stream->inth(stream->inthparam);
402
403 stream->trigblk++;
404 stream->trigblk %= stream->blkmod;
405 }
406
407 auvia_reg_write_8(&card->config, stream->base + AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
408 }
409 } else {
410 TRACE(("SGD_SHADOW %x %x\n", card->interrupt_mask,
411 auvia_reg_read_32(&card->config, AUVIA_SGD_SHADOW)));
412 }
413
414 if(gotone)
415 return B_INVOKE_SCHEDULER;
416
417 TRACE(("Got unhandled interrupt\n"));
418 return B_UNHANDLED_INTERRUPT;
419 }
420
421 /* Auvia driver functions */
422
423 /* detect presence of our hardware */
424 status_t
init_hardware(void)425 init_hardware(void)
426 {
427 int ix=0;
428 pci_info info;
429 status_t err = ENODEV;
430
431 LOG_CREATE();
432
433 PRINT(("init_hardware()\n"));
434
435 if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci))
436 return ENOSYS;
437
438 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
439 if (info.vendor_id == VIATECH_VENDOR_ID &&
440 (info.device_id == VIATECH_82C686_AC97_DEVICE_ID
441 || info.device_id == VIATECH_8233_AC97_DEVICE_ID
442 )) {
443 err = B_OK;
444 }
445 ix++;
446 }
447
448 put_module(B_PCI_MODULE_NAME);
449
450 return err;
451 }
452
453 static void
make_device_names(auvia_dev * card)454 make_device_names(
455 auvia_dev * card)
456 {
457 sprintf(card->name, "audio/hmulti/auvia/%ld", card-cards+1);
458 names[num_names++] = card->name;
459
460 names[num_names] = NULL;
461 }
462
463
464 static status_t
auvia_init(auvia_dev * card)465 auvia_init(auvia_dev * card)
466 {
467 uint32 pr;
468
469 pr = (*pci->read_pci_config)(card->info.bus, card->info.device,
470 card->info.function, AUVIA_PCICONF_JUNK, 4);
471 PRINT(("AUVIA_PCICONF_JUNK before: %" B_PRIx32 "\n", pr));
472 pr &= ~AUVIA_PCICONF_ENABLES;
473 pr |= AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST
474 | AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD;
475 pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB);
476 (*pci->write_pci_config)(card->info.bus, card->info.device,
477 card->info.function, AUVIA_PCICONF_JUNK, 4, pr );
478 snooze(100);
479 pr = (*pci->read_pci_config)(card->info.bus, card->info.device,
480 card->info.function, AUVIA_PCICONF_JUNK, 4);
481 PRINT(("AUVIA_PCICONF_JUNK after: %" B_PRIx32 "\n", pr));
482
483 if(IS_8233(&card->config)) {
484 card->interrupt_mask =
485 AUVIA_8233_SGD_STAT_FLAG_EOL |
486 AUVIA_8233_SGD_STAT_FLAG_EOL << 4 |
487 AUVIA_8233_SGD_STAT_FLAG_EOL << 8 |
488 AUVIA_8233_SGD_STAT_FLAG_EOL << 12 |
489 AUVIA_8233_SGD_STAT_FLAG_EOL << 16 |
490 AUVIA_8233_SGD_STAT_FLAG_EOL << 24 |
491 AUVIA_8233_SGD_STAT_FLAG_EOL << 28;
492 } else {
493 card->interrupt_mask = AUVIA_SGD_STAT_ALL | (AUVIA_SGD_STAT_ALL << 4);
494 }
495
496
497 /* Init streams list */
498 LIST_INIT(&(card->streams));
499
500 /* Init mems list */
501 LIST_INIT(&(card->mems));
502
503 return B_OK;
504 }
505
506
507 static void
auvia_shutdown(auvia_dev * card)508 auvia_shutdown(auvia_dev *card)
509 {
510 PRINT(("shutdown(%p)\n", card));
511 ac97_detach(card->config.ac97);
512 remove_io_interrupt_handler(card->config.irq, auvia_int, card);
513 }
514
515
516 static status_t
auvia_setup(auvia_dev * card)517 auvia_setup(auvia_dev * card)
518 {
519 status_t err = B_OK;
520 unsigned char cmd;
521
522 PRINT(("auvia_setup(%p)\n", card));
523
524 make_device_names(card);
525
526 card->config.subvendor_id = card->info.u.h0.subsystem_vendor_id;
527 card->config.subsystem_id = card->info.u.h0.subsystem_id;
528 card->config.nabmbar = card->info.u.h0.base_registers[0];
529 card->config.irq = card->info.u.h0.interrupt_line;
530 card->config.type = 0;
531 if(card->info.device_id == VIATECH_82C686_AC97_DEVICE_ID)
532 card->config.type |= TYPE_686;
533 if(card->info.device_id == VIATECH_8233_AC97_DEVICE_ID)
534 card->config.type |= TYPE_8233;
535
536 PRINT(("%s deviceid = %#04x chiprev = %x model = %x enhanced "
537 "at %" B_PRIx32 "\n",
538 card->name, card->info.device_id, card->info.revision,
539 card->info.u.h0.subsystem_id, card->config.nabmbar));
540
541 cmd = (*pci->read_pci_config)(card->info.bus, card->info.device,
542 card->info.function, PCI_command, 2);
543 PRINT(("PCI command before: %x\n", cmd));
544 (*pci->write_pci_config)(card->info.bus, card->info.device,
545 card->info.function, PCI_command, 2, cmd | PCI_command_io);
546 cmd = (*pci->read_pci_config)(card->info.bus, card->info.device,
547 card->info.function, PCI_command, 2);
548 PRINT(("PCI command after: %x\n", cmd));
549
550 /* attach the codec */
551 PRINT(("codec attach\n"));
552 ac97_attach(&card->config.ac97, (codec_reg_read)auvia_codec_read,
553 (codec_reg_write)auvia_codec_write, &card->config,
554 card->config.subvendor_id, card->config.subsystem_id);
555
556 PRINT(("installing interrupt : %" B_PRIx32 "\n", card->config.irq));
557 err = install_io_interrupt_handler(card->config.irq, auvia_int, card, 0);
558 if (err != B_OK) {
559 PRINT(("failed to install interrupt\n"));
560 ac97_detach(card->config.ac97);
561 return err;
562 }
563
564 if ((err = auvia_init(card))) {
565 auvia_shutdown(card);
566 return err;
567 }
568
569 PRINT(("init_driver done\n"));
570
571 return err;
572 }
573
574
575 status_t
init_driver(void)576 init_driver(void)
577 {
578 pci_info info;
579 status_t err;
580 int ix = 0;
581 num_cards = 0;
582
583 PRINT(("init_driver()\n"));
584
585 if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci))
586 return ENOSYS;
587
588 while ((*pci->get_nth_pci_info)(ix++, &info) == B_OK) {
589 if (info.vendor_id == VIATECH_VENDOR_ID &&
590 (info.device_id == VIATECH_82C686_AC97_DEVICE_ID
591 || info.device_id == VIATECH_8233_AC97_DEVICE_ID
592 )) {
593 if (num_cards == NUM_CARDS) {
594 PRINT(("Too many auvia cards installed!\n"));
595 break;
596 }
597 memset(&cards[num_cards], 0, sizeof(auvia_dev));
598 cards[num_cards].info = info;
599 #ifdef __HAIKU__
600 if ((err = (*pci->reserve_device)(info.bus, info.device, info.function,
601 DRIVER_NAME, &cards[num_cards])) < B_OK) {
602 dprintf("%s: failed to reserve_device(%d, %d, %d,): %s\n",
603 DRIVER_NAME, info.bus, info.device, info.function,
604 strerror(err));
605 continue;
606 }
607 #endif
608 if (auvia_setup(&cards[num_cards])) {
609 PRINT(("Setup of auvia %" B_PRId32 " failed\n", num_cards + 1));
610 #ifdef __HAIKU__
611 (*pci->unreserve_device)(info.bus, info.device, info.function,
612 DRIVER_NAME, &cards[num_cards]);
613 #endif
614 }
615 else {
616 num_cards++;
617 }
618 }
619 }
620 if (!num_cards) {
621 PRINT(("no cards\n"));
622 put_module(B_PCI_MODULE_NAME);
623 PRINT(("no suitable cards found\n"));
624 return ENODEV;
625 }
626
627
628 #if DEBUG
629 //add_debugger_command("auvia", auvia_debug, "auvia [card# (1-n)]");
630 #endif
631 return B_OK;
632 }
633
634
635 void
uninit_driver(void)636 uninit_driver(void)
637 {
638 int ix, cnt = num_cards;
639 num_cards = 0;
640
641 PRINT(("uninit_driver()\n"));
642 //remove_debugger_command("auvia", auvia_debug);
643
644 for (ix=0; ix<cnt; ix++) {
645 auvia_shutdown(&cards[ix]);
646 #ifdef __HAIKU__
647 (*pci->unreserve_device)(cards[ix].info.bus,
648 cards[ix].info.device, cards[ix].info.function,
649 DRIVER_NAME, &cards[ix]);
650 #endif
651 }
652 memset(&cards, 0, sizeof(cards));
653 put_module(B_PCI_MODULE_NAME);
654 }
655
656
657 const char **
publish_devices(void)658 publish_devices(void)
659 {
660 int ix = 0;
661 PRINT(("publish_devices()\n"));
662
663 for (ix=0; names[ix]; ix++) {
664 PRINT(("publish %s\n", names[ix]));
665 }
666 return (const char **)names;
667 }
668
669
670 device_hooks *
find_device(const char * name)671 find_device(const char * name)
672 {
673 int ix;
674
675 PRINT(("find_device(%s)\n", name));
676
677 for (ix=0; ix<num_cards; ix++) {
678 if (!strcmp(cards[ix].name, name)) {
679 return &multi_hooks;
680 }
681 }
682 PRINT(("find_device(%s) failed\n", name));
683 return NULL;
684 }
685
686 int32 api_version = B_CUR_DRIVER_API_VERSION;
687