/* 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
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; }