mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-29 23:28:52 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
73
drivers/media/usb/em28xx/Kconfig
Normal file
73
drivers/media/usb/em28xx/Kconfig
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
config VIDEO_EM28XX
|
||||
tristate "Empia EM28xx USB devices support"
|
||||
depends on VIDEO_DEV && I2C
|
||||
select VIDEO_TUNER
|
||||
select VIDEO_TVEEPROM
|
||||
|
||||
config VIDEO_EM28XX_V4L2
|
||||
tristate "Empia EM28xx analog TV, video capture and/or webcam support"
|
||||
depends on VIDEO_EM28XX
|
||||
select VIDEOBUF2_VMALLOC
|
||||
select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT
|
||||
|
||||
---help---
|
||||
This is a video4linux driver for Empia 28xx based TV cards.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called em28xx
|
||||
|
||||
config VIDEO_EM28XX_ALSA
|
||||
depends on VIDEO_EM28XX && SND
|
||||
select SND_PCM
|
||||
tristate "Empia EM28xx ALSA audio module"
|
||||
---help---
|
||||
This is an ALSA driver for some Empia 28xx based TV cards.
|
||||
|
||||
This is not required for em2800/em2820/em2821 boards. However,
|
||||
newer em28xx devices uses Vendor Class for audio, instead of
|
||||
implementing the USB Audio Class. For those chips, this module
|
||||
will enable digital audio.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called em28xx-alsa
|
||||
|
||||
config VIDEO_EM28XX_DVB
|
||||
tristate "DVB/ATSC Support for em28xx based TV cards"
|
||||
depends on VIDEO_EM28XX && DVB_CORE
|
||||
select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_S921 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DRXD if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CXD2820R if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA10071 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
|
||||
---help---
|
||||
This adds support for DVB cards based on the
|
||||
Empiatech em28xx chips.
|
||||
|
||||
config VIDEO_EM28XX_RC
|
||||
tristate "EM28XX Remote Controller support"
|
||||
depends on RC_CORE
|
||||
depends on VIDEO_EM28XX
|
||||
depends on !(RC_CORE=m && VIDEO_EM28XX=y)
|
||||
default VIDEO_EM28XX
|
||||
---help---
|
||||
Enables Remote Controller support on em28xx driver.
|
||||
16
drivers/media/usb/em28xx/Makefile
Normal file
16
drivers/media/usb/em28xx/Makefile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
em28xx-y += em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
|
||||
|
||||
em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
|
||||
em28xx-alsa-objs := em28xx-audio.o
|
||||
em28xx-rc-objs := em28xx-input.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
|
||||
obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
|
||||
obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
|
||||
obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
|
||||
obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
|
||||
|
||||
ccflags-y += -Idrivers/media/i2c
|
||||
ccflags-y += -Idrivers/media/tuners
|
||||
ccflags-y += -Idrivers/media/dvb-core
|
||||
ccflags-y += -Idrivers/media/dvb-frontends
|
||||
1055
drivers/media/usb/em28xx/em28xx-audio.c
Normal file
1055
drivers/media/usb/em28xx/em28xx-audio.c
Normal file
File diff suppressed because it is too large
Load diff
458
drivers/media/usb/em28xx/em28xx-camera.c
Normal file
458
drivers/media/usb/em28xx/em28xx-camera.c
Normal file
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices
|
||||
|
||||
Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.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, or
|
||||
(at your option) any later version.
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <media/soc_camera.h>
|
||||
#include <media/mt9v011.h>
|
||||
#include <media/v4l2-clk.h>
|
||||
#include <media/v4l2-common.h>
|
||||
|
||||
#include "em28xx.h"
|
||||
|
||||
|
||||
/* Possible i2c addresses of Micron sensors */
|
||||
static unsigned short micron_sensor_addrs[] = {
|
||||
0xb8 >> 1, /* MT9V111, MT9V403 */
|
||||
0xba >> 1, /* MT9M001/011/111/112, MT9V011/012/112, MT9D011 */
|
||||
0x90 >> 1, /* MT9V012/112, MT9D011 (alternative address) */
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
|
||||
/* Possible i2c addresses of Omnivision sensors */
|
||||
static unsigned short omnivision_sensor_addrs[] = {
|
||||
0x42 >> 1, /* OV7725, OV7670/60/48 */
|
||||
0x60 >> 1, /* OV2640, OV9650/53/55 */
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
|
||||
|
||||
static struct soc_camera_link camlink = {
|
||||
.bus_id = 0,
|
||||
.flags = 0,
|
||||
.module_name = "em28xx",
|
||||
.unbalanced_power = true,
|
||||
};
|
||||
|
||||
|
||||
/* FIXME: Should be replaced by a proper mt9m111 driver */
|
||||
static int em28xx_initialize_mt9m111(struct em28xx *dev)
|
||||
{
|
||||
int i;
|
||||
unsigned char regs[][3] = {
|
||||
{ 0x0d, 0x00, 0x01, }, /* reset and use defaults */
|
||||
{ 0x0d, 0x00, 0x00, },
|
||||
{ 0x0a, 0x00, 0x21, },
|
||||
{ 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regs); i++)
|
||||
i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
|
||||
®s[i][0], 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: Should be replaced by a proper mt9m001 driver */
|
||||
static int em28xx_initialize_mt9m001(struct em28xx *dev)
|
||||
{
|
||||
int i;
|
||||
unsigned char regs[][3] = {
|
||||
{ 0x0d, 0x00, 0x01, },
|
||||
{ 0x0d, 0x00, 0x00, },
|
||||
{ 0x04, 0x05, 0x00, }, /* hres = 1280 */
|
||||
{ 0x03, 0x04, 0x00, }, /* vres = 1024 */
|
||||
{ 0x20, 0x11, 0x00, },
|
||||
{ 0x06, 0x00, 0x10, },
|
||||
{ 0x2b, 0x00, 0x24, },
|
||||
{ 0x2e, 0x00, 0x24, },
|
||||
{ 0x35, 0x00, 0x24, },
|
||||
{ 0x2d, 0x00, 0x20, },
|
||||
{ 0x2c, 0x00, 0x20, },
|
||||
{ 0x09, 0x0a, 0xd4, },
|
||||
{ 0x35, 0x00, 0x57, },
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regs); i++)
|
||||
i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
|
||||
®s[i][0], 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Probes Micron sensors with 8 bit address and 16 bit register width
|
||||
*/
|
||||
static int em28xx_probe_sensor_micron(struct em28xx *dev)
|
||||
{
|
||||
int ret, i;
|
||||
char *name;
|
||||
u8 reg;
|
||||
__be16 id_be;
|
||||
u16 id;
|
||||
|
||||
struct i2c_client client = dev->i2c_client[dev->def_i2c_bus];
|
||||
|
||||
dev->em28xx_sensor = EM28XX_NOSENSOR;
|
||||
for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) {
|
||||
client.addr = micron_sensor_addrs[i];
|
||||
/* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */
|
||||
/* Read chip ID from register 0x00 */
|
||||
reg = 0x00;
|
||||
ret = i2c_master_send(&client, ®, 1);
|
||||
if (ret < 0) {
|
||||
if (ret != -ENXIO)
|
||||
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
|
||||
client.addr << 1, ret);
|
||||
continue;
|
||||
}
|
||||
ret = i2c_master_recv(&client, (u8 *)&id_be, 2);
|
||||
if (ret < 0) {
|
||||
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
|
||||
client.addr << 1, ret);
|
||||
continue;
|
||||
}
|
||||
id = be16_to_cpu(id_be);
|
||||
/* Read chip ID from register 0xff */
|
||||
reg = 0xff;
|
||||
ret = i2c_master_send(&client, ®, 1);
|
||||
if (ret < 0) {
|
||||
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
|
||||
client.addr << 1, ret);
|
||||
continue;
|
||||
}
|
||||
ret = i2c_master_recv(&client, (u8 *)&id_be, 2);
|
||||
if (ret < 0) {
|
||||
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
|
||||
client.addr << 1, ret);
|
||||
continue;
|
||||
}
|
||||
/* Validate chip ID to be sure we have a Micron device */
|
||||
if (id != be16_to_cpu(id_be))
|
||||
continue;
|
||||
/* Check chip ID */
|
||||
id = be16_to_cpu(id_be);
|
||||
switch (id) {
|
||||
case 0x1222:
|
||||
name = "MT9V012"; /* MI370 */ /* 640x480 */
|
||||
break;
|
||||
case 0x1229:
|
||||
name = "MT9V112"; /* 640x480 */
|
||||
break;
|
||||
case 0x1433:
|
||||
name = "MT9M011"; /* 1280x1024 */
|
||||
break;
|
||||
case 0x143a: /* found in the ECS G200 */
|
||||
name = "MT9M111"; /* MI1310 */ /* 1280x1024 */
|
||||
dev->em28xx_sensor = EM28XX_MT9M111;
|
||||
break;
|
||||
case 0x148c:
|
||||
name = "MT9M112"; /* MI1320 */ /* 1280x1024 */
|
||||
break;
|
||||
case 0x1511:
|
||||
name = "MT9D011"; /* MI2010 */ /* 1600x1200 */
|
||||
break;
|
||||
case 0x8232:
|
||||
case 0x8243: /* rev B */
|
||||
name = "MT9V011"; /* MI360 */ /* 640x480 */
|
||||
dev->em28xx_sensor = EM28XX_MT9V011;
|
||||
break;
|
||||
case 0x8431:
|
||||
name = "MT9M001"; /* 1280x1024 */
|
||||
dev->em28xx_sensor = EM28XX_MT9M001;
|
||||
break;
|
||||
default:
|
||||
em28xx_info("unknown Micron sensor detected: 0x%04x\n",
|
||||
id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dev->em28xx_sensor == EM28XX_NOSENSOR)
|
||||
em28xx_info("unsupported sensor detected: %s\n", name);
|
||||
else
|
||||
em28xx_info("sensor %s detected\n", name);
|
||||
|
||||
dev->i2c_client[dev->def_i2c_bus].addr = client.addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Probes Omnivision sensors with 8 bit address and register width
|
||||
*/
|
||||
static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
|
||||
{
|
||||
int ret, i;
|
||||
char *name;
|
||||
u8 reg;
|
||||
u16 id;
|
||||
struct i2c_client client = dev->i2c_client[dev->def_i2c_bus];
|
||||
|
||||
dev->em28xx_sensor = EM28XX_NOSENSOR;
|
||||
/* NOTE: these devices have the register auto incrementation disabled
|
||||
* by default, so we have to use single byte reads ! */
|
||||
for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) {
|
||||
client.addr = omnivision_sensor_addrs[i];
|
||||
/* Read manufacturer ID from registers 0x1c-0x1d (BE) */
|
||||
reg = 0x1c;
|
||||
ret = i2c_smbus_read_byte_data(&client, reg);
|
||||
if (ret < 0) {
|
||||
if (ret != -ENXIO)
|
||||
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
|
||||
client.addr << 1, ret);
|
||||
continue;
|
||||
}
|
||||
id = ret << 8;
|
||||
reg = 0x1d;
|
||||
ret = i2c_smbus_read_byte_data(&client, reg);
|
||||
if (ret < 0) {
|
||||
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
|
||||
client.addr << 1, ret);
|
||||
continue;
|
||||
}
|
||||
id += ret;
|
||||
/* Check manufacturer ID */
|
||||
if (id != 0x7fa2)
|
||||
continue;
|
||||
/* Read product ID from registers 0x0a-0x0b (BE) */
|
||||
reg = 0x0a;
|
||||
ret = i2c_smbus_read_byte_data(&client, reg);
|
||||
if (ret < 0) {
|
||||
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
|
||||
client.addr << 1, ret);
|
||||
continue;
|
||||
}
|
||||
id = ret << 8;
|
||||
reg = 0x0b;
|
||||
ret = i2c_smbus_read_byte_data(&client, reg);
|
||||
if (ret < 0) {
|
||||
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
|
||||
client.addr << 1, ret);
|
||||
continue;
|
||||
}
|
||||
id += ret;
|
||||
/* Check product ID */
|
||||
switch (id) {
|
||||
case 0x2642:
|
||||
name = "OV2640";
|
||||
dev->em28xx_sensor = EM28XX_OV2640;
|
||||
break;
|
||||
case 0x7648:
|
||||
name = "OV7648";
|
||||
break;
|
||||
case 0x7660:
|
||||
name = "OV7660";
|
||||
break;
|
||||
case 0x7673:
|
||||
name = "OV7670";
|
||||
break;
|
||||
case 0x7720:
|
||||
name = "OV7720";
|
||||
break;
|
||||
case 0x7721:
|
||||
name = "OV7725";
|
||||
break;
|
||||
case 0x9648: /* Rev 2 */
|
||||
case 0x9649: /* Rev 3 */
|
||||
name = "OV9640";
|
||||
break;
|
||||
case 0x9650:
|
||||
case 0x9652: /* OV9653 */
|
||||
name = "OV9650";
|
||||
break;
|
||||
case 0x9656: /* Rev 4 */
|
||||
case 0x9657: /* Rev 5 */
|
||||
name = "OV9655";
|
||||
break;
|
||||
default:
|
||||
em28xx_info("unknown OmniVision sensor detected: 0x%04x\n",
|
||||
id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dev->em28xx_sensor == EM28XX_NOSENSOR)
|
||||
em28xx_info("unsupported sensor detected: %s\n", name);
|
||||
else
|
||||
em28xx_info("sensor %s detected\n", name);
|
||||
|
||||
dev->i2c_client[dev->def_i2c_bus].addr = client.addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int em28xx_detect_sensor(struct em28xx *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = em28xx_probe_sensor_micron(dev);
|
||||
|
||||
if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0)
|
||||
ret = em28xx_probe_sensor_omnivision(dev);
|
||||
|
||||
/*
|
||||
* NOTE: the Windows driver also probes i2c addresses
|
||||
* 0x22 (Samsung ?) and 0x66 (Kodak ?)
|
||||
*/
|
||||
|
||||
if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) {
|
||||
em28xx_info("No sensor detected\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int em28xx_init_camera(struct em28xx *dev)
|
||||
{
|
||||
char clk_name[V4L2_SUBDEV_NAME_SIZE];
|
||||
struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
|
||||
struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus];
|
||||
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
||||
int ret = 0;
|
||||
|
||||
v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
|
||||
i2c_adapter_id(adap), client->addr);
|
||||
v4l2->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL);
|
||||
if (IS_ERR(v4l2->clk))
|
||||
return PTR_ERR(v4l2->clk);
|
||||
|
||||
switch (dev->em28xx_sensor) {
|
||||
case EM28XX_MT9V011:
|
||||
{
|
||||
struct mt9v011_platform_data pdata;
|
||||
struct i2c_board_info mt9v011_info = {
|
||||
.type = "mt9v011",
|
||||
.addr = client->addr,
|
||||
.platform_data = &pdata,
|
||||
};
|
||||
|
||||
v4l2->sensor_xres = 640;
|
||||
v4l2->sensor_yres = 480;
|
||||
|
||||
/*
|
||||
* FIXME: mt9v011 uses I2S speed as xtal clk - at least with
|
||||
* the Silvercrest cam I have here for testing - for higher
|
||||
* resolutions, a high clock cause horizontal artifacts, so we
|
||||
* need to use a lower xclk frequency.
|
||||
* Yet, it would be possible to adjust xclk depending on the
|
||||
* desired resolution, since this affects directly the
|
||||
* frame rate.
|
||||
*/
|
||||
dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;
|
||||
em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
|
||||
v4l2->sensor_xtal = 4300000;
|
||||
pdata.xtal = v4l2->sensor_xtal;
|
||||
if (NULL ==
|
||||
v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
|
||||
&mt9v011_info, NULL)) {
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
}
|
||||
/* probably means GRGB 16 bit bayer */
|
||||
v4l2->vinmode = 0x0d;
|
||||
v4l2->vinctl = 0x00;
|
||||
|
||||
break;
|
||||
}
|
||||
case EM28XX_MT9M001:
|
||||
v4l2->sensor_xres = 1280;
|
||||
v4l2->sensor_yres = 1024;
|
||||
|
||||
em28xx_initialize_mt9m001(dev);
|
||||
|
||||
/* probably means BGGR 16 bit bayer */
|
||||
v4l2->vinmode = 0x0c;
|
||||
v4l2->vinctl = 0x00;
|
||||
|
||||
break;
|
||||
case EM28XX_MT9M111:
|
||||
v4l2->sensor_xres = 640;
|
||||
v4l2->sensor_yres = 512;
|
||||
|
||||
dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;
|
||||
em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
|
||||
em28xx_initialize_mt9m111(dev);
|
||||
|
||||
v4l2->vinmode = 0x0a;
|
||||
v4l2->vinctl = 0x00;
|
||||
|
||||
break;
|
||||
case EM28XX_OV2640:
|
||||
{
|
||||
struct v4l2_subdev *subdev;
|
||||
struct i2c_board_info ov2640_info = {
|
||||
.type = "ov2640",
|
||||
.flags = I2C_CLIENT_SCCB,
|
||||
.addr = client->addr,
|
||||
.platform_data = &camlink,
|
||||
};
|
||||
struct v4l2_mbus_framefmt fmt;
|
||||
|
||||
/*
|
||||
* FIXME: sensor supports resolutions up to 1600x1200, but
|
||||
* resolution setting/switching needs to be modified to
|
||||
* - switch sensor output resolution (including further
|
||||
* configuration changes)
|
||||
* - adjust bridge xclk
|
||||
* - disable 16 bit (12 bit) output formats on high resolutions
|
||||
*/
|
||||
v4l2->sensor_xres = 640;
|
||||
v4l2->sensor_yres = 480;
|
||||
|
||||
subdev =
|
||||
v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
|
||||
&ov2640_info, NULL);
|
||||
if (NULL == subdev) {
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
||||
fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
|
||||
fmt.width = 640;
|
||||
fmt.height = 480;
|
||||
v4l2_subdev_call(subdev, video, s_mbus_fmt, &fmt);
|
||||
|
||||
/* NOTE: for UXGA=1600x1200 switch to 12MHz */
|
||||
dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ;
|
||||
em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
|
||||
v4l2->vinmode = 0x08;
|
||||
v4l2->vinctl = 0x00;
|
||||
|
||||
break;
|
||||
}
|
||||
case EM28XX_NOSENSOR:
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
v4l2_clk_unregister_fixed(v4l2->clk);
|
||||
v4l2->clk = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(em28xx_init_camera);
|
||||
3522
drivers/media/usb/em28xx/em28xx-cards.c
Normal file
3522
drivers/media/usb/em28xx/em28xx-cards.c
Normal file
File diff suppressed because it is too large
Load diff
1147
drivers/media/usb/em28xx/em28xx-core.c
Normal file
1147
drivers/media/usb/em28xx/em28xx-core.c
Normal file
File diff suppressed because it is too large
Load diff
1786
drivers/media/usb/em28xx/em28xx-dvb.c
Normal file
1786
drivers/media/usb/em28xx/em28xx-dvb.c
Normal file
File diff suppressed because it is too large
Load diff
987
drivers/media/usb/em28xx/em28xx-i2c.c
Normal file
987
drivers/media/usb/em28xx/em28xx-i2c.c
Normal file
|
|
@ -0,0 +1,987 @@
|
|||
/*
|
||||
em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
|
||||
|
||||
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
|
||||
Markus Rechberger <mrechberger@gmail.com>
|
||||
Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
Sascha Sommer <saschasommer@freenet.de>
|
||||
Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.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, or
|
||||
(at your option) any later version.
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include "em28xx.h"
|
||||
#include "tuner-xc2028.h"
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/tuner.h>
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
||||
static unsigned int i2c_scan;
|
||||
module_param(i2c_scan, int, 0444);
|
||||
MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
|
||||
|
||||
static unsigned int i2c_debug;
|
||||
module_param(i2c_debug, int, 0644);
|
||||
MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)");
|
||||
|
||||
/*
|
||||
* em2800_i2c_send_bytes()
|
||||
* send up to 4 bytes to the em2800 i2c device
|
||||
*/
|
||||
static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
|
||||
int ret;
|
||||
u8 b2[6];
|
||||
|
||||
if (len < 1 || len > 4)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
BUG_ON(len < 1 || len > 4);
|
||||
b2[5] = 0x80 + len - 1;
|
||||
b2[4] = addr;
|
||||
b2[3] = buf[0];
|
||||
if (len > 1)
|
||||
b2[2] = buf[1];
|
||||
if (len > 2)
|
||||
b2[1] = buf[2];
|
||||
if (len > 3)
|
||||
b2[0] = buf[3];
|
||||
|
||||
/* trigger write */
|
||||
ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
|
||||
if (ret != 2 + len) {
|
||||
em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n",
|
||||
addr, ret);
|
||||
return (ret < 0) ? ret : -EIO;
|
||||
}
|
||||
/* wait for completion */
|
||||
while (time_is_after_jiffies(timeout)) {
|
||||
ret = dev->em28xx_read_reg(dev, 0x05);
|
||||
if (ret == 0x80 + len - 1)
|
||||
return len;
|
||||
if (ret == 0x94 + len - 1) {
|
||||
if (i2c_debug == 1)
|
||||
em28xx_warn("R05 returned 0x%02x: I2C ACK error\n",
|
||||
ret);
|
||||
return -ENXIO;
|
||||
}
|
||||
if (ret < 0) {
|
||||
em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
msleep(5);
|
||||
}
|
||||
if (i2c_debug)
|
||||
em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* em2800_i2c_recv_bytes()
|
||||
* read up to 4 bytes from the em2800 i2c device
|
||||
*/
|
||||
static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
|
||||
u8 buf2[4];
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (len < 1 || len > 4)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* trigger read */
|
||||
buf2[1] = 0x84 + len - 1;
|
||||
buf2[0] = addr;
|
||||
ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2);
|
||||
if (ret != 2) {
|
||||
em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n",
|
||||
addr, ret);
|
||||
return (ret < 0) ? ret : -EIO;
|
||||
}
|
||||
|
||||
/* wait for completion */
|
||||
while (time_is_after_jiffies(timeout)) {
|
||||
ret = dev->em28xx_read_reg(dev, 0x05);
|
||||
if (ret == 0x84 + len - 1)
|
||||
break;
|
||||
if (ret == 0x94 + len - 1) {
|
||||
if (i2c_debug == 1)
|
||||
em28xx_warn("R05 returned 0x%02x: I2C ACK error\n",
|
||||
ret);
|
||||
return -ENXIO;
|
||||
}
|
||||
if (ret < 0) {
|
||||
em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
msleep(5);
|
||||
}
|
||||
if (ret != 0x84 + len - 1) {
|
||||
if (i2c_debug)
|
||||
em28xx_warn("read from i2c device at 0x%x timed out\n",
|
||||
addr);
|
||||
}
|
||||
|
||||
/* get the received message */
|
||||
ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
|
||||
if (ret != len) {
|
||||
em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
|
||||
addr, ret);
|
||||
return (ret < 0) ? ret : -EIO;
|
||||
}
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = buf2[len - 1 - i];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* em2800_i2c_check_for_device()
|
||||
* check if there is an i2c device at the supplied address
|
||||
*/
|
||||
static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
|
||||
{
|
||||
u8 buf;
|
||||
int ret;
|
||||
|
||||
ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
|
||||
if (ret == 1)
|
||||
return 0;
|
||||
return (ret < 0) ? ret : -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* em28xx_i2c_send_bytes()
|
||||
*/
|
||||
static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
|
||||
u16 len, int stop)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
|
||||
int ret;
|
||||
|
||||
if (len < 1 || len > 64)
|
||||
return -EOPNOTSUPP;
|
||||
/*
|
||||
* NOTE: limited by the USB ctrl message constraints
|
||||
* Zero length reads always succeed, even if no device is connected
|
||||
*/
|
||||
|
||||
/* Write to i2c device */
|
||||
ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
|
||||
if (ret != len) {
|
||||
if (ret < 0) {
|
||||
em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n",
|
||||
addr, ret);
|
||||
return ret;
|
||||
} else {
|
||||
em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
|
||||
len, addr, ret);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* wait for completion */
|
||||
while (time_is_after_jiffies(timeout)) {
|
||||
ret = dev->em28xx_read_reg(dev, 0x05);
|
||||
if (ret == 0) /* success */
|
||||
return len;
|
||||
if (ret == 0x10) {
|
||||
if (i2c_debug == 1)
|
||||
em28xx_warn("I2C ACK error on writing to addr 0x%02x\n",
|
||||
addr);
|
||||
return -ENXIO;
|
||||
}
|
||||
if (ret < 0) {
|
||||
em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
msleep(5);
|
||||
/*
|
||||
* NOTE: do we really have to wait for success ?
|
||||
* Never seen anything else than 0x00 or 0x10
|
||||
* (even with high payload) ...
|
||||
*/
|
||||
}
|
||||
|
||||
if (ret == 0x02 || ret == 0x04) {
|
||||
/* NOTE: these errors seem to be related to clock stretching */
|
||||
if (i2c_debug)
|
||||
em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
|
||||
addr, ret);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n",
|
||||
addr, ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* em28xx_i2c_recv_bytes()
|
||||
* read a byte from the i2c device
|
||||
*/
|
||||
static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (len < 1 || len > 64)
|
||||
return -EOPNOTSUPP;
|
||||
/*
|
||||
* NOTE: limited by the USB ctrl message constraints
|
||||
* Zero length reads always succeed, even if no device is connected
|
||||
*/
|
||||
|
||||
/* Read data from i2c device */
|
||||
ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
|
||||
if (ret < 0) {
|
||||
em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
|
||||
addr, ret);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* NOTE: some devices with two i2c busses have the bad habit to return 0
|
||||
* bytes if we are on bus B AND there was no write attempt to the
|
||||
* specified slave address before AND no device is present at the
|
||||
* requested slave address.
|
||||
* Anyway, the next check will fail with -ENXIO in this case, so avoid
|
||||
* spamming the system log on device probing and do nothing here.
|
||||
*/
|
||||
|
||||
/* Check success of the i2c operation */
|
||||
ret = dev->em28xx_read_reg(dev, 0x05);
|
||||
if (ret == 0) /* success */
|
||||
return len;
|
||||
if (ret < 0) {
|
||||
em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret == 0x10) {
|
||||
if (i2c_debug == 1)
|
||||
em28xx_warn("I2C ACK error on writing to addr 0x%02x\n",
|
||||
addr);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (ret == 0x02 || ret == 0x04) {
|
||||
/* NOTE: these errors seem to be related to clock stretching */
|
||||
if (i2c_debug)
|
||||
em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
|
||||
addr, ret);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n",
|
||||
addr, ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* em28xx_i2c_check_for_device()
|
||||
* check if there is a i2c_device at the supplied address
|
||||
*/
|
||||
static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
|
||||
{
|
||||
int ret;
|
||||
u8 buf;
|
||||
|
||||
ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
|
||||
if (ret == 1)
|
||||
return 0;
|
||||
return (ret < 0) ? ret : -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* em25xx_bus_B_send_bytes
|
||||
* write bytes to the i2c device
|
||||
*/
|
||||
static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
|
||||
u16 len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (len < 1 || len > 64)
|
||||
return -EOPNOTSUPP;
|
||||
/*
|
||||
* NOTE: limited by the USB ctrl message constraints
|
||||
* Zero length reads always succeed, even if no device is connected
|
||||
*/
|
||||
|
||||
/* Set register and write value */
|
||||
ret = dev->em28xx_write_regs_req(dev, 0x06, addr, buf, len);
|
||||
if (ret != len) {
|
||||
if (ret < 0) {
|
||||
em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n",
|
||||
addr, ret);
|
||||
return ret;
|
||||
} else {
|
||||
em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
|
||||
len, addr, ret);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
/* Check success */
|
||||
ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
|
||||
/*
|
||||
* NOTE: the only error we've seen so far is
|
||||
* 0x01 when the slave device is not present
|
||||
*/
|
||||
if (!ret)
|
||||
return len;
|
||||
else if (ret > 0) {
|
||||
if (i2c_debug == 1)
|
||||
em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n",
|
||||
ret);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
/*
|
||||
* NOTE: With chip types (other chip IDs) which actually don't support
|
||||
* this operation, it seems to succeed ALWAYS ! (even if there is no
|
||||
* slave device or even no second i2c bus provided)
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* em25xx_bus_B_recv_bytes
|
||||
* read bytes from the i2c device
|
||||
*/
|
||||
static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
|
||||
u16 len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (len < 1 || len > 64)
|
||||
return -EOPNOTSUPP;
|
||||
/*
|
||||
* NOTE: limited by the USB ctrl message constraints
|
||||
* Zero length reads always succeed, even if no device is connected
|
||||
*/
|
||||
|
||||
/* Read value */
|
||||
ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len);
|
||||
if (ret < 0) {
|
||||
em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
|
||||
addr, ret);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* NOTE: some devices with two i2c busses have the bad habit to return 0
|
||||
* bytes if we are on bus B AND there was no write attempt to the
|
||||
* specified slave address before AND no device is present at the
|
||||
* requested slave address.
|
||||
* Anyway, the next check will fail with -ENXIO in this case, so avoid
|
||||
* spamming the system log on device probing and do nothing here.
|
||||
*/
|
||||
|
||||
/* Check success */
|
||||
ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
|
||||
/*
|
||||
* NOTE: the only error we've seen so far is
|
||||
* 0x01 when the slave device is not present
|
||||
*/
|
||||
if (!ret)
|
||||
return len;
|
||||
else if (ret > 0) {
|
||||
if (i2c_debug == 1)
|
||||
em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n",
|
||||
ret);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
/*
|
||||
* NOTE: With chip types (other chip IDs) which actually don't support
|
||||
* this operation, it seems to succeed ALWAYS ! (even if there is no
|
||||
* slave device or even no second i2c bus provided)
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* em25xx_bus_B_check_for_device()
|
||||
* check if there is a i2c device at the supplied address
|
||||
*/
|
||||
static int em25xx_bus_B_check_for_device(struct em28xx *dev, u16 addr)
|
||||
{
|
||||
u8 buf;
|
||||
int ret;
|
||||
|
||||
ret = em25xx_bus_B_recv_bytes(dev, addr, &buf, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* NOTE: With chips which do not support this operation,
|
||||
* it seems to succeed ALWAYS ! (even if no device connected)
|
||||
*/
|
||||
}
|
||||
|
||||
static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
|
||||
{
|
||||
struct em28xx *dev = i2c_bus->dev;
|
||||
int rc = -EOPNOTSUPP;
|
||||
|
||||
if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
|
||||
rc = em28xx_i2c_check_for_device(dev, addr);
|
||||
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
|
||||
rc = em2800_i2c_check_for_device(dev, addr);
|
||||
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
|
||||
rc = em25xx_bus_B_check_for_device(dev, addr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
|
||||
struct i2c_msg msg)
|
||||
{
|
||||
struct em28xx *dev = i2c_bus->dev;
|
||||
u16 addr = msg.addr << 1;
|
||||
int rc = -EOPNOTSUPP;
|
||||
|
||||
if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
|
||||
rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
|
||||
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
|
||||
rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
|
||||
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
|
||||
rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus,
|
||||
struct i2c_msg msg, int stop)
|
||||
{
|
||||
struct em28xx *dev = i2c_bus->dev;
|
||||
u16 addr = msg.addr << 1;
|
||||
int rc = -EOPNOTSUPP;
|
||||
|
||||
if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
|
||||
rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop);
|
||||
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
|
||||
rc = em2800_i2c_send_bytes(dev, addr, msg.buf, msg.len);
|
||||
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
|
||||
rc = em25xx_bus_B_send_bytes(dev, addr, msg.buf, msg.len);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* em28xx_i2c_xfer()
|
||||
* the main i2c transfer function
|
||||
*/
|
||||
static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
|
||||
struct em28xx *dev = i2c_bus->dev;
|
||||
unsigned bus = i2c_bus->bus;
|
||||
int addr, rc, i;
|
||||
u8 reg;
|
||||
|
||||
/* prevent i2c xfer attempts after device is disconnected
|
||||
some fe's try to do i2c writes/reads from their release
|
||||
interfaces when called in disconnect path */
|
||||
if (dev->disconnected)
|
||||
return -ENODEV;
|
||||
|
||||
rc = rt_mutex_trylock(&dev->i2c_bus_lock);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Switch I2C bus if needed */
|
||||
if (bus != dev->cur_i2c_bus &&
|
||||
i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) {
|
||||
if (bus == 1)
|
||||
reg = EM2874_I2C_SECONDARY_BUS_SELECT;
|
||||
else
|
||||
reg = 0;
|
||||
em28xx_write_reg_bits(dev, EM28XX_R06_I2C_CLK, reg,
|
||||
EM2874_I2C_SECONDARY_BUS_SELECT);
|
||||
dev->cur_i2c_bus = bus;
|
||||
}
|
||||
|
||||
if (num <= 0) {
|
||||
rt_mutex_unlock(&dev->i2c_bus_lock);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < num; i++) {
|
||||
addr = msgs[i].addr << 1;
|
||||
if (i2c_debug > 1)
|
||||
printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:",
|
||||
dev->name, __func__ ,
|
||||
(msgs[i].flags & I2C_M_RD) ? "read" : "write",
|
||||
i == num - 1 ? "stop" : "nonstop",
|
||||
addr, msgs[i].len);
|
||||
if (!msgs[i].len) {
|
||||
/*
|
||||
* no len: check only for device presence
|
||||
* This code is only called during device probe.
|
||||
*/
|
||||
rc = i2c_check_for_device(i2c_bus, addr);
|
||||
if (rc < 0) {
|
||||
if (rc == -ENXIO) {
|
||||
if (i2c_debug > 1)
|
||||
printk(KERN_CONT " no device\n");
|
||||
rc = -ENODEV;
|
||||
} else {
|
||||
if (i2c_debug > 1)
|
||||
printk(KERN_CONT " ERROR: %i\n", rc);
|
||||
}
|
||||
rt_mutex_unlock(&dev->i2c_bus_lock);
|
||||
return rc;
|
||||
}
|
||||
} else if (msgs[i].flags & I2C_M_RD) {
|
||||
/* read bytes */
|
||||
rc = i2c_recv_bytes(i2c_bus, msgs[i]);
|
||||
|
||||
if (i2c_debug > 1 && rc >= 0)
|
||||
printk(KERN_CONT " %*ph",
|
||||
msgs[i].len, msgs[i].buf);
|
||||
} else {
|
||||
if (i2c_debug > 1)
|
||||
printk(KERN_CONT " %*ph",
|
||||
msgs[i].len, msgs[i].buf);
|
||||
|
||||
/* write bytes */
|
||||
rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1);
|
||||
}
|
||||
if (rc < 0) {
|
||||
if (i2c_debug > 1)
|
||||
printk(KERN_CONT " ERROR: %i\n", rc);
|
||||
rt_mutex_unlock(&dev->i2c_bus_lock);
|
||||
return rc;
|
||||
}
|
||||
if (i2c_debug > 1)
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
|
||||
rt_mutex_unlock(&dev->i2c_bus_lock);
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
* based on linux/sunrpc/svcauth.h and linux/hash.h
|
||||
* The original hash function returns a different value, if arch is x86_64
|
||||
* or i386.
|
||||
*/
|
||||
static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
|
||||
{
|
||||
unsigned long hash = 0;
|
||||
unsigned long l = 0;
|
||||
int len = 0;
|
||||
unsigned char c;
|
||||
do {
|
||||
if (len == length) {
|
||||
c = (char)len;
|
||||
len = -1;
|
||||
} else
|
||||
c = *buf++;
|
||||
l = (l << 8) | c;
|
||||
len++;
|
||||
if ((len & (32 / 8 - 1)) == 0)
|
||||
hash = ((hash^l) * 0x9e370001UL);
|
||||
} while (len);
|
||||
|
||||
return (hash >> (32 - bits)) & 0xffffffffUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to read data blocks from i2c clients with 8 or 16 bit
|
||||
* address width, 8 bit register width and auto incrementation been activated
|
||||
*/
|
||||
static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr,
|
||||
bool addr_w16, u16 len, u8 *data)
|
||||
{
|
||||
int remain = len, rsize, rsize_max, ret;
|
||||
u8 buf[2];
|
||||
|
||||
/* Sanity check */
|
||||
if (addr + remain > (addr_w16 * 0xff00 + 0xff + 1))
|
||||
return -EINVAL;
|
||||
/* Select address */
|
||||
buf[0] = addr >> 8;
|
||||
buf[1] = addr & 0xff;
|
||||
ret = i2c_master_send(&dev->i2c_client[bus], buf + !addr_w16, 1 + addr_w16);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Read data */
|
||||
if (dev->board.is_em2800)
|
||||
rsize_max = 4;
|
||||
else
|
||||
rsize_max = 64;
|
||||
while (remain > 0) {
|
||||
if (remain > rsize_max)
|
||||
rsize = rsize_max;
|
||||
else
|
||||
rsize = remain;
|
||||
|
||||
ret = i2c_master_recv(&dev->i2c_client[bus], data, rsize);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
remain -= rsize;
|
||||
data += rsize;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
|
||||
u8 **eedata, u16 *eedata_len)
|
||||
{
|
||||
const u16 len = 256;
|
||||
/*
|
||||
* FIXME common length/size for bytes to read, to display, hash
|
||||
* calculation and returned device dataset. Simplifies the code a lot,
|
||||
* but we might have to deal with multiple sizes in the future !
|
||||
*/
|
||||
int err;
|
||||
struct em28xx_eeprom *dev_config;
|
||||
u8 buf, *data;
|
||||
|
||||
*eedata = NULL;
|
||||
*eedata_len = 0;
|
||||
|
||||
/* EEPROM is always on i2c bus 0 on all known devices. */
|
||||
|
||||
dev->i2c_client[bus].addr = 0xa0 >> 1;
|
||||
|
||||
/* Check if board has eeprom */
|
||||
err = i2c_master_recv(&dev->i2c_client[bus], &buf, 0);
|
||||
if (err < 0) {
|
||||
em28xx_info("board has no eeprom\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data = kzalloc(len, GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Read EEPROM content */
|
||||
err = em28xx_i2c_read_block(dev, bus, 0x0000,
|
||||
dev->eeprom_addrwidth_16bit,
|
||||
len, data);
|
||||
if (err != len) {
|
||||
em28xx_errdev("failed to read eeprom (err=%d)\n", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (i2c_debug) {
|
||||
/* Display eeprom content */
|
||||
print_hex_dump(KERN_INFO, "eeprom ", DUMP_PREFIX_OFFSET,
|
||||
16, 1, data, len, true);
|
||||
|
||||
if (dev->eeprom_addrwidth_16bit)
|
||||
em28xx_info("eeprom %06x: ... (skipped)\n", 256);
|
||||
}
|
||||
|
||||
if (dev->eeprom_addrwidth_16bit &&
|
||||
data[0] == 0x26 && data[3] == 0x00) {
|
||||
/* new eeprom format; size 4-64kb */
|
||||
u16 mc_start;
|
||||
u16 hwconf_offset;
|
||||
|
||||
dev->hash = em28xx_hash_mem(data, len, 32);
|
||||
mc_start = (data[1] << 8) + 4; /* usually 0x0004 */
|
||||
|
||||
em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
|
||||
data[0], data[1], data[2], data[3], dev->hash);
|
||||
em28xx_info("EEPROM info:\n");
|
||||
em28xx_info("\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n",
|
||||
mc_start, data[2]);
|
||||
/*
|
||||
* boot configuration (address 0x0002):
|
||||
* [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz
|
||||
* [1] always selects 12 kb RAM
|
||||
* [2] USB device speed: 1 = force Full Speed; 0 = auto detect
|
||||
* [4] 1 = force fast mode and no suspend for device testing
|
||||
* [5:7] USB PHY tuning registers; determined by device
|
||||
* characterization
|
||||
*/
|
||||
|
||||
/*
|
||||
* Read hardware config dataset offset from address
|
||||
* (microcode start + 46)
|
||||
*/
|
||||
err = em28xx_i2c_read_block(dev, bus, mc_start + 46, 1, 2,
|
||||
data);
|
||||
if (err != 2) {
|
||||
em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n",
|
||||
err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Calculate hardware config dataset start address */
|
||||
hwconf_offset = mc_start + data[0] + (data[1] << 8);
|
||||
|
||||
/* Read hardware config dataset */
|
||||
/*
|
||||
* NOTE: the microcode copy can be multiple pages long, but
|
||||
* we assume the hardware config dataset is the same as in
|
||||
* the old eeprom and not longer than 256 bytes.
|
||||
* tveeprom is currently also limited to 256 bytes.
|
||||
*/
|
||||
err = em28xx_i2c_read_block(dev, bus, hwconf_offset, 1, len,
|
||||
data);
|
||||
if (err != len) {
|
||||
em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n",
|
||||
err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Verify hardware config dataset */
|
||||
/* NOTE: not all devices provide this type of dataset */
|
||||
if (data[0] != 0x1a || data[1] != 0xeb ||
|
||||
data[2] != 0x67 || data[3] != 0x95) {
|
||||
em28xx_info("\tno hardware configuration dataset found in eeprom\n");
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: decrypt eeprom data for camera bridges (em25xx, em276x+) */
|
||||
|
||||
} else if (!dev->eeprom_addrwidth_16bit &&
|
||||
data[0] == 0x1a && data[1] == 0xeb &&
|
||||
data[2] == 0x67 && data[3] == 0x95) {
|
||||
dev->hash = em28xx_hash_mem(data, len, 32);
|
||||
em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
|
||||
data[0], data[1], data[2], data[3], dev->hash);
|
||||
em28xx_info("EEPROM info:\n");
|
||||
} else {
|
||||
em28xx_info("unknown eeprom format or eeprom corrupted !\n");
|
||||
err = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*eedata = data;
|
||||
*eedata_len = len;
|
||||
dev_config = (void *)*eedata;
|
||||
|
||||
switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) {
|
||||
case 0:
|
||||
em28xx_info("\tNo audio on board.\n");
|
||||
break;
|
||||
case 1:
|
||||
em28xx_info("\tAC97 audio (5 sample rates)\n");
|
||||
break;
|
||||
case 2:
|
||||
if (dev->chip_id < CHIP_ID_EM2860)
|
||||
em28xx_info("\tI2S audio, sample rate=32k\n");
|
||||
else
|
||||
em28xx_info("\tI2S audio, 3 sample rates\n");
|
||||
break;
|
||||
case 3:
|
||||
if (dev->chip_id < CHIP_ID_EM2860)
|
||||
em28xx_info("\tI2S audio, 3 sample rates\n");
|
||||
else
|
||||
em28xx_info("\tI2S audio, 5 sample rates\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(dev_config->chip_conf) & 1 << 3)
|
||||
em28xx_info("\tUSB Remote wakeup capable\n");
|
||||
|
||||
if (le16_to_cpu(dev_config->chip_conf) & 1 << 2)
|
||||
em28xx_info("\tUSB Self power capable\n");
|
||||
|
||||
switch (le16_to_cpu(dev_config->chip_conf) & 0x3) {
|
||||
case 0:
|
||||
em28xx_info("\t500mA max power\n");
|
||||
break;
|
||||
case 1:
|
||||
em28xx_info("\t400mA max power\n");
|
||||
break;
|
||||
case 2:
|
||||
em28xx_info("\t300mA max power\n");
|
||||
break;
|
||||
case 3:
|
||||
em28xx_info("\t200mA max power\n");
|
||||
break;
|
||||
}
|
||||
em28xx_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
|
||||
dev_config->string_idx_table,
|
||||
le16_to_cpu(dev_config->string1),
|
||||
le16_to_cpu(dev_config->string2),
|
||||
le16_to_cpu(dev_config->string3));
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* functionality()
|
||||
*/
|
||||
static u32 functionality(struct i2c_adapter *i2c_adap)
|
||||
{
|
||||
struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
|
||||
|
||||
if ((i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) ||
|
||||
(i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)) {
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
} else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) {
|
||||
return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL) &
|
||||
~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
|
||||
}
|
||||
|
||||
WARN(1, "Unknown i2c bus algorithm.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm em28xx_algo = {
|
||||
.master_xfer = em28xx_i2c_xfer,
|
||||
.functionality = functionality,
|
||||
};
|
||||
|
||||
static struct i2c_adapter em28xx_adap_template = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "em28xx",
|
||||
.algo = &em28xx_algo,
|
||||
};
|
||||
|
||||
static struct i2c_client em28xx_client_template = {
|
||||
.name = "em28xx internal",
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* i2c_devs
|
||||
* incomplete list of known devices
|
||||
*/
|
||||
static char *i2c_devs[128] = {
|
||||
[0x3e >> 1] = "remote IR sensor",
|
||||
[0x4a >> 1] = "saa7113h",
|
||||
[0x52 >> 1] = "drxk",
|
||||
[0x60 >> 1] = "remote IR sensor",
|
||||
[0x8e >> 1] = "remote IR sensor",
|
||||
[0x86 >> 1] = "tda9887",
|
||||
[0x80 >> 1] = "msp34xx",
|
||||
[0x88 >> 1] = "msp34xx",
|
||||
[0xa0 >> 1] = "eeprom",
|
||||
[0xb0 >> 1] = "tda9874",
|
||||
[0xb8 >> 1] = "tvp5150a",
|
||||
[0xba >> 1] = "webcam sensor or tvp5150a",
|
||||
[0xc0 >> 1] = "tuner (analog)",
|
||||
[0xc2 >> 1] = "tuner (analog)",
|
||||
[0xc4 >> 1] = "tuner (analog)",
|
||||
[0xc6 >> 1] = "tuner (analog)",
|
||||
};
|
||||
|
||||
/*
|
||||
* do_i2c_scan()
|
||||
* check i2c address range for devices
|
||||
*/
|
||||
void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus)
|
||||
{
|
||||
u8 i2c_devicelist[128];
|
||||
unsigned char buf;
|
||||
int i, rc;
|
||||
|
||||
memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
|
||||
dev->i2c_client[bus].addr = i;
|
||||
rc = i2c_master_recv(&dev->i2c_client[bus], &buf, 0);
|
||||
if (rc < 0)
|
||||
continue;
|
||||
i2c_devicelist[i] = i;
|
||||
em28xx_info("found i2c device @ 0x%x on bus %d [%s]\n",
|
||||
i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???");
|
||||
}
|
||||
|
||||
if (bus == dev->def_i2c_bus)
|
||||
dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
|
||||
ARRAY_SIZE(i2c_devicelist), 32);
|
||||
}
|
||||
|
||||
/*
|
||||
* em28xx_i2c_register()
|
||||
* register i2c bus
|
||||
*/
|
||||
int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
|
||||
enum em28xx_i2c_algo_type algo_type)
|
||||
{
|
||||
int retval;
|
||||
|
||||
BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
|
||||
BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
|
||||
|
||||
if (bus >= NUM_I2C_BUSES)
|
||||
return -ENODEV;
|
||||
|
||||
dev->i2c_adap[bus] = em28xx_adap_template;
|
||||
dev->i2c_adap[bus].dev.parent = &dev->udev->dev;
|
||||
strcpy(dev->i2c_adap[bus].name, dev->name);
|
||||
|
||||
dev->i2c_bus[bus].bus = bus;
|
||||
dev->i2c_bus[bus].algo_type = algo_type;
|
||||
dev->i2c_bus[bus].dev = dev;
|
||||
dev->i2c_adap[bus].algo_data = &dev->i2c_bus[bus];
|
||||
|
||||
retval = i2c_add_adapter(&dev->i2c_adap[bus]);
|
||||
if (retval < 0) {
|
||||
em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
|
||||
__func__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
dev->i2c_client[bus] = em28xx_client_template;
|
||||
dev->i2c_client[bus].adapter = &dev->i2c_adap[bus];
|
||||
|
||||
/* Up to now, all eeproms are at bus 0 */
|
||||
if (!bus) {
|
||||
retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len);
|
||||
if ((retval < 0) && (retval != -ENODEV)) {
|
||||
em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
|
||||
__func__, retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
if (i2c_scan)
|
||||
em28xx_do_i2c_scan(dev, bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* em28xx_i2c_unregister()
|
||||
* unregister i2c_bus
|
||||
*/
|
||||
int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus)
|
||||
{
|
||||
if (bus >= NUM_I2C_BUSES)
|
||||
return -ENODEV;
|
||||
|
||||
i2c_del_adapter(&dev->i2c_adap[bus]);
|
||||
return 0;
|
||||
}
|
||||
919
drivers/media/usb/em28xx/em28xx-input.c
Normal file
919
drivers/media/usb/em28xx/em28xx-input.c
Normal file
|
|
@ -0,0 +1,919 @@
|
|||
/*
|
||||
handle em28xx IR remotes via linux kernel input layer.
|
||||
|
||||
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
|
||||
Markus Rechberger <mrechberger@gmail.com>
|
||||
Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
Sascha Sommer <saschasommer@freenet.de>
|
||||
|
||||
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, or
|
||||
(at your option) any later version.
|
||||
|
||||
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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bitrev.h>
|
||||
|
||||
#include "em28xx.h"
|
||||
|
||||
#define EM28XX_SNAPSHOT_KEY KEY_CAMERA
|
||||
#define EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL 500 /* [ms] */
|
||||
#define EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL 100 /* [ms] */
|
||||
|
||||
static unsigned int ir_debug;
|
||||
module_param(ir_debug, int, 0644);
|
||||
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
|
||||
|
||||
#define MODULE_NAME "em28xx"
|
||||
|
||||
#define dprintk(fmt, arg...) \
|
||||
if (ir_debug) { \
|
||||
printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
Polling structure used by em28xx IR's
|
||||
**********************************************************/
|
||||
|
||||
struct em28xx_ir_poll_result {
|
||||
unsigned int toggle_bit:1;
|
||||
unsigned int read_count:7;
|
||||
|
||||
enum rc_type protocol;
|
||||
u32 scancode;
|
||||
};
|
||||
|
||||
struct em28xx_IR {
|
||||
struct em28xx *dev;
|
||||
struct rc_dev *rc;
|
||||
char name[32];
|
||||
char phys[32];
|
||||
|
||||
/* poll decoder */
|
||||
int polling;
|
||||
struct delayed_work work;
|
||||
unsigned int full_code:1;
|
||||
unsigned int last_readcount;
|
||||
u64 rc_type;
|
||||
|
||||
struct i2c_client *i2c_client;
|
||||
|
||||
int (*get_key_i2c)(struct i2c_client *ir, enum rc_type *protocol, u32 *scancode);
|
||||
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
|
||||
};
|
||||
|
||||
/**********************************************************
|
||||
I2C IR based get keycodes - should be used with ir-kbd-i2c
|
||||
**********************************************************/
|
||||
|
||||
static int em28xx_get_key_terratec(struct i2c_client *i2c_dev,
|
||||
enum rc_type *protocol, u32 *scancode)
|
||||
{
|
||||
unsigned char b;
|
||||
|
||||
/* poll IR chip */
|
||||
if (1 != i2c_master_recv(i2c_dev, &b, 1))
|
||||
return -EIO;
|
||||
|
||||
/* it seems that 0xFE indicates that a button is still hold
|
||||
down, while 0xff indicates that no button is hold down. */
|
||||
|
||||
if (b == 0xff)
|
||||
return 0;
|
||||
|
||||
if (b == 0xfe)
|
||||
/* keep old data */
|
||||
return 1;
|
||||
|
||||
*protocol = RC_TYPE_UNKNOWN;
|
||||
*scancode = b;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev,
|
||||
enum rc_type *protocol, u32 *scancode)
|
||||
{
|
||||
unsigned char buf[2];
|
||||
int size;
|
||||
|
||||
/* poll IR chip */
|
||||
size = i2c_master_recv(i2c_dev, buf, sizeof(buf));
|
||||
|
||||
if (size != 2)
|
||||
return -EIO;
|
||||
|
||||
/* Does eliminate repeated parity code */
|
||||
if (buf[1] == 0xff)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Rearranges bits to the right order.
|
||||
* The bit order were determined experimentally by using
|
||||
* The original Hauppauge Grey IR and another RC5 that uses addr=0x08
|
||||
* The RC5 code has 14 bits, but we've experimentally determined
|
||||
* the meaning for only 11 bits.
|
||||
* So, the code translation is not complete. Yet, it is enough to
|
||||
* work with the provided RC5 IR.
|
||||
*/
|
||||
*protocol = RC_TYPE_RC5;
|
||||
*scancode = (bitrev8(buf[1]) & 0x1f) << 8 | bitrev8(buf[0]) >> 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
|
||||
enum rc_type *protocol, u32 *scancode)
|
||||
{
|
||||
unsigned char buf[3];
|
||||
|
||||
/* poll IR chip */
|
||||
|
||||
if (3 != i2c_master_recv(i2c_dev, buf, 3))
|
||||
return -EIO;
|
||||
|
||||
if (buf[0] != 0x00)
|
||||
return 0;
|
||||
|
||||
*protocol = RC_TYPE_UNKNOWN;
|
||||
*scancode = buf[2] & 0x3f;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
|
||||
enum rc_type *protocol, u32 *scancode)
|
||||
{
|
||||
unsigned char subaddr, keydetect, key;
|
||||
|
||||
struct i2c_msg msg[] = { { .addr = i2c_dev->addr, .flags = 0, .buf = &subaddr, .len = 1},
|
||||
{ .addr = i2c_dev->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} };
|
||||
|
||||
subaddr = 0x10;
|
||||
if (2 != i2c_transfer(i2c_dev->adapter, msg, 2))
|
||||
return -EIO;
|
||||
if (keydetect == 0x00)
|
||||
return 0;
|
||||
|
||||
subaddr = 0x00;
|
||||
msg[1].buf = &key;
|
||||
if (2 != i2c_transfer(i2c_dev->adapter, msg, 2))
|
||||
return -EIO;
|
||||
if (key == 0x00)
|
||||
return 0;
|
||||
|
||||
*protocol = RC_TYPE_UNKNOWN;
|
||||
*scancode = key;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
Poll based get keycode functions
|
||||
**********************************************************/
|
||||
|
||||
/* This is for the em2860/em2880 */
|
||||
static int default_polling_getkey(struct em28xx_IR *ir,
|
||||
struct em28xx_ir_poll_result *poll_result)
|
||||
{
|
||||
struct em28xx *dev = ir->dev;
|
||||
int rc;
|
||||
u8 msg[3] = { 0, 0, 0 };
|
||||
|
||||
/* Read key toggle, brand, and key code
|
||||
on registers 0x45, 0x46 and 0x47
|
||||
*/
|
||||
rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
|
||||
msg, sizeof(msg));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Infrared toggle (Reg 0x45[7]) */
|
||||
poll_result->toggle_bit = (msg[0] >> 7);
|
||||
|
||||
/* Infrared read count (Reg 0x45[6:0] */
|
||||
poll_result->read_count = (msg[0] & 0x7f);
|
||||
|
||||
/* Remote Control Address/Data (Regs 0x46/0x47) */
|
||||
switch (ir->rc_type) {
|
||||
case RC_BIT_RC5:
|
||||
poll_result->protocol = RC_TYPE_RC5;
|
||||
poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]);
|
||||
break;
|
||||
|
||||
case RC_BIT_NEC:
|
||||
poll_result->protocol = RC_TYPE_NEC;
|
||||
poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
poll_result->protocol = RC_TYPE_UNKNOWN;
|
||||
poll_result->scancode = msg[1] << 8 | msg[2];
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int em2874_polling_getkey(struct em28xx_IR *ir,
|
||||
struct em28xx_ir_poll_result *poll_result)
|
||||
{
|
||||
struct em28xx *dev = ir->dev;
|
||||
int rc;
|
||||
u8 msg[5] = { 0, 0, 0, 0, 0 };
|
||||
|
||||
/* Read key toggle, brand, and key code
|
||||
on registers 0x51-55
|
||||
*/
|
||||
rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR,
|
||||
msg, sizeof(msg));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Infrared toggle (Reg 0x51[7]) */
|
||||
poll_result->toggle_bit = (msg[0] >> 7);
|
||||
|
||||
/* Infrared read count (Reg 0x51[6:0] */
|
||||
poll_result->read_count = (msg[0] & 0x7f);
|
||||
|
||||
/*
|
||||
* Remote Control Address (Reg 0x52)
|
||||
* Remote Control Data (Reg 0x53-0x55)
|
||||
*/
|
||||
switch (ir->rc_type) {
|
||||
case RC_BIT_RC5:
|
||||
poll_result->protocol = RC_TYPE_RC5;
|
||||
poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]);
|
||||
break;
|
||||
|
||||
case RC_BIT_NEC:
|
||||
poll_result->protocol = RC_TYPE_RC5;
|
||||
poll_result->scancode = msg[1] << 8 | msg[2];
|
||||
if ((msg[3] ^ msg[4]) != 0xff) /* 32 bits NEC */
|
||||
poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) |
|
||||
(msg[2] << 16) |
|
||||
(msg[3] << 8) |
|
||||
(msg[4]));
|
||||
else if ((msg[1] ^ msg[2]) != 0xff) /* 24 bits NEC */
|
||||
poll_result->scancode = RC_SCANCODE_NECX(msg[1] << 8 |
|
||||
msg[2], msg[3]);
|
||||
else /* Normal NEC */
|
||||
poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[3]);
|
||||
break;
|
||||
|
||||
case RC_BIT_RC6_0:
|
||||
poll_result->protocol = RC_TYPE_RC6_0;
|
||||
poll_result->scancode = RC_SCANCODE_RC6_0(msg[1], msg[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
poll_result->protocol = RC_TYPE_UNKNOWN;
|
||||
poll_result->scancode = (msg[1] << 24) | (msg[2] << 16) |
|
||||
(msg[3] << 8) | msg[4];
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
Polling code for em28xx
|
||||
**********************************************************/
|
||||
|
||||
static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
|
||||
{
|
||||
static u32 scancode;
|
||||
enum rc_type protocol;
|
||||
int rc;
|
||||
|
||||
rc = ir->get_key_i2c(ir->i2c_client, &protocol, &scancode);
|
||||
if (rc < 0) {
|
||||
dprintk("ir->get_key_i2c() failed: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
dprintk("%s: proto = 0x%04x, scancode = 0x%04x\n",
|
||||
__func__, protocol, scancode);
|
||||
rc_keydown(ir->rc, protocol, scancode, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void em28xx_ir_handle_key(struct em28xx_IR *ir)
|
||||
{
|
||||
int result;
|
||||
struct em28xx_ir_poll_result poll_result;
|
||||
|
||||
/* read the registers containing the IR status */
|
||||
result = ir->get_key(ir, &poll_result);
|
||||
if (unlikely(result < 0)) {
|
||||
dprintk("ir->get_key() failed: %d\n", result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(poll_result.read_count != ir->last_readcount)) {
|
||||
dprintk("%s: toggle: %d, count: %d, key 0x%04x\n", __func__,
|
||||
poll_result.toggle_bit, poll_result.read_count,
|
||||
poll_result.scancode);
|
||||
if (ir->full_code)
|
||||
rc_keydown(ir->rc,
|
||||
poll_result.protocol,
|
||||
poll_result.scancode,
|
||||
poll_result.toggle_bit);
|
||||
else
|
||||
rc_keydown(ir->rc,
|
||||
RC_TYPE_UNKNOWN,
|
||||
poll_result.scancode & 0xff,
|
||||
poll_result.toggle_bit);
|
||||
|
||||
if (ir->dev->chip_id == CHIP_ID_EM2874 ||
|
||||
ir->dev->chip_id == CHIP_ID_EM2884)
|
||||
/* The em2874 clears the readcount field every time the
|
||||
register is read. The em2860/2880 datasheet says that it
|
||||
is supposed to clear the readcount, but it doesn't. So with
|
||||
the em2874, we are looking for a non-zero read count as
|
||||
opposed to a readcount that is incrementing */
|
||||
ir->last_readcount = 0;
|
||||
else
|
||||
ir->last_readcount = poll_result.read_count;
|
||||
}
|
||||
}
|
||||
|
||||
static void em28xx_ir_work(struct work_struct *work)
|
||||
{
|
||||
struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
|
||||
|
||||
if (ir->i2c_client) /* external i2c device */
|
||||
em28xx_i2c_ir_handle_key(ir);
|
||||
else /* internal device */
|
||||
em28xx_ir_handle_key(ir);
|
||||
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
|
||||
}
|
||||
|
||||
static int em28xx_ir_start(struct rc_dev *rc)
|
||||
{
|
||||
struct em28xx_IR *ir = rc->priv;
|
||||
|
||||
INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
|
||||
schedule_delayed_work(&ir->work, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void em28xx_ir_stop(struct rc_dev *rc)
|
||||
{
|
||||
struct em28xx_IR *ir = rc->priv;
|
||||
|
||||
cancel_delayed_work_sync(&ir->work);
|
||||
}
|
||||
|
||||
static int em2860_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
|
||||
{
|
||||
struct em28xx_IR *ir = rc_dev->priv;
|
||||
struct em28xx *dev = ir->dev;
|
||||
|
||||
/* Adjust xclk based on IR table for RC5/NEC tables */
|
||||
if (*rc_type & RC_BIT_RC5) {
|
||||
dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
|
||||
ir->full_code = 1;
|
||||
*rc_type = RC_BIT_RC5;
|
||||
} else if (*rc_type & RC_BIT_NEC) {
|
||||
dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
|
||||
ir->full_code = 1;
|
||||
*rc_type = RC_BIT_NEC;
|
||||
} else if (*rc_type & RC_BIT_UNKNOWN) {
|
||||
*rc_type = RC_BIT_UNKNOWN;
|
||||
} else {
|
||||
*rc_type = ir->rc_type;
|
||||
return -EINVAL;
|
||||
}
|
||||
em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
|
||||
EM28XX_XCLK_IR_RC5_MODE);
|
||||
|
||||
ir->rc_type = *rc_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int em2874_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
|
||||
{
|
||||
struct em28xx_IR *ir = rc_dev->priv;
|
||||
struct em28xx *dev = ir->dev;
|
||||
u8 ir_config = EM2874_IR_RC5;
|
||||
|
||||
/* Adjust xclk and set type based on IR table for RC5/NEC/RC6 tables */
|
||||
if (*rc_type & RC_BIT_RC5) {
|
||||
dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
|
||||
ir->full_code = 1;
|
||||
*rc_type = RC_BIT_RC5;
|
||||
} else if (*rc_type & RC_BIT_NEC) {
|
||||
dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
|
||||
ir_config = EM2874_IR_NEC | EM2874_IR_NEC_NO_PARITY;
|
||||
ir->full_code = 1;
|
||||
*rc_type = RC_BIT_NEC;
|
||||
} else if (*rc_type & RC_BIT_RC6_0) {
|
||||
dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
|
||||
ir_config = EM2874_IR_RC6_MODE_0;
|
||||
ir->full_code = 1;
|
||||
*rc_type = RC_BIT_RC6_0;
|
||||
} else if (*rc_type & RC_BIT_UNKNOWN) {
|
||||
*rc_type = RC_BIT_UNKNOWN;
|
||||
} else {
|
||||
*rc_type = ir->rc_type;
|
||||
return -EINVAL;
|
||||
}
|
||||
em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
|
||||
em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
|
||||
EM28XX_XCLK_IR_RC5_MODE);
|
||||
|
||||
ir->rc_type = *rc_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
|
||||
{
|
||||
struct em28xx_IR *ir = rc_dev->priv;
|
||||
struct em28xx *dev = ir->dev;
|
||||
|
||||
/* Setup the proper handler based on the chip */
|
||||
switch (dev->chip_id) {
|
||||
case CHIP_ID_EM2860:
|
||||
case CHIP_ID_EM2883:
|
||||
return em2860_ir_change_protocol(rc_dev, rc_type);
|
||||
case CHIP_ID_EM2884:
|
||||
case CHIP_ID_EM2874:
|
||||
case CHIP_ID_EM28174:
|
||||
case CHIP_ID_EM28178:
|
||||
return em2874_ir_change_protocol(rc_dev, rc_type);
|
||||
default:
|
||||
printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n",
|
||||
dev->chip_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int em28xx_probe_i2c_ir(struct em28xx *dev)
|
||||
{
|
||||
int i = 0;
|
||||
/* Leadtek winfast tv USBII deluxe can find a non working IR-device */
|
||||
/* at address 0x18, so if that address is needed for another board in */
|
||||
/* the future, please put it after 0x1f. */
|
||||
const unsigned short addr_list[] = {
|
||||
0x1f, 0x30, 0x47, I2C_CLIENT_END
|
||||
};
|
||||
|
||||
while (addr_list[i] != I2C_CLIENT_END) {
|
||||
if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus], addr_list[i]) == 1)
|
||||
return addr_list[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
Handle buttons
|
||||
**********************************************************/
|
||||
|
||||
static void em28xx_query_buttons(struct work_struct *work)
|
||||
{
|
||||
struct em28xx *dev =
|
||||
container_of(work, struct em28xx, buttons_query_work.work);
|
||||
u8 i, j;
|
||||
int regval;
|
||||
bool is_pressed, was_pressed;
|
||||
const struct em28xx_led *led;
|
||||
|
||||
/* Poll and evaluate all addresses */
|
||||
for (i = 0; i < dev->num_button_polling_addresses; i++) {
|
||||
/* Read value from register */
|
||||
regval = em28xx_read_reg(dev, dev->button_polling_addresses[i]);
|
||||
if (regval < 0)
|
||||
continue;
|
||||
/* Check states of the buttons and act */
|
||||
j = 0;
|
||||
while (dev->board.buttons[j].role >= 0 &&
|
||||
dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) {
|
||||
struct em28xx_button *button = &dev->board.buttons[j];
|
||||
/* Check if button uses the current address */
|
||||
if (button->reg_r != dev->button_polling_addresses[i]) {
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
/* Determine if button is and was pressed last time */
|
||||
is_pressed = regval & button->mask;
|
||||
was_pressed = dev->button_polling_last_values[i]
|
||||
& button->mask;
|
||||
if (button->inverted) {
|
||||
is_pressed = !is_pressed;
|
||||
was_pressed = !was_pressed;
|
||||
}
|
||||
/* Clear button state (if needed) */
|
||||
if (is_pressed && button->reg_clearing)
|
||||
em28xx_write_reg(dev, button->reg_clearing,
|
||||
(~regval & button->mask)
|
||||
| (regval & ~button->mask));
|
||||
/* Handle button state */
|
||||
if (!is_pressed || was_pressed) {
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
switch (button->role) {
|
||||
case EM28XX_BUTTON_SNAPSHOT:
|
||||
/* Emulate the keypress */
|
||||
input_report_key(dev->sbutton_input_dev,
|
||||
EM28XX_SNAPSHOT_KEY, 1);
|
||||
/* Unpress the key */
|
||||
input_report_key(dev->sbutton_input_dev,
|
||||
EM28XX_SNAPSHOT_KEY, 0);
|
||||
break;
|
||||
case EM28XX_BUTTON_ILLUMINATION:
|
||||
led = em28xx_find_led(dev,
|
||||
EM28XX_LED_ILLUMINATION);
|
||||
/* Switch illumination LED on/off */
|
||||
if (led)
|
||||
em28xx_toggle_reg_bits(dev,
|
||||
led->gpio_reg,
|
||||
led->gpio_mask);
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "BUG: unhandled button role.");
|
||||
}
|
||||
/* Next button */
|
||||
j++;
|
||||
}
|
||||
/* Save current value for comparison during the next polling */
|
||||
dev->button_polling_last_values[i] = regval;
|
||||
}
|
||||
/* Schedule next poll */
|
||||
schedule_delayed_work(&dev->buttons_query_work,
|
||||
msecs_to_jiffies(dev->button_polling_interval));
|
||||
}
|
||||
|
||||
static int em28xx_register_snapshot_button(struct em28xx *dev)
|
||||
{
|
||||
struct input_dev *input_dev;
|
||||
int err;
|
||||
|
||||
em28xx_info("Registering snapshot button...\n");
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
usb_make_path(dev->udev, dev->snapshot_button_path,
|
||||
sizeof(dev->snapshot_button_path));
|
||||
strlcat(dev->snapshot_button_path, "/sbutton",
|
||||
sizeof(dev->snapshot_button_path));
|
||||
|
||||
input_dev->name = "em28xx snapshot button";
|
||||
input_dev->phys = dev->snapshot_button_path;
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||
set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit);
|
||||
input_dev->keycodesize = 0;
|
||||
input_dev->keycodemax = 0;
|
||||
input_dev->id.bustype = BUS_USB;
|
||||
input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
|
||||
input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
|
||||
input_dev->id.version = 1;
|
||||
input_dev->dev.parent = &dev->udev->dev;
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
em28xx_errdev("input_register_device failed\n");
|
||||
input_free_device(input_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
dev->sbutton_input_dev = input_dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void em28xx_init_buttons(struct em28xx *dev)
|
||||
{
|
||||
u8 i = 0, j = 0;
|
||||
bool addr_new = false;
|
||||
|
||||
dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL;
|
||||
while (dev->board.buttons[i].role >= 0 &&
|
||||
dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) {
|
||||
struct em28xx_button *button = &dev->board.buttons[i];
|
||||
/* Check if polling address is already on the list */
|
||||
addr_new = true;
|
||||
for (j = 0; j < dev->num_button_polling_addresses; j++) {
|
||||
if (button->reg_r == dev->button_polling_addresses[j]) {
|
||||
addr_new = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Check if max. number of polling addresses is exceeded */
|
||||
if (addr_new && dev->num_button_polling_addresses
|
||||
>= EM28XX_NUM_BUTTON_ADDRESSES_MAX) {
|
||||
WARN_ONCE(1, "BUG: maximum number of button polling addresses exceeded.");
|
||||
goto next_button;
|
||||
}
|
||||
/* Button role specific checks and actions */
|
||||
if (button->role == EM28XX_BUTTON_SNAPSHOT) {
|
||||
/* Register input device */
|
||||
if (em28xx_register_snapshot_button(dev) < 0)
|
||||
goto next_button;
|
||||
} else if (button->role == EM28XX_BUTTON_ILLUMINATION) {
|
||||
/* Check sanity */
|
||||
if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) {
|
||||
em28xx_errdev("BUG: illumination button defined, but no illumination LED.\n");
|
||||
goto next_button;
|
||||
}
|
||||
}
|
||||
/* Add read address to list of polling addresses */
|
||||
if (addr_new) {
|
||||
unsigned int index = dev->num_button_polling_addresses;
|
||||
dev->button_polling_addresses[index] = button->reg_r;
|
||||
dev->num_button_polling_addresses++;
|
||||
}
|
||||
/* Reduce polling interval if necessary */
|
||||
if (!button->reg_clearing)
|
||||
dev->button_polling_interval =
|
||||
EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL;
|
||||
next_button:
|
||||
/* Next button */
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Start polling */
|
||||
if (dev->num_button_polling_addresses) {
|
||||
memset(dev->button_polling_last_values, 0,
|
||||
EM28XX_NUM_BUTTON_ADDRESSES_MAX);
|
||||
INIT_DELAYED_WORK(&dev->buttons_query_work,
|
||||
em28xx_query_buttons);
|
||||
schedule_delayed_work(&dev->buttons_query_work,
|
||||
msecs_to_jiffies(dev->button_polling_interval));
|
||||
}
|
||||
}
|
||||
|
||||
static void em28xx_shutdown_buttons(struct em28xx *dev)
|
||||
{
|
||||
/* Cancel polling */
|
||||
cancel_delayed_work_sync(&dev->buttons_query_work);
|
||||
/* Clear polling addresses list */
|
||||
dev->num_button_polling_addresses = 0;
|
||||
/* Deregister input devices */
|
||||
if (dev->sbutton_input_dev != NULL) {
|
||||
em28xx_info("Deregistering snapshot button\n");
|
||||
input_unregister_device(dev->sbutton_input_dev);
|
||||
dev->sbutton_input_dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int em28xx_ir_init(struct em28xx *dev)
|
||||
{
|
||||
struct em28xx_IR *ir;
|
||||
struct rc_dev *rc;
|
||||
int err = -ENOMEM;
|
||||
u64 rc_type;
|
||||
u16 i2c_rc_dev_addr = 0;
|
||||
|
||||
if (dev->is_audio_only) {
|
||||
/* Shouldn't initialize IR for this interface */
|
||||
return 0;
|
||||
}
|
||||
|
||||
kref_get(&dev->ref);
|
||||
|
||||
if (dev->board.buttons)
|
||||
em28xx_init_buttons(dev);
|
||||
|
||||
if (dev->board.has_ir_i2c) {
|
||||
i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev);
|
||||
if (!i2c_rc_dev_addr) {
|
||||
dev->board.has_ir_i2c = 0;
|
||||
em28xx_warn("No i2c IR remote control device found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) {
|
||||
/* No remote control support */
|
||||
em28xx_warn("Remote control support is not available for "
|
||||
"this card.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
em28xx_info("Registering input extension\n");
|
||||
|
||||
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
|
||||
if (!ir)
|
||||
return -ENOMEM;
|
||||
rc = rc_allocate_device();
|
||||
if (!rc)
|
||||
goto error;
|
||||
|
||||
/* record handles to ourself */
|
||||
ir->dev = dev;
|
||||
dev->ir = ir;
|
||||
ir->rc = rc;
|
||||
|
||||
rc->priv = ir;
|
||||
rc->open = em28xx_ir_start;
|
||||
rc->close = em28xx_ir_stop;
|
||||
|
||||
if (dev->board.has_ir_i2c) { /* external i2c device */
|
||||
switch (dev->model) {
|
||||
case EM2800_BOARD_TERRATEC_CINERGY_200:
|
||||
case EM2820_BOARD_TERRATEC_CINERGY_250:
|
||||
rc->map_name = RC_MAP_EM_TERRATEC;
|
||||
ir->get_key_i2c = em28xx_get_key_terratec;
|
||||
break;
|
||||
case EM2820_BOARD_PINNACLE_USB_2:
|
||||
rc->map_name = RC_MAP_PINNACLE_GREY;
|
||||
ir->get_key_i2c = em28xx_get_key_pinnacle_usb_grey;
|
||||
break;
|
||||
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
|
||||
rc->map_name = RC_MAP_HAUPPAUGE;
|
||||
ir->get_key_i2c = em28xx_get_key_em_haup;
|
||||
rc->allowed_protocols = RC_BIT_RC5;
|
||||
break;
|
||||
case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
|
||||
rc->map_name = RC_MAP_WINFAST_USBII_DELUXE;
|
||||
ir->get_key_i2c = em28xx_get_key_winfast_usbii_deluxe;
|
||||
break;
|
||||
default:
|
||||
err = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ir->i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!ir->i2c_client)
|
||||
goto error;
|
||||
ir->i2c_client->adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
|
||||
ir->i2c_client->addr = i2c_rc_dev_addr;
|
||||
ir->i2c_client->flags = 0;
|
||||
/* NOTE: all other fields of i2c_client are unused */
|
||||
} else { /* internal device */
|
||||
switch (dev->chip_id) {
|
||||
case CHIP_ID_EM2860:
|
||||
case CHIP_ID_EM2883:
|
||||
rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC;
|
||||
ir->get_key = default_polling_getkey;
|
||||
break;
|
||||
case CHIP_ID_EM2884:
|
||||
case CHIP_ID_EM2874:
|
||||
case CHIP_ID_EM28174:
|
||||
case CHIP_ID_EM28178:
|
||||
ir->get_key = em2874_polling_getkey;
|
||||
rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC |
|
||||
RC_BIT_RC6_0;
|
||||
break;
|
||||
default:
|
||||
err = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc->change_protocol = em28xx_ir_change_protocol;
|
||||
rc->map_name = dev->board.ir_codes;
|
||||
|
||||
/* By default, keep protocol field untouched */
|
||||
rc_type = RC_BIT_UNKNOWN;
|
||||
err = em28xx_ir_change_protocol(rc, &rc_type);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* This is how often we ask the chip for IR information */
|
||||
ir->polling = 100; /* ms */
|
||||
|
||||
/* init input device */
|
||||
snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", dev->name);
|
||||
|
||||
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
|
||||
strlcat(ir->phys, "/input0", sizeof(ir->phys));
|
||||
|
||||
rc->input_name = ir->name;
|
||||
rc->input_phys = ir->phys;
|
||||
rc->input_id.bustype = BUS_USB;
|
||||
rc->input_id.version = 1;
|
||||
rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
|
||||
rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
|
||||
rc->dev.parent = &dev->udev->dev;
|
||||
rc->driver_name = MODULE_NAME;
|
||||
|
||||
/* all done */
|
||||
err = rc_register_device(rc);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
em28xx_info("Input extension successfully initalized\n");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(ir->i2c_client);
|
||||
dev->ir = NULL;
|
||||
rc_free_device(rc);
|
||||
kfree(ir);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int em28xx_ir_fini(struct em28xx *dev)
|
||||
{
|
||||
struct em28xx_IR *ir = dev->ir;
|
||||
|
||||
if (dev->is_audio_only) {
|
||||
/* Shouldn't initialize IR for this interface */
|
||||
return 0;
|
||||
}
|
||||
|
||||
em28xx_info("Closing input extension\n");
|
||||
|
||||
em28xx_shutdown_buttons(dev);
|
||||
|
||||
/* skip detach on non attached boards */
|
||||
if (!ir)
|
||||
goto ref_put;
|
||||
|
||||
if (ir->rc)
|
||||
rc_unregister_device(ir->rc);
|
||||
|
||||
kfree(ir->i2c_client);
|
||||
|
||||
/* done */
|
||||
kfree(ir);
|
||||
dev->ir = NULL;
|
||||
|
||||
ref_put:
|
||||
kref_put(&dev->ref, em28xx_free_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int em28xx_ir_suspend(struct em28xx *dev)
|
||||
{
|
||||
struct em28xx_IR *ir = dev->ir;
|
||||
|
||||
if (dev->is_audio_only)
|
||||
return 0;
|
||||
|
||||
em28xx_info("Suspending input extension\n");
|
||||
if (ir)
|
||||
cancel_delayed_work_sync(&ir->work);
|
||||
cancel_delayed_work_sync(&dev->buttons_query_work);
|
||||
/* is canceling delayed work sufficient or does the rc event
|
||||
kthread needs stopping? kthread is stopped in
|
||||
ir_raw_event_unregister() */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int em28xx_ir_resume(struct em28xx *dev)
|
||||
{
|
||||
struct em28xx_IR *ir = dev->ir;
|
||||
|
||||
if (dev->is_audio_only)
|
||||
return 0;
|
||||
|
||||
em28xx_info("Resuming input extension\n");
|
||||
/* if suspend calls ir_raw_event_unregister(), the should call
|
||||
ir_raw_event_register() */
|
||||
if (ir)
|
||||
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
|
||||
if (dev->num_button_polling_addresses)
|
||||
schedule_delayed_work(&dev->buttons_query_work,
|
||||
msecs_to_jiffies(dev->button_polling_interval));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct em28xx_ops rc_ops = {
|
||||
.id = EM28XX_RC,
|
||||
.name = "Em28xx Input Extension",
|
||||
.init = em28xx_ir_init,
|
||||
.fini = em28xx_ir_fini,
|
||||
.suspend = em28xx_ir_suspend,
|
||||
.resume = em28xx_ir_resume,
|
||||
};
|
||||
|
||||
static int __init em28xx_rc_register(void)
|
||||
{
|
||||
return em28xx_register_extension(&rc_ops);
|
||||
}
|
||||
|
||||
static void __exit em28xx_rc_unregister(void)
|
||||
{
|
||||
em28xx_unregister_extension(&rc_ops);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC " - input interface");
|
||||
MODULE_VERSION(EM28XX_VERSION);
|
||||
|
||||
module_init(em28xx_rc_register);
|
||||
module_exit(em28xx_rc_unregister);
|
||||
266
drivers/media/usb/em28xx/em28xx-reg.h
Normal file
266
drivers/media/usb/em28xx/em28xx-reg.h
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
#define EM_GPIO_0 (1 << 0)
|
||||
#define EM_GPIO_1 (1 << 1)
|
||||
#define EM_GPIO_2 (1 << 2)
|
||||
#define EM_GPIO_3 (1 << 3)
|
||||
#define EM_GPIO_4 (1 << 4)
|
||||
#define EM_GPIO_5 (1 << 5)
|
||||
#define EM_GPIO_6 (1 << 6)
|
||||
#define EM_GPIO_7 (1 << 7)
|
||||
|
||||
#define EM_GPO_0 (1 << 0)
|
||||
#define EM_GPO_1 (1 << 1)
|
||||
#define EM_GPO_2 (1 << 2)
|
||||
#define EM_GPO_3 (1 << 3)
|
||||
|
||||
/* em28xx endpoints */
|
||||
/* 0x82: (always ?) analog */
|
||||
#define EM28XX_EP_AUDIO 0x83
|
||||
/* 0x84: digital or analog */
|
||||
|
||||
/* em2800 registers */
|
||||
#define EM2800_R08_AUDIOSRC 0x08
|
||||
|
||||
/* em28xx registers */
|
||||
|
||||
#define EM28XX_R00_CHIPCFG 0x00
|
||||
|
||||
/* em28xx Chip Configuration 0x00 */
|
||||
#define EM2860_CHIPCFG_VENDOR_AUDIO 0x80
|
||||
#define EM2860_CHIPCFG_I2S_VOLUME_CAPABLE 0x40
|
||||
#define EM2820_CHIPCFG_I2S_3_SAMPRATES 0x30
|
||||
#define EM2860_CHIPCFG_I2S_5_SAMPRATES 0x30
|
||||
#define EM2820_CHIPCFG_I2S_1_SAMPRATE 0x20
|
||||
#define EM2860_CHIPCFG_I2S_3_SAMPRATES 0x20
|
||||
#define EM28XX_CHIPCFG_AC97 0x10
|
||||
#define EM28XX_CHIPCFG_AUDIOMASK 0x30
|
||||
|
||||
#define EM28XX_R01_CHIPCFG2 0x01
|
||||
|
||||
/* em28xx Chip Configuration 2 0x01 */
|
||||
#define EM28XX_CHIPCFG2_TS_PRESENT 0x10
|
||||
#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_MASK 0x0c /* bits 3-2 */
|
||||
#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_1MF 0x00
|
||||
#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_2MF 0x04
|
||||
#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_4MF 0x08
|
||||
#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_8MF 0x0c
|
||||
#define EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK 0x03 /* bits 0-1 */
|
||||
#define EM28XX_CHIPCFG2_TS_PACKETSIZE_188 0x00
|
||||
#define EM28XX_CHIPCFG2_TS_PACKETSIZE_376 0x01
|
||||
#define EM28XX_CHIPCFG2_TS_PACKETSIZE_564 0x02
|
||||
#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752 0x03
|
||||
|
||||
|
||||
/* GPIO/GPO registers */
|
||||
#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
|
||||
#define EM2820_R08_GPIO_CTRL 0x08 /* em2820-em2873/83 only */
|
||||
#define EM2820_R09_GPIO_STATE 0x09 /* em2820-em2873/83 only */
|
||||
|
||||
#define EM28XX_R06_I2C_CLK 0x06
|
||||
|
||||
/* em28xx I2C Clock Register (0x06) */
|
||||
#define EM28XX_I2C_CLK_ACK_LAST_READ 0x80
|
||||
#define EM28XX_I2C_CLK_WAIT_ENABLE 0x40
|
||||
#define EM28XX_I2C_EEPROM_ON_BOARD 0x08
|
||||
#define EM28XX_I2C_EEPROM_KEY_VALID 0x04
|
||||
#define EM2874_I2C_SECONDARY_BUS_SELECT 0x04 /* em2874 has two i2c busses */
|
||||
#define EM28XX_I2C_FREQ_1_5_MHZ 0x03 /* bus frequency (bits [1-0]) */
|
||||
#define EM28XX_I2C_FREQ_25_KHZ 0x02
|
||||
#define EM28XX_I2C_FREQ_400_KHZ 0x01
|
||||
#define EM28XX_I2C_FREQ_100_KHZ 0x00
|
||||
|
||||
|
||||
#define EM28XX_R0A_CHIPID 0x0a
|
||||
#define EM28XX_R0C_USBSUSP 0x0c
|
||||
#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20 /* 1=button pressed, needs reset */
|
||||
|
||||
#define EM28XX_R0E_AUDIOSRC 0x0e
|
||||
#define EM28XX_R0F_XCLK 0x0f
|
||||
|
||||
/* em28xx XCLK Register (0x0f) */
|
||||
#define EM28XX_XCLK_AUDIO_UNMUTE 0x80 /* otherwise audio muted */
|
||||
#define EM28XX_XCLK_I2S_MSB_TIMING 0x40 /* otherwise standard timing */
|
||||
#define EM28XX_XCLK_IR_RC5_MODE 0x20 /* otherwise NEC mode */
|
||||
#define EM28XX_XCLK_IR_NEC_CHK_PARITY 0x10
|
||||
#define EM28XX_XCLK_FREQUENCY_30MHZ 0x00 /* Freq. select (bits [3-0]) */
|
||||
#define EM28XX_XCLK_FREQUENCY_15MHZ 0x01
|
||||
#define EM28XX_XCLK_FREQUENCY_10MHZ 0x02
|
||||
#define EM28XX_XCLK_FREQUENCY_7_5MHZ 0x03
|
||||
#define EM28XX_XCLK_FREQUENCY_6MHZ 0x04
|
||||
#define EM28XX_XCLK_FREQUENCY_5MHZ 0x05
|
||||
#define EM28XX_XCLK_FREQUENCY_4_3MHZ 0x06
|
||||
#define EM28XX_XCLK_FREQUENCY_12MHZ 0x07
|
||||
#define EM28XX_XCLK_FREQUENCY_20MHZ 0x08
|
||||
#define EM28XX_XCLK_FREQUENCY_20MHZ_2 0x09
|
||||
#define EM28XX_XCLK_FREQUENCY_48MHZ 0x0a
|
||||
#define EM28XX_XCLK_FREQUENCY_24MHZ 0x0b
|
||||
|
||||
#define EM28XX_R10_VINMODE 0x10
|
||||
|
||||
#define EM28XX_R11_VINCTRL 0x11
|
||||
|
||||
/* em28xx Video Input Control Register 0x11 */
|
||||
#define EM28XX_VINCTRL_VBI_SLICED 0x80
|
||||
#define EM28XX_VINCTRL_VBI_RAW 0x40
|
||||
#define EM28XX_VINCTRL_VOUT_MODE_IN 0x20 /* HREF,VREF,VACT in output */
|
||||
#define EM28XX_VINCTRL_CCIR656_ENABLE 0x10
|
||||
#define EM28XX_VINCTRL_VBI_16BIT_RAW 0x08 /* otherwise 8-bit raw */
|
||||
#define EM28XX_VINCTRL_FID_ON_HREF 0x04
|
||||
#define EM28XX_VINCTRL_DUAL_EDGE_STROBE 0x02
|
||||
#define EM28XX_VINCTRL_INTERLACED 0x01
|
||||
|
||||
#define EM28XX_R12_VINENABLE 0x12 /* */
|
||||
|
||||
#define EM28XX_R14_GAMMA 0x14
|
||||
#define EM28XX_R15_RGAIN 0x15
|
||||
#define EM28XX_R16_GGAIN 0x16
|
||||
#define EM28XX_R17_BGAIN 0x17
|
||||
#define EM28XX_R18_ROFFSET 0x18
|
||||
#define EM28XX_R19_GOFFSET 0x19
|
||||
#define EM28XX_R1A_BOFFSET 0x1a
|
||||
|
||||
#define EM28XX_R1B_OFLOW 0x1b
|
||||
#define EM28XX_R1C_HSTART 0x1c
|
||||
#define EM28XX_R1D_VSTART 0x1d
|
||||
#define EM28XX_R1E_CWIDTH 0x1e
|
||||
#define EM28XX_R1F_CHEIGHT 0x1f
|
||||
|
||||
#define EM28XX_R20_YGAIN 0x20 /* contrast [0:4] */
|
||||
#define CONTRAST_DEFAULT 0x10
|
||||
|
||||
#define EM28XX_R21_YOFFSET 0x21 /* brightness */ /* signed */
|
||||
#define BRIGHTNESS_DEFAULT 0x00
|
||||
|
||||
#define EM28XX_R22_UVGAIN 0x22 /* saturation [0:4] */
|
||||
#define SATURATION_DEFAULT 0x10
|
||||
|
||||
#define EM28XX_R23_UOFFSET 0x23 /* blue balance */ /* signed */
|
||||
#define BLUE_BALANCE_DEFAULT 0x00
|
||||
|
||||
#define EM28XX_R24_VOFFSET 0x24 /* red balance */ /* signed */
|
||||
#define RED_BALANCE_DEFAULT 0x00
|
||||
|
||||
#define EM28XX_R25_SHARPNESS 0x25 /* sharpness [0:4] */
|
||||
#define SHARPNESS_DEFAULT 0x00
|
||||
|
||||
#define EM28XX_R26_COMPR 0x26
|
||||
#define EM28XX_R27_OUTFMT 0x27
|
||||
|
||||
/* em28xx Output Format Register (0x27) */
|
||||
#define EM28XX_OUTFMT_RGB_8_RGRG 0x00
|
||||
#define EM28XX_OUTFMT_RGB_8_GRGR 0x01
|
||||
#define EM28XX_OUTFMT_RGB_8_GBGB 0x02
|
||||
#define EM28XX_OUTFMT_RGB_8_BGBG 0x03
|
||||
#define EM28XX_OUTFMT_RGB_16_656 0x04
|
||||
#define EM28XX_OUTFMT_RGB_8_BAYER 0x08 /* Pattern in Reg 0x10[1-0] */
|
||||
#define EM28XX_OUTFMT_YUV211 0x10
|
||||
#define EM28XX_OUTFMT_YUV422_Y0UY1V 0x14
|
||||
#define EM28XX_OUTFMT_YUV422_Y1UY0V 0x15
|
||||
#define EM28XX_OUTFMT_YUV411 0x18
|
||||
|
||||
|
||||
#define EM28XX_R28_XMIN 0x28
|
||||
#define EM28XX_R29_XMAX 0x29
|
||||
#define EM28XX_R2A_YMIN 0x2a
|
||||
#define EM28XX_R2B_YMAX 0x2b
|
||||
|
||||
#define EM28XX_R30_HSCALELOW 0x30
|
||||
#define EM28XX_R31_HSCALEHIGH 0x31
|
||||
#define EM28XX_R32_VSCALELOW 0x32
|
||||
#define EM28XX_R33_VSCALEHIGH 0x33
|
||||
#define EM28XX_HVSCALE_MAX 0x3fff /* => 20% */
|
||||
|
||||
#define EM28XX_R34_VBI_START_H 0x34
|
||||
#define EM28XX_R35_VBI_START_V 0x35
|
||||
/*
|
||||
* NOTE: the EM276x (and EM25xx, EM277x/8x ?) (camera bridges) use these
|
||||
* registers for a different unknown purpose.
|
||||
* => register 0x34 is set to capture width / 16
|
||||
* => register 0x35 is set to capture height / 16
|
||||
*/
|
||||
|
||||
#define EM28XX_R36_VBI_WIDTH 0x36
|
||||
#define EM28XX_R37_VBI_HEIGHT 0x37
|
||||
|
||||
#define EM28XX_R40_AC97LSB 0x40
|
||||
#define EM28XX_R41_AC97MSB 0x41
|
||||
#define EM28XX_R42_AC97ADDR 0x42
|
||||
#define EM28XX_R43_AC97BUSY 0x43
|
||||
|
||||
#define EM28XX_R45_IR 0x45
|
||||
/* 0x45 bit 7 - parity bit
|
||||
bits 6-0 - count
|
||||
0x46 IR brand
|
||||
0x47 IR data
|
||||
*/
|
||||
|
||||
/* em2874 registers */
|
||||
#define EM2874_R50_IR_CONFIG 0x50
|
||||
#define EM2874_R51_IR 0x51
|
||||
#define EM2874_R5F_TS_ENABLE 0x5f
|
||||
|
||||
/* em2874/174/84, em25xx, em276x/7x/8x GPIO registers */
|
||||
/*
|
||||
* NOTE: not all ports are bonded out;
|
||||
* Some ports are multiplexed with special function I/O
|
||||
*/
|
||||
#define EM2874_R80_GPIO_P0_CTRL 0x80
|
||||
#define EM2874_R81_GPIO_P1_CTRL 0x81
|
||||
#define EM2874_R82_GPIO_P2_CTRL 0x82
|
||||
#define EM2874_R83_GPIO_P3_CTRL 0x83
|
||||
#define EM2874_R84_GPIO_P0_STATE 0x84
|
||||
#define EM2874_R85_GPIO_P1_STATE 0x85
|
||||
#define EM2874_R86_GPIO_P2_STATE 0x86
|
||||
#define EM2874_R87_GPIO_P3_STATE 0x87
|
||||
|
||||
/* em2874 IR config register (0x50) */
|
||||
#define EM2874_IR_NEC 0x00
|
||||
#define EM2874_IR_NEC_NO_PARITY 0x01
|
||||
#define EM2874_IR_RC5 0x04
|
||||
#define EM2874_IR_RC6_MODE_0 0x08
|
||||
#define EM2874_IR_RC6_MODE_6A 0x0b
|
||||
|
||||
/* em2874 Transport Stream Enable Register (0x5f) */
|
||||
#define EM2874_TS1_CAPTURE_ENABLE (1 << 0)
|
||||
#define EM2874_TS1_FILTER_ENABLE (1 << 1)
|
||||
#define EM2874_TS1_NULL_DISCARD (1 << 2)
|
||||
#define EM2874_TS2_CAPTURE_ENABLE (1 << 4)
|
||||
#define EM2874_TS2_FILTER_ENABLE (1 << 5)
|
||||
#define EM2874_TS2_NULL_DISCARD (1 << 6)
|
||||
|
||||
/* register settings */
|
||||
#define EM2800_AUDIO_SRC_TUNER 0x0d
|
||||
#define EM2800_AUDIO_SRC_LINE 0x0c
|
||||
#define EM28XX_AUDIO_SRC_TUNER 0xc0
|
||||
#define EM28XX_AUDIO_SRC_LINE 0x80
|
||||
|
||||
/* FIXME: Need to be populated with the other chip ID's */
|
||||
enum em28xx_chip_id {
|
||||
CHIP_ID_EM2800 = 7,
|
||||
CHIP_ID_EM2710 = 17,
|
||||
CHIP_ID_EM2820 = 18, /* Also used by some em2710 */
|
||||
CHIP_ID_EM2840 = 20,
|
||||
CHIP_ID_EM2750 = 33,
|
||||
CHIP_ID_EM2860 = 34,
|
||||
CHIP_ID_EM2870 = 35,
|
||||
CHIP_ID_EM2883 = 36,
|
||||
CHIP_ID_EM2765 = 54,
|
||||
CHIP_ID_EM2874 = 65,
|
||||
CHIP_ID_EM2884 = 68,
|
||||
CHIP_ID_EM28174 = 113,
|
||||
CHIP_ID_EM28178 = 114,
|
||||
};
|
||||
|
||||
/*
|
||||
* Registers used by em202
|
||||
*/
|
||||
|
||||
/* EMP202 vendor registers */
|
||||
#define EM202_EXT_MODEM_CTRL 0x3e
|
||||
#define EM202_GPIO_CONF 0x4c
|
||||
#define EM202_GPIO_POLARITY 0x4e
|
||||
#define EM202_GPIO_STICKY 0x50
|
||||
#define EM202_GPIO_MASK 0x52
|
||||
#define EM202_GPIO_STATUS 0x54
|
||||
#define EM202_SPDIF_OUT_SEL 0x6a
|
||||
#define EM202_ANTIPOP 0x72
|
||||
#define EM202_EAPD_GPIO_ACCESS 0x74
|
||||
20
drivers/media/usb/em28xx/em28xx-v4l.h
Normal file
20
drivers/media/usb/em28xx/em28xx-v4l.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
|
||||
video capture devices
|
||||
|
||||
Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.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 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.
|
||||
*/
|
||||
|
||||
|
||||
int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
|
||||
void em28xx_stop_vbi_streaming(struct vb2_queue *vq);
|
||||
extern struct vb2_ops em28xx_vbi_qops;
|
||||
104
drivers/media/usb/em28xx/em28xx-vbi.c
Normal file
104
drivers/media/usb/em28xx/em28xx-vbi.c
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
em28xx-vbi.c - VBI driver for em28xx
|
||||
|
||||
Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
|
||||
|
||||
This work was sponsored by EyeMagnet Limited.
|
||||
|
||||
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, or
|
||||
(at your option) any later version.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "em28xx.h"
|
||||
#include "em28xx-v4l.h"
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
|
||||
unsigned int *nbuffers, unsigned int *nplanes,
|
||||
unsigned int sizes[], void *alloc_ctxs[])
|
||||
{
|
||||
struct em28xx *dev = vb2_get_drv_priv(vq);
|
||||
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
||||
unsigned long size;
|
||||
|
||||
if (fmt)
|
||||
size = fmt->fmt.pix.sizeimage;
|
||||
else
|
||||
size = v4l2->vbi_width * v4l2->vbi_height * 2;
|
||||
|
||||
if (0 == *nbuffers)
|
||||
*nbuffers = 32;
|
||||
if (*nbuffers < 2)
|
||||
*nbuffers = 2;
|
||||
if (*nbuffers > 32)
|
||||
*nbuffers = 32;
|
||||
|
||||
*nplanes = 1;
|
||||
sizes[0] = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vbi_buffer_prepare(struct vb2_buffer *vb)
|
||||
{
|
||||
struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
||||
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
|
||||
unsigned long size;
|
||||
|
||||
size = v4l2->vbi_width * v4l2->vbi_height * 2;
|
||||
|
||||
if (vb2_plane_size(vb, 0) < size) {
|
||||
printk(KERN_INFO "%s data will not fit into plane (%lu < %lu)\n",
|
||||
__func__, vb2_plane_size(vb, 0), size);
|
||||
return -EINVAL;
|
||||
}
|
||||
vb2_set_plane_payload(&buf->vb, 0, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
vbi_buffer_queue(struct vb2_buffer *vb)
|
||||
{
|
||||
struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
|
||||
struct em28xx_dmaqueue *vbiq = &dev->vbiq;
|
||||
unsigned long flags = 0;
|
||||
|
||||
buf->mem = vb2_plane_vaddr(vb, 0);
|
||||
buf->length = vb2_plane_size(vb, 0);
|
||||
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
list_add_tail(&buf->list, &vbiq->active);
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
}
|
||||
|
||||
|
||||
struct vb2_ops em28xx_vbi_qops = {
|
||||
.queue_setup = vbi_queue_setup,
|
||||
.buf_prepare = vbi_buffer_prepare,
|
||||
.buf_queue = vbi_buffer_queue,
|
||||
.start_streaming = em28xx_start_analog_streaming,
|
||||
.stop_streaming = em28xx_stop_vbi_streaming,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
};
|
||||
2626
drivers/media/usb/em28xx/em28xx-video.c
Normal file
2626
drivers/media/usb/em28xx/em28xx-video.c
Normal file
File diff suppressed because it is too large
Load diff
805
drivers/media/usb/em28xx/em28xx.h
Normal file
805
drivers/media/usb/em28xx/em28xx.h
Normal file
|
|
@ -0,0 +1,805 @@
|
|||
/*
|
||||
em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices
|
||||
|
||||
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
|
||||
Ludovico Cavedon <cavedon@sssup.it>
|
||||
Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
|
||||
|
||||
Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
|
||||
|
||||
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, or
|
||||
(at your option) any later version.
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _EM28XX_H
|
||||
#define _EM28XX_H
|
||||
|
||||
#define EM28XX_VERSION "0.2.1"
|
||||
#define DRIVER_DESC "Empia em28xx device driver"
|
||||
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include <media/videobuf2-vmalloc.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/ir-kbd-i2c.h>
|
||||
#include <media/rc-core.h>
|
||||
#include "tuner-xc2028.h"
|
||||
#include "xc5000.h"
|
||||
#include "em28xx-reg.h"
|
||||
|
||||
/* Boards supported by driver */
|
||||
#define EM2800_BOARD_UNKNOWN 0
|
||||
#define EM2820_BOARD_UNKNOWN 1
|
||||
#define EM2820_BOARD_TERRATEC_CINERGY_250 2
|
||||
#define EM2820_BOARD_PINNACLE_USB_2 3
|
||||
#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
|
||||
#define EM2820_BOARD_MSI_VOX_USB_2 5
|
||||
#define EM2800_BOARD_TERRATEC_CINERGY_200 6
|
||||
#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
|
||||
#define EM2800_BOARD_KWORLD_USB2800 8
|
||||
#define EM2820_BOARD_PINNACLE_DVC_90 9
|
||||
#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
|
||||
#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
|
||||
#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
|
||||
#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
|
||||
#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
|
||||
#define EM2800_BOARD_VGEAR_POCKETTV 15
|
||||
#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16
|
||||
#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17
|
||||
#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18
|
||||
#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19
|
||||
#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20
|
||||
#define EM2800_BOARD_GRABBEEX_USB2800 21
|
||||
#define EM2750_BOARD_UNKNOWN 22
|
||||
#define EM2750_BOARD_DLCW_130 23
|
||||
#define EM2820_BOARD_DLINK_USB_TV 24
|
||||
#define EM2820_BOARD_GADMEI_UTV310 25
|
||||
#define EM2820_BOARD_HERCULES_SMART_TV_USB2 26
|
||||
#define EM2820_BOARD_PINNACLE_USB_2_FM1216ME 27
|
||||
#define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28
|
||||
#define EM2860_BOARD_TVP5150_REFERENCE_DESIGN 29
|
||||
#define EM2820_BOARD_VIDEOLOGY_20K14XUSB 30
|
||||
#define EM2821_BOARD_USBGEAR_VD204 31
|
||||
#define EM2821_BOARD_SUPERCOMP_USB_2 32
|
||||
#define EM2860_BOARD_ELGATO_VIDEO_CAPTURE 33
|
||||
#define EM2860_BOARD_TERRATEC_HYBRID_XS 34
|
||||
#define EM2860_BOARD_TYPHOON_DVD_MAKER 35
|
||||
#define EM2860_BOARD_NETGMBH_CAM 36
|
||||
#define EM2860_BOARD_GADMEI_UTV330 37
|
||||
#define EM2861_BOARD_YAKUMO_MOVIE_MIXER 38
|
||||
#define EM2861_BOARD_KWORLD_PVRTV_300U 39
|
||||
#define EM2861_BOARD_PLEXTOR_PX_TV100U 40
|
||||
#define EM2870_BOARD_KWORLD_350U 41
|
||||
#define EM2870_BOARD_KWORLD_355U 42
|
||||
#define EM2870_BOARD_TERRATEC_XS 43
|
||||
#define EM2870_BOARD_TERRATEC_XS_MT2060 44
|
||||
#define EM2870_BOARD_PINNACLE_PCTV_DVB 45
|
||||
#define EM2870_BOARD_COMPRO_VIDEOMATE 46
|
||||
#define EM2880_BOARD_KWORLD_DVB_305U 47
|
||||
#define EM2880_BOARD_KWORLD_DVB_310U 48
|
||||
#define EM2880_BOARD_MSI_DIGIVOX_AD 49
|
||||
#define EM2880_BOARD_MSI_DIGIVOX_AD_II 50
|
||||
#define EM2880_BOARD_TERRATEC_HYBRID_XS_FR 51
|
||||
#define EM2881_BOARD_DNT_DA2_HYBRID 52
|
||||
#define EM2881_BOARD_PINNACLE_HYBRID_PRO 53
|
||||
#define EM2882_BOARD_KWORLD_VS_DVBT 54
|
||||
#define EM2882_BOARD_TERRATEC_HYBRID_XS 55
|
||||
#define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56
|
||||
#define EM2883_BOARD_KWORLD_HYBRID_330U 57
|
||||
#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
|
||||
#define EM2874_BOARD_PCTV_HD_MINI_80E 59
|
||||
#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60
|
||||
#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61
|
||||
#define EM2820_BOARD_GADMEI_TVR200 62
|
||||
#define EM2860_BOARD_KAIOMY_TVNPC_U2 63
|
||||
#define EM2860_BOARD_EASYCAP 64
|
||||
#define EM2820_BOARD_IODATA_GVMVP_SZ 65
|
||||
#define EM2880_BOARD_EMPIRE_DUAL_TV 66
|
||||
#define EM2860_BOARD_TERRATEC_GRABBY 67
|
||||
#define EM2860_BOARD_TERRATEC_AV350 68
|
||||
#define EM2882_BOARD_KWORLD_ATSC_315U 69
|
||||
#define EM2882_BOARD_EVGA_INDTUBE 70
|
||||
#define EM2820_BOARD_SILVERCREST_WEBCAM 71
|
||||
#define EM2861_BOARD_GADMEI_UTV330PLUS 72
|
||||
#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73
|
||||
#define EM2800_BOARD_VC211A 74
|
||||
#define EM2882_BOARD_DIKOM_DK300 75
|
||||
#define EM2870_BOARD_KWORLD_A340 76
|
||||
#define EM2874_BOARD_LEADERSHIP_ISDBT 77
|
||||
#define EM28174_BOARD_PCTV_290E 78
|
||||
#define EM2884_BOARD_TERRATEC_H5 79
|
||||
#define EM28174_BOARD_PCTV_460E 80
|
||||
#define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81
|
||||
#define EM2884_BOARD_CINERGY_HTC_STICK 82
|
||||
#define EM2860_BOARD_HT_VIDBOX_NW03 83
|
||||
#define EM2874_BOARD_MAXMEDIA_UB425_TC 84
|
||||
#define EM2884_BOARD_PCTV_510E 85
|
||||
#define EM2884_BOARD_PCTV_520E 86
|
||||
#define EM2884_BOARD_TERRATEC_HTC_USB_XS 87
|
||||
#define EM2884_BOARD_C3TECH_DIGITAL_DUO 88
|
||||
#define EM2874_BOARD_DELOCK_61959 89
|
||||
#define EM2874_BOARD_KWORLD_UB435Q_V2 90
|
||||
#define EM2765_BOARD_SPEEDLINK_VAD_LAPLACE 91
|
||||
#define EM28178_BOARD_PCTV_461E 92
|
||||
#define EM2874_BOARD_KWORLD_UB435Q_V3 93
|
||||
#define EM28178_BOARD_PCTV_292E 94
|
||||
|
||||
/* Limits minimum and default number of buffers */
|
||||
#define EM28XX_MIN_BUF 4
|
||||
#define EM28XX_DEF_BUF 8
|
||||
|
||||
/*Limits the max URB message size */
|
||||
#define URB_MAX_CTRL_SIZE 80
|
||||
|
||||
/* Params for validated field */
|
||||
#define EM28XX_BOARD_NOT_VALIDATED 1
|
||||
#define EM28XX_BOARD_VALIDATED 0
|
||||
|
||||
/* Params for em28xx_cmd() audio */
|
||||
#define EM28XX_START_AUDIO 1
|
||||
#define EM28XX_STOP_AUDIO 0
|
||||
|
||||
/* maximum number of em28xx boards */
|
||||
#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
|
||||
|
||||
/* maximum number of frames that can be queued */
|
||||
#define EM28XX_NUM_FRAMES 5
|
||||
/* number of frames that get used for v4l2_read() */
|
||||
#define EM28XX_NUM_READ_FRAMES 2
|
||||
|
||||
/* number of buffers for isoc transfers */
|
||||
#define EM28XX_NUM_BUFS 5
|
||||
#define EM28XX_DVB_NUM_BUFS 5
|
||||
|
||||
/* max number of I2C buses on em28xx devices */
|
||||
#define NUM_I2C_BUSES 2
|
||||
|
||||
/* isoc transfers: number of packets for each buffer
|
||||
windows requests only 64 packets .. so we better do the same
|
||||
this is what I found out for all alternate numbers there!
|
||||
*/
|
||||
#define EM28XX_NUM_ISOC_PACKETS 64
|
||||
#define EM28XX_DVB_NUM_ISOC_PACKETS 64
|
||||
|
||||
/* bulk transfers: transfer buffer size = packet size * packet multiplier
|
||||
USB 2.0 spec says bulk packet size is always 512 bytes
|
||||
*/
|
||||
#define EM28XX_BULK_PACKET_MULTIPLIER 384
|
||||
#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384
|
||||
|
||||
#define EM28XX_INTERLACED_DEFAULT 1
|
||||
|
||||
/*
|
||||
* Time in msecs to wait for i2c xfers to finish.
|
||||
* 35ms is the maximum time a SMBUS device could wait when
|
||||
* clock stretching is used. As the transfer itself will take
|
||||
* some time to happen, set it to 35 ms.
|
||||
*
|
||||
* Ok, I2C doesn't specify any limit. So, eventually, we may need
|
||||
* to increase this timeout.
|
||||
*
|
||||
* FIXME: this assumes that an I2C message is not longer than 1ms.
|
||||
* This is actually dependent on the I2C bus speed, although most
|
||||
* devices use a 100kHz clock. So, this assumtion is true most of
|
||||
* the time.
|
||||
*/
|
||||
#define EM28XX_I2C_XFER_TIMEOUT 36
|
||||
|
||||
/* time in msecs to wait for AC97 xfers to finish */
|
||||
#define EM28XX_AC97_XFER_TIMEOUT 100
|
||||
|
||||
/* max. number of button state polling addresses */
|
||||
#define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5
|
||||
|
||||
enum em28xx_mode {
|
||||
EM28XX_SUSPEND,
|
||||
EM28XX_ANALOG_MODE,
|
||||
EM28XX_DIGITAL_MODE,
|
||||
};
|
||||
|
||||
|
||||
struct em28xx;
|
||||
|
||||
struct em28xx_usb_bufs {
|
||||
/* max packet size of isoc transaction */
|
||||
int max_pkt_size;
|
||||
|
||||
/* number of packets in each buffer */
|
||||
int num_packets;
|
||||
|
||||
/* number of allocated urbs */
|
||||
int num_bufs;
|
||||
|
||||
/* urb for isoc/bulk transfers */
|
||||
struct urb **urb;
|
||||
|
||||
/* transfer buffers for isoc/bulk transfer */
|
||||
char **transfer_buffer;
|
||||
};
|
||||
|
||||
struct em28xx_usb_ctl {
|
||||
/* isoc/bulk transfer buffers for analog mode */
|
||||
struct em28xx_usb_bufs analog_bufs;
|
||||
|
||||
/* isoc/bulk transfer buffers for digital mode */
|
||||
struct em28xx_usb_bufs digital_bufs;
|
||||
|
||||
/* Stores already requested buffers */
|
||||
struct em28xx_buffer *vid_buf;
|
||||
struct em28xx_buffer *vbi_buf;
|
||||
|
||||
/* copy data from URB */
|
||||
int (*urb_data_copy) (struct em28xx *dev, struct urb *urb);
|
||||
|
||||
};
|
||||
|
||||
/* Struct to enumberate video formats */
|
||||
struct em28xx_fmt {
|
||||
char *name;
|
||||
u32 fourcc; /* v4l2 format id */
|
||||
int depth;
|
||||
int reg;
|
||||
};
|
||||
|
||||
/* buffer for one video frame */
|
||||
struct em28xx_buffer {
|
||||
/* common v4l buffer stuff -- must be first */
|
||||
struct vb2_buffer vb;
|
||||
struct list_head list;
|
||||
|
||||
void *mem;
|
||||
unsigned int length;
|
||||
int top_field;
|
||||
|
||||
/* counter to control buffer fill */
|
||||
unsigned int pos;
|
||||
/* NOTE; in interlaced mode, this value is reset to zero at
|
||||
* the start of each new field (not frame !) */
|
||||
|
||||
/* pointer to vmalloc memory address in vb */
|
||||
char *vb_buf;
|
||||
};
|
||||
|
||||
struct em28xx_dmaqueue {
|
||||
struct list_head active;
|
||||
|
||||
wait_queue_head_t wq;
|
||||
};
|
||||
|
||||
/* inputs */
|
||||
|
||||
#define MAX_EM28XX_INPUT 4
|
||||
enum enum28xx_itype {
|
||||
EM28XX_VMUX_COMPOSITE1 = 1,
|
||||
EM28XX_VMUX_COMPOSITE2,
|
||||
EM28XX_VMUX_COMPOSITE3,
|
||||
EM28XX_VMUX_COMPOSITE4,
|
||||
EM28XX_VMUX_SVIDEO,
|
||||
EM28XX_VMUX_TELEVISION,
|
||||
EM28XX_VMUX_CABLE,
|
||||
EM28XX_VMUX_DVB,
|
||||
EM28XX_VMUX_DEBUG,
|
||||
EM28XX_RADIO,
|
||||
};
|
||||
|
||||
enum em28xx_ac97_mode {
|
||||
EM28XX_NO_AC97 = 0,
|
||||
EM28XX_AC97_EM202,
|
||||
EM28XX_AC97_SIGMATEL,
|
||||
EM28XX_AC97_OTHER,
|
||||
};
|
||||
|
||||
struct em28xx_audio_mode {
|
||||
enum em28xx_ac97_mode ac97;
|
||||
};
|
||||
|
||||
enum em28xx_int_audio_type {
|
||||
EM28XX_INT_AUDIO_NONE = 0,
|
||||
EM28XX_INT_AUDIO_AC97,
|
||||
EM28XX_INT_AUDIO_I2S,
|
||||
};
|
||||
|
||||
enum em28xx_usb_audio_type {
|
||||
EM28XX_USB_AUDIO_NONE = 0,
|
||||
EM28XX_USB_AUDIO_CLASS,
|
||||
EM28XX_USB_AUDIO_VENDOR,
|
||||
};
|
||||
|
||||
/* em28xx has two audio inputs: tuner and line in.
|
||||
However, on most devices, an auxiliary AC97 codec device is used.
|
||||
The AC97 device may have several different inputs and outputs,
|
||||
depending on their model. So, it is possible to use AC97 mixer to
|
||||
address more than two different entries.
|
||||
*/
|
||||
enum em28xx_amux {
|
||||
/* This is the only entry for em28xx tuner input */
|
||||
EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */
|
||||
|
||||
EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */
|
||||
|
||||
/* Some less-common mixer setups */
|
||||
EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */
|
||||
EM28XX_AMUX_PHONE,
|
||||
EM28XX_AMUX_MIC,
|
||||
EM28XX_AMUX_CD,
|
||||
EM28XX_AMUX_AUX,
|
||||
EM28XX_AMUX_PCM_OUT,
|
||||
};
|
||||
|
||||
enum em28xx_aout {
|
||||
/* AC97 outputs */
|
||||
EM28XX_AOUT_MASTER = 1 << 0,
|
||||
EM28XX_AOUT_LINE = 1 << 1,
|
||||
EM28XX_AOUT_MONO = 1 << 2,
|
||||
EM28XX_AOUT_LFE = 1 << 3,
|
||||
EM28XX_AOUT_SURR = 1 << 4,
|
||||
|
||||
/* PCM IN Mixer - used by AC97_RECORD_SELECT register */
|
||||
EM28XX_AOUT_PCM_IN = 1 << 7,
|
||||
|
||||
/* Bits 10-8 are used to indicate the PCM IN record select */
|
||||
EM28XX_AOUT_PCM_MIC_PCM = 0 << 8,
|
||||
EM28XX_AOUT_PCM_CD = 1 << 8,
|
||||
EM28XX_AOUT_PCM_VIDEO = 2 << 8,
|
||||
EM28XX_AOUT_PCM_AUX = 3 << 8,
|
||||
EM28XX_AOUT_PCM_LINE = 4 << 8,
|
||||
EM28XX_AOUT_PCM_STEREO = 5 << 8,
|
||||
EM28XX_AOUT_PCM_MONO = 6 << 8,
|
||||
EM28XX_AOUT_PCM_PHONE = 7 << 8,
|
||||
};
|
||||
|
||||
static inline int ac97_return_record_select(int a_out)
|
||||
{
|
||||
return (a_out & 0x700) >> 8;
|
||||
}
|
||||
|
||||
struct em28xx_reg_seq {
|
||||
int reg;
|
||||
unsigned char val, mask;
|
||||
int sleep;
|
||||
};
|
||||
|
||||
struct em28xx_input {
|
||||
enum enum28xx_itype type;
|
||||
unsigned int vmux;
|
||||
enum em28xx_amux amux;
|
||||
enum em28xx_aout aout;
|
||||
struct em28xx_reg_seq *gpio;
|
||||
};
|
||||
|
||||
#define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
|
||||
|
||||
enum em28xx_decoder {
|
||||
EM28XX_NODECODER = 0,
|
||||
EM28XX_TVP5150,
|
||||
EM28XX_SAA711X,
|
||||
};
|
||||
|
||||
enum em28xx_sensor {
|
||||
EM28XX_NOSENSOR = 0,
|
||||
EM28XX_MT9V011,
|
||||
EM28XX_MT9M001,
|
||||
EM28XX_MT9M111,
|
||||
EM28XX_OV2640,
|
||||
};
|
||||
|
||||
enum em28xx_adecoder {
|
||||
EM28XX_NOADECODER = 0,
|
||||
EM28XX_TVAUDIO,
|
||||
};
|
||||
|
||||
enum em28xx_led_role {
|
||||
EM28XX_LED_ANALOG_CAPTURING = 0,
|
||||
EM28XX_LED_DIGITAL_CAPTURING,
|
||||
EM28XX_LED_ILLUMINATION,
|
||||
EM28XX_NUM_LED_ROLES, /* must be the last */
|
||||
};
|
||||
|
||||
struct em28xx_led {
|
||||
enum em28xx_led_role role;
|
||||
u8 gpio_reg;
|
||||
u8 gpio_mask;
|
||||
bool inverted;
|
||||
};
|
||||
|
||||
enum em28xx_button_role {
|
||||
EM28XX_BUTTON_SNAPSHOT = 0,
|
||||
EM28XX_BUTTON_ILLUMINATION,
|
||||
EM28XX_NUM_BUTTON_ROLES, /* must be the last */
|
||||
};
|
||||
|
||||
struct em28xx_button {
|
||||
enum em28xx_button_role role;
|
||||
u8 reg_r;
|
||||
u8 reg_clearing;
|
||||
u8 mask;
|
||||
bool inverted;
|
||||
};
|
||||
|
||||
struct em28xx_board {
|
||||
char *name;
|
||||
int vchannels;
|
||||
int tuner_type;
|
||||
int tuner_addr;
|
||||
unsigned def_i2c_bus; /* Default I2C bus */
|
||||
|
||||
/* i2c flags */
|
||||
unsigned int tda9887_conf;
|
||||
|
||||
/* GPIO sequences */
|
||||
struct em28xx_reg_seq *dvb_gpio;
|
||||
struct em28xx_reg_seq *suspend_gpio;
|
||||
struct em28xx_reg_seq *tuner_gpio;
|
||||
struct em28xx_reg_seq *mute_gpio;
|
||||
|
||||
unsigned int is_em2800:1;
|
||||
unsigned int has_msp34xx:1;
|
||||
unsigned int mts_firmware:1;
|
||||
unsigned int max_range_640_480:1;
|
||||
unsigned int has_dvb:1;
|
||||
unsigned int is_webcam:1;
|
||||
unsigned int valid:1;
|
||||
unsigned int has_ir_i2c:1;
|
||||
|
||||
unsigned char xclk, i2c_speed;
|
||||
unsigned char radio_addr;
|
||||
unsigned short tvaudio_addr;
|
||||
|
||||
enum em28xx_decoder decoder;
|
||||
enum em28xx_adecoder adecoder;
|
||||
|
||||
struct em28xx_input input[MAX_EM28XX_INPUT];
|
||||
struct em28xx_input radio;
|
||||
char *ir_codes;
|
||||
|
||||
/* LEDs that need to be controlled explicitly */
|
||||
struct em28xx_led *leds;
|
||||
|
||||
/* Buttons */
|
||||
struct em28xx_button *buttons;
|
||||
};
|
||||
|
||||
struct em28xx_eeprom {
|
||||
u8 id[4]; /* 1a eb 67 95 */
|
||||
__le16 vendor_ID;
|
||||
__le16 product_ID;
|
||||
|
||||
__le16 chip_conf;
|
||||
|
||||
__le16 board_conf;
|
||||
|
||||
__le16 string1, string2, string3;
|
||||
|
||||
u8 string_idx_table;
|
||||
};
|
||||
|
||||
#define EM28XX_CAPTURE_STREAM_EN 1
|
||||
|
||||
/* em28xx extensions */
|
||||
#define EM28XX_AUDIO 0x10
|
||||
#define EM28XX_DVB 0x20
|
||||
#define EM28XX_RC 0x30
|
||||
#define EM28XX_V4L2 0x40
|
||||
|
||||
/* em28xx resource types (used for res_get/res_lock etc */
|
||||
#define EM28XX_RESOURCE_VIDEO 0x01
|
||||
#define EM28XX_RESOURCE_VBI 0x02
|
||||
|
||||
struct em28xx_v4l2 {
|
||||
struct kref ref;
|
||||
struct em28xx *dev;
|
||||
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
struct v4l2_clk *clk;
|
||||
|
||||
struct video_device *vdev;
|
||||
struct video_device *vbi_dev;
|
||||
struct video_device *radio_dev;
|
||||
|
||||
/* Videobuf2 */
|
||||
struct vb2_queue vb_vidq;
|
||||
struct vb2_queue vb_vbiq;
|
||||
struct mutex vb_queue_lock;
|
||||
struct mutex vb_vbi_queue_lock;
|
||||
|
||||
u8 vinmode;
|
||||
u8 vinctl;
|
||||
|
||||
/* Camera specific fields */
|
||||
int sensor_xres;
|
||||
int sensor_yres;
|
||||
int sensor_xtal;
|
||||
|
||||
int users; /* user count for exclusive use */
|
||||
int streaming_users; /* number of actively streaming users */
|
||||
|
||||
u32 frequency; /* selected tuner frequency */
|
||||
|
||||
struct em28xx_fmt *format;
|
||||
v4l2_std_id norm; /* selected tv norm */
|
||||
|
||||
/* Progressive/interlaced mode */
|
||||
bool progressive;
|
||||
int interlaced_fieldmode; /* 1=interlaced fields, 0=just top fields */
|
||||
/* FIXME: everything else than interlaced_fieldmode=1 doesn't work */
|
||||
|
||||
/* Frame properties */
|
||||
int width; /* current frame width */
|
||||
int height; /* current frame height */
|
||||
unsigned hscale; /* horizontal scale factor (see datasheet) */
|
||||
unsigned vscale; /* vertical scale factor (see datasheet) */
|
||||
unsigned int vbi_width;
|
||||
unsigned int vbi_height; /* lines per field */
|
||||
|
||||
/* Capture state tracking */
|
||||
int capture_type;
|
||||
bool top_field;
|
||||
int vbi_read;
|
||||
unsigned int field_count;
|
||||
};
|
||||
|
||||
struct em28xx_audio {
|
||||
char name[50];
|
||||
unsigned num_urb;
|
||||
char **transfer_buffer;
|
||||
struct urb **urb;
|
||||
struct usb_device *udev;
|
||||
unsigned int capture_transfer_done;
|
||||
struct snd_pcm_substream *capture_pcm_substream;
|
||||
|
||||
unsigned int hwptr_done_capture;
|
||||
struct snd_card *sndcard;
|
||||
|
||||
size_t period;
|
||||
|
||||
int users;
|
||||
spinlock_t slock;
|
||||
|
||||
/* Controls streaming */
|
||||
struct work_struct wq_trigger; /* trigger to start/stop audio */
|
||||
atomic_t stream_started; /* stream should be running if true */
|
||||
};
|
||||
|
||||
struct em28xx;
|
||||
|
||||
enum em28xx_i2c_algo_type {
|
||||
EM28XX_I2C_ALGO_EM28XX = 0,
|
||||
EM28XX_I2C_ALGO_EM2800,
|
||||
EM28XX_I2C_ALGO_EM25XX_BUS_B,
|
||||
};
|
||||
|
||||
struct em28xx_i2c_bus {
|
||||
struct em28xx *dev;
|
||||
|
||||
unsigned bus;
|
||||
enum em28xx_i2c_algo_type algo_type;
|
||||
};
|
||||
|
||||
/* main device struct */
|
||||
struct em28xx {
|
||||
struct kref ref;
|
||||
|
||||
/* Sub-module data */
|
||||
struct em28xx_v4l2 *v4l2;
|
||||
struct em28xx_dvb *dvb;
|
||||
struct em28xx_audio adev;
|
||||
struct em28xx_IR *ir;
|
||||
|
||||
/* generic device properties */
|
||||
char name[30]; /* name (including minor) of the device */
|
||||
int model; /* index in the device_data struct */
|
||||
int devno; /* marks the number of this device */
|
||||
enum em28xx_chip_id chip_id;
|
||||
|
||||
unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */
|
||||
unsigned char disconnected:1; /* device has been diconnected */
|
||||
unsigned int has_video:1;
|
||||
unsigned int is_audio_only:1;
|
||||
enum em28xx_int_audio_type int_audio_type;
|
||||
enum em28xx_usb_audio_type usb_audio_type;
|
||||
|
||||
struct em28xx_board board;
|
||||
|
||||
enum em28xx_sensor em28xx_sensor; /* camera specific */
|
||||
|
||||
/* Some older em28xx chips needs a waiting time after writing */
|
||||
unsigned int wait_after_write;
|
||||
|
||||
struct list_head devlist;
|
||||
|
||||
u32 i2s_speed; /* I2S speed for audio digital stream */
|
||||
|
||||
struct em28xx_audio_mode audio_mode;
|
||||
|
||||
int tuner_type; /* type of the tuner */
|
||||
|
||||
/* i2c i/o */
|
||||
struct i2c_adapter i2c_adap[NUM_I2C_BUSES];
|
||||
struct i2c_client i2c_client[NUM_I2C_BUSES];
|
||||
struct em28xx_i2c_bus i2c_bus[NUM_I2C_BUSES];
|
||||
|
||||
unsigned char eeprom_addrwidth_16bit:1;
|
||||
unsigned def_i2c_bus; /* Default I2C bus */
|
||||
unsigned cur_i2c_bus; /* Current I2C bus */
|
||||
struct rt_mutex i2c_bus_lock;
|
||||
|
||||
/* video for linux */
|
||||
unsigned int ctl_input; /* selected input */
|
||||
unsigned int ctl_ainput;/* selected audio input */
|
||||
unsigned int ctl_aoutput;/* selected audio output */
|
||||
int mute;
|
||||
int volume;
|
||||
|
||||
unsigned long hash; /* eeprom hash - for boards with generic ID */
|
||||
unsigned long i2c_hash; /* i2c devicelist hash -
|
||||
for boards with generic ID */
|
||||
|
||||
struct work_struct request_module_wk;
|
||||
|
||||
/* locks */
|
||||
struct mutex lock;
|
||||
struct mutex ctrl_urb_lock; /* protects urb_buf */
|
||||
|
||||
/* resources in use */
|
||||
unsigned int resources;
|
||||
|
||||
/* eeprom content */
|
||||
u8 *eedata;
|
||||
u16 eedata_len;
|
||||
|
||||
/* Isoc control struct */
|
||||
struct em28xx_dmaqueue vidq;
|
||||
struct em28xx_dmaqueue vbiq;
|
||||
struct em28xx_usb_ctl usb_ctl;
|
||||
spinlock_t slock;
|
||||
|
||||
/* usb transfer */
|
||||
struct usb_device *udev; /* the usb device */
|
||||
u8 ifnum; /* number of the assigned usb interface */
|
||||
u8 analog_ep_isoc; /* address of isoc endpoint for analog */
|
||||
u8 analog_ep_bulk; /* address of bulk endpoint for analog */
|
||||
u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */
|
||||
u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */
|
||||
int alt; /* alternate setting */
|
||||
int max_pkt_size; /* max packet size of the selected ep at alt */
|
||||
int packet_multiplier; /* multiplier for wMaxPacketSize, used for
|
||||
URB buffer size definition */
|
||||
int num_alt; /* number of alternative settings */
|
||||
unsigned int *alt_max_pkt_size_isoc; /* array of isoc wMaxPacketSize */
|
||||
unsigned int analog_xfer_bulk:1; /* use bulk instead of isoc
|
||||
transfers for analog */
|
||||
int dvb_alt_isoc; /* alternate setting for DVB isoc transfers */
|
||||
unsigned int dvb_max_pkt_size_isoc; /* isoc max packet size of the
|
||||
selected DVB ep at dvb_alt */
|
||||
unsigned int dvb_xfer_bulk:1; /* use bulk instead of isoc
|
||||
transfers for DVB */
|
||||
char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
|
||||
|
||||
/* helper funcs that call usb_control_msg */
|
||||
int (*em28xx_write_regs) (struct em28xx *dev, u16 reg,
|
||||
char *buf, int len);
|
||||
int (*em28xx_read_reg) (struct em28xx *dev, u16 reg);
|
||||
int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
|
||||
char *buf, int len);
|
||||
int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg,
|
||||
char *buf, int len);
|
||||
int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg);
|
||||
|
||||
enum em28xx_mode mode;
|
||||
|
||||
/* Button state polling */
|
||||
struct delayed_work buttons_query_work;
|
||||
u8 button_polling_addresses[EM28XX_NUM_BUTTON_ADDRESSES_MAX];
|
||||
u8 button_polling_last_values[EM28XX_NUM_BUTTON_ADDRESSES_MAX];
|
||||
u8 num_button_polling_addresses;
|
||||
u16 button_polling_interval; /* [ms] */
|
||||
/* Snapshot button input device */
|
||||
char snapshot_button_path[30]; /* path of the input dev */
|
||||
struct input_dev *sbutton_input_dev;
|
||||
};
|
||||
|
||||
#define kref_to_dev(d) container_of(d, struct em28xx, ref)
|
||||
|
||||
struct em28xx_ops {
|
||||
struct list_head next;
|
||||
char *name;
|
||||
int id;
|
||||
int (*init)(struct em28xx *);
|
||||
int (*fini)(struct em28xx *);
|
||||
int (*suspend)(struct em28xx *);
|
||||
int (*resume)(struct em28xx *);
|
||||
};
|
||||
|
||||
/* Provided by em28xx-i2c.c */
|
||||
void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus);
|
||||
int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
|
||||
enum em28xx_i2c_algo_type algo_type);
|
||||
int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus);
|
||||
|
||||
/* Provided by em28xx-core.c */
|
||||
int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
|
||||
char *buf, int len);
|
||||
int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg);
|
||||
int em28xx_read_reg(struct em28xx *dev, u16 reg);
|
||||
int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
|
||||
int len);
|
||||
int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
|
||||
int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val);
|
||||
int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
|
||||
u8 bitmask);
|
||||
int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask);
|
||||
|
||||
int em28xx_read_ac97(struct em28xx *dev, u8 reg);
|
||||
int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
|
||||
|
||||
int em28xx_audio_analog_set(struct em28xx *dev);
|
||||
int em28xx_audio_setup(struct em28xx *dev);
|
||||
|
||||
const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
|
||||
enum em28xx_led_role role);
|
||||
int em28xx_capture_start(struct em28xx *dev, int start);
|
||||
int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
|
||||
int num_bufs, int max_pkt_size, int packet_multiplier);
|
||||
int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
|
||||
int xfer_bulk,
|
||||
int num_bufs, int max_pkt_size, int packet_multiplier,
|
||||
int (*urb_data_copy)
|
||||
(struct em28xx *dev, struct urb *urb));
|
||||
void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode);
|
||||
void em28xx_stop_urbs(struct em28xx *dev);
|
||||
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
|
||||
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
|
||||
int em28xx_register_extension(struct em28xx_ops *dev);
|
||||
void em28xx_unregister_extension(struct em28xx_ops *dev);
|
||||
void em28xx_init_extension(struct em28xx *dev);
|
||||
void em28xx_close_extension(struct em28xx *dev);
|
||||
int em28xx_suspend_extension(struct em28xx *dev);
|
||||
int em28xx_resume_extension(struct em28xx *dev);
|
||||
|
||||
/* Provided by em28xx-cards.c */
|
||||
extern struct em28xx_board em28xx_boards[];
|
||||
extern struct usb_device_id em28xx_id_table[];
|
||||
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
|
||||
void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
|
||||
void em28xx_free_device(struct kref *ref);
|
||||
|
||||
/* Provided by em28xx-camera.c */
|
||||
int em28xx_detect_sensor(struct em28xx *dev);
|
||||
int em28xx_init_camera(struct em28xx *dev);
|
||||
|
||||
/* printk macros */
|
||||
|
||||
#define em28xx_err(fmt, arg...) do {\
|
||||
printk(KERN_ERR fmt , ##arg); } while (0)
|
||||
|
||||
#define em28xx_errdev(fmt, arg...) do {\
|
||||
printk(KERN_ERR "%s: "fmt,\
|
||||
dev->name , ##arg); } while (0)
|
||||
|
||||
#define em28xx_info(fmt, arg...) do {\
|
||||
printk(KERN_INFO "%s: "fmt,\
|
||||
dev->name , ##arg); } while (0)
|
||||
#define em28xx_warn(fmt, arg...) do {\
|
||||
printk(KERN_WARNING "%s: "fmt,\
|
||||
dev->name , ##arg); } while (0)
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue