em28xx-core.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 736 行 · 第 1/2 页

C
736
字号
/*   em28xx-core.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>   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/init.h>#include <linux/list.h>#include <linux/module.h>#include <linux/usb.h>#include <linux/vmalloc.h>#include "em28xx.h"/* #define ENABLE_DEBUG_ISOC_FRAMES */static unsigned int core_debug;module_param(core_debug,int,0644);MODULE_PARM_DESC(core_debug,"enable debug messages [core]");#define em28xx_coredbg(fmt, arg...) do {\	if (core_debug) \		printk(KERN_INFO "%s %s :"fmt, \			 dev->name, __func__ , ##arg); } while (0)static unsigned int reg_debug;module_param(reg_debug,int,0644);MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");#define em28xx_regdbg(fmt, arg...) do {\	if (reg_debug) \		printk(KERN_INFO "%s %s :"fmt, \			 dev->name, __func__ , ##arg); } while (0)static int alt = EM28XX_PINOUT;module_param(alt, int, 0644);MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");/* FIXME */#define em28xx_isocdbg(fmt, arg...) do {\	if (core_debug) \		printk(KERN_INFO "%s %s :"fmt, \			 dev->name, __func__ , ##arg); } while (0)/* * em28xx_read_reg_req() * reads data from the usb device specifying bRequest */int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,				   char *buf, int len){	int ret, byte;	if (dev->state & DEV_DISCONNECTED)		return(-ENODEV);	em28xx_regdbg("req=%02x, reg=%02x ", req, reg);	ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,			      0x0000, reg, buf, len, HZ);	if (reg_debug) {		printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);		for (byte = 0; byte < len; byte++)			printk(" %02x", (unsigned char)buf[byte]);		printk("\n");	}	return ret;}/* * em28xx_read_reg_req() * reads data from the usb device specifying bRequest */int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg){	u8 val;	int ret;	if (dev->state & DEV_DISCONNECTED)		return(-ENODEV);	em28xx_regdbg("req=%02x, reg=%02x:", req, reg);	ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,			      0x0000, reg, &val, 1, HZ);	if (reg_debug)		printk(ret < 0 ? " failed!\n" :				 "%02x\n", (unsigned char) val);	if (ret < 0)		return ret;	return val;}int em28xx_read_reg(struct em28xx *dev, u16 reg){	return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg);}/* * em28xx_write_regs_req() * sends data to the usb device, specifying bRequest */int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,				 int len){	int ret;	/*usb_control_msg seems to expect a kmalloced buffer */	unsigned char *bufs;	if (dev->state & DEV_DISCONNECTED)		return -ENODEV;	if (len < 1)		return -EINVAL;	bufs = kmalloc(len, GFP_KERNEL);	em28xx_regdbg("req=%02x reg=%02x:", req, reg);	if (reg_debug) {		int i;		for (i = 0; i < len; ++i)			printk(" %02x", (unsigned char)buf[i]);		printk("\n");	}	if (!bufs)		return -ENOMEM;	memcpy(bufs, buf, len);	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,			      0x0000, reg, bufs, len, HZ);	if (dev->wait_after_write)		msleep(dev->wait_after_write);	kfree(bufs);	return ret;}int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len){	int rc;	rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);	/* Stores GPO/GPIO values at the cache, if changed	   Only write values should be stored, since input on a GPIO	   register will return the input bits.	   Not sure what happens on reading GPO register.	 */	if (rc >= 0) {		if (reg == EM2880_R04_GPO)			dev->reg_gpo = buf[0];		else if (reg == EM28XX_R08_GPIO)			dev->reg_gpio = buf[0];	}	return rc;}/* * em28xx_write_reg_bits() * sets only some bits (specified by bitmask) of a register, by first reading * the actual value */static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,				 u8 bitmask){	int oldval;	u8 newval;	/* Uses cache for gpo/gpio registers */	if (reg == EM2880_R04_GPO)		oldval = dev->reg_gpo;	else if (reg == EM28XX_R08_GPIO)		oldval = dev->reg_gpio;	else		oldval = em28xx_read_reg(dev, reg);	if (oldval < 0)		return oldval;	newval = (((u8) oldval) & ~bitmask) | (val & bitmask);	return em28xx_write_regs(dev, reg, &newval, 1);}/* * em28xx_write_ac97() * write a 16 bit value to the specified AC97 address (LSB first!) */static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val){	int ret, i;	u8 addr = reg & 0x7f;	ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2);	if (ret < 0)		return ret;	ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);	if (ret < 0)		return ret;	/* Wait up to 50 ms for AC97 command to complete */	for (i = 0; i < 10; i++) {		ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);		if (ret < 0)			return ret;		if (!(ret & 0x01))			return 0;		msleep(5);	}	em28xx_warn("AC97 command still being executed: not handled properly!\n");	return 0;}static int em28xx_set_audio_source(struct em28xx *dev){	static char *enable  = "\x08\x08";	static char *disable = "\x08\x88";	char *video = enable, *line = disable;	int ret;	u8 input;	if (dev->is_em2800) {		if (dev->ctl_ainput)			input = EM2800_AUDIO_SRC_LINE;		else			input = EM2800_AUDIO_SRC_TUNER;		ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);		if (ret < 0)			return ret;	}	if (dev->has_msp34xx)		input = EM28XX_AUDIO_SRC_TUNER;	else {		switch (dev->ctl_ainput) {		case EM28XX_AMUX_VIDEO:			input = EM28XX_AUDIO_SRC_TUNER;			break;		case EM28XX_AMUX_LINE_IN:			input = EM28XX_AUDIO_SRC_LINE;			break;		case EM28XX_AMUX_AC97_VIDEO:			input = EM28XX_AUDIO_SRC_LINE;			break;		case EM28XX_AMUX_AC97_LINE_IN:			input = EM28XX_AUDIO_SRC_LINE;			video = disable;			line  = enable;			break;		}	}	ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);	if (ret < 0)		return ret;	msleep(5);	/* Sets AC97 mixer registers	   This is seems to be needed, even for non-ac97 configs	 */	ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video);	if (ret < 0)		return ret;	ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line);	return ret;}int em28xx_audio_analog_set(struct em28xx *dev){	int ret;	char s[2] = { 0x00, 0x00 };	u8 xclk = 0x07;	s[0] |= 0x1f - dev->volume;	s[1] |= 0x1f - dev->volume;	/* Mute */	s[1] |= 0x80;	ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);	if (ret < 0)		return ret;	if (dev->has_12mhz_i2s)		xclk |= 0x20;	if (!dev->mute)		xclk |= 0x80;	ret = em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, xclk, 0xa7);	if (ret < 0)		return ret;	msleep(10);	/* Selects the proper audio input */	ret = em28xx_set_audio_source(dev);	/* Unmute device */	if (!dev->mute)		s[1] &= ~0x80;	ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);	return ret;}EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);int em28xx_colorlevels_set_default(struct em28xx *dev){	em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1);	/* contrast */	em28xx_write_regs(dev, EM28XX_R21_YOFFSET, "\x00", 1);	/* brightness */	em28xx_write_regs(dev, EM28XX_R22_UVGAIN, "\x10", 1);	/* saturation */	em28xx_write_regs(dev, EM28XX_R23_UOFFSET, "\x00", 1);	em28xx_write_regs(dev, EM28XX_R24_VOFFSET, "\x00", 1);	em28xx_write_regs(dev, EM28XX_R25_SHARPNESS, "\x00", 1);	em28xx_write_regs(dev, EM28XX_R14_GAMMA, "\x20", 1);	em28xx_write_regs(dev, EM28XX_R15_RGAIN, "\x20", 1);	em28xx_write_regs(dev, EM28XX_R16_GGAIN, "\x20", 1);	em28xx_write_regs(dev, EM28XX_R17_BGAIN, "\x20", 1);	em28xx_write_regs(dev, EM28XX_R18_ROFFSET, "\x00", 1);	em28xx_write_regs(dev, EM28XX_R19_GOFFSET, "\x00", 1);	return em28xx_write_regs(dev, EM28XX_R1A_BOFFSET, "\x00", 1);}int em28xx_capture_start(struct em28xx *dev, int start){	int rc;	/* FIXME: which is the best order? */	/* video registers are sampled by VREF */	rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,				   start ? 0x10 : 0x00, 0x10);	if (rc < 0)		return rc;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?