linux/drivers/media/video/hdpvr/hdpvr-i2c.c
<<
>>
Prefs
   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