Fix 6288 camera to work with hardware resolution changing
[microdia.git] / microdia-debugfs.c
blobcf910e59de893bdb959e5ff9eeb973508bcc3e7f
1 /**
2 * @file microdia-debugfs.c
3 * @author Brian johnson
4 * @date 2008-03-28
6 * @brief Debugfs interface for direct device manipulation
8 * @note Copyright (C) Brian Johnson
10 * @par Licences
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <linux/debugfs.h>
28 #include <linux/seq_file.h>
30 #include "microdia.h"
31 #include "sn9c20x.h"
33 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
34 #undef DEFINE_SIMPLE_ATTRIBUTE
35 #define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \
36 static void __fops ## _set_wrapper(void *data, __u64 val) \
37 { \
38 __set(data, val); \
39 } \
40 static __u64 __fops ## _get_wrapper(void *data) \
41 { \
42 __u64 value; \
43 __get(data, &value); \
44 return value; \
45 } \
46 static int __fops ## _open(struct inode *inode, struct file *file) \
47 { \
48 __simple_attr_check_format(__fmt, 0ull); \
49 return simple_attr_open(inode, file, \
50 __fops ## _get_wrapper, \
51 __fops ## _set_wrapper, \
52 __fmt); \
53 } \
54 static struct file_operations __fops = { \
55 .owner = THIS_MODULE, \
56 .open = __fops ## _open, \
57 .release = simple_attr_close, \
58 .read = simple_attr_read, \
59 .write = simple_attr_write, \
61 #endif
63 /**
64 * @var debug_dir_name
65 * Name of our directory in debugfs
67 static const char *debug_dir_name = "microdia";
69 /**
70 * @var debug_dir
71 * Dentry for our debug dir (for cleanup)
73 static struct dentry *debug_dir;
75 struct kref debug_ref;
76 /**
77 * @var dent_log_level
78 * debugfs entry for dynamically changing the log level
80 static struct dentry *dent_log_level;
82 static int debugfs_u16_set(void *data, __u64 val)
84 *(u16 *)data = val;
85 return 0;
88 static int debugfs_u16_get(void *data, __u64 *val)
90 *val = *(u16 *)data;
91 return 0;
94 static int debugfs_u8_set(void *data, __u64 val)
96 *(u8 *)data = val;
97 return 0;
100 static int debugfs_u8_get(void *data, __u64 *val)
102 *val = *(u8 *)data;
103 return 0;
106 static void *bridge_dump_start(struct seq_file *m, loff_t *pos)
108 loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL);
109 if (spos == NULL)
110 return ERR_PTR(-ENOMEM);
112 if (*pos < 0 || *pos > 31)
113 return NULL;
115 *spos = *pos;
116 return spos;
119 static void *bridge_dump_next(struct seq_file *m, void *v, loff_t *pos)
121 loff_t *spos = (loff_t *)v;
122 *pos = ++(*spos);
124 if (*spos > 31)
125 return ERR_PTR(-EACCES);
127 return spos;
130 static void bridge_dump_stop(struct seq_file *m, void *v)
132 if (v && !IS_ERR(v))
133 kfree(v);
137 * @brief Print out the values of registers 0x1000-0x1200 of the bridge
139 * @param m
140 * @param v
142 * @return 0
145 static int bridge_dump_show(struct seq_file *m, void *v)
147 __u8 values[16];
148 loff_t *spos = (loff_t *)v;
149 __u16 reg = 0x1000 + (*spos * 16);
150 struct usb_microdia *dev = m->private;
152 if (usb_microdia_control_read(dev, reg, values, 16) < 0)
153 return -EACCES;
155 seq_printf(m, "0x%X %02X %02X %02X %02X %02X %02X %02X %02X "
156 "%02X %02X %02X %02X %02X %02X %02X %02X\n", reg,
157 values[0], values[1], values[2], values[3],
158 values[4], values[5], values[6], values[7],
159 values[8], values[9], values[10], values[11],
160 values[12], values[13], values[14], values[15]);
162 return 0;
165 static struct seq_operations bridge_dump_seq_ops = {
166 .start = bridge_dump_start,
167 .next = bridge_dump_next,
168 .stop = bridge_dump_stop,
169 .show = bridge_dump_show
172 static int bridge_dump_open(struct inode *inode, struct file *file)
174 int ret;
175 ret = seq_open(file, &bridge_dump_seq_ops);
176 if (ret == 0)
177 ((struct seq_file *)file->private_data)->private =
178 inode->i_private;
179 return ret;
182 static struct file_operations bridge_dump_ops = {
183 .owner = THIS_MODULE,
184 .open = bridge_dump_open,
185 .read = seq_read,
186 .llseek = seq_lseek,
187 .release = seq_release,
191 * @brief Set the value for a specific register of the bridge
193 * @param data
194 * @param val
196 * @return 0
199 int bridge_value_set(void *data, __u64 val)
201 struct usb_microdia *dev = data;
202 __u8 value = (__u64)val;
203 if (dev != NULL) {
204 if (dev->debug.bridge_addr >= 0x1000 &&
205 dev->debug.bridge_addr <= 0x11ff) {
206 usb_microdia_control_write(dev,
207 dev->debug.bridge_addr,
208 &value, 1);
211 return 0;
215 * @brief Print out the value of a specific register of the bridge
217 * @param data
218 * @param val
220 * @return 0
223 int bridge_value_get(void *data, __u64 *val)
225 struct usb_microdia *dev = data;
226 __u8 value;
227 if (dev != NULL) {
228 if (dev->debug.bridge_addr >= 0x1000 &&
229 dev->debug.bridge_addr <= 0x11ff) {
230 if (usb_microdia_control_read(dev,
231 dev->debug.bridge_addr,
232 &value, 1) >= 0) {
233 *val = value;
237 return 0;
241 * @brief Set the value (8-bit) for a specific register of the sensor
243 * @param data
244 * @param val
246 * @return 0
249 int sensor_value8_set(void *data, __u64 val)
251 struct usb_microdia *dev = data;
252 __u8 value = (__u8)val;
253 if (dev != NULL) {
254 sn9c20x_write_i2c_data(dev, dev->sensor_slave_address,
255 1, dev->debug.sensor_addr,
256 dev->sensor_flags, &value);
258 return 0;
262 * @brief Print out the value (8-bit) of a specific register of the sensor
264 * @param data
265 * @param val
267 * @return 0
270 int sensor_value8_get(void *data, __u64 *val)
272 struct usb_microdia *dev = data;
273 __u8 value;
274 if (dev != NULL) {
275 if (sn9c20x_read_i2c_data(dev, dev->sensor_slave_address,
276 1, dev->debug.sensor_addr,
277 dev->sensor_flags, &value) >= 0) {
278 *val = value & 0xFF;
281 return 0;
285 * @brief Set the value (16-bit) for a specific register of the sensor
287 * @param data
288 * @param val
290 * @return 0
293 int sensor_value16_set(void *data, __u64 val)
295 struct usb_microdia *dev = data;
296 __u8 buf[2];
297 buf[0] = (val >> 8) & 0xFF;
298 buf[1] = val & 0xFF;
299 if (dev != NULL) {
300 sn9c20x_write_i2c_data(dev, dev->sensor_slave_address,
301 2, dev->debug.sensor_addr,
302 dev->sensor_flags, buf);
304 return 0;
308 * @brief Print out the value (16-bit) of a specific register of the sensor
310 * @param data
311 * @param val
313 * @return 0
316 int sensor_value16_get(void *data, __u64 *val)
318 struct usb_microdia *dev = data;
319 __u8 buf[2];
320 if (dev != NULL) {
321 if (sn9c20x_read_i2c_data(dev, dev->sensor_slave_address,
322 2, dev->debug.sensor_addr,
323 dev->sensor_flags, buf) >= 0) {
324 *val = ((buf[0] << 8) | buf[1]) & 0xFFFF;
327 return 0;
331 * @brief Set the value (32-bit) for a specific register of the sensor
333 * @param data
334 * @param val
336 * @return 0
339 int sensor_value32_set(void *data, __u64 val)
341 struct usb_microdia *dev = data;
342 __u8 buf[4];
343 buf[0] = (val >> 24) & 0xFF;
344 buf[1] = (val >> 16) & 0xFF;
345 buf[2] = (val >> 8) & 0xFF;
346 buf[3] = val & 0xFF;
347 if (dev != NULL) {
348 sn9c20x_write_i2c_data(dev, dev->sensor_slave_address,
349 4, dev->debug.sensor_addr,
350 dev->sensor_flags, buf);
352 return 0;
356 * @brief Print out the value (32-bit) of a specific register of the sensor
358 * @param data
359 * @param val
361 * @return 0
364 int sensor_value32_get(void *data, __u64 *val)
366 struct usb_microdia *dev = data;
367 __u8 buf[4];
368 if (dev != NULL) {
369 if (sn9c20x_read_i2c_data(dev, dev->sensor_slave_address,
370 4, dev->debug.sensor_addr,
371 dev->sensor_flags, buf) >= 0) {
372 *val = ((buf[0] << 24) | (buf[1] << 16)
373 | (buf[2] << 8) | buf[3]) & 0xFFFFFFFF;
376 return 0;
379 DEFINE_SIMPLE_ATTRIBUTE(fops_x16,
380 debugfs_u16_get,
381 debugfs_u16_set,
382 "0x%04llx\n");
384 DEFINE_SIMPLE_ATTRIBUTE(fops_x8,
385 debugfs_u8_get,
386 debugfs_u8_set,
387 "0x%02llx\n");
389 DEFINE_SIMPLE_ATTRIBUTE(bridge_value_ops,
390 bridge_value_get,
391 bridge_value_set,
392 "0x%02llx\n");
394 DEFINE_SIMPLE_ATTRIBUTE(sensor_value8_ops,
395 sensor_value8_get,
396 sensor_value8_set,
397 "0x%02llX\n");
399 DEFINE_SIMPLE_ATTRIBUTE(sensor_value16_ops,
400 sensor_value16_get,
401 sensor_value16_set,
402 "0x%04llX\n");
404 DEFINE_SIMPLE_ATTRIBUTE(sensor_value32_ops,
405 sensor_value32_get,
406 sensor_value32_set,
407 "0x%08llX\n");
409 void debugfs_delete(struct kref *ref)
411 if (debug_dir)
412 debugfs_remove(debug_dir);
415 void microdia_init_debugfs()
417 debug_dir = debugfs_create_dir(debug_dir_name, NULL);
418 if (debug_dir)
419 dent_log_level = debugfs_create_u8("log_level",
420 S_IRUGO | S_IWUGO,
421 debug_dir,
422 &log_level);
423 kref_init(&debug_ref);
427 void microdia_uninit_debugfs()
429 if (dent_log_level)
430 debugfs_remove(dent_log_level);
431 kref_put(&debug_ref, debugfs_delete);
435 * @brief Create the 'debug' entries.
437 * This function permits to create all the entries in the 'debug' filesystem.
439 * @param dev device structure
441 * @returns 0 if all is OK
443 int microdia_create_debugfs_files(struct usb_microdia *dev)
445 char device_name[9];
446 if (debug_dir) {
447 snprintf(device_name, 9, "video%d", dev->vdev->minor);
448 dev->debug.dent_device =
449 debugfs_create_dir(device_name, debug_dir);
450 if (dev->debug.dent_device) {
451 dev->debug.bridge_addr = 0x1000;
452 dev->debug.sensor_addr = 0x00;
453 dev->debug.dent_bridge_addr =
454 debugfs_create_file("bridge.address",
455 S_IRUGO | S_IWUGO,
456 dev->debug.dent_device,
457 &dev->debug.bridge_addr,
458 &fops_x16);
459 dev->debug.dent_bridge_val =
460 debugfs_create_file("bridge.value",
461 S_IRUGO | S_IWUGO,
462 dev->debug.dent_device,
463 dev, &bridge_value_ops);
464 dev->debug.dent_bridge_dump =
465 debugfs_create_file("bridge.dump",
466 S_IRUGO,
467 dev->debug.dent_device,
468 dev, &bridge_dump_ops);
469 dev->debug.dent_sensor_addr =
470 debugfs_create_file("sensor.address",
471 S_IRUGO | S_IWUGO,
472 dev->debug.dent_device,
473 &dev->debug.sensor_addr,
474 &fops_x8);
475 dev->debug.dent_sensor_val8 =
476 debugfs_create_file("sensor.value8",
477 S_IRUGO | S_IWUGO,
478 dev->debug.dent_device,
479 dev, &sensor_value8_ops);
480 dev->debug.dent_sensor_val16 =
481 debugfs_create_file("sensor.value16",
482 S_IRUGO | S_IWUGO,
483 dev->debug.dent_device,
484 dev, &sensor_value16_ops);
485 dev->debug.dent_sensor_val32 =
486 debugfs_create_file("sensor.value32",
487 S_IRUGO | S_IWUGO,
488 dev->debug.dent_device,
489 dev, &sensor_value32_ops);
492 kref_get(&debug_ref);
493 return 0;
497 * @brief Remove the 'debugfs' entries.
499 * This function permits to remove all the entries in the 'debug' filesystem.
501 * @param dev device structure
503 * @returns 0 if all is OK
505 int microdia_remove_debugfs_files(struct usb_microdia *dev)
507 if (dev->debug.dent_bridge_val)
508 debugfs_remove(dev->debug.dent_bridge_val);
509 if (dev->debug.dent_bridge_addr)
510 debugfs_remove(dev->debug.dent_bridge_addr);
511 if (dev->debug.dent_bridge_dump)
512 debugfs_remove(dev->debug.dent_bridge_dump);
513 if (dev->debug.dent_sensor_addr)
514 debugfs_remove(dev->debug.dent_sensor_addr);
515 if (dev->debug.dent_sensor_val8)
516 debugfs_remove(dev->debug.dent_sensor_val8);
517 if (dev->debug.dent_sensor_val16)
518 debugfs_remove(dev->debug.dent_sensor_val16);
519 if (dev->debug.dent_sensor_val32)
520 debugfs_remove(dev->debug.dent_sensor_val32);
521 if (dev->debug.dent_device)
522 debugfs_remove(dev->debug.dent_device);
523 kref_put(&debug_ref, debugfs_delete);
524 return 0;