static int write_regs_fp(struct i2c_client *client, u16 *regs)
{
	int i;

	for (i = 0; !((regs[i] == 0x00) && (regs[i+1] == 0x00)); i += 2) {
		if (write_reg_fp(client, regs[i], regs[i+1]) < 0) {
			printk(KERN_INFO "s2250: failed fp\n");
			return -1;
		}
	}
	return 0;
}
static int s2250_detect(struct i2c_adapter *adapter, int addr, int kind)
{
	struct i2c_client *client;
	struct s2250 *dec;
	u8 *data;
	struct go7007 *go = i2c_get_adapdata(adapter);
	struct go7007_usb *usb = go->hpi_context;

	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
	if (client == NULL)
		return -ENOMEM;
	memcpy(client, &s2250_client_templ,
	       sizeof(s2250_client_templ));
	client->adapter = adapter;

	dec = kmalloc(sizeof(struct s2250), GFP_KERNEL);
	if (dec == NULL) {
		kfree(client);
		return -ENOMEM;
	}

	dec->std = V4L2_STD_NTSC;
	dec->brightness = 50;
	dec->contrast = 50;
	dec->saturation = 50;
	dec->hue = 0;
	client->addr = TLV320_ADDRESS;
	i2c_set_clientdata(client, dec);

	printk(KERN_DEBUG
	       "s2250: initializing video decoder on %s\n",
	       adapter->name);

	/* initialize the audio */
	client->addr = TLV320_ADDRESS;
	if (write_regs(client, aud_regs) < 0) {
		printk(KERN_ERR
		       "s2250: error initializing audio\n");
		kfree(client);
		kfree(dec);
		return 0;
	}
	client->addr = S2250_VIDDEC;
	i2c_set_clientdata(client, dec);

	if (write_regs(client, vid_regs) < 0) {
		printk(KERN_ERR
		       "s2250: error initializing decoder\n");
		kfree(client);
		kfree(dec);
		return 0;
	}
	if (write_regs_fp(client, vid_regs_fp) < 0) {
		printk(KERN_ERR
		       "s2250: error initializing decoder\n");
		kfree(client);
		kfree(dec);
		return 0;
	}
	/* set default channel */
	/* composite */
	write_reg_fp(client, 0x20, 0x020 | 1);
	write_reg_fp(client, 0x21, 0x662);
	write_reg_fp(client, 0x140, 0x060);

	/* set default audio input */
	dec->audio_input = 0;
	write_reg(client, 0x08, 0x02); /* Line In */

	if (down_interruptible(&usb->i2c_lock) == 0) {
		data = kzalloc(16, GFP_KERNEL);
		if (data != NULL) {
			int rc;
			rc = go7007_usb_vendor_request(go, 0x41, 0, 0,
						       data, 16, 1);
			if (rc > 0) {
				u8 mask;
				data[0] = 0;
				mask = 1<<5;
				data[0] &= ~mask;
				data[1] |= mask;
				go7007_usb_vendor_request(go, 0x40, 0,
							  (data[1]<<8)
							  + data[1],
							  data, 16, 0);
			}
			kfree(data);
		}
		up(&usb->i2c_lock);
	}

	i2c_attach_client(client);
	printk("s2250: initialized successfully\n");
	return 0;
}
static int s2250_command(struct i2c_client *client,
			 unsigned int cmd, void *arg)
{
	struct s2250 *dec = i2c_get_clientdata(client);

	switch (cmd) {
	case VIDIOC_S_INPUT:
	{
		int vidsys;
		int *input = arg;

		vidsys = (dec->std == V4L2_STD_NTSC) ? 0x01 : 0x00;
		if (*input == 0) {
			/* composite */
			write_reg_fp(client, 0x20, 0x020 | vidsys);
			write_reg_fp(client, 0x21, 0x662);
			write_reg_fp(client, 0x140, 0x060);
		} else {
			/* S-Video */
			write_reg_fp(client, 0x20, 0x040 | vidsys);
			write_reg_fp(client, 0x21, 0x666);
			write_reg_fp(client, 0x140, 0x060);
		}
		dec->input = *input;
		break;
	}
	case VIDIOC_S_STD:
	{
		v4l2_std_id *std = arg;
		u16 vidsource;

		vidsource = (dec->input == 1) ? 0x040 : 0x020;
		dec->std = *std;
		switch (dec->std) {
		case V4L2_STD_NTSC:
			write_regs_fp(client, vid_regs_fp);
			write_reg_fp(client, 0x20, vidsource | 1);
			break;
		case V4L2_STD_PAL:
			write_regs_fp(client, vid_regs_fp);
			write_regs_fp(client, vid_regs_fp_pal);
			write_reg_fp(client, 0x20, vidsource);
			break;
		default:
			return -EINVAL;
		}
		break;
	}
	case VIDIOC_QUERYCTRL:
	{
		struct v4l2_queryctrl *ctrl = arg;
		static const u32 user_ctrls[] = {
			V4L2_CID_BRIGHTNESS,
			V4L2_CID_CONTRAST,
			V4L2_CID_SATURATION,
			V4L2_CID_HUE,
			0
		};
		static const u32 *ctrl_classes[] = {
			user_ctrls,
			NULL
		};

		ctrl->id = v4l2_ctrl_next(ctrl_classes, ctrl->id);
		switch (ctrl->id) {
		case V4L2_CID_BRIGHTNESS:
			v4l2_ctrl_query_fill(ctrl, 0, 100, 1, 50);
			break;
		case V4L2_CID_CONTRAST:
			v4l2_ctrl_query_fill(ctrl, 0, 100, 1, 50);
			break;
		case V4L2_CID_SATURATION:
			v4l2_ctrl_query_fill(ctrl, 0, 100, 1, 50);
			break;
		case V4L2_CID_HUE:
			v4l2_ctrl_query_fill(ctrl, -50, 50, 1, 0);
			break;
		default:
			ctrl->name[0] = '\0';
			return -EINVAL;
		}
		break;
	}
	case VIDIOC_S_CTRL:
	{
		struct v4l2_control *ctrl = arg;
		int value1;

		switch (ctrl->id) {
		case V4L2_CID_BRIGHTNESS:
			printk(KERN_INFO "s2250: future setting\n");
			return -EINVAL;
		case V4L2_CID_CONTRAST:
			printk(KERN_INFO "s2250: future setting\n");
			return -EINVAL;
			break;
		case V4L2_CID_SATURATION:
			if (ctrl->value > 127)
				dec->saturation = 127;
			else if (ctrl->value < 0)
				dec->saturation = 0;
			else
				dec->saturation = ctrl->value;

			value1 = dec->saturation * 4140 / 100;
			if (value1 > 4094)
				value1 = 4094;
			write_reg_fp(client, VPX322_ADDR_SAT, value1);
			break;
		case V4L2_CID_HUE:
			if (ctrl->value > 50)
				dec->hue = 50;
			else if (ctrl->value < -50)
				dec->hue = -50;
			else
				dec->hue = ctrl->value;
			/* clamp the hue range */
			value1 = dec->hue * 280 / 50;
			write_reg_fp(client, VPX322_ADDR_HUE, value1);
			break;
		}
		break;
	}
	case VIDIOC_G_CTRL:
	{
		struct v4l2_control *ctrl = arg;

		switch (ctrl->id) {
		case V4L2_CID_BRIGHTNESS:
			ctrl->value = dec->brightness;
			break;
		case V4L2_CID_CONTRAST:
			ctrl->value = dec->contrast;
			break;
		case V4L2_CID_SATURATION:
			ctrl->value = dec->saturation;
			break;
		case V4L2_CID_HUE:
			ctrl->value = dec->hue;
			break;
		}
		break;
	}
	case VIDIOC_S_FMT:
	{
		struct v4l2_format *fmt = arg;
		if (fmt->fmt.pix.height < 640) {
			write_reg_fp(client, 0x12b, dec->reg12b_val | 0x400);
			write_reg_fp(client, 0x140, 0x060);
		} else {
			write_reg_fp(client, 0x12b, dec->reg12b_val & ~0x400);
			write_reg_fp(client, 0x140, 0x060);
		}
		return 0;
	}
	case VIDIOC_G_AUDIO:
	{
		struct v4l2_audio *audio = arg;

		memset(audio, 0, sizeof(*audio));
		audio->index = dec->audio_input;
		/* fall through */
	}
	case VIDIOC_ENUMAUDIO:
	{
		struct v4l2_audio *audio = arg;

		switch (audio->index) {
		case 0:
			strcpy(audio->name, "Line In");
			break;
		case 1:
			strcpy(audio->name, "Mic");
			break;
		case 2:
			strcpy(audio->name, "Mic Boost");
			break;
		default:
			audio->name[0] = '\0';
			return 0;
		}
		audio->capability = V4L2_AUDCAP_STEREO;
		audio->mode = 0;
		return 0;
	}
	case VIDIOC_S_AUDIO:
	{
		struct v4l2_audio *audio = arg;

		client->addr = TLV320_ADDRESS;
		switch (audio->index) {
		case 0:
			write_reg(client, 0x08, 0x02); /* Line In */
			break;
		case 1:
			write_reg(client, 0x08, 0x04); /* Mic */
			break;
		case 2:
			write_reg(client, 0x08, 0x05); /* Mic Boost */
			break;
		default:
			return -EINVAL;
		}
		dec->audio_input = audio->index;
		return 0;
	}

	default:
		printk(KERN_INFO "s2250: unknown command 0x%x\n", cmd);
		break;
	}
	return 0;
}
Esempio n. 4
0
static int s2250_probe(struct i2c_client *client,
		       const struct i2c_device_id *id)
{
	struct i2c_client *audio;
	struct i2c_adapter *adapter = client->adapter;
	struct s2250 *dec;
	u8 *data;
	struct go7007 *go = i2c_get_adapdata(adapter);
	struct go7007_usb *usb = go->hpi_context;

	audio = i2c_new_dummy(adapter, TLV320_ADDRESS >> 1);
	if (audio == NULL)
		return -ENOMEM;

	dec = kmalloc(sizeof(struct s2250), GFP_KERNEL);
	if (dec == NULL) {
		i2c_unregister_device(audio);
		return -ENOMEM;
	}

	dec->std = V4L2_STD_NTSC;
	dec->brightness = 50;
	dec->contrast = 50;
	dec->saturation = 50;
	dec->hue = 0;
	dec->audio = audio;
	i2c_set_clientdata(client, dec);

	printk(KERN_DEBUG
	       "s2250: initializing video decoder on %s\n",
	       adapter->name);

	/* initialize the audio */
	if (write_regs(audio, aud_regs) < 0) {
		printk(KERN_ERR
		       "s2250: error initializing audio\n");
		i2c_unregister_device(audio);
		kfree(dec);
		return 0;
	}

	if (write_regs(client, vid_regs) < 0) {
		printk(KERN_ERR
		       "s2250: error initializing decoder\n");
		i2c_unregister_device(audio);
		kfree(dec);
		return 0;
	}
	if (write_regs_fp(client, vid_regs_fp) < 0) {
		printk(KERN_ERR
		       "s2250: error initializing decoder\n");
		i2c_unregister_device(audio);
		kfree(dec);
		return 0;
	}
	/* set default channel */
	/* composite */
	write_reg_fp(client, 0x20, 0x020 | 1);
	write_reg_fp(client, 0x21, 0x662);
	write_reg_fp(client, 0x140, 0x060);

	/* set default audio input */
	dec->audio_input = 0;
	write_reg(client, 0x08, 0x02); /* Line In */

	if (mutex_lock_interruptible(&usb->i2c_lock) == 0) {
		data = kzalloc(16, GFP_KERNEL);
		if (data != NULL) {
			int rc;
			rc = go7007_usb_vendor_request(go, 0x41, 0, 0,
						       data, 16, 1);
			if (rc > 0) {
				u8 mask;
				data[0] = 0;
				mask = 1<<5;
				data[0] &= ~mask;
				data[1] |= mask;
				go7007_usb_vendor_request(go, 0x40, 0,
							  (data[1]<<8)
							  + data[1],
							  data, 16, 0);
			}
			kfree(data);
		}
		mutex_unlock(&usb->i2c_lock);
	}

	printk("s2250: initialized successfully\n");
	return 0;
}