PageRenderTime 46ms CodeModel.GetById 16ms app.highlight 18ms RepoModel.GetById 9ms app.codeStats 0ms

/drivers/media/video/hdpvr/hdpvr-i2c.c

https://bitbucket.org/abioy/linux
C | 145 lines | 103 code | 32 blank | 10 comment | 18 complexity | 30203acb58aa1f42f1bf0eba159c7b6a MD5 | raw file
Possible License(s): CC-BY-SA-3.0, GPL-2.0, LGPL-2.0, AGPL-1.0
  1
  2/*
  3 * Hauppauge HD PVR USB driver
  4 *
  5 * Copyright (C) 2008      Janne Grunau (j@jannau.net)
  6 *
  7 *	This program is free software; you can redistribute it and/or
  8 *	modify it under the terms of the GNU General Public License as
  9 *	published by the Free Software Foundation, version 2.
 10 *
 11 */
 12
 13#include <linux/i2c.h>
 14#include <linux/slab.h>
 15
 16#include "hdpvr.h"
 17
 18#define CTRL_READ_REQUEST	0xb8
 19#define CTRL_WRITE_REQUEST	0x38
 20
 21#define REQTYPE_I2C_READ	0xb1
 22#define REQTYPE_I2C_WRITE	0xb0
 23#define REQTYPE_I2C_WRITE_STATT	0xd0
 24
 25static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
 26			  char *data, int len)
 27{
 28	int ret;
 29	char *buf = kmalloc(len, GFP_KERNEL);
 30	if (!buf)
 31		return -ENOMEM;
 32
 33	ret = usb_control_msg(dev->udev,
 34			      usb_rcvctrlpipe(dev->udev, 0),
 35			      REQTYPE_I2C_READ, CTRL_READ_REQUEST,
 36			      0x100|addr, 0, buf, len, 1000);
 37
 38	if (ret == len) {
 39		memcpy(data, buf, len);
 40		ret = 0;
 41	} else if (ret >= 0)
 42		ret = -EIO;
 43
 44	kfree(buf);
 45
 46	return ret;
 47}
 48
 49static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
 50			   char *data, int len)
 51{
 52	int ret;
 53	char *buf = kmalloc(len, GFP_KERNEL);
 54	if (!buf)
 55		return -ENOMEM;
 56
 57	memcpy(buf, data, len);
 58	ret = usb_control_msg(dev->udev,
 59			      usb_sndctrlpipe(dev->udev, 0),
 60			      REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
 61			      0x100|addr, 0, buf, len, 1000);
 62
 63	if (ret < 0)
 64		goto error;
 65
 66	ret = usb_control_msg(dev->udev,
 67			      usb_rcvctrlpipe(dev->udev, 0),
 68			      REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
 69			      0, 0, buf, 2, 1000);
 70
 71	if (ret == 2)
 72		ret = 0;
 73	else if (ret >= 0)
 74		ret = -EIO;
 75
 76error:
 77	kfree(buf);
 78	return ret;
 79}
 80
 81static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
 82			  int num)
 83{
 84	struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter);
 85	int retval = 0, i, addr;
 86
 87	if (num <= 0)
 88		return 0;
 89
 90	mutex_lock(&dev->i2c_mutex);
 91
 92	for (i = 0; i < num && !retval; i++) {
 93		addr = msgs[i].addr << 1;
 94
 95		if (msgs[i].flags & I2C_M_RD)
 96			retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
 97						msgs[i].len);
 98		else
 99			retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
100						 msgs[i].len);
101	}
102
103	mutex_unlock(&dev->i2c_mutex);
104
105	return retval ? retval : num;
106}
107
108static u32 hdpvr_functionality(struct i2c_adapter *adapter)
109{
110	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
111}
112
113static struct i2c_algorithm hdpvr_algo = {
114	.master_xfer   = hdpvr_transfer,
115	.functionality = hdpvr_functionality,
116};
117
118int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
119{
120	struct i2c_adapter *i2c_adap;
121	int retval = -ENOMEM;
122
123	i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
124	if (i2c_adap == NULL)
125		goto error;
126
127	strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
128		sizeof(i2c_adap->name));
129	i2c_adap->algo  = &hdpvr_algo;
130	i2c_adap->class = I2C_CLASS_TV_ANALOG;
131	i2c_adap->owner = THIS_MODULE;
132	i2c_adap->dev.parent = &dev->udev->dev;
133
134	i2c_set_adapdata(i2c_adap, dev);
135
136	retval = i2c_add_adapter(i2c_adap);
137
138	if (!retval)
139		dev->i2c_adapter = i2c_adap;
140	else
141		kfree(i2c_adap);
142
143error:
144	return retval;
145}