Ejemplo n.º 1
0
/* Try to find a free mailbox. Note mailbox 0 is reserved for DMA and so is not
   attempted here. */
static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int flags)
{
	unsigned long then = jiffies;
	int i, mb;
	int max_mbox = mbdata->max_mbox;
	int retries = 100;

	/* All slow commands use the same mailbox, serializing them and also
	   leaving the other mailbox free for simple fast commands. */
	if ((flags & API_FAST_RESULT) == API_RESULT)
		max_mbox = 1;

	/* find free non-DMA mailbox */
	for (i = 0; i < retries; i++) {
		for (mb = 1; mb <= max_mbox; mb++)
			if (try_mailbox(itv, mbdata, mb))
				return mb;

		/* Sleep before a retry, if not atomic */
		if (!(flags & API_NO_WAIT_MB)) {
			if (time_after(jiffies,
				       then + msecs_to_jiffies(10*retries)))
			       break;
			ivtv_msleep_timeout(10, 0);
		}
	}
	return -ENODEV
Ejemplo n.º 2
0
static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
{
    struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
    volatile struct ivtv_mailbox __iomem *mbox;
    int api_timeout = msecs_to_jiffies(1000);
    int flags, mb, i;
    unsigned long then;

    /* sanity checks */
    if (NULL == mbdata) {
        IVTV_ERR("No mailbox allocated\n");
        return -ENODEV;
    }
    if (args < 0 || args > CX2341X_MBOX_MAX_DATA ||
        cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) {
        IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args);
        return -EINVAL;
    }

    if (api_info[cmd].flags & API_HIGH_VOL) {
        IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name);
    }
    else {
        IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name);
    }

    /* clear possibly uninitialized part of data array */
    for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
        data[i] = 0;

    /* If this command was issued within the last 30 minutes and with identical
       data, then just return 0 as there is no need to issue this command again.
       Just an optimization to prevent unnecessary use of mailboxes. */
    if (itv->api_cache[cmd].last_jiffies &&
        time_before(jiffies,
            itv->api_cache[cmd].last_jiffies +
            msecs_to_jiffies(1800000)) &&
        !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
        itv->api_cache[cmd].last_jiffies = jiffies;
        return 0;
    }

    flags = api_info[cmd].flags;

    if (flags & API_DMA) {
        for (i = 0; i < 100; i++) {
            mb = i % (mbdata->max_mbox + 1);
            if (try_mailbox(itv, mbdata, mb)) {
                write_mailbox(&mbdata->mbox[mb], cmd, args, data);
                clear_bit(mb, &mbdata->busy);
                return 0;
            }
            IVTV_DEBUG_WARN("%s: mailbox %d not free %08x\n",
                    api_info[cmd].name, mb, readl(&mbdata->mbox[mb].flags));
        }
        IVTV_WARN("Could not find free DMA mailbox for %s\n", api_info[cmd].name);
        clear_all_mailboxes(itv, mbdata);
        return -EBUSY;
    }

    if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
        api_timeout = msecs_to_jiffies(100);

    mb = get_mailbox(itv, mbdata, flags);
    if (mb < 0) {
        IVTV_DEBUG_WARN("No free mailbox found (%s)\n", api_info[cmd].name);
        clear_all_mailboxes(itv, mbdata);
        return -EBUSY;
    }
    mbox = &mbdata->mbox[mb];
    write_mailbox(mbox, cmd, args, data);
    if (flags & API_CACHE) {
        memcpy(itv->api_cache[cmd].data, data, sizeof(itv->api_cache[cmd].data));
        itv->api_cache[cmd].last_jiffies = jiffies;
    }
    if ((flags & API_RESULT) == 0) {
        clear_bit(mb, &mbdata->busy);
        return 0;
    }

    /* Get results */
    then = jiffies;

    if (!(flags & API_NO_POLL)) {
        /* First try to poll, then switch to delays */
        for (i = 0; i < 100; i++) {
            if (readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)
                break;
        }
    }
    while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) {
        if (time_after(jiffies, then + api_timeout)) {
            IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name);
            /* reset the mailbox, but it is likely too late already */
            write_sync(0, &mbox->flags);
            clear_bit(mb, &mbdata->busy);
            return -EIO;
        }
        if (flags & API_NO_WAIT_RES)
            mdelay(1);
        else
            ivtv_msleep_timeout(1, 0);
    }
    if (time_after(jiffies, then + msecs_to_jiffies(100)))
        IVTV_DEBUG_WARN("%s took %u jiffies\n",
                api_info[cmd].name,
                jiffies_to_msecs(jiffies - then));

    for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
        data[i] = readl(&mbox->data[i]);
    write_sync(0, &mbox->flags);
    clear_bit(mb, &mbdata->busy);
    return 0;
}