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} 146