saa5249.c
来自「trident tm5600的linux驱动」· C语言 代码 · 共 642 行 · 第 1/2 页
C
642 行
info.headline = !!(infobits[5] & 4); info.subtitle = !!(infobits[5] & 8); info.supp_header = !!(infobits[6] & 1); info.update = !!(infobits[6] & 2); info.inter_seq = !!(infobits[6] & 4); info.dis_disp = !!(infobits[6] & 8); info.serial = !!(infobits[7] & 1); info.notfound = !!(infobits[8] & 0x10); info.pblf = !!(infobits[9] & 0x20); info.hamming = 0; for (a = 0; a <= 7; a++) { if (infobits[a] & 0xf0) { info.hamming = 1; break; } } if (t->vdau[req->pgbuf].clrfound) info.notfound = 1; if (copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t))) return -EFAULT; if (!info.hamming && !info.notfound) t->is_searching[req->pgbuf] = false; return 0; } case VTXIOCGETPAGE: { vtx_pagereq_t *req = arg; int start, end; if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 || req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE)) return -EINVAL; if (copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1)) return -EFAULT; /* * Always read the time directly from SAA5249 */ if (req->start <= 39 && req->end >= 32) { int len; char buf[16]; start = max(req->start, 32); end = min(req->end, 39); len = end - start + 1; if (i2c_senddata(t, 8, 0, 0, start, -1) || i2c_getdata(t, len, buf)) return -EIO; if (copy_to_user(req->buffer + start - req->start, buf, len)) return -EFAULT; } /* Insert the current header if DAU is still searching for a page */ if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf]) { char buf[32]; int len; start = max(req->start, 7); end = min(req->end, 31); len = end - start + 1; if (i2c_senddata(t, 8, 0, 0, start, -1) || i2c_getdata(t, len, buf)) return -EIO; if (copy_to_user(req->buffer + start - req->start, buf, len)) return -EFAULT; } return 0; } case VTXIOCSTOPDAU: { vtx_pagereq_t *req = arg; if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS) return -EINVAL; t->vdau[req->pgbuf].stopped = true; t->is_searching[req->pgbuf] = false; return 0; } case VTXIOCPUTPAGE: case VTXIOCSETDISP: case VTXIOCPUTSTAT: return 0; case VTXIOCCLRCACHE: { if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1)) return -EIO; if (i2c_senddata(t, 3, 0x20, -1)) return -EIO; jdelay(10 * CLEAR_DELAY); /* I have no idea how long we have to wait here */ return 0; } case VTXIOCSETVIRT: { /* The SAA5249 has virtual-row reception turned on always */ t->virtual_mode = (int)(long)arg; return 0; } } return -EINVAL;}/* * Translates old vtx IOCTLs to new ones * * This keeps new kernel versions compatible with old userspace programs. */static inline unsigned int vtx_fix_command(unsigned int cmd){ switch (cmd) { case VTXIOCGETINFO_OLD: cmd = VTXIOCGETINFO; break; case VTXIOCCLRPAGE_OLD: cmd = VTXIOCCLRPAGE; break; case VTXIOCCLRFOUND_OLD: cmd = VTXIOCCLRFOUND; break; case VTXIOCPAGEREQ_OLD: cmd = VTXIOCPAGEREQ; break; case VTXIOCGETSTAT_OLD: cmd = VTXIOCGETSTAT; break; case VTXIOCGETPAGE_OLD: cmd = VTXIOCGETPAGE; break; case VTXIOCSTOPDAU_OLD: cmd = VTXIOCSTOPDAU; break; case VTXIOCPUTPAGE_OLD: cmd = VTXIOCPUTPAGE; break; case VTXIOCSETDISP_OLD: cmd = VTXIOCSETDISP; break; case VTXIOCPUTSTAT_OLD: cmd = VTXIOCPUTSTAT; break; case VTXIOCCLRCACHE_OLD: cmd = VTXIOCCLRCACHE; break; case VTXIOCSETVIRT_OLD: cmd = VTXIOCSETVIRT; break; } return cmd;}/* * Handle the locking */static int saa5249_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct saa5249_device *t = video_drvdata(file); int err; cmd = vtx_fix_command(cmd); mutex_lock(&t->lock); err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl); mutex_unlock(&t->lock); return err;}static int saa5249_open(struct inode *inode, struct file *file){ struct saa5249_device *t = video_drvdata(file); int pgbuf; if (t->client == NULL) return -ENODEV; if (test_and_set_bit(0, &t->in_use)) return -EBUSY; if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */ /* Turn off parity checks (we do this ourselves) */ i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) || /* Display TV-picture, no virtual rows */ i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1)) /* Set display to page 4 */ { clear_bit(0, &t->in_use); return -EIO; } for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) { memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf)); memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs)); memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat)); t->vdau[pgbuf].expire = 0; t->vdau[pgbuf].clrfound = true; t->vdau[pgbuf].stopped = true; t->is_searching[pgbuf] = false; } t->virtual_mode = false; return 0;}static int saa5249_release(struct inode *inode, struct file *file){ struct saa5249_device *t = video_drvdata(file); i2c_senddata(t, 1, 0x20, -1); /* Turn off CCT */ i2c_senddata(t, 5, 3, 3, -1); /* Turn off TV-display */ clear_bit(0, &t->in_use); return 0;}static const struct file_operations saa_fops = { .owner = THIS_MODULE, .open = saa5249_open, .release = saa5249_release, .ioctl = saa5249_ioctl,#ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32,#endif .llseek = no_llseek,};static struct video_device saa_template ={ .name = "saa5249", .fops = &saa_fops, .release = video_device_release,};/* Addresses to scan */static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };I2C_CLIENT_INSMOD;static int saa5249_probe(struct i2c_client *client, const struct i2c_device_id *id){ int pgbuf; int err; struct video_device *vd; struct saa5249_device *t; v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); v4l_info(client, "VideoText version %d.%d\n", VTX_VER_MAJ, VTX_VER_MIN); t = kzalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) return -ENOMEM; mutex_init(&t->lock); /* Now create a video4linux device */ vd = kmalloc(sizeof(struct video_device), GFP_KERNEL); if (vd == NULL) { kfree(client); return -ENOMEM; } i2c_set_clientdata(client, vd); memcpy(vd, &saa_template, sizeof(*vd)); for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) { memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf)); memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs)); memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat)); t->vdau[pgbuf].expire = 0; t->vdau[pgbuf].clrfound = true; t->vdau[pgbuf].stopped = true; t->is_searching[pgbuf] = false; } video_set_drvdata(vd, t); /* Register it */ err = video_register_device(vd, VFL_TYPE_VTX, -1); if (err < 0) { kfree(t); kfree(vd); return err; } t->client = client; return 0;}static int saa5249_remove(struct i2c_client *client){ struct video_device *vd = i2c_get_clientdata(client); video_unregister_device(vd); kfree(video_get_drvdata(vd)); kfree(vd); return 0;}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)static const struct i2c_device_id saa5249_id[] = { { "saa5249", 0 }, { }};MODULE_DEVICE_TABLE(i2c, saa5249_id);#endifstatic struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "saa5249", .driverid = I2C_DRIVERID_SAA5249, .probe = saa5249_probe, .remove = saa5249_remove,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) .id_table = saa5249_id,#endif};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?