📄 saa7113-new.c
字号:
/* SAA7113 - Philips video decoder driver Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> for Convergence Integrated Media GmbH based on the SAAA7110 and SAA7111 drivers by: Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl> Copyright (C) 1998 Dave Perks <dperks@ibm.net> 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/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/mm.h>#include <linux/pci.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/video_decoder.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/version.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/page.h>#include <asm/segment.h>#include <linux/videodev.h>#include <linux/i2c.h>#include <linux/video_decoder.h>#define DEBUG(x) /* remove when no long debugging */#define I2C_DELAY 10 /* 10 us or 100khz *///addresses to scanstatic unsigned short normal_i2c[] = { I2C_CLIENT_END };static unsigned short normal_i2c_range[] = { 0x48>>1, 0x4A>>1, I2C_CLIENT_END };static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static struct i2c_client_address_data addr_data = { normal_i2c, normal_i2c_range, probe, probe_range, ignore, ignore_range, force};static struct i2c_client client_template;struct saa7113 { struct i2c_client *client; int addr; unsigned char reg[0x62]; int norm; int input; int enable; int bright; int contrast; int hue; int sat;};/* helper functions to access driver private data. */static inline void *i2c_get_clientdata(struct i2c_client *client){ return client->data;}static inline void i2c_set_clientdata(struct i2c_client *client, void *data){ client->data = data;}static int saa7113_write(struct i2c_client *client, unsigned char reg, unsigned char data){ struct saa7113 *decoder = i2c_get_clientdata(client); int ret; unsigned char msg[] = {0x1f, 0x00}; msg[0]=reg; msg[1]=data; ret=i2c_master_send(client, msg, 2); if (ret!=2) { printk("saa7113_write error\n"); } decoder->reg[reg]=data; return ret;}static int saa7113_write_block(struct i2c_client *client, const unsigned char *regs){ unsigned char reg, data; while (*regs!=0xff) { reg =*(regs++); data=*(regs++); if (saa7113_write(client, reg, data)<0) return -1; } return 0;}static int saa7113_read(struct i2c_client *client, unsigned char subaddr){ unsigned char buffer; if (1 != i2c_master_send(client, &subaddr, 1)) { printk(KERN_WARNING "saa7113: I/O error, trying (write %d)\n", subaddr); return -1; } if (1 != i2c_master_recv(client, &buffer, 1)) { printk(KERN_WARNING "saa7113: I/O error, trying (read)\n"); return -1; } printk(KERN_WARNING "saa7113_read 0x%02X\n", buffer); return (int)buffer;}static const unsigned char init_saa7113[] = { 0x01, 0x08, 0x02, 0xc0, /* c7 s-video */ 0x03, 0x23, 0x04, 0x00, 0x05, 0x00, 0x06, 0xe9, /* Start of hsync */ 0x07, 0x0d, /* End of hsync */ 0x08, 0x88, 0x09, 0x00, 0x0a, 0x80, 0x0b, 0x47, 0x0c, 0x40, 0x0d, 0x00, 0x0e, 0x01, 0x0f, 0x2a, /* Use automatic chromance gain */ 0x10, 0x28, 0x11, 0x1C, 0x12, 0xc8, /* RTS0 -> programmable HS, RTS1 -> V123., don't know about RTS1 */ 0x13, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x0a, 0x5b, 0x83, 0x5e, 0x00, 0xff};void init(struct i2c_client *client){ struct saa7113 *decoder = i2c_get_clientdata(client); decoder->addr = client->addr; decoder->norm = VIDEO_MODE_AUTO; decoder->input = 0; decoder->enable = 1; decoder->bright = 32768; decoder->contrast = 32768; decoder->hue = 32768; decoder->sat = 32768; decoder->client=client; saa7113_write_block(client, init_saa7113); printk("saa7113: status=%02x\n", saa7113_read(client, 0x1f));}static int saa7113_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind){ struct saa7113 *decoder; struct i2c_client *client; client = kmalloc(sizeof *client, GFP_KERNEL); if (!client) return -ENOMEM; memcpy(client, &client_template, sizeof(struct i2c_client)); client->adapter = adap; client->addr = addr; strcpy(client->name, "saa7113"); decoder=kmalloc(sizeof(struct saa7113),GFP_KERNEL); if (decoder==NULL) { kfree(client); return -ENOMEM; } i2c_set_clientdata(client, decoder); memset(decoder, 0, sizeof(struct saa7113)); init(client); printk("saa7113: version=%02x\n", saa7113_read(client, 0x00)); MOD_INC_USE_COUNT; printk("saa7113: attaching SAA7113 at 0x%02x\n", (client->addr)<<1); i2c_attach_client(client); printk("saa7113: attached to adapter %s\n", adap->name); return 0;}/* ----------------------------------------------------------------------- */static int saa7113_probe(struct i2c_adapter *adap){ return i2c_probe(adap, &addr_data, saa7113_attach);}int saa7113_detach(struct i2c_client *client){ i2c_detach_client(client); kfree(i2c_get_clientdata(client)); kfree(client); MOD_DEC_USE_COUNT; return 0;}static int saa7113_command(struct i2c_client *client, unsigned int cmd, void *arg){ struct saa7113 *decoder = i2c_get_clientdata(client); int v; switch (cmd) { case DECODER_GET_CAPABILITIES: { struct video_decoder_capability *dc = arg; dc->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC | VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR; dc->inputs = 8; dc->outputs = 1; break; } case DECODER_GET_STATUS: { int *iarg = arg; int status; int res; status = saa7113_read(client, 0x1f); res = 0; if ((status & (1 << 6)) == 0) { res |= DECODER_STATUS_GOOD; } switch (decoder->norm) { case VIDEO_MODE_NTSC: res |= DECODER_STATUS_NTSC; break; case VIDEO_MODE_PAL: res |= DECODER_STATUS_PAL; break; case VIDEO_MODE_SECAM: res |= DECODER_STATUS_SECAM; break; default: case VIDEO_MODE_AUTO: if ((status & (1 << 5)) != 0) { res |= DECODER_STATUS_NTSC; } else { res |= DECODER_STATUS_PAL; } break; } if ((status & (1 << 0)) != 0) { res |= DECODER_STATUS_COLOR; } *iarg = res; break; } case DECODER_SET_NORM: { v = *(int*)arg; switch (v) { case VIDEO_MODE_NTSC: { //Field selection 60Hz saa7113_write(client, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40); //Colour standard NTSC_MJ saa7113_write(client, 0x0E, (decoder->reg[0x0E] & 0x8F) | 0x00); break; } case VIDEO_MODE_PAL: { //Field selection 50Hz saa7113_write(client, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00); //Colour standard PAL_BGHI saa7113_write(client, 0x0E, (decoder->reg[0x0E] & 0x8F) | 0x00); break; } case VIDEO_MODE_SECAM: { //Field selection 50Hz saa7113_write(client, 0x08, (decoder->reg[0x08] & 0x3F) | 0x00); //Colour standard PAL/SECAM saa7113_write(client, 0x0E, (decoder->reg[0x0E] & 0x8F) | 0x50); break; } case VIDEO_MODE_AUTO: { //Field selection auto saa7113_write(client, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80); //Colour standard PAL_BGHI/NTSC_MJ saa7113_write(client, 0x0E, (decoder->reg[0x0E] & 0x8F) | 0x00); break; } default: printk(KERN_WARNING "Could not determine video mode for usbvision device"); return -EINVAL; } decoder->norm = v; break; } case DECODER_SET_INPUT: { int *iarg = arg; if (*iarg < 0 || *iarg > 7) { return -EINVAL; } if (decoder->input != *iarg) { decoder->input = *iarg; /* select mode */ saa7113_write(client, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); /* bypass chrominance trap for modes 4..7 */ saa7113_write(client, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0)); } break; } case DECODER_SET_OUTPUT: { v = *(int*)arg; // not much choice of outputs if (v != 0) { return -EINVAL; } break; } case DECODER_ENABLE_OUTPUT: { int *iarg = arg; int enable = (*iarg != 0); if (decoder->enable != enable) { decoder->enable = enable; // RJ: If output should be disabled (for playing videos), we also need a open PLL. // The input is set to 0 (where no input source is connected), although this // is not necessary. // // If output should be enabled, we have to reverse the above. if (decoder->enable) { saa7113_write(client, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); saa7113_write(client, 0x08, (decoder->reg[0x08] & 0xfb)); saa7113_write(client, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c); } else { saa7113_write(client, 0x02, (decoder->reg[0x02] & 0xf8)); saa7113_write(client, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04); saa7113_write(client, 0x11, (decoder->reg[0x11] & 0xf3)); } } break; } case DECODER_SET_PICTURE: { struct video_picture *pic = arg; if (decoder->bright != pic->brightness) { /* We want 0 to 255 we get 0-65535 */ decoder->bright = pic->brightness; saa7113_write(client, 0x0a, decoder->bright >> 8); } if (decoder->contrast != pic->contrast) { /* We want 0 to 127 we get 0-65535 */ decoder->contrast = pic->contrast; saa7113_write(client, 0x0b, decoder->contrast >> 9); } if (decoder->sat != pic->colour) { /* We want 0 to 127 we get 0-65535 */ decoder->sat = pic->colour; saa7113_write(client, 0x0c, decoder->sat >> 9); } if (decoder->hue != pic->hue) { /* We want -128 to 127 we get 0-65535 */ decoder->hue = pic->hue; saa7113_write(client, 0x0d, (decoder->hue - 32768) >> 8); } break; } default: return -EINVAL; } return 0;}static struct i2c_driver saa7113_driver = { .name = "SAA7113", .id = I2C_DRIVERID_SAA7113, .flags = I2C_DF_NOTIFY, .attach_adapter = saa7113_probe, .detach_client = saa7113_detach, .command = saa7113_command,};static struct i2c_client client_template = { .name = "(unset)", .id = I2C_DRIVERID_SAA7113, .flags = 0, .addr = 0, .adapter = NULL, .driver = &saa7113_driver,};#ifdef MODULEint init_module(void)#elseint saa7113_init(void)#endif{ int res; if ((res = i2c_add_driver(&saa7113_driver))) { printk("saa7113: Driver registration failed, module not inserted.\n"); return res; } printk("saa7113: init_module\n"); return 0;}#ifdef MODULEvoid cleanup_module(void){ int res; if ((res = i2c_del_driver(&saa7113_driver))) { printk("saa7113: Driver deregistration failed, " "module not removed.\n"); }}#endifMODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -