fm801.c revision 65340
1/* 2 * Copyright (c) 2000 Dmitry Dicky diwil@dataart.com 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/dev/sound/pci/fm801.c 65340 2000-09-01 20:09:24Z cg $ 27 */ 28 29#include <dev/sound/pcm/sound.h> 30#include <dev/sound/pcm/ac97.h> 31#include <pci/pcireg.h> 32#include <pci/pcivar.h> 33 34#define PCI_VENDOR_FORTEMEDIA 0x1319 35#define PCI_DEVICE_FORTEMEDIA1 0x08011319 36#define PCI_DEVICE_FORTEMEDIA2 0x08021319 /* ??? have no idea what's this... */ 37 38#define FM_PCM_VOLUME 0x00 39#define FM_FM_VOLUME 0x02 40#define FM_I2S_VOLUME 0x04 41#define FM_RECORD_SOURCE 0x06 42 43#define FM_PLAY_CTL 0x08 44#define FM_PLAY_RATE_MASK 0x0f00 45#define FM_PLAY_BUF1_LAST 0x0001 46#define FM_PLAY_BUF2_LAST 0x0002 47#define FM_PLAY_START 0x0020 48#define FM_PLAY_PAUSE 0x0040 49#define FM_PLAY_STOPNOW 0x0080 50#define FM_PLAY_16BIT 0x4000 51#define FM_PLAY_STEREO 0x8000 52 53#define FM_PLAY_DMALEN 0x0a 54#define FM_PLAY_DMABUF1 0x0c 55#define FM_PLAY_DMABUF2 0x10 56 57 58#define FM_REC_CTL 0x14 59#define FM_REC_RATE_MASK 0x0f00 60#define FM_REC_BUF1_LAST 0x0001 61#define FM_REC_BUF2_LAST 0x0002 62#define FM_REC_START 0x0020 63#define FM_REC_PAUSE 0x0040 64#define FM_REC_STOPNOW 0x0080 65#define FM_REC_16BIT 0x4000 66#define FM_REC_STEREO 0x8000 67 68 69#define FM_REC_DMALEN 0x16 70#define FM_REC_DMABUF1 0x18 71#define FM_REC_DMABUF2 0x1c 72 73#define FM_CODEC_CTL 0x22 74#define FM_VOLUME 0x26 75#define FM_VOLUME_MUTE 0x8000 76 77#define FM_CODEC_CMD 0x2a 78#define FM_CODEC_CMD_READ 0x0080 79#define FM_CODEC_CMD_VALID 0x0100 80#define FM_CODEC_CMD_BUSY 0x0200 81 82#define FM_CODEC_DATA 0x2c 83 84#define FM_IO_CTL 0x52 85#define FM_CARD_CTL 0x54 86 87#define FM_INTMASK 0x56 88#define FM_INTMASK_PLAY 0x0001 89#define FM_INTMASK_REC 0x0002 90#define FM_INTMASK_VOL 0x0040 91#define FM_INTMASK_MPU 0x0080 92 93#define FM_INTSTATUS 0x5a 94#define FM_INTSTATUS_PLAY 0x0100 95#define FM_INTSTATUS_REC 0x0200 96#define FM_INTSTATUS_VOL 0x4000 97#define FM_INTSTATUS_MPU 0x8000 98 99#define FM801_BUFFSIZE 1024*4 /* Other values do not work!!! */ 100 101/* debug purposes */ 102#define DPRINT if(0) printf 103 104 105/* channel interface */ 106static void *fm801ch_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); 107static int fm801ch_setdir(void *data, int dir); 108static int fm801ch_setformat(void *data, u_int32_t format); 109static int fm801ch_setspeed(void *data, u_int32_t speed); 110static int fm801ch_setblocksize(void *data, u_int32_t blocksize); 111static int fm801ch_trigger(void *data, int go); 112static int fm801ch_getptr(void *data); 113static pcmchan_caps *fm801ch_getcaps(void *data); 114/* 115static int fm801ch_setup(pcm_channel *c); 116*/ 117 118static u_int32_t fmts[] = { 119 AFMT_U8, 120 AFMT_STEREO | AFMT_U8, 121 AFMT_S16_LE, 122 AFMT_STEREO | AFMT_S16_LE, /* 123 AFMT_STEREO | (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE), 124 (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE), */ 125 0 126}; 127 128static pcmchan_caps fm801ch_caps = { 129 4000, 48000, 130 fmts, 0 131}; 132 133static pcm_channel fm801_chantemplate = { 134 fm801ch_init, 135 fm801ch_setdir, 136 fm801ch_setformat, 137 fm801ch_setspeed, 138 fm801ch_setblocksize, 139 fm801ch_trigger, 140 fm801ch_getptr, 141 fm801ch_getcaps, 142 NULL, /* free */ 143 NULL, /* nop1 */ 144 NULL, /* nop2 */ 145 NULL, /* nop3 */ 146 NULL, /* nop4 */ 147 NULL, /* nop5 */ 148 NULL, /* nop6 */ 149 NULL, /* nop7 */ 150}; 151 152struct fm801_info; 153 154struct fm801_chinfo { 155 struct fm801_info *parent; 156 pcm_channel *channel; 157 snd_dbuf *buffer; 158 u_int32_t spd, dir, fmt; /* speed, direction, format */ 159 u_int32_t shift; 160}; 161 162struct fm801_info { 163 int type; 164 bus_space_tag_t st; 165 bus_space_handle_t sh; 166 bus_dma_tag_t parent_dmat; 167 168 device_t dev; 169 int num; 170 u_int32_t unit; 171 172 struct resource *reg, *irq; 173 int regtype, regid, irqid; 174 void *ih; 175 176 u_int32_t play_flip, 177 play_nextblk, 178 play_start, 179 play_blksize, 180 play_fmt, 181 play_shift, 182 play_size; 183 184 u_int32_t rec_flip, 185 rec_nextblk, 186 rec_start, 187 rec_blksize, 188 rec_fmt, 189 rec_shift, 190 rec_size; 191 192 struct fm801_chinfo pch, rch; 193}; 194 195 196/* several procedures to release the thing properly if compiled as module */ 197static struct fm801_info *save801; 198struct fm801_info *fm801_get __P((void )); 199 200static void 201fm801_save(struct fm801_info *fm801) 202{ 203 save801 = fm801; 204} 205 206struct fm801_info * 207fm801_get(void ) 208{ 209 return save801; 210} 211 212/* Bus Read / Write routines */ 213static u_int32_t 214fm801_rd(struct fm801_info *fm801, int regno, int size) 215{ 216 switch(size) { 217 case 1: 218 return (bus_space_read_1(fm801->st, fm801->sh, regno)); 219 case 2: 220 return (bus_space_read_2(fm801->st, fm801->sh, regno)); 221 case 4: 222 return (bus_space_read_4(fm801->st, fm801->sh, regno)); 223 default: 224 return 0xffffffff; 225 } 226} 227 228static void 229fm801_wr(struct fm801_info *fm801, int regno, u_int32_t data, int size) 230{ 231 switch(size) { 232 case 1: 233 return bus_space_write_1(fm801->st, fm801->sh, regno, data); 234 case 2: 235 return bus_space_write_2(fm801->st, fm801->sh, regno, data); 236 case 4: 237 return bus_space_write_4(fm801->st, fm801->sh, regno, data); 238 default: 239 return; 240 } 241} 242 243/* 244 * ac97 codec routines 245 */ 246#define TIMO 50 247static u_int32_t 248fm801_rdcd(void *devinfo, int regno) 249{ 250 struct fm801_info *fm801 = (struct fm801_info *)devinfo; 251 int i; 252 253 for (i = 0; i < TIMO && fm801_rd(fm801,FM_CODEC_CMD,2) & FM_CODEC_CMD_BUSY; i++) { 254 DELAY(10000); 255 DPRINT("fm801 rdcd: 1 - DELAY\n"); 256 } 257 if (i >= TIMO) { 258 printf("fm801 rdcd: codec busy\n"); 259 return 0; 260 } 261 262 fm801_wr(fm801,FM_CODEC_CMD, regno|FM_CODEC_CMD_READ,2); 263 264 for (i = 0; i < TIMO && !(fm801_rd(fm801,FM_CODEC_CMD,2) & FM_CODEC_CMD_VALID); i++) 265 { 266 DELAY(10000); 267 DPRINT("fm801 rdcd: 2 - DELAY\n"); 268 } 269 if (i >= TIMO) { 270 printf("fm801 rdcd: write codec invalid\n"); 271 return 0; 272 } 273 274 return fm801_rd(fm801,FM_CODEC_DATA,2); 275} 276 277static void 278fm801_wrcd(void *devinfo, int regno, u_int32_t data) 279{ 280 struct fm801_info *fm801 = (struct fm801_info *)devinfo; 281 int i; 282 283 DPRINT("fm801_wrcd reg 0x%x val 0x%x\n",regno, data); 284/* 285 if(regno == AC97_REG_RECSEL) return; 286*/ 287 /* Poll until codec is ready */ 288 for (i = 0; i < TIMO && fm801_rd(fm801,FM_CODEC_CMD,2) & FM_CODEC_CMD_BUSY; i++) { 289 DELAY(10000); 290 DPRINT("fm801 rdcd: 1 - DELAY\n"); 291 } 292 if (i >= TIMO) { 293 printf("fm801 wrcd: read codec busy\n"); 294 return; 295 } 296 297 fm801_wr(fm801,FM_CODEC_DATA,data, 2); 298 fm801_wr(fm801,FM_CODEC_CMD, regno,2); 299 300 /* wait until codec is ready */ 301 for (i = 0; i < TIMO && fm801_rd(fm801,FM_CODEC_CMD,2) & FM_CODEC_CMD_BUSY; i++) { 302 DELAY(10000); 303 DPRINT("fm801 wrcd: 2 - DELAY\n"); 304 } 305 if (i >= TIMO) { 306 printf("fm801 wrcd: read codec busy\n"); 307 return; 308 } 309 DPRINT("fm801 wrcd release reg 0x%x val 0x%x\n",regno, data); 310 return; 311} 312 313/* 314 * The interrupt handler 315 */ 316static void 317fm801_intr(void *p) 318{ 319 struct fm801_info *fm801 = (struct fm801_info *)p; 320 u_int32_t intsrc = fm801_rd(fm801, FM_INTSTATUS, 2); 321 struct fm801_chinfo *ch = &(fm801->pch); 322 snd_dbuf *b = ch->buffer; 323 324 DPRINT("\nfm801_intr intsrc 0x%x ", intsrc); 325 DPRINT("rp %d, rl %d, fp %d fl %d, size=%d\n", 326 b->rp,b->rl, b->fp,b->fl, b->blksz); 327 328 if(intsrc & FM_INTSTATUS_PLAY) { 329 fm801->play_flip++; 330 if(fm801->play_flip & 1) { 331 fm801_wr(fm801, FM_PLAY_DMABUF1, fm801->play_start,4); 332 } else 333 fm801_wr(fm801, FM_PLAY_DMABUF2, fm801->play_nextblk,4); 334 chn_intr(fm801->pch.channel); 335 } 336 337 if(intsrc & FM_INTSTATUS_REC) { 338 fm801->rec_flip++; 339 if(fm801->rec_flip & 1) { 340 fm801_wr(fm801, FM_REC_DMABUF1, fm801->rec_start,4); 341 } else 342 fm801_wr(fm801, FM_REC_DMABUF2, fm801->rec_nextblk,4); 343 chn_intr(fm801->rch.channel); 344 } 345 346 if ( intsrc & FM_INTSTATUS_MPU ) { 347 /* This is a TODOish thing... */ 348 fm801_wr(fm801, FM_INTSTATUS, intsrc & FM_INTSTATUS_MPU,2); 349 } 350 351 if ( intsrc & FM_INTSTATUS_VOL ) { 352 /* This is a TODOish thing... */ 353 fm801_wr(fm801, FM_INTSTATUS, intsrc & FM_INTSTATUS_VOL,2); 354 } 355 356 DPRINT("fm801_intr clear\n\n"); 357 fm801_wr(fm801, FM_INTSTATUS, intsrc & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC), 2); 358} 359 360/* 361 * Init routine is taken from an original NetBSD driver 362 */ 363static int 364fm801_init(struct fm801_info *fm801) 365{ 366 u_int32_t k1; 367 368 /* reset codec */ 369 fm801_wr(fm801, FM_CODEC_CTL, 0x0020,2); 370 DELAY(100000); 371 fm801_wr(fm801, FM_CODEC_CTL, 0x0000,2); 372 DELAY(100000); 373 374 fm801_wr(fm801, FM_PCM_VOLUME, 0x0808,2); 375 fm801_wr(fm801, FM_FM_VOLUME, 0x0808,2); 376 fm801_wr(fm801, FM_I2S_VOLUME, 0x0808,2); 377 fm801_wr(fm801, 0x40,0x107f,2); /* enable legacy audio */ 378 379 fm801_wr((void *)fm801, FM_RECORD_SOURCE, 0x0000,2); 380 381 /* Unmask playback, record and mpu interrupts, mask the rest */ 382 k1 = fm801_rd((void *)fm801, FM_INTMASK,2); 383 fm801_wr(fm801, FM_INTMASK, 384 (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) | 385 FM_INTMASK_VOL,2); 386 fm801_wr(fm801, FM_INTSTATUS, 387 FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU | 388 FM_INTSTATUS_VOL,2); 389 390 DPRINT("FM801 init Ok\n"); 391 return 0; 392} 393 394static int 395fm801_pci_attach(device_t dev) 396{ 397 u_int32_t data; 398 struct ac97_info *codec; 399 struct fm801_info *fm801; 400 int i; 401 int mapped = 0; 402 char status[SND_STATUSLEN]; 403 404 if ((fm801 = (struct fm801_info *)malloc(sizeof(*fm801),M_DEVBUF, M_NOWAIT)) == NULL) { 405 device_printf(dev, "cannot allocate softc\n"); 406 return ENXIO; 407 } 408 409 bzero(fm801, sizeof(*fm801)); 410 fm801->type = pci_get_devid(dev); 411 412 data = pci_read_config(dev, PCIR_COMMAND, 2); 413 data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 414 pci_write_config(dev, PCIR_COMMAND, data, 2); 415 data = pci_read_config(dev, PCIR_COMMAND, 2); 416 417 for (i = 0; (mapped == 0) && (i < PCI_MAXMAPS_0); i++) { 418 fm801->regid = PCIR_MAPS + i*4; 419 fm801->regtype = SYS_RES_MEMORY; 420 fm801->reg = bus_alloc_resource(dev, fm801->regtype, &fm801->regid, 421 0, ~0, 1, RF_ACTIVE); 422 if(!fm801->reg) 423 { 424 fm801->regtype = SYS_RES_IOPORT; 425 fm801->reg = bus_alloc_resource(dev, fm801->regtype, &fm801->regid, 426 0, ~0, 1, RF_ACTIVE); 427 } 428 429 if(fm801->reg) { 430 fm801->st = rman_get_bustag(fm801->reg); 431 fm801->sh = rman_get_bushandle(fm801->reg); 432 mapped++; 433 } 434 } 435 436 if (mapped == 0) { 437 device_printf(dev, "unable to map register space\n"); 438 goto oops; 439 } 440 441 fm801_init(fm801); 442 443 codec = ac97_create(dev, (void *)fm801, NULL, fm801_rdcd, fm801_wrcd); 444 if (codec == NULL) goto oops; 445 446 if (mixer_init(dev, &ac97_mixer, codec) == -1) goto oops; 447 448 fm801->irqid = 0; 449 fm801->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &fm801->irqid, 450 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 451 if (!fm801->irq || 452 bus_setup_intr(dev, fm801->irq, INTR_TYPE_TTY, 453 fm801_intr, fm801, &fm801->ih)) { 454 device_printf(dev, "unable to map interrupt\n"); 455 goto oops; 456 } 457 458 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 459 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 460 /*highaddr*/BUS_SPACE_MAXADDR, 461 /*filter*/NULL, /*filterarg*/NULL, 462 /*maxsize*/FM801_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, 463 /*flags*/0, &fm801->parent_dmat) != 0) { 464 device_printf(dev, "unable to create dma tag\n"); 465 goto oops; 466 } 467 468 snprintf(status, 64, "at %s 0x%lx irq %ld", 469 (fm801->regtype == SYS_RES_IOPORT)? "io" : "memory", 470 rman_get_start(fm801->reg), rman_get_start(fm801->irq)); 471 472#define FM801_MAXPLAYCH 1 473 if (pcm_register(dev, fm801, FM801_MAXPLAYCH, 1)) goto oops; 474 pcm_addchan(dev, PCMDIR_PLAY, &fm801_chantemplate, fm801); 475 pcm_addchan(dev, PCMDIR_REC, &fm801_chantemplate, fm801); 476 pcm_setstatus(dev, status); 477 478 fm801_save(fm801); 479 return 0; 480 481oops: 482 printf("Forte Media FM801 initialization failed\n"); 483 if (fm801->reg) bus_release_resource(dev, fm801->regtype, fm801->regid, fm801->reg); 484 if (fm801->ih) bus_teardown_intr(dev, fm801->irq, fm801->ih); 485 if (fm801->irq) bus_release_resource(dev, SYS_RES_IRQ, fm801->irqid, fm801->irq); 486 free(fm801, M_DEVBUF); 487 return ENXIO; 488} 489 490static int 491fm801_pci_probe( device_t dev ) 492{ 493 int id; 494 if ((id = pci_get_devid(dev)) == PCI_DEVICE_FORTEMEDIA1 ) { 495 device_set_desc(dev, "Forte Media FM801 Audio Controller"); 496 return 0; 497 } 498/* 499 if ((id = pci_get_devid(dev)) == PCI_DEVICE_FORTEMEDIA2 ) { 500 device_set_desc(dev, "Forte Media FM801 Joystick (Not Supported)"); 501 return ENXIO; 502 } 503*/ 504 return ENXIO; 505} 506 507 508 509/* channel interface */ 510static void * 511fm801ch_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 512{ 513 struct fm801_info *fm801 = (struct fm801_info *)devinfo; 514 struct fm801_chinfo *ch = (dir == PCMDIR_PLAY)? &fm801->pch : &fm801->rch; 515 516 DPRINT("fm801ch_init, direction = %d\n", dir); 517 ch->parent = fm801; 518 ch->channel = c; 519 ch->buffer = b; 520 ch->buffer->bufsize = FM801_BUFFSIZE; 521 ch->dir = dir; 522 if( chn_allocbuf(ch->buffer, fm801->parent_dmat) == -1) return NULL; 523 return (void *)ch; 524} 525 526static int 527fm801ch_setdir(void *data, int dir) 528{ 529 struct fm801_chinfo *ch = data; 530 ch->dir = dir; 531 return 0; 532} 533 534static int 535fm801ch_setformat(void *data, u_int32_t format) 536{ 537 struct fm801_chinfo *ch = data; 538 struct fm801_info *fm801 = ch->parent; 539 540 DPRINT("fm801ch_setformat 0x%x : %s, %s, %s, %s\n", format, 541 (format & AFMT_STEREO)?"stereo":"mono", 542 (format & (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)) ? "16bit":"8bit", 543 (format & AFMT_SIGNED)? "signed":"unsigned", 544 (format & AFMT_BIGENDIAN)?"bigendiah":"littleendian" ); 545 546 if(ch->dir == PCMDIR_PLAY) { 547 fm801->play_fmt = (format & AFMT_STEREO)? FM_PLAY_STEREO : 0; 548 fm801->play_fmt |= (format & AFMT_16BIT) ? FM_PLAY_16BIT : 0; 549 return 0; 550 } 551 552 if(ch->dir == PCMDIR_REC ) { 553 fm801->rec_fmt = (format & AFMT_STEREO)? FM_REC_STEREO:0; 554 fm801->rec_fmt |= (format & AFMT_16BIT) ? FM_PLAY_16BIT : 0; 555 return 0; 556 } 557 558 return 0; 559} 560 561struct { 562 int limit; 563 int rate; 564} fm801_rates[11] = { 565 { 6600, 5500 }, 566 { 8750, 8000 }, 567 { 10250, 9600 }, 568 { 13200, 11025 }, 569 { 17500, 16000 }, 570 { 20500, 19200 }, 571 { 26500, 22050 }, 572 { 35000, 32000 }, 573 { 41000, 38400 }, 574 { 46000, 44100 }, 575 { 48000, 48000 }, 576/* anything above -> 48000 */ 577}; 578 579static int 580fm801ch_setspeed(void *data, u_int32_t speed) 581{ 582 struct fm801_chinfo *ch = data; 583 struct fm801_info *fm801 = ch->parent; 584 register int i; 585 586 587 for (i = 0; i < 10 && fm801_rates[i].limit <= speed; i++) ; 588 589 if(ch->dir == PCMDIR_PLAY) { 590 fm801->pch.spd = fm801_rates[i].rate; 591 fm801->play_shift = (i<<8); 592 fm801->play_shift &= FM_PLAY_RATE_MASK; 593 } 594 595 if(ch->dir == PCMDIR_REC ) { 596 fm801->rch.spd = fm801_rates[i].rate; 597 fm801->rec_shift = (i<<8); 598 fm801->rec_shift &= FM_REC_RATE_MASK; 599 } 600 601 ch->spd = fm801_rates[i].rate; 602 603 return fm801_rates[i].rate; 604} 605 606static int 607fm801ch_setblocksize(void *data, u_int32_t blocksize) 608{ 609 struct fm801_chinfo *ch = data; 610 struct fm801_info *fm801 = ch->parent; 611 612 if(ch->dir == PCMDIR_PLAY) { 613 if(fm801->play_flip) return fm801->play_blksize; 614 fm801->play_blksize = blocksize; 615 } 616 617 if(ch->dir == PCMDIR_REC) { 618 if(fm801->rec_flip) return fm801->rec_blksize; 619 fm801->rec_blksize = blocksize; 620 } 621 622 DPRINT("fm801ch_setblocksize %d (dir %d)\n",blocksize, ch->dir); 623 624 return blocksize; 625} 626 627static int 628fm801ch_trigger(void *data, int go) 629{ 630 struct fm801_chinfo *ch = data; 631 struct fm801_info *fm801 = ch->parent; 632 u_int32_t baseaddr = vtophys(ch->buffer->buf); 633 snd_dbuf *b = ch->buffer; 634 u_int32_t k1; 635 636 DPRINT("fm801ch_trigger go %d , ", go); 637 DPRINT("rp %d, rl %d, fp %d fl %d, dl %d, blksize=%d\n", 638 b->rp,b->rl, b->fp,b->fl, b->dl, b->blksz); 639 640 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) { 641 return 0; 642 } 643 644 if (ch->dir == PCMDIR_PLAY) { 645 if (go == PCMTRIG_START) { 646 647 fm801->play_start = baseaddr; 648 fm801->play_nextblk = fm801->play_start + fm801->play_blksize; 649 fm801->play_flip = 0; 650 fm801_wr(fm801, FM_PLAY_DMALEN, fm801->play_blksize - 1, 2); 651 fm801_wr(fm801, FM_PLAY_DMABUF1,fm801->play_start,4); 652 fm801_wr(fm801, FM_PLAY_DMABUF2,fm801->play_nextblk,4); 653 fm801_wr(fm801, FM_PLAY_CTL, 654 FM_PLAY_START | FM_PLAY_STOPNOW | fm801->play_fmt | fm801->play_shift, 655 2 ); 656 } else { 657 fm801->play_flip = 0; 658 k1 = fm801_rd(fm801, FM_PLAY_CTL,2); 659 fm801_wr(fm801, FM_PLAY_CTL, 660 (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) | 661 FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST, 2 ); 662 } 663 } else if(ch->dir == PCMDIR_REC) { 664 if (go == PCMTRIG_START) { 665 fm801->rec_start = baseaddr; 666 fm801->rec_nextblk = fm801->rec_start + fm801->rec_blksize; 667 fm801->rec_flip = 0; 668 fm801_wr(fm801, FM_REC_DMALEN, fm801->rec_blksize - 1, 2); 669 fm801_wr(fm801, FM_REC_DMABUF1,fm801->rec_start,4); 670 fm801_wr(fm801, FM_REC_DMABUF2,fm801->rec_nextblk,4); 671 fm801_wr(fm801, FM_REC_CTL, 672 FM_REC_START | FM_REC_STOPNOW | fm801->rec_fmt | fm801->rec_shift, 673 2 ); 674 } else { 675 fm801->rec_flip = 0; 676 k1 = fm801_rd(fm801, FM_REC_CTL,2); 677 fm801_wr(fm801, FM_REC_CTL, 678 (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) | 679 FM_REC_BUF1_LAST | FM_REC_BUF2_LAST, 2); 680 } 681 } 682 683 return 0; 684} 685 686/* Almost ALSA copy */ 687static int 688fm801ch_getptr(void *data) 689{ 690 struct fm801_chinfo *ch = data; 691 struct fm801_info *fm801 = ch->parent; 692 int result = 0; 693 snd_dbuf *b = ch->buffer; 694 695 if (ch->dir == PCMDIR_PLAY) { 696 result = fm801_rd(fm801, 697 (fm801->play_flip&1) ? 698 FM_PLAY_DMABUF2:FM_PLAY_DMABUF1, 4) - fm801->play_start; 699 } 700 701 if (ch->dir == PCMDIR_REC) { 702 result = fm801_rd(fm801, 703 (fm801->rec_flip&1) ? 704 FM_REC_DMABUF2:FM_REC_DMABUF1, 4) - fm801->rec_start; 705 } 706 707 DPRINT("fm801ch_getptr:%d, rp %d, rl %d, fp %d fl %d\n", 708 result, b->rp,b->rl, b->fp,b->fl); 709 710 return result; 711} 712 713static pcmchan_caps * 714fm801ch_getcaps(void *data) 715{ 716 return &fm801ch_caps; 717} 718 719static int 720fm801_pci_detach(device_t dev) 721{ 722 struct fm801_info *fm801 = fm801_get(); 723 724 DPRINT("Forte Media FM801 detach\n"); 725 726 if (fm801->reg) bus_release_resource(dev, fm801->regtype, fm801->regid, fm801->reg); 727 if (fm801->ih) bus_teardown_intr(dev, fm801->irq, fm801->ih); 728 if (fm801->irq) bus_release_resource(dev, SYS_RES_IRQ, fm801->irqid, fm801->irq); 729 free(fm801, M_DEVBUF); 730 return 0; 731} 732 733static device_method_t fm801_methods[] = { 734 /* Device interface */ 735 DEVMETHOD(device_probe, fm801_pci_probe), 736 DEVMETHOD(device_attach, fm801_pci_attach), 737 DEVMETHOD(device_detach, fm801_pci_detach), 738 { 0, 0} 739}; 740 741static driver_t fm801_driver = { 742 "pcm", 743 fm801_methods, 744 sizeof(snddev_info), 745}; 746 747static devclass_t pcm_devclass; 748 749DRIVER_MODULE(fm801, pci, fm801_driver, pcm_devclass,0, 0); 750