1 /* 2 * Driver for the Conexant CX23885/7/8 PCIe bridge 3 * 4 * Various common ioctl() support functions 5 * 6 * Copyright (c) 2009 Andy Walls <awalls@md.metrocast.net> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 */ 23 24 #include "cx23885.h" 25 #include "cx23885-ioctl.h" 26 27 #include <media/v4l2-chip-ident.h> 28 29 int cx23885_g_chip_ident(struct file *file, void *fh, 30 struct v4l2_dbg_chip_ident *chip) 31 { 32 struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; 33 int err = 0; 34 u8 rev; 35 36 chip->ident = V4L2_IDENT_NONE; 37 chip->revision = 0; 38 switch (chip->match.type) { 39 case V4L2_CHIP_MATCH_HOST: 40 switch (chip->match.addr) { 41 case 0: 42 rev = cx_read(RDR_CFG2) & 0xff; 43 switch (dev->pci->device) { 44 case 0x8852: 45 /* rev 0x04 could be '885 or '888. Pick '888. */ 46 if (rev == 0x04) 47 chip->ident = V4L2_IDENT_CX23888; 48 else 49 chip->ident = V4L2_IDENT_CX23885; 50 break; 51 case 0x8880: 52 if (rev == 0x0e || rev == 0x0f) 53 chip->ident = V4L2_IDENT_CX23887; 54 else 55 chip->ident = V4L2_IDENT_CX23888; 56 break; 57 default: 58 chip->ident = V4L2_IDENT_UNKNOWN; 59 break; 60 } 61 chip->revision = (dev->pci->device << 16) | (rev << 8) | 62 (dev->hwrevision & 0xff); 63 break; 64 case 1: 65 if (dev->v4l_device != NULL) { 66 chip->ident = V4L2_IDENT_CX23417; 67 chip->revision = 0; 68 } 69 break; 70 case 2: 71 /* 72 * The integrated IR controller on the CX23888 is 73 * host chip 2. It may not be used/initialized or sd_ir 74 * may be pointing at the cx25840 subdevice for the 75 * IR controller on the CX23885. Thus we find it 76 * without using the dev->sd_ir pointer. 77 */ 78 call_hw(dev, CX23885_HW_888_IR, core, g_chip_ident, 79 chip); 80 break; 81 default: 82 err = -EINVAL; /* per V4L2 spec */ 83 break; 84 } 85 break; 86 case V4L2_CHIP_MATCH_I2C_DRIVER: 87 /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */ 88 call_all(dev, core, g_chip_ident, chip); 89 break; 90 case V4L2_CHIP_MATCH_I2C_ADDR: 91 /* 92 * We could return V4L2_IDENT_UNKNOWN, but we don't do the work 93 * to look if a chip is at the address with no driver. That's a 94 * dangerous thing to do with EEPROMs anyway. 95 */ 96 call_all(dev, core, g_chip_ident, chip); 97 break; 98 default: 99 err = -EINVAL; 100 break; 101 } 102 return err; 103 } 104 105 #ifdef CONFIG_VIDEO_ADV_DEBUG 106 static int cx23885_g_host_register(struct cx23885_dev *dev, 107 struct v4l2_dbg_register *reg) 108 { 109 if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) 110 return -EINVAL; 111 112 reg->size = 4; 113 reg->val = cx_read(reg->reg); 114 return 0; 115 } 116 117 static int cx23417_g_register(struct cx23885_dev *dev, 118 struct v4l2_dbg_register *reg) 119 { 120 u32 value; 121 122 if (dev->v4l_device == NULL) 123 return -EINVAL; 124 125 if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000) 126 return -EINVAL; 127 128 if (mc417_register_read(dev, (u16) reg->reg, &value)) 129 return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ 130 131 reg->size = 4; 132 reg->val = value; 133 return 0; 134 } 135 136 int cx23885_g_register(struct file *file, void *fh, 137 struct v4l2_dbg_register *reg) 138 { 139 struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; 140 141 if (!capable(CAP_SYS_ADMIN)) 142 return -EPERM; 143 144 if (reg->match.type == V4L2_CHIP_MATCH_HOST) { 145 switch (reg->match.addr) { 146 case 0: 147 return cx23885_g_host_register(dev, reg); 148 case 1: 149 return cx23417_g_register(dev, reg); 150 default: 151 break; 152 } 153 } 154 155 /* FIXME - any error returns should not be ignored */ 156 call_all(dev, core, g_register, reg); 157 return 0; 158 } 159 160 static int cx23885_s_host_register(struct cx23885_dev *dev, 161 const struct v4l2_dbg_register *reg) 162 { 163 if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) 164 return -EINVAL; 165 166 cx_write(reg->reg, reg->val); 167 return 0; 168 } 169 170 static int cx23417_s_register(struct cx23885_dev *dev, 171 const struct v4l2_dbg_register *reg) 172 { 173 if (dev->v4l_device == NULL) 174 return -EINVAL; 175 176 if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000) 177 return -EINVAL; 178 179 if (mc417_register_write(dev, (u16) reg->reg, (u32) reg->val)) 180 return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ 181 return 0; 182 } 183 184 int cx23885_s_register(struct file *file, void *fh, 185 const struct v4l2_dbg_register *reg) 186 { 187 struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; 188 189 if (!capable(CAP_SYS_ADMIN)) 190 return -EPERM; 191 192 if (reg->match.type == V4L2_CHIP_MATCH_HOST) { 193 switch (reg->match.addr) { 194 case 0: 195 return cx23885_s_host_register(dev, reg); 196 case 1: 197 return cx23417_s_register(dev, reg); 198 default: 199 break; 200 } 201 } 202 203 /* FIXME - any error returns should not be ignored */ 204 call_all(dev, core, s_register, reg); 205 return 0; 206 } 207 #endif 208