indycam.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. /*
  2. * indycam.c - Silicon Graphics IndyCam digital camera driver
  3. *
  4. * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
  5. * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/module.h>
  12. #include <linux/init.h>
  13. #include <linux/delay.h>
  14. #include <linux/errno.h>
  15. #include <linux/fs.h>
  16. #include <linux/kernel.h>
  17. #include <linux/major.h>
  18. #include <linux/slab.h>
  19. #include <linux/mm.h>
  20. #include <linux/sched.h>
  21. #include <linux/videodev.h>
  22. /* IndyCam decodes stream of photons into digital image representation ;-) */
  23. #include <linux/video_decoder.h>
  24. #include <linux/i2c.h>
  25. #include "indycam.h"
  26. //#define INDYCAM_DEBUG
  27. #define INDYCAM_MODULE_VERSION "0.0.3"
  28. MODULE_DESCRIPTION("SGI IndyCam driver");
  29. MODULE_VERSION(INDYCAM_MODULE_VERSION);
  30. MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
  31. MODULE_LICENSE("GPL");
  32. #ifdef INDYCAM_DEBUG
  33. #define dprintk(x...) printk("IndyCam: " x);
  34. #define indycam_regdump(client) indycam_regdump_debug(client)
  35. #else
  36. #define dprintk(x...)
  37. #define indycam_regdump(client)
  38. #endif
  39. #define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO)
  40. struct indycam {
  41. struct i2c_client *client;
  42. int version;
  43. };
  44. static struct i2c_driver i2c_driver_indycam;
  45. static const unsigned char initseq[] = {
  46. INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */
  47. INDYCAM_SHUTTER_DEFAULT, /* INDYCAM_SHUTTER */
  48. INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */
  49. 0x00, /* INDYCAM_BRIGHTNESS (read-only) */
  50. INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */
  51. INDYCAM_BLUE_BALANCE_DEFAULT, /* INDYCAM_BLUE_BALANCE */
  52. INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */
  53. INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */
  54. };
  55. /* IndyCam register handling */
  56. static int indycam_read_reg(struct i2c_client *client, unsigned char reg,
  57. unsigned char *value)
  58. {
  59. int ret;
  60. if (reg == INDYCAM_RESET) {
  61. dprintk("indycam_read_reg(): "
  62. "skipping write-only register %d\n", reg);
  63. *value = 0;
  64. return 0;
  65. }
  66. ret = i2c_smbus_read_byte_data(client, reg);
  67. if (ret < 0) {
  68. printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, "
  69. "register = 0x%02x\n", reg);
  70. return ret;
  71. }
  72. *value = (unsigned char)ret;
  73. return 0;
  74. }
  75. static int indycam_write_reg(struct i2c_client *client, unsigned char reg,
  76. unsigned char value)
  77. {
  78. int err;
  79. if ((reg == INDYCAM_BRIGHTNESS)
  80. || (reg == INDYCAM_VERSION)) {
  81. dprintk("indycam_write_reg(): "
  82. "skipping read-only register %d\n", reg);
  83. return 0;
  84. }
  85. dprintk("Writing Reg %d = 0x%02x\n", reg, value);
  86. err = i2c_smbus_write_byte_data(client, reg, value);
  87. if (err) {
  88. printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, "
  89. "register = 0x%02x, value = 0x%02x\n", reg, value);
  90. }
  91. return err;
  92. }
  93. static int indycam_write_block(struct i2c_client *client, unsigned char reg,
  94. unsigned char length, unsigned char *data)
  95. {
  96. unsigned char i;
  97. int err;
  98. for (i = reg; i < length; i++) {
  99. err = indycam_write_reg(client, reg + i, data[i]);
  100. if (err)
  101. return err;
  102. }
  103. return 0;
  104. }
  105. /* Helper functions */
  106. #ifdef INDYCAM_DEBUG
  107. static void indycam_regdump_debug(struct i2c_client *client)
  108. {
  109. int i;
  110. unsigned char val;
  111. for (i = 0; i < 9; i++) {
  112. indycam_read_reg(client, i, &val);
  113. dprintk("Reg %d = 0x%02x\n", i, val);
  114. }
  115. }
  116. #endif
  117. static int indycam_get_controls(struct i2c_client *client,
  118. struct indycam_control *ctrl)
  119. {
  120. unsigned char ctrl_reg;
  121. indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg);
  122. ctrl->agc = (ctrl_reg & INDYCAM_CONTROL_AGCENA)
  123. ? INDYCAM_VALUE_ENABLED
  124. : INDYCAM_VALUE_DISABLED;
  125. ctrl->awb = (ctrl_reg & INDYCAM_CONTROL_AWBCTL)
  126. ? INDYCAM_VALUE_ENABLED
  127. : INDYCAM_VALUE_DISABLED;
  128. indycam_read_reg(client, INDYCAM_SHUTTER,
  129. (unsigned char *)&ctrl->shutter);
  130. indycam_read_reg(client, INDYCAM_GAIN,
  131. (unsigned char *)&ctrl->gain);
  132. indycam_read_reg(client, INDYCAM_RED_BALANCE,
  133. (unsigned char *)&ctrl->red_balance);
  134. indycam_read_reg(client, INDYCAM_BLUE_BALANCE,
  135. (unsigned char *)&ctrl->blue_balance);
  136. indycam_read_reg(client, INDYCAM_RED_SATURATION,
  137. (unsigned char *)&ctrl->red_saturation);
  138. indycam_read_reg(client, INDYCAM_BLUE_SATURATION,
  139. (unsigned char *)&ctrl->blue_saturation);
  140. indycam_read_reg(client, INDYCAM_GAMMA,
  141. (unsigned char *)&ctrl->gamma);
  142. return 0;
  143. }
  144. static int indycam_set_controls(struct i2c_client *client,
  145. struct indycam_control *ctrl)
  146. {
  147. unsigned char ctrl_reg;
  148. indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg);
  149. if (ctrl->agc != INDYCAM_VALUE_UNCHANGED) {
  150. if (ctrl->agc)
  151. ctrl_reg |= INDYCAM_CONTROL_AGCENA;
  152. else
  153. ctrl_reg &= ~INDYCAM_CONTROL_AGCENA;
  154. }
  155. if (ctrl->awb != INDYCAM_VALUE_UNCHANGED) {
  156. if (ctrl->awb)
  157. ctrl_reg |= INDYCAM_CONTROL_AWBCTL;
  158. else
  159. ctrl_reg &= ~INDYCAM_CONTROL_AWBCTL;
  160. }
  161. indycam_write_reg(client, INDYCAM_CONTROL, ctrl_reg);
  162. if (ctrl->shutter >= 0)
  163. indycam_write_reg(client, INDYCAM_SHUTTER, ctrl->shutter);
  164. if (ctrl->gain >= 0)
  165. indycam_write_reg(client, INDYCAM_GAIN, ctrl->gain);
  166. if (ctrl->red_balance >= 0)
  167. indycam_write_reg(client, INDYCAM_RED_BALANCE,
  168. ctrl->red_balance);
  169. if (ctrl->blue_balance >= 0)
  170. indycam_write_reg(client, INDYCAM_BLUE_BALANCE,
  171. ctrl->blue_balance);
  172. if (ctrl->red_saturation >= 0)
  173. indycam_write_reg(client, INDYCAM_RED_SATURATION,
  174. ctrl->red_saturation);
  175. if (ctrl->blue_saturation >= 0)
  176. indycam_write_reg(client, INDYCAM_BLUE_SATURATION,
  177. ctrl->blue_saturation);
  178. if (ctrl->gamma >= 0)
  179. indycam_write_reg(client, INDYCAM_GAMMA, ctrl->gamma);
  180. return 0;
  181. }
  182. /* I2C-interface */
  183. static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
  184. {
  185. int err = 0;
  186. struct indycam *camera;
  187. struct i2c_client *client;
  188. printk(KERN_INFO "SGI IndyCam driver version %s\n",
  189. INDYCAM_MODULE_VERSION);
  190. client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
  191. if (!client)
  192. return -ENOMEM;
  193. camera = kmalloc(sizeof(struct indycam), GFP_KERNEL);
  194. if (!camera) {
  195. err = -ENOMEM;
  196. goto out_free_client;
  197. }
  198. memset(client, 0, sizeof(struct i2c_client));
  199. memset(camera, 0, sizeof(struct indycam));
  200. client->addr = addr;
  201. client->adapter = adap;
  202. client->driver = &i2c_driver_indycam;
  203. client->flags = 0;
  204. strcpy(client->name, "IndyCam client");
  205. i2c_set_clientdata(client, camera);
  206. camera->client = client;
  207. err = i2c_attach_client(client);
  208. if (err)
  209. goto out_free_camera;
  210. camera->version = i2c_smbus_read_byte_data(client, INDYCAM_VERSION);
  211. if (camera->version != CAMERA_VERSION_INDY &&
  212. camera->version != CAMERA_VERSION_MOOSE) {
  213. err = -ENODEV;
  214. goto out_detach_client;
  215. }
  216. printk(KERN_INFO "IndyCam v%d.%d detected\n",
  217. INDYCAM_VERSION_MAJOR(camera->version),
  218. INDYCAM_VERSION_MINOR(camera->version));
  219. indycam_regdump(client);
  220. // initialize
  221. err = indycam_write_block(client, 0, sizeof(initseq),
  222. (unsigned char *)&initseq);
  223. if (err) {
  224. printk(KERN_ERR "IndyCam initalization failed\n");
  225. err = -EIO;
  226. goto out_detach_client;
  227. }
  228. indycam_regdump(client);
  229. // white balance
  230. err = indycam_write_reg(client, INDYCAM_CONTROL,
  231. INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
  232. if (err) {
  233. printk(KERN_ERR "IndyCam white balance "
  234. "initialization failed\n");
  235. err = -EIO;
  236. goto out_detach_client;
  237. }
  238. indycam_regdump(client);
  239. printk(KERN_INFO "IndyCam initialized\n");
  240. return 0;
  241. out_detach_client:
  242. i2c_detach_client(client);
  243. out_free_camera:
  244. kfree(camera);
  245. out_free_client:
  246. kfree(client);
  247. return err;
  248. }
  249. static int indycam_probe(struct i2c_adapter *adap)
  250. {
  251. /* Indy specific crap */
  252. if (adap->id == VINO_ADAPTER)
  253. return indycam_attach(adap, INDYCAM_ADDR, 0);
  254. /* Feel free to add probe here :-) */
  255. return -ENODEV;
  256. }
  257. static int indycam_detach(struct i2c_client *client)
  258. {
  259. struct indycam *camera = i2c_get_clientdata(client);
  260. i2c_detach_client(client);
  261. kfree(camera);
  262. kfree(client);
  263. return 0;
  264. }
  265. static int indycam_command(struct i2c_client *client, unsigned int cmd,
  266. void *arg)
  267. {
  268. // struct indycam *camera = i2c_get_clientdata(client);
  269. /* The old video_decoder interface just isn't enough,
  270. * so we'll use some custom commands. */
  271. switch (cmd) {
  272. case DECODER_GET_CAPABILITIES: {
  273. struct video_decoder_capability *cap = arg;
  274. cap->flags = VIDEO_DECODER_NTSC;
  275. cap->inputs = 1;
  276. cap->outputs = 1;
  277. break;
  278. }
  279. case DECODER_GET_STATUS: {
  280. int *iarg = arg;
  281. *iarg = DECODER_STATUS_GOOD | DECODER_STATUS_NTSC |
  282. DECODER_STATUS_COLOR;
  283. break;
  284. }
  285. case DECODER_SET_NORM: {
  286. int *iarg = arg;
  287. switch (*iarg) {
  288. case VIDEO_MODE_NTSC:
  289. break;
  290. default:
  291. return -EINVAL;
  292. }
  293. break;
  294. }
  295. case DECODER_SET_INPUT: {
  296. int *iarg = arg;
  297. if (*iarg != 0)
  298. return -EINVAL;
  299. break;
  300. }
  301. case DECODER_SET_OUTPUT: {
  302. int *iarg = arg;
  303. if (*iarg != 0)
  304. return -EINVAL;
  305. break;
  306. }
  307. case DECODER_ENABLE_OUTPUT: {
  308. /* Always enabled */
  309. break;
  310. }
  311. case DECODER_SET_PICTURE: {
  312. // struct video_picture *pic = arg;
  313. /* TODO: convert values for indycam_set_controls() */
  314. break;
  315. }
  316. case DECODER_INDYCAM_GET_CONTROLS: {
  317. struct indycam_control *ctrl = arg;
  318. indycam_get_controls(client, ctrl);
  319. }
  320. case DECODER_INDYCAM_SET_CONTROLS: {
  321. struct indycam_control *ctrl = arg;
  322. indycam_set_controls(client, ctrl);
  323. }
  324. default:
  325. return -EINVAL;
  326. }
  327. return 0;
  328. }
  329. static struct i2c_driver i2c_driver_indycam = {
  330. .owner = THIS_MODULE,
  331. .name = "indycam",
  332. .id = I2C_DRIVERID_INDYCAM,
  333. .flags = I2C_DF_NOTIFY,
  334. .attach_adapter = indycam_probe,
  335. .detach_client = indycam_detach,
  336. .command = indycam_command,
  337. };
  338. static int __init indycam_init(void)
  339. {
  340. return i2c_add_driver(&i2c_driver_indycam);
  341. }
  342. static void __exit indycam_exit(void)
  343. {
  344. i2c_del_driver(&i2c_driver_indycam);
  345. }
  346. module_init(indycam_init);
  347. module_exit(indycam_exit);