MODULE_AUTHOR("Takashi Iwai ");
MODULE_DESCRIPTION("Common routines for Digigram VX drivers");
MODULE_LICENSE("GPL");
/* * vx_check_reg_bit - wait for the specified bit is set/reset on a register * @reg: register to check * @mask: bit mask * @bit: resultant bit to be checked * @time: time-out of loop in msec * * returns zero if a bit matches, or a negative error code.
*/ int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int time)
{ unsignedlong end_time = jiffies + (time * HZ + 999) / 1000; staticconstchar * const reg_names[VX_REG_MAX] = { "ICR", "CVR", "ISR", "IVR", "RXH", "RXM", "RXL", "DMA", "CDSP", "RFREQ", "RUER/V2", "DATA", "MEMIRQ", "ACQ", "BIT0", "BIT1", "MIC0", "MIC1", "MIC2", "MIC3", "INTCSR", "CNTRL", "GPIOC", "LOFREQ", "HIFREQ", "CSUER", "RUER"
};
do { if ((snd_vx_inb(chip, reg) & mask) == bit) return 0; //msleep(10);
} while (time_after_eq(end_time, jiffies));
dev_dbg(chip->card->dev, "vx_check_reg_bit: timeout, reg=%s, mask=0x%x, val=0x%x\n",
reg_names[reg], mask, snd_vx_inb(chip, reg)); return -EIO;
}
EXPORT_SYMBOL(snd_vx_check_reg_bit);
/* * vx_send_irq_dsp - set command irq bit * @num: the requested IRQ type, IRQ_XXX * * this triggers the specified IRQ request * returns 0 if successful, or a negative error code. *
*/ staticint vx_send_irq_dsp(struct vx_core *chip, int num)
{ int nirq;
/* wait for Hc = 0 */ if (snd_vx_check_reg_bit(chip, VX_CVR, CVR_HC, 0, 200) < 0) return -EIO;
/* * vx_reset_chk - reset CHK bit on ISR * * returns 0 if successful, or a negative error code.
*/ staticint vx_reset_chk(struct vx_core *chip)
{ /* Reset irq CHK */ if (vx_send_irq_dsp(chip, IRQ_RESET_CHK) < 0) return -EIO; /* Wait until CHK = 0 */ if (vx_check_isr(chip, ISR_CHK, 0, 200) < 0) return -EIO; return 0;
}
/* * vx_transfer_end - terminate message transfer * @cmd: IRQ message to send (IRQ_MESS_XXX_END) * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). * NB: call with mutex held!
*/ staticint vx_transfer_end(struct vx_core *chip, int cmd)
{ int err;
err = vx_reset_chk(chip); if (err < 0) return err;
/* * vx_read_status - return the status rmh * @rmh: rmh record to store the status * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). * NB: call with mutex held!
*/ staticint vx_read_status(struct vx_core *chip, struct vx_rmh *rmh)
{ int i, err, val, size;
/* no read necessary? */ if (rmh->DspStat == RMH_SSIZE_FIXED && rmh->LgStat == 0) return 0;
/* Wait for RX full (with timeout protection) * The first word of status is in RX
*/
err = vx_wait_for_rx_full(chip); if (err < 0) return err;
/* Read RX */
val = vx_inb(chip, RXH) << 16;
val |= vx_inb(chip, RXM) << 8;
val |= vx_inb(chip, RXL);
/* If status given by DSP, let's decode its size */ switch (rmh->DspStat) { case RMH_SSIZE_ARG:
size = val & 0xff;
rmh->Stat[0] = val & 0xffff00;
rmh->LgStat = size + 1; break; case RMH_SSIZE_MASK: /* Let's count the arg numbers from a mask */
rmh->Stat[0] = val;
size = 0; while (val) { if (val & 0x01)
size++;
val >>= 1;
}
rmh->LgStat = size + 1; break; default: /* else retrieve the status length given by the driver */
size = rmh->LgStat;
rmh->Stat[0] = val; /* Val is the status 1st word */
size--; /* hence adjust remaining length */ break;
}
if (size < 1) return 0; if (snd_BUG_ON(size >= SIZE_MAX_STATUS)) return -EINVAL;
for (i = 1; i <= size; i++) { /* trigger an irq MESS_WRITE_NEXT */
err = vx_send_irq_dsp(chip, IRQ_MESS_WRITE_NEXT); if (err < 0) return err; /* Wait for RX full (with timeout protection) */
err = vx_wait_for_rx_full(chip); if (err < 0) return err;
rmh->Stat[i] = vx_inb(chip, RXH) << 16;
rmh->Stat[i] |= vx_inb(chip, RXM) << 8;
rmh->Stat[i] |= vx_inb(chip, RXL);
}
/* * vx_send_msg_nolock - send a DSP message and read back the status * @rmh: the rmh record to send and receive * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). * * this function doesn't call mutex lock at all.
*/ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
{ int i, err;
if (chip->chip_status & VX_STAT_IS_STALE) return -EBUSY;
/* Check bit M is set according to length of the command */ if (rmh->LgCmd > 1)
rmh->Cmd[0] |= MASK_MORE_THAN_1_WORD_COMMAND; else
rmh->Cmd[0] &= MASK_1_WORD_COMMAND;
/* Wait for CHK = 1 */
err = vx_wait_isr_bit(chip, ISR_CHK); if (err < 0) return err;
/* If error, get error value from RX */ if (vx_inb(chip, ISR) & ISR_ERR) {
err = vx_wait_for_rx_full(chip); if (err < 0) {
dev_dbg(chip->card->dev, "vx_send_msg: rx_full read error\n"); return err;
}
err = vx_inb(chip, RXH) << 16;
err |= vx_inb(chip, RXM) << 8;
err |= vx_inb(chip, RXL);
dev_dbg(chip->card->dev, "msg got error = 0x%x at cmd[0]\n", err);
err = -(VX_ERR_MASK | err); return err;
}
/* Send the other words */ if (rmh->LgCmd > 1) { for (i = 1; i < rmh->LgCmd; i++) { /* Wait for TX ready */
err = vx_wait_isr_bit(chip, ISR_TX_READY); if (err < 0) {
dev_dbg(chip->card->dev, "vx_send_msg: tx_ready error\n"); return err;
}
/* Trigger irq MESS_READ_NEXT */
err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT); if (err < 0) {
dev_dbg(chip->card->dev, "vx_send_msg: IRQ_READ_NEXT error\n"); return err;
}
} /* Wait for TX empty */
err = vx_wait_isr_bit(chip, ISR_TX_READY); if (err < 0) {
dev_dbg(chip->card->dev, "vx_send_msg: TX_READY error\n"); return err;
} /* End of transfer */
err = vx_transfer_end(chip, IRQ_MESS_READ_END); if (err < 0) return err;
}
return vx_read_status(chip, rmh);
}
/* * vx_send_msg - send a DSP message with mutex * @rmh: the rmh record to send and receive * * returns 0 if successful, or a negative error code. * see vx_send_msg_nolock().
*/ int vx_send_msg(struct vx_core *chip, struct vx_rmh *rmh)
{ int err;
/* * vx_send_rih_nolock - send an RIH to xilinx * @cmd: the command to send * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). * * this function doesn't call mutex at all. * * unlike RMH, no command is sent to DSP.
*/ int vx_send_rih_nolock(struct vx_core *chip, int cmd)
{ int err;
if (chip->chip_status & VX_STAT_IS_STALE) return -EBUSY;
/* * vx_send_rih - send an RIH with mutex * @cmd: the command to send * * see vx_send_rih_nolock().
*/ int vx_send_rih(struct vx_core *chip, int cmd)
{ int err;
/** * snd_vx_load_boot_image - boot up the xilinx interface * @chip: VX core instance * @boot: the boot record to load
*/ int snd_vx_load_boot_image(struct vx_core *chip, conststruct firmware *boot)
{ unsignedint i; int no_fillup = vx_has_new_dsp(chip);
/* check the length of boot image */ if (boot->size <= 0) return -EINVAL; if (boot->size % 3) return -EINVAL; #if 0
{ /* more strict check */ unsignedint c = ((u32)boot->data[0] << 16) | ((u32)boot->data[1] << 8) | boot->data[2]; if (boot->size != (c + 2) * 3) return -EINVAL;
} #endif
/* reset dsp */
vx_reset_dsp(chip);
udelay(END_OF_RESET_WAIT_TIME); /* another wait? */
/* download boot strap */ for (i = 0; i < 0x600; i += 3) { if (i >= boot->size) { if (no_fillup) break; if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) {
dev_err(chip->card->dev, "dsp boot failed at %d\n", i); return -EIO;
}
vx_outb(chip, TXH, 0);
vx_outb(chip, TXM, 0);
vx_outb(chip, TXL, 0);
} else { constunsignedchar *image = boot->data + i; if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) {
dev_err(chip->card->dev, "dsp boot failed at %d\n", i); return -EIO;
}
vx_outb(chip, TXH, image[0]);
vx_outb(chip, TXM, image[1]);
vx_outb(chip, TXL, image[2]);
}
} return 0;
}
EXPORT_SYMBOL(snd_vx_load_boot_image);
/* * vx_test_irq_src - query the source of interrupts * * called from irq handler only
*/ staticint vx_test_irq_src(struct vx_core *chip, unsignedint *ret)
{ int err;
if (chip->chip_status & VX_STAT_IS_STALE) return IRQ_HANDLED;
if (vx_test_irq_src(chip, &events) < 0) return IRQ_HANDLED;
/* We must prevent any application using this DSP * and block any further request until the application * either unregisters or reloads the DSP
*/ if (events & FATAL_DSP_ERROR) {
dev_err(chip->card->dev, "vx_core: fatal DSP error!!\n"); return IRQ_HANDLED;
}
/* The start on time code conditions are filled (ie the time code * received by the board is equal to one of those given to it).
*/ if (events & TIME_CODE_EVENT_PENDING) {
; /* so far, nothing to do yet */
}
/* The frequency has changed on the board (UER mode). */ if (events & FREQUENCY_CHANGE_EVENT_PENDING)
vx_change_frequency(chip);
/** * snd_vx_create - constructor for struct vx_core * @card: card instance * @hw: hardware specific record * @ops: VX ops pointer * @extra_size: extra byte size to allocate appending to chip * * this function allocates the instance and prepare for the hardware * initialization. * * The object is managed via devres, and will be automatically released. * * return the instance pointer if successful, NULL in error.
*/ struct vx_core *snd_vx_create(struct snd_card *card, conststruct snd_vx_hardware *hw, conststruct snd_vx_ops *ops, int extra_size)
{ struct vx_core *chip;
if (snd_BUG_ON(!card || !hw || !ops)) return NULL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.