cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hexium_gemini.c (11630B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3    hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
      4
      5    Visit http://www.mihu.de/linux/saa7146/ and follow the link
      6    to "hexium" for further details about this card.
      7
      8    Copyright (C) 2003 Michael Hunold <michael@mihu.de>
      9
     10*/
     11
     12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     13
     14#define DEBUG_VARIABLE debug
     15
     16#include <media/drv-intf/saa7146_vv.h>
     17#include <linux/module.h>
     18#include <linux/kernel.h>
     19
     20static int debug;
     21module_param(debug, int, 0);
     22MODULE_PARM_DESC(debug, "debug verbosity");
     23
     24/* global variables */
     25static int hexium_num;
     26
     27#define HEXIUM_GEMINI			4
     28#define HEXIUM_GEMINI_DUAL		5
     29
     30#define HEXIUM_INPUTS	9
     31static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
     32	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
     33	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
     34	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
     35	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
     36	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
     37	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
     38	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
     39	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
     40	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
     41};
     42
     43#define HEXIUM_AUDIOS	0
     44
     45struct hexium_data
     46{
     47	s8 adr;
     48	u8 byte;
     49};
     50
     51#define HEXIUM_GEMINI_V_1_0		1
     52#define HEXIUM_GEMINI_DUAL_V_1_0	2
     53
     54struct hexium
     55{
     56	int type;
     57
     58	struct video_device	video_dev;
     59	struct i2c_adapter	i2c_adapter;
     60
     61	int		cur_input;	/* current input */
     62	v4l2_std_id	cur_std;	/* current standard */
     63};
     64
     65/* Samsung KS0127B decoder default registers */
     66static u8 hexium_ks0127b[0x100]={
     67/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
     68/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
     69/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
     70/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
     71/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     72/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
     73/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
     74/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
     75/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     76/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     77/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     78/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     79/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     80/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     81/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     82/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     83/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     84/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     85/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     86/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     87/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     88/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     89/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     90/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     91/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     92/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     93/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     94/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     95/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     96/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     97/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     98/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
     99};
    100
    101static struct hexium_data hexium_pal[] = {
    102	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
    103};
    104
    105static struct hexium_data hexium_ntsc[] = {
    106	{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
    107};
    108
    109static struct hexium_data hexium_secam[] = {
    110	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
    111};
    112
    113static struct hexium_data hexium_input_select[] = {
    114	{ 0x02, 0x60 },
    115	{ 0x02, 0x64 },
    116	{ 0x02, 0x61 },
    117	{ 0x02, 0x65 },
    118	{ 0x02, 0x62 },
    119	{ 0x02, 0x66 },
    120	{ 0x02, 0x68 },
    121	{ 0x02, 0x69 },
    122	{ 0x02, 0x6A },
    123};
    124
    125/* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
    126   are currently *not* supported*/
    127static struct saa7146_standard hexium_standards[] = {
    128	{
    129		.name	= "PAL",	.id	= V4L2_STD_PAL,
    130		.v_offset	= 28,	.v_field	= 288,
    131		.h_offset	= 1,	.h_pixels	= 680,
    132		.v_max_out	= 576,	.h_max_out	= 768,
    133	}, {
    134		.name	= "NTSC",	.id	= V4L2_STD_NTSC,
    135		.v_offset	= 28,	.v_field	= 240,
    136		.h_offset	= 1,	.h_pixels	= 640,
    137		.v_max_out	= 480,	.h_max_out	= 640,
    138	}, {
    139		.name	= "SECAM",	.id	= V4L2_STD_SECAM,
    140		.v_offset	= 28,	.v_field	= 288,
    141		.h_offset	= 1,	.h_pixels	= 720,
    142		.v_max_out	= 576,	.h_max_out	= 768,
    143	}
    144};
    145
    146/* bring hardware to a sane state. this has to be done, just in case someone
    147   wants to capture from this device before it has been properly initialized.
    148   the capture engine would badly fail, because no valid signal arrives on the
    149   saa7146, thus leading to timeouts and stuff. */
    150static int hexium_init_done(struct saa7146_dev *dev)
    151{
    152	struct hexium *hexium = (struct hexium *) dev->ext_priv;
    153	union i2c_smbus_data data;
    154	int i = 0;
    155
    156	DEB_D("hexium_init_done called\n");
    157
    158	/* initialize the helper ics to useful values */
    159	for (i = 0; i < sizeof(hexium_ks0127b); i++) {
    160		data.byte = hexium_ks0127b[i];
    161		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
    162			pr_err("hexium_init_done() failed for address 0x%02x\n",
    163			       i);
    164		}
    165	}
    166
    167	return 0;
    168}
    169
    170static int hexium_set_input(struct hexium *hexium, int input)
    171{
    172	union i2c_smbus_data data;
    173
    174	DEB_D("\n");
    175
    176	data.byte = hexium_input_select[input].byte;
    177	if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
    178		return -1;
    179	}
    180
    181	return 0;
    182}
    183
    184static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
    185{
    186	union i2c_smbus_data data;
    187	int i = 0;
    188
    189	DEB_D("\n");
    190
    191	while (vdec[i].adr != -1) {
    192		data.byte = vdec[i].byte;
    193		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
    194			pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n",
    195			       i);
    196			return -1;
    197		}
    198		i++;
    199	}
    200	return 0;
    201}
    202
    203static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
    204{
    205	DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
    206
    207	if (i->index >= HEXIUM_INPUTS)
    208		return -EINVAL;
    209
    210	memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
    211
    212	DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
    213	return 0;
    214}
    215
    216static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
    217{
    218	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
    219	struct hexium *hexium = (struct hexium *) dev->ext_priv;
    220
    221	*input = hexium->cur_input;
    222
    223	DEB_D("VIDIOC_G_INPUT: %d\n", *input);
    224	return 0;
    225}
    226
    227static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
    228{
    229	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
    230	struct hexium *hexium = (struct hexium *) dev->ext_priv;
    231
    232	DEB_EE("VIDIOC_S_INPUT %d\n", input);
    233
    234	if (input >= HEXIUM_INPUTS)
    235		return -EINVAL;
    236
    237	hexium->cur_input = input;
    238	hexium_set_input(hexium, input);
    239	return 0;
    240}
    241
    242static struct saa7146_ext_vv vv_data;
    243
    244/* this function only gets called when the probing was successful */
    245static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
    246{
    247	struct hexium *hexium;
    248	int ret;
    249
    250	DEB_EE("\n");
    251
    252	hexium = kzalloc(sizeof(*hexium), GFP_KERNEL);
    253	if (!hexium)
    254		return -ENOMEM;
    255
    256	dev->ext_priv = hexium;
    257
    258	/* enable i2c-port pins */
    259	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
    260
    261	strscpy(hexium->i2c_adapter.name, "hexium gemini",
    262		sizeof(hexium->i2c_adapter.name));
    263	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
    264	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
    265		DEB_S("cannot register i2c-device. skipping.\n");
    266		kfree(hexium);
    267		return -EFAULT;
    268	}
    269
    270	/*  set HWControl GPIO number 2 */
    271	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
    272
    273	saa7146_write(dev, DD1_INIT, 0x07000700);
    274	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
    275	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
    276
    277	/* the rest */
    278	hexium->cur_input = 0;
    279	hexium_init_done(dev);
    280
    281	hexium_set_standard(hexium, hexium_pal);
    282	hexium->cur_std = V4L2_STD_PAL;
    283
    284	hexium_set_input(hexium, 0);
    285	hexium->cur_input = 0;
    286
    287	ret = saa7146_vv_init(dev, &vv_data);
    288	if (ret) {
    289		i2c_del_adapter(&hexium->i2c_adapter);
    290		kfree(hexium);
    291		return ret;
    292	}
    293
    294	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
    295	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
    296	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
    297	ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_VIDEO);
    298	if (ret < 0) {
    299		pr_err("cannot register capture v4l2 device. skipping.\n");
    300		saa7146_vv_release(dev);
    301		i2c_del_adapter(&hexium->i2c_adapter);
    302		kfree(hexium);
    303		return ret;
    304	}
    305
    306	pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
    307	hexium_num++;
    308
    309	return 0;
    310}
    311
    312static int hexium_detach(struct saa7146_dev *dev)
    313{
    314	struct hexium *hexium = (struct hexium *) dev->ext_priv;
    315
    316	DEB_EE("dev:%p\n", dev);
    317
    318	saa7146_unregister_device(&hexium->video_dev, dev);
    319	saa7146_vv_release(dev);
    320
    321	hexium_num--;
    322
    323	i2c_del_adapter(&hexium->i2c_adapter);
    324	kfree(hexium);
    325	return 0;
    326}
    327
    328static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
    329{
    330	struct hexium *hexium = (struct hexium *) dev->ext_priv;
    331
    332	if (V4L2_STD_PAL == std->id) {
    333		hexium_set_standard(hexium, hexium_pal);
    334		hexium->cur_std = V4L2_STD_PAL;
    335		return 0;
    336	} else if (V4L2_STD_NTSC == std->id) {
    337		hexium_set_standard(hexium, hexium_ntsc);
    338		hexium->cur_std = V4L2_STD_NTSC;
    339		return 0;
    340	} else if (V4L2_STD_SECAM == std->id) {
    341		hexium_set_standard(hexium, hexium_secam);
    342		hexium->cur_std = V4L2_STD_SECAM;
    343		return 0;
    344	}
    345
    346	return -1;
    347}
    348
    349static struct saa7146_extension hexium_extension;
    350
    351static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
    352	.ext_priv = "Hexium Gemini (4 BNC)",
    353	.ext = &hexium_extension,
    354};
    355
    356static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
    357	.ext_priv = "Hexium Gemini Dual (4 BNC)",
    358	.ext = &hexium_extension,
    359};
    360
    361static const struct pci_device_id pci_tbl[] = {
    362	{
    363	 .vendor = PCI_VENDOR_ID_PHILIPS,
    364	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
    365	 .subvendor = 0x17c8,
    366	 .subdevice = 0x2401,
    367	 .driver_data = (unsigned long) &hexium_gemini_4bnc,
    368	 },
    369	{
    370	 .vendor = PCI_VENDOR_ID_PHILIPS,
    371	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
    372	 .subvendor = 0x17c8,
    373	 .subdevice = 0x2402,
    374	 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
    375	 },
    376	{
    377	 .vendor = 0,
    378	 }
    379};
    380
    381MODULE_DEVICE_TABLE(pci, pci_tbl);
    382
    383static struct saa7146_ext_vv vv_data = {
    384	.inputs = HEXIUM_INPUTS,
    385	.capabilities = 0,
    386	.stds = &hexium_standards[0],
    387	.num_stds = ARRAY_SIZE(hexium_standards),
    388	.std_callback = &std_callback,
    389};
    390
    391static struct saa7146_extension hexium_extension = {
    392	.name = "hexium gemini",
    393	.flags = SAA7146_USE_I2C_IRQ,
    394
    395	.pci_tbl = &pci_tbl[0],
    396	.module = THIS_MODULE,
    397
    398	.attach = hexium_attach,
    399	.detach = hexium_detach,
    400
    401	.irq_mask = 0,
    402	.irq_func = NULL,
    403};
    404
    405static int __init hexium_init_module(void)
    406{
    407	if (0 != saa7146_register_extension(&hexium_extension)) {
    408		DEB_S("failed to register extension\n");
    409		return -ENODEV;
    410	}
    411
    412	return 0;
    413}
    414
    415static void __exit hexium_cleanup_module(void)
    416{
    417	saa7146_unregister_extension(&hexium_extension);
    418}
    419
    420module_init(hexium_init_module);
    421module_exit(hexium_cleanup_module);
    422
    423MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
    424MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
    425MODULE_LICENSE("GPL");