 5338c16905
			
		
	
	
	5338c16905
	
	
	
		
			
			This kind of memcpy() is error-prone. Its replacement with a struct assignment is prefered because it's type-safe and much easier to read. Found by coccinelle. Hand patched and reviewed. Tested by compilation only. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @@ identifier struct_name; struct struct_name to; struct struct_name from; expression E; @@ -memcpy(&(to), &(from), E); +to = from; // </smpl> Signed-off-by: Peter Senna Tschudin <peter.senna@gmail.com> Signed-off-by: Ezequiel Garcia <elezegarcia@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
		
			
				
	
	
		
			698 lines
		
	
	
	
		
			20 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			698 lines
		
	
	
	
		
			20 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *
 | |
|  *
 | |
|  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
 | |
|  *
 | |
|  *  This program is free software; you can redistribute it and/or modify
 | |
|  *  it under the terms of the GNU General Public License as published by
 | |
|  *  the Free Software Foundation; either version 2 of the License
 | |
|  *
 | |
|  *  This program is distributed in the hope that it will be useful,
 | |
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  *  GNU General Public License for more details.
 | |
|  *
 | |
|  *  You should have received a copy of the GNU General Public License
 | |
|  *  along with this program; if not, write to the Free Software
 | |
|  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <linux/i2c.h>
 | |
| #include <linux/module.h>
 | |
| #include <media/ir-kbd-i2c.h>
 | |
| #include "pvrusb2-i2c-core.h"
 | |
| #include "pvrusb2-hdw-internal.h"
 | |
| #include "pvrusb2-debug.h"
 | |
| #include "pvrusb2-fx2-cmd.h"
 | |
| #include "pvrusb2.h"
 | |
| 
 | |
| #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
 | |
| 
 | |
| /*
 | |
| 
 | |
|   This module attempts to implement a compliant I2C adapter for the pvrusb2
 | |
|   device.
 | |
| 
 | |
| */
 | |
| 
 | |
| static unsigned int i2c_scan;
 | |
| module_param(i2c_scan, int, S_IRUGO|S_IWUSR);
 | |
| MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
 | |
| 
 | |
| static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
 | |
| module_param_array(ir_mode, int, NULL, 0444);
 | |
| MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
 | |
| 
 | |
| static int 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");
 | |
| 
 | |
| static int 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,(unsigned int)(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;
 | |
| }
 | |
| 
 | |
| static int 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,(unsigned int)(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,(unsigned int)(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. */
 | |
| static int 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
 | |
|    the IR receiver.  The implementation here simulates the IR receiver by
 | |
|    issuing a command to the FX2 firmware and using that response to return
 | |
|    what the real I2C receiver would have returned.  We use this for 24xxx
 | |
|    devices, where the IR receiver chip has been removed and replaced with
 | |
|    FX2 related logic. */
 | |
| static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
 | |
| 			u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
 | |
| {
 | |
| 	u8 dat[4];
 | |
| 	unsigned int stat;
 | |
| 
 | |
| 	if (!(rlen || wlen)) {
 | |
| 		/* This is a probe attempt.  Just let it succeed. */
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	/* 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
 | |
| 		   attempt from lirc.  Just fill in zeroes and return.  If
 | |
| 		   we try instead to do the full transaction here, then bad
 | |
| 		   things seem to happen within the lirc driver module
 | |
| 		   (version 0.8.0-7 sources from Debian, when run under
 | |
| 		   vanilla 2.6.17.6 kernel) - and I don't have the patience
 | |
| 		   to chase it down. */
 | |
| 		if (rlen > 0) rdata[0] = 0;
 | |
| 		if (rlen > 1) rdata[1] = 0;
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	/* 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;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* This is a special entry point that is entered if an I2C operation is
 | |
|    attempted to a wm8775 chip on model 24xxx hardware.  Autodetect of this
 | |
|    part doesn't work, but we know it is really there.  So let's look for
 | |
|    the autodetect attempt and just return success if we see that. */
 | |
| static int 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.
 | |
| 		return 0;
 | |
| 	}
 | |
| 	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.  We use this to cause certain I2C addresses to not be
 | |
|    probed. */
 | |
| static int 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
 | |
|    attempted to a cx25840 chip on model 24xxx hardware.  This chip can
 | |
|    sometimes wedge itself.  Worse still, when this happens msp3400 can
 | |
|    falsely detect this part and then the system gets hosed up after msp3400
 | |
|    gets confused and dies.  What we want to do here is try to keep msp3400
 | |
|    away and also try to notice if the chip is wedged and send a warning to
 | |
|    the system log. */
 | |
| static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
 | |
| 			    u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
 | |
| {
 | |
| 	int ret;
 | |
| 	unsigned int 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).
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	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
 | |
| 	   is being read.  The cx25840 module will always look at the
 | |
| 	   revision register first.  Any other pattern of access therefore
 | |
| 	   has to be a probe attempt from somebody else so we'll reject it.
 | |
| 	   Normally we could just let each client just probe the part
 | |
| 	   anyway, but when the cx25840 is wedged, msp3400 will get a false
 | |
| 	   positive and that just screws things up... */
 | |
| 
 | |
| 	if (wlen == 0) {
 | |
| 		switch (state) {
 | |
| 		case 1: subaddr = 0x0100; break;
 | |
| 		case 2: subaddr = 0x0101; break;
 | |
| 		default: goto fail;
 | |
| 		}
 | |
| 	} else if (wlen == 2) {
 | |
| 		subaddr = (wdata[0] << 8) | wdata[1];
 | |
| 		switch (subaddr) {
 | |
| 		case 0x0100: state = 1; break;
 | |
| 		case 0x0101: state = 2; break;
 | |
| 		default: goto fail;
 | |
| 		}
 | |
| 	} else {
 | |
| 		goto fail;
 | |
| 	}
 | |
| 	if (!rlen) goto success;
 | |
| 	state = 0;
 | |
| 	if (rlen != 1) goto fail;
 | |
| 
 | |
| 	/* 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;
 | |
| 
 | |
|  success:
 | |
| 	hdw->i2c_cx25840_hack_state = state;
 | |
| 	return 0;
 | |
| 
 | |
|  fail:
 | |
| 	hdw->i2c_cx25840_hack_state = state;
 | |
| 	return -EIO;
 | |
| }
 | |
| 
 | |
| /* This is a very, very limited I2C adapter implementation.  We can only
 | |
|    support what we actually know will work on the device... */
 | |
| static int 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
 | |
| 			   thing atomically.  Otherwise we have no choice
 | |
| 			   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;
 | |
| 		}
 | |
| 	} else if (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
 | |
| 			   portion is short enough we'll do the whole thing
 | |
| 			   atomically.  Otherwise we have no choice but to
 | |
| 			   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);
 | |
| 	}
 | |
| 
 | |
|  done:
 | |
| 	if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) {
 | |
| 		unsigned int idx,offs,cnt;
 | |
| 		for (idx = 0; idx < num; idx++) {
 | |
| 			cnt = msgs[idx].len;
 | |
| 			printk(KERN_INFO
 | |
| 			       "pvrusb2 i2c xfer %u/%u:"
 | |
| 			       " addr=0x%x len=%d %s",
 | |
| 			       idx+1,num,
 | |
| 			       msgs[idx].addr,
 | |
| 			       cnt,
 | |
| 			       (msgs[idx].flags & I2C_M_RD ?
 | |
| 				"read" : "write"));
 | |
| 			if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
 | |
| 				if (cnt > 8) cnt = 8;
 | |
| 				printk(" [");
 | |
| 				for (offs = 0; offs < (cnt>8?8:cnt); offs++) {
 | |
| 					if (offs) printk(" ");
 | |
| 					printk("%02x",msgs[idx].buf[offs]);
 | |
| 				}
 | |
| 				if (offs < cnt) printk(" ...");
 | |
| 				printk("]");
 | |
| 			}
 | |
| 			if (idx+1 == num) {
 | |
| 				printk(" result=%d",ret);
 | |
| 			}
 | |
| 			printk("\n");
 | |
| 		}
 | |
| 		if (!num) {
 | |
| 			printk(KERN_INFO
 | |
| 			       "pvrusb2 i2c xfer null transfer result=%d\n",
 | |
| 			       ret);
 | |
| 		}
 | |
| 	}
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
 | |
| {
 | |
| 	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
 | |
| }
 | |
| 
 | |
| static struct i2c_algorithm pvr2_i2c_algo_template = {
 | |
| 	.master_xfer   = pvr2_i2c_xfer,
 | |
| 	.functionality = pvr2_i2c_functionality,
 | |
| };
 | |
| 
 | |
| static struct i2c_adapter pvr2_i2c_adap_template = {
 | |
| 	.owner         = THIS_MODULE,
 | |
| 	.class	       = 0,
 | |
| };
 | |
| 
 | |
| 
 | |
| /* Return true if device exists at given address */
 | |
| static int do_i2c_probe(struct pvr2_hdw *hdw, int addr)
 | |
| {
 | |
| 	struct i2c_msg msg[1];
 | |
| 	int rc;
 | |
| 	msg[0].addr = 0;
 | |
| 	msg[0].flags = I2C_M_RD;
 | |
| 	msg[0].len = 0;
 | |
| 	msg[0].buf = NULL;
 | |
| 	msg[0].addr = addr;
 | |
| 	rc = i2c_transfer(&hdw->i2c_adap, msg, ARRAY_SIZE(msg));
 | |
| 	return rc == 1;
 | |
| }
 | |
| 
 | |
| static void do_i2c_scan(struct pvr2_hdw *hdw)
 | |
| {
 | |
| 	int i;
 | |
| 	printk(KERN_INFO "%s: i2c scan beginning\n", hdw->name);
 | |
| 	for (i = 0; i < 128; i++) {
 | |
| 		if (do_i2c_probe(hdw, i)) {
 | |
| 			printk(KERN_INFO "%s: i2c scan: found device @ 0x%x\n",
 | |
| 			       hdw->name, i);
 | |
| 		}
 | |
| 	}
 | |
| 	printk(KERN_INFO "%s: i2c scan done.\n", hdw->name);
 | |
| }
 | |
| 
 | |
| static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
 | |
| {
 | |
| 	struct i2c_board_info info;
 | |
| 	struct IR_i2c_init_data *init_data = &hdw->ir_init_data;
 | |
| 	if (pvr2_disable_ir_video) {
 | |
| 		pvr2_trace(PVR2_TRACE_INFO,
 | |
| 			   "Automatic binding of ir_video has been disabled.");
 | |
| 		return;
 | |
| 	}
 | |
| 	memset(&info, 0, sizeof(struct i2c_board_info));
 | |
| 	switch (hdw->ir_scheme_active) {
 | |
| 	case PVR2_IR_SCHEME_24XXX: /* FX2-controlled IR */
 | |
| 	case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */
 | |
| 		init_data->ir_codes              = RC_MAP_HAUPPAUGE;
 | |
| 		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
 | |
| 		init_data->type                  = RC_BIT_RC5;
 | |
| 		init_data->name                  = hdw->hdw_desc->description;
 | |
| 		init_data->polling_interval      = 100; /* ms From ir-kbd-i2c */
 | |
| 		/* IR Receiver */
 | |
| 		info.addr          = 0x18;
 | |
| 		info.platform_data = init_data;
 | |
| 		strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
 | |
| 		pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
 | |
| 			   info.type, info.addr);
 | |
| 		i2c_new_device(&hdw->i2c_adap, &info);
 | |
| 		break;
 | |
| 	case PVR2_IR_SCHEME_ZILOG:     /* HVR-1950 style */
 | |
| 	case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */
 | |
| 		init_data->ir_codes              = RC_MAP_HAUPPAUGE;
 | |
| 		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
 | |
| 		init_data->type                  = RC_BIT_RC5;
 | |
| 		init_data->name                  = hdw->hdw_desc->description;
 | |
| 		/* IR Receiver */
 | |
| 		info.addr          = 0x71;
 | |
| 		info.platform_data = init_data;
 | |
| 		strlcpy(info.type, "ir_rx_z8f0811_haup", I2C_NAME_SIZE);
 | |
| 		pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
 | |
| 			   info.type, info.addr);
 | |
| 		i2c_new_device(&hdw->i2c_adap, &info);
 | |
| 		/* IR Trasmitter */
 | |
| 		info.addr          = 0x70;
 | |
| 		info.platform_data = init_data;
 | |
| 		strlcpy(info.type, "ir_tx_z8f0811_haup", I2C_NAME_SIZE);
 | |
| 		pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
 | |
| 			   info.type, info.addr);
 | |
| 		i2c_new_device(&hdw->i2c_adap, &info);
 | |
| 		break;
 | |
| 	default:
 | |
| 		/* The device either doesn't support I2C-based IR or we
 | |
| 		   don't know (yet) how to operate IR on the device. */
 | |
| 		break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
 | |
| {
 | |
| 	unsigned int idx;
 | |
| 
 | |
| 	/* 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) {
 | |
| 		printk(KERN_INFO "%s: IR disabled\n",hdw->name);
 | |
| 		hdw->i2c_func[0x18] = i2c_black_hole;
 | |
| 	} else if (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;
 | |
| 	strlcpy(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.  This is really the only way to differentiate
 | |
| 		   older 24xxx devices from 24xxx variants that include an
 | |
| 		   IR blaster.  If the IR blaster is present, the IR
 | |
| 		   receiver is part of that chip and thus we must disable
 | |
| 		   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);
 | |
| 
 | |
| 	pvr2_i2c_register_ir(hdw);
 | |
| }
 | |
| 
 | |
| void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
 | |
| {
 | |
| 	if (hdw->i2c_linked) {
 | |
| 		i2c_del_adapter(&hdw->i2c_adap);
 | |
| 		hdw->i2c_linked = 0;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Stuff for Emacs to see, in order to encourage consistent editing style:
 | |
|   *** Local Variables: ***
 | |
|   *** mode: c ***
 | |
|   *** fill-column: 75 ***
 | |
|   *** tab-width: 8 ***
 | |
|   *** c-basic-offset: 8 ***
 | |
|   *** End: ***
 | |
|   */
 |