staticint pvr2_disable_ir_video;
module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(disable_autoload_ir_video, "1=do not try to autoload ir_video IR receiver");
staticint pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
u8 i2c_addr, /* I2C address we're talking to */
u8 *data, /* Data to write */
u16 length) /* Size of data to write */
{ /* Return value - default 0 means success */ int ret;
if (!data) length = 0; if (length > (sizeof(hdw->cmd_buffer) - 3)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Killing an I2C write to %u that is too large (desired=%u limit=%u)",
i2c_addr,
length,(unsignedint)(sizeof(hdw->cmd_buffer) - 3)); return -ENOTSUPP;
}
LOCK_TAKE(hdw->ctl_lock);
/* Clear the command buffer (likely to be paranoia) */
memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
/* Set up command buffer for an I2C write */
hdw->cmd_buffer[0] = FX2CMD_I2C_WRITE; /* write prefix */
hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */
hdw->cmd_buffer[2] = length; /* length of what follows */ if (length) memcpy(hdw->cmd_buffer + 3, data, length);
/* Do the operation */
ret = pvr2_send_request(hdw,
hdw->cmd_buffer,
length + 3,
hdw->cmd_buffer, 1); if (!ret) { if (hdw->cmd_buffer[0] != 8) {
ret = -EIO; if (hdw->cmd_buffer[0] != 7) {
trace_i2c("unexpected status from i2_write[%d]: %d",
i2c_addr,hdw->cmd_buffer[0]);
}
}
}
LOCK_GIVE(hdw->ctl_lock);
return ret;
}
staticint pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
u8 i2c_addr, /* I2C address we're talking to */
u8 *data, /* Data to write */
u16 dlen, /* Size of data to write */
u8 *res, /* Where to put data we read */
u16 rlen) /* Amount of data to read */
{ /* Return value - default 0 means success */ int ret;
if (!data) dlen = 0; if (dlen > (sizeof(hdw->cmd_buffer) - 4)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Killing an I2C read to %u that has wlen too large (desired=%u limit=%u)",
i2c_addr,
dlen,(unsignedint)(sizeof(hdw->cmd_buffer) - 4)); return -ENOTSUPP;
} if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Killing an I2C read to %u that has rlen too large (desired=%u limit=%u)",
i2c_addr,
rlen,(unsignedint)(sizeof(hdw->cmd_buffer) - 1)); return -ENOTSUPP;
}
LOCK_TAKE(hdw->ctl_lock);
/* Clear the command buffer (likely to be paranoia) */
memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
/* Set up command buffer for an I2C write followed by a read */
hdw->cmd_buffer[0] = FX2CMD_I2C_READ; /* read prefix */
hdw->cmd_buffer[1] = dlen; /* arg length */
hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one
more byte (status). */
hdw->cmd_buffer[3] = i2c_addr; /* i2c addr of chip */ if (dlen) memcpy(hdw->cmd_buffer + 4, data, dlen);
/* Do the operation */
ret = pvr2_send_request(hdw,
hdw->cmd_buffer, 4 + dlen,
hdw->cmd_buffer,
rlen + 1); if (!ret) { if (hdw->cmd_buffer[0] != 8) {
ret = -EIO; if (hdw->cmd_buffer[0] != 7) {
trace_i2c("unexpected status from i2_read[%d]: %d",
i2c_addr,hdw->cmd_buffer[0]);
}
}
}
/* Copy back the result */ if (res && rlen) { if (ret) { /* Error, just blank out the return buffer */
memset(res, 0, rlen);
} else {
memcpy(res, hdw->cmd_buffer + 1, rlen);
}
}
LOCK_GIVE(hdw->ctl_lock);
return ret;
}
/* This is the common low level entry point for doing I2C operations to the
hardware. */ staticint pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
u8 i2c_addr,
u8 *wdata,
u16 wlen,
u8 *rdata,
u16 rlen)
{ if (!rdata) rlen = 0; if (!wdata) wlen = 0; if (rlen || !wlen) { return pvr2_i2c_read(hdw,i2c_addr,wdata,wlen,rdata,rlen);
} else { return pvr2_i2c_write(hdw,i2c_addr,wdata,wlen);
}
}
/* This is a special entry point for cases of I2C transaction attempts to theIRreceiver.TheimplementationheresimulatestheIRreceiverby issuingacommandtotheFX2firmwareandusingthatresponsetoreturn whattherealI2Creceiverwouldhavereturned.Weusethisfor24xxx devices,wheretheIRreceiverchiphasbeenremovedandreplacedwith
FX2 related logic. */ staticint i2c_24xxx_ir(struct pvr2_hdw *hdw,
u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
{
u8 dat[4]; unsignedint stat;
if (!(rlen || wlen)) { /* This is a probe attempt. Just let it succeed. */ return0;
}
/* We don't understand this kind of transaction */ if ((wlen != 0) || (rlen == 0)) return -EIO;
if (rlen < 3) { /* Mike Isely <isely@pobox.com> Appears to be a probe attemptfromlirc.Justfillinzeroesandreturn.If wetryinsteadtodothefulltransactionhere,thenbad thingsseemtohappenwithinthelircdrivermodule (version0.8.0-7sourcesfromDebian,whenrununder vanilla2.6.17.6kernel)-andIdon'thavethepatience
to chase it down. */ if (rlen > 0) rdata[0] = 0; if (rlen > 1) rdata[1] = 0; return0;
}
/* Issue a command to the FX2 to read the IR receiver. */
LOCK_TAKE(hdw->ctl_lock); do {
hdw->cmd_buffer[0] = FX2CMD_GET_IR_CODE;
stat = pvr2_send_request(hdw,
hdw->cmd_buffer,1,
hdw->cmd_buffer,4);
dat[0] = hdw->cmd_buffer[0];
dat[1] = hdw->cmd_buffer[1];
dat[2] = hdw->cmd_buffer[2];
dat[3] = hdw->cmd_buffer[3];
} while (0); LOCK_GIVE(hdw->ctl_lock);
/* Give up if that operation failed. */ if (stat != 0) return stat;
/* Mangle the results into something that looks like the real IR
receiver. */
rdata[2] = 0xc1; if (dat[0] != 1) { /* No code received. */
rdata[0] = 0;
rdata[1] = 0;
} else {
u16 val; /* Mash the FX2 firmware-provided IR code into something
that the normal i2c chip-level driver expects. */
val = dat[1];
val <<= 8;
val |= dat[2];
val >>= 1;
val &= ~0x0003;
val |= 0x8000;
rdata[0] = (val >> 8) & 0xffu;
rdata[1] = val & 0xffu;
}
return0;
}
/* This is a special entry point that is entered if an I2C operation is attemptedtoawm8775chiponmodel24xxxhardware.Autodetectofthis partdoesn'twork,butweknowitisreallythere.Solet'slookfor
the autodetect attempt and just return success if we see that. */ staticint i2c_hack_wm8775(struct pvr2_hdw *hdw,
u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
{ if (!(rlen || wlen)) { // This is a probe attempt. Just let it succeed. return0;
} return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
}
/* This is an entry point designed to always fail any attempt to perform a transfer.WeusethistocausecertainI2Caddressestonotbe
probed. */ staticint i2c_black_hole(struct pvr2_hdw *hdw,
u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
{ return -EIO;
}
/* This is a special entry point that is entered if an I2C operation is attemptedtoacx25840chiponmodel24xxxhardware.Thischipcan sometimeswedgeitself.Worsestill,whenthishappensmsp3400can falselydetectthispartandthenthesystemgetshosedupaftermsp3400 getsconfusedanddies.Whatwewanttodohereistrytokeepmsp3400 awayandalsotrytonoticeifthechipiswedgedandsendawarningto
the system log. */ staticint i2c_hack_cx25840(struct pvr2_hdw *hdw,
u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
{ int ret; unsignedint subaddr;
u8 wbuf[2]; int state = hdw->i2c_cx25840_hack_state;
if (!(rlen || wlen)) { // Probe attempt - always just succeed and don't bother the // hardware (this helps to make the state machine further // down somewhat easier). return0;
}
if (state == 3) { return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
}
/* We're looking for the exact pattern where the revision register isbeingread.Thecx25840modulewillalwayslookatthe revisionregisterfirst.Anyotherpatternofaccesstherefore hastobeaprobeattemptfromsomebodyelsesowe'llrejectit. Normallywecouldjustleteachclientjustprobethepart anyway,butwhenthecx25840iswedged,msp3400willgetafalse
positive and that just screws things up... */
/* If we get to here then we have a legitimate read for one of the
two revision bytes, so pass it through. */
wbuf[0] = subaddr >> 8;
wbuf[1] = subaddr;
ret = pvr2_i2c_basic_op(hdw,i2c_addr,wbuf,2,rdata,rlen);
if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS, "***WARNING*** Detected a wedged cx25840 chip; the device will not work.");
pvr2_trace(PVR2_TRACE_ERROR_LEGS, "***WARNING*** Try power cycling the pvrusb2 device.");
pvr2_trace(PVR2_TRACE_ERROR_LEGS, "***WARNING*** Disabling further access to the device to prevent other foul-ups."); // This blocks all further communication with the part.
hdw->i2c_func[0x44] = NULL;
pvr2_hdw_render_useless(hdw); goto fail;
}
/* Success! */
pvr2_trace(PVR2_TRACE_CHIPS,"cx25840 appears to be OK.");
state = 3;
/* This is a very, very limited I2C adapter implementation. We can only
support what we actually know will work on the device... */ staticint pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
{ int ret = -ENOTSUPP;
pvr2_i2c_func funcp = NULL; struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data);
if (!num) {
ret = -EINVAL; goto done;
} if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
funcp = hdw->i2c_func[msgs[0].addr];
} if (!funcp) {
ret = -EIO; goto done;
}
if (num == 1) { if (msgs[0].flags & I2C_M_RD) { /* Simple read */
u16 tcnt,bcnt,offs; if (!msgs[0].len) { /* Length == 0 read. This is a probe. */ if (funcp(hdw,msgs[0].addr,NULL,0,NULL,0)) {
ret = -EIO; goto done;
}
ret = 1; goto done;
} /* If the read is short enough we'll do the whole thingatomically.Otherwisewehavenochoice
but to break apart the reads. */
tcnt = msgs[0].len;
offs = 0; while (tcnt) {
bcnt = tcnt; if (bcnt > sizeof(hdw->cmd_buffer)-1) {
bcnt = sizeof(hdw->cmd_buffer)-1;
} if (funcp(hdw,msgs[0].addr,NULL,0,
msgs[0].buf+offs,bcnt)) {
ret = -EIO; goto done;
}
offs += bcnt;
tcnt -= bcnt;
}
ret = 1; goto done;
} else { /* Simple write */
ret = 1; if (funcp(hdw,msgs[0].addr,
msgs[0].buf,msgs[0].len,NULL,0)) {
ret = -EIO;
} goto done;
}
} elseif (num == 2) { if (msgs[0].addr != msgs[1].addr) {
trace_i2c("i2c refusing 2 phase transfer with conflicting target addresses");
ret = -ENOTSUPP; goto done;
} if ((!((msgs[0].flags & I2C_M_RD))) &&
(msgs[1].flags & I2C_M_RD)) {
u16 tcnt,bcnt,wcnt,offs; /* Write followed by atomic read. If the read portionisshortenoughwe'lldothewholething atomically.Otherwisewehavenochoicebutto
break apart the reads. */
tcnt = msgs[1].len;
wcnt = msgs[0].len;
offs = 0; while (tcnt || wcnt) {
bcnt = tcnt; if (bcnt > sizeof(hdw->cmd_buffer)-1) {
bcnt = sizeof(hdw->cmd_buffer)-1;
} if (funcp(hdw,msgs[0].addr,
msgs[0].buf,wcnt,
msgs[1].buf+offs,bcnt)) {
ret = -EIO; goto done;
}
offs += bcnt;
tcnt -= bcnt;
wcnt = 0;
}
ret = 2; goto done;
} else {
trace_i2c("i2c refusing complex transfer read0=%d read1=%d",
(msgs[0].flags & I2C_M_RD),
(msgs[1].flags & I2C_M_RD));
}
} else {
trace_i2c("i2c refusing %d phase transfer",num);
}
/* The default action for all possible I2C addresses is just to do
the transfer normally. */ for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
hdw->i2c_func[idx] = pvr2_i2c_basic_op;
}
/* However, deal with various special cases for 24xxx hardware. */ if (ir_mode[hdw->unit_number] == 0) {
pr_info("%s: IR disabled\n", hdw->name);
hdw->i2c_func[0x18] = i2c_black_hole;
} elseif (ir_mode[hdw->unit_number] == 1) { if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) { /* Set up translation so that our IR looks like a
29xxx device */
hdw->i2c_func[0x18] = i2c_24xxx_ir;
}
} if (hdw->hdw_desc->flag_has_cx25840) {
hdw->i2c_func[0x44] = i2c_hack_cx25840;
} if (hdw->hdw_desc->flag_has_wm8775) {
hdw->i2c_func[0x1b] = i2c_hack_wm8775;
}
// Configure the adapter and set up everything else related to it.
hdw->i2c_adap = pvr2_i2c_adap_template;
hdw->i2c_algo = pvr2_i2c_algo_template;
strscpy(hdw->i2c_adap.name, hdw->name, sizeof(hdw->i2c_adap.name));
hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
hdw->i2c_adap.algo = &hdw->i2c_algo;
hdw->i2c_adap.algo_data = hdw;
hdw->i2c_linked = !0;
i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
i2c_add_adapter(&hdw->i2c_adap); if (hdw->i2c_func[0x18] == i2c_24xxx_ir) { /* Probe for a different type of IR receiver on this device.Thisisreallytheonlywaytodifferentiate older24xxxdevicesfrom24xxxvariantsthatincludean IRblaster.IftheIRblasterispresent,theIR receiverispartofthatchipandthuswemustdisable
the emulated IR receiver. */ if (do_i2c_probe(hdw, 0x71)) {
pvr2_trace(PVR2_TRACE_INFO, "Device has newer IR hardware; disabling unneeded virtual IR device");
hdw->i2c_func[0x18] = NULL; /* Remember that this is a different device... */
hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE;
}
} if (i2c_scan) do_i2c_scan(hdw);
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.