static int wss_set_codec_fmt(struct net_device *dev, struct sm_state *sm, unsigned char fmt, unsigned char fmt2, char fdx, char fullcalib) { unsigned long time; unsigned long flags; save_flags(flags); cli(); /* Clock and data format register */ write_codec(dev, 0x48, fmt); if (SCSTATE->crystal) { write_codec(dev, 0x5c, fmt2 & 0xf0); /* MCE and interface config reg */ write_codec(dev, 0x49, (fdx ? 0 : 0x4) | (fullcalib ? 0x18 : 0)); } else /* MCE and interface config reg */ write_codec(dev, 0x49, fdx ? 0x8 : 0xc); outb(0xb, WSS_CODEC_IA(dev->base_addr)); /* leave MCE */ if (SCSTATE->crystal && !fullcalib) { restore_flags(flags); return 0; } /* * wait for ACI start */ time = 1000; while (!(read_codec(dev, 0x0b) & 0x20)) if (!(--time)) { printk(KERN_WARNING "%s: ad1848 auto calibration timed out (1)\n", sm_drvname); restore_flags(flags); return -1; } /* * wait for ACI end */ sti(); time = jiffies + HZ/4; while ((read_codec(dev, 0x0b) & 0x20) && ((signed)(jiffies - time) < 0)); restore_flags(flags); if ((signed)(jiffies - time) >= 0) { printk(KERN_WARNING "%s: ad1848 auto calibration timed out (2)\n", sm_drvname); return -1; } return 0; }
static int wss_init_codec(struct device *dev, struct sm_state *sm, char fdx, unsigned char src_l, unsigned char src_r, int igain_l, int igain_r, int ogain_l, int ogain_r) { unsigned char tmp, reg0, reg1, reg6, reg7; static const signed char irqtab[16] = { -1, -1, 0x10, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20, -1, -1, -1, -1 }; static const signed char dmatab[4] = { 1, 2, -1, 3 }; tmp = inb(WSS_STATUS(dev->base_addr)); if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x00 && (tmp & 0x3f) != 0x0f) { printk(KERN_WARNING "sm: WSS card id register not found, " "address 0x%lx, ID register 0x%02x\n", dev->base_addr, (int)tmp); /* return -1; */ SCSTATE->revwss = 0; } else { if ((tmp & 0x80) && ((dev->dma == 0) || ((dev->irq >= 8) && (dev->irq != 9)))) { printk(KERN_ERR "%s: WSS: DMA0 and/or IRQ8..IRQ15 " "(except IRQ9) cannot be used on an 8bit " "card\n", sm_drvname); return -1; } if (dev->irq > 15 || irqtab[dev->irq] == -1) { printk(KERN_ERR "%s: WSS: invalid interrupt %d\n", sm_drvname, (int)dev->irq); return -1; } if (dev->dma > 3 || dmatab[dev->dma] == -1) { printk(KERN_ERR "%s: WSS: invalid dma channel %d\n", sm_drvname, (int)dev->dma); return -1; } tmp = irqtab[dev->irq] | dmatab[dev->dma]; /* irq probe */ outb((tmp & 0x38) | 0x40, WSS_CONFIG(dev->base_addr)); if (!(inb(WSS_STATUS(dev->base_addr)) & 0x40)) { outb(0, WSS_CONFIG(dev->base_addr)); printk(KERN_ERR "%s: WSS: IRQ%d is not free!\n", sm_drvname, dev->irq); } outb(tmp, WSS_CONFIG(dev->base_addr)); SCSTATE->revwss = inb(WSS_STATUS(dev->base_addr)) & 0x3f; } /* * initialize the codec */ if (igain_l < 0) igain_l = 0; if (igain_r < 0) igain_r = 0; if (ogain_l > 0) ogain_l = 0; if (ogain_r > 0) ogain_r = 0; reg0 = (src_l << 6) & 0xc0; reg1 = (src_r << 6) & 0xc0; if (reg0 == 0x80 && igain_l >= 20) { reg0 |= 0x20; igain_l -= 20; } if (reg1 == 0x80 && igain_r >= 20) { reg1 |= 0x20; igain_r -= 20; } if (igain_l > 23) igain_l = 23; if (igain_r > 23) igain_r = 23; reg0 |= igain_l * 2 / 3; reg1 |= igain_r * 2 / 3; reg6 = (ogain_l < -95) ? 0x80 : (ogain_l * (-2) / 3); reg7 = (ogain_r < -95) ? 0x80 : (ogain_r * (-2) / 3); write_codec(dev, 9, 0); write_codec(dev, 0, 0x45); if (read_codec(dev, 0) != 0x45) goto codec_err; write_codec(dev, 0, 0xaa); if (read_codec(dev, 0) != 0xaa) goto codec_err; write_codec(dev, 12, 0x40); /* enable MODE2 */ write_codec(dev, 16, 0); write_codec(dev, 0, 0x45); SCSTATE->crystal = (read_codec(dev, 16) != 0x45); write_codec(dev, 0, 0xaa); SCSTATE->crystal &= (read_codec(dev, 16) != 0xaa); if (SCSTATE->crystal) { SCSTATE->revcid = read_codec(dev, 0x19); SCSTATE->revv = (SCSTATE->revcid >> 5) & 7; SCSTATE->revcid &= 7; write_codec(dev, 0x10, 0x80); /* maximum output level */ write_codec(dev, 0x11, 0x02); /* xtal enable and no HPF */ write_codec(dev, 0x12, 0x80); /* left line input control */ write_codec(dev, 0x13, 0x80); /* right line input control */ write_codec(dev, 0x16, 0); /* disable alternative freq sel */ write_codec(dev, 0x1a, 0xe0); /* mono IO disable */ write_codec(dev, 0x1b, 0x00); /* left out no att */ write_codec(dev, 0x1d, 0x00); /* right out no att */ }