/drivers/media/video/pwc/pwc-v4l.c

https://bitbucket.org/ndreys/linux-sunxi · C · 914 lines · 793 code · 84 blank · 37 comment · 126 complexity · a02b5ec3683e86ff99ad8db73a02fa1b MD5 · raw file

  1. /* Linux driver for Philips webcam
  2. USB and Video4Linux interface part.
  3. (C) 1999-2004 Nemosoft Unv.
  4. (C) 2004-2006 Luc Saillard (luc@saillard.org)
  5. NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
  6. driver and thus may have bugs that are not present in the original version.
  7. Please send bug reports and support requests to <luc@saillard.org>.
  8. The decompression routines have been implemented by reverse-engineering the
  9. Nemosoft binary pwcx module. Caveat emptor.
  10. This program is free software; you can redistribute it and/or modify
  11. it under the terms of the GNU General Public License as published by
  12. the Free Software Foundation; either version 2 of the License, or
  13. (at your option) any later version.
  14. This program is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. GNU General Public License for more details.
  18. You should have received a copy of the GNU General Public License
  19. along with this program; if not, write to the Free Software
  20. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21. */
  22. #include <linux/errno.h>
  23. #include <linux/init.h>
  24. #include <linux/mm.h>
  25. #include <linux/module.h>
  26. #include <linux/poll.h>
  27. #include <linux/vmalloc.h>
  28. #include <asm/io.h>
  29. #include "pwc.h"
  30. static struct v4l2_queryctrl pwc_controls[] = {
  31. {
  32. .id = V4L2_CID_BRIGHTNESS,
  33. .type = V4L2_CTRL_TYPE_INTEGER,
  34. .name = "Brightness",
  35. .minimum = 0,
  36. .maximum = 128,
  37. .step = 1,
  38. .default_value = 64,
  39. },
  40. {
  41. .id = V4L2_CID_CONTRAST,
  42. .type = V4L2_CTRL_TYPE_INTEGER,
  43. .name = "Contrast",
  44. .minimum = 0,
  45. .maximum = 64,
  46. .step = 1,
  47. .default_value = 0,
  48. },
  49. {
  50. .id = V4L2_CID_SATURATION,
  51. .type = V4L2_CTRL_TYPE_INTEGER,
  52. .name = "Saturation",
  53. .minimum = -100,
  54. .maximum = 100,
  55. .step = 1,
  56. .default_value = 0,
  57. },
  58. {
  59. .id = V4L2_CID_GAMMA,
  60. .type = V4L2_CTRL_TYPE_INTEGER,
  61. .name = "Gamma",
  62. .minimum = 0,
  63. .maximum = 32,
  64. .step = 1,
  65. .default_value = 0,
  66. },
  67. {
  68. .id = V4L2_CID_RED_BALANCE,
  69. .type = V4L2_CTRL_TYPE_INTEGER,
  70. .name = "Red Gain",
  71. .minimum = 0,
  72. .maximum = 256,
  73. .step = 1,
  74. .default_value = 0,
  75. },
  76. {
  77. .id = V4L2_CID_BLUE_BALANCE,
  78. .type = V4L2_CTRL_TYPE_INTEGER,
  79. .name = "Blue Gain",
  80. .minimum = 0,
  81. .maximum = 256,
  82. .step = 1,
  83. .default_value = 0,
  84. },
  85. {
  86. .id = V4L2_CID_AUTO_WHITE_BALANCE,
  87. .type = V4L2_CTRL_TYPE_BOOLEAN,
  88. .name = "Auto White Balance",
  89. .minimum = 0,
  90. .maximum = 1,
  91. .step = 1,
  92. .default_value = 0,
  93. },
  94. {
  95. .id = V4L2_CID_EXPOSURE,
  96. .type = V4L2_CTRL_TYPE_INTEGER,
  97. .name = "Shutter Speed (Exposure)",
  98. .minimum = 0,
  99. .maximum = 256,
  100. .step = 1,
  101. .default_value = 200,
  102. },
  103. {
  104. .id = V4L2_CID_AUTOGAIN,
  105. .type = V4L2_CTRL_TYPE_BOOLEAN,
  106. .name = "Auto Gain Enabled",
  107. .minimum = 0,
  108. .maximum = 1,
  109. .step = 1,
  110. .default_value = 1,
  111. },
  112. {
  113. .id = V4L2_CID_GAIN,
  114. .type = V4L2_CTRL_TYPE_INTEGER,
  115. .name = "Gain Level",
  116. .minimum = 0,
  117. .maximum = 256,
  118. .step = 1,
  119. .default_value = 0,
  120. },
  121. {
  122. .id = V4L2_CID_PRIVATE_SAVE_USER,
  123. .type = V4L2_CTRL_TYPE_BUTTON,
  124. .name = "Save User Settings",
  125. .minimum = 0,
  126. .maximum = 0,
  127. .step = 0,
  128. .default_value = 0,
  129. },
  130. {
  131. .id = V4L2_CID_PRIVATE_RESTORE_USER,
  132. .type = V4L2_CTRL_TYPE_BUTTON,
  133. .name = "Restore User Settings",
  134. .minimum = 0,
  135. .maximum = 0,
  136. .step = 0,
  137. .default_value = 0,
  138. },
  139. {
  140. .id = V4L2_CID_PRIVATE_RESTORE_FACTORY,
  141. .type = V4L2_CTRL_TYPE_BUTTON,
  142. .name = "Restore Factory Settings",
  143. .minimum = 0,
  144. .maximum = 0,
  145. .step = 0,
  146. .default_value = 0,
  147. },
  148. {
  149. .id = V4L2_CID_PRIVATE_COLOUR_MODE,
  150. .type = V4L2_CTRL_TYPE_BOOLEAN,
  151. .name = "Colour mode",
  152. .minimum = 0,
  153. .maximum = 1,
  154. .step = 1,
  155. .default_value = 0,
  156. },
  157. {
  158. .id = V4L2_CID_PRIVATE_AUTOCONTOUR,
  159. .type = V4L2_CTRL_TYPE_BOOLEAN,
  160. .name = "Auto contour",
  161. .minimum = 0,
  162. .maximum = 1,
  163. .step = 1,
  164. .default_value = 0,
  165. },
  166. {
  167. .id = V4L2_CID_PRIVATE_CONTOUR,
  168. .type = V4L2_CTRL_TYPE_INTEGER,
  169. .name = "Contour",
  170. .minimum = 0,
  171. .maximum = 63,
  172. .step = 1,
  173. .default_value = 0,
  174. },
  175. {
  176. .id = V4L2_CID_PRIVATE_BACKLIGHT,
  177. .type = V4L2_CTRL_TYPE_BOOLEAN,
  178. .name = "Backlight compensation",
  179. .minimum = 0,
  180. .maximum = 1,
  181. .step = 1,
  182. .default_value = 0,
  183. },
  184. {
  185. .id = V4L2_CID_PRIVATE_FLICKERLESS,
  186. .type = V4L2_CTRL_TYPE_BOOLEAN,
  187. .name = "Flickerless",
  188. .minimum = 0,
  189. .maximum = 1,
  190. .step = 1,
  191. .default_value = 0,
  192. },
  193. {
  194. .id = V4L2_CID_PRIVATE_NOISE_REDUCTION,
  195. .type = V4L2_CTRL_TYPE_INTEGER,
  196. .name = "Noise reduction",
  197. .minimum = 0,
  198. .maximum = 3,
  199. .step = 1,
  200. .default_value = 0,
  201. },
  202. };
  203. static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
  204. {
  205. memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
  206. f->fmt.pix.width = pdev->view.x;
  207. f->fmt.pix.height = pdev->view.y;
  208. f->fmt.pix.field = V4L2_FIELD_NONE;
  209. if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
  210. f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
  211. f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
  212. f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
  213. } else {
  214. /* vbandlength contains 4 lines ... */
  215. f->fmt.pix.bytesperline = pdev->vbandlength/4;
  216. f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
  217. if (DEVICE_USE_CODEC1(pdev->type))
  218. f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1;
  219. else
  220. f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2;
  221. }
  222. PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
  223. "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
  224. f->fmt.pix.width,
  225. f->fmt.pix.height,
  226. f->fmt.pix.bytesperline,
  227. f->fmt.pix.sizeimage,
  228. (f->fmt.pix.pixelformat)&255,
  229. (f->fmt.pix.pixelformat>>8)&255,
  230. (f->fmt.pix.pixelformat>>16)&255,
  231. (f->fmt.pix.pixelformat>>24)&255);
  232. }
  233. /* ioctl(VIDIOC_TRY_FMT) */
  234. static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
  235. {
  236. if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
  237. PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
  238. return -EINVAL;
  239. }
  240. switch (f->fmt.pix.pixelformat) {
  241. case V4L2_PIX_FMT_YUV420:
  242. break;
  243. case V4L2_PIX_FMT_PWC1:
  244. if (DEVICE_USE_CODEC23(pdev->type)) {
  245. PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
  246. return -EINVAL;
  247. }
  248. break;
  249. case V4L2_PIX_FMT_PWC2:
  250. if (DEVICE_USE_CODEC1(pdev->type)) {
  251. PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
  252. return -EINVAL;
  253. }
  254. break;
  255. default:
  256. PWC_DEBUG_IOCTL("Unsupported pixel format\n");
  257. return -EINVAL;
  258. }
  259. if (f->fmt.pix.width > pdev->view_max.x)
  260. f->fmt.pix.width = pdev->view_max.x;
  261. else if (f->fmt.pix.width < pdev->view_min.x)
  262. f->fmt.pix.width = pdev->view_min.x;
  263. if (f->fmt.pix.height > pdev->view_max.y)
  264. f->fmt.pix.height = pdev->view_max.y;
  265. else if (f->fmt.pix.height < pdev->view_min.y)
  266. f->fmt.pix.height = pdev->view_min.y;
  267. return 0;
  268. }
  269. /* ioctl(VIDIOC_SET_FMT) */
  270. static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
  271. {
  272. int ret, fps, snapshot, compression, pixelformat;
  273. ret = pwc_vidioc_try_fmt(pdev, f);
  274. if (ret<0)
  275. return ret;
  276. pixelformat = f->fmt.pix.pixelformat;
  277. compression = pdev->vcompression;
  278. snapshot = 0;
  279. fps = pdev->vframes;
  280. if (f->fmt.pix.priv) {
  281. compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
  282. snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
  283. fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
  284. if (fps == 0)
  285. fps = pdev->vframes;
  286. }
  287. if (pixelformat != V4L2_PIX_FMT_YUV420 &&
  288. pixelformat != V4L2_PIX_FMT_PWC1 &&
  289. pixelformat != V4L2_PIX_FMT_PWC2)
  290. return -EINVAL;
  291. if (pdev->iso_init)
  292. return -EBUSY;
  293. PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
  294. "compression=%d snapshot=%d format=%c%c%c%c\n",
  295. f->fmt.pix.width, f->fmt.pix.height, fps,
  296. compression, snapshot,
  297. (pixelformat)&255,
  298. (pixelformat>>8)&255,
  299. (pixelformat>>16)&255,
  300. (pixelformat>>24)&255);
  301. ret = pwc_set_video_mode(pdev,
  302. f->fmt.pix.width,
  303. f->fmt.pix.height,
  304. fps,
  305. compression,
  306. snapshot);
  307. PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret);
  308. if (ret)
  309. return ret;
  310. pdev->pixfmt = pixelformat;
  311. pwc_vidioc_fill_fmt(pdev, f);
  312. return 0;
  313. }
  314. static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
  315. {
  316. struct video_device *vdev = video_devdata(file);
  317. struct pwc_device *pdev = video_drvdata(file);
  318. strcpy(cap->driver, PWC_NAME);
  319. strlcpy(cap->card, vdev->name, sizeof(cap->card));
  320. usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
  321. cap->version = PWC_VERSION_CODE;
  322. cap->capabilities =
  323. V4L2_CAP_VIDEO_CAPTURE |
  324. V4L2_CAP_STREAMING |
  325. V4L2_CAP_READWRITE;
  326. return 0;
  327. }
  328. static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
  329. {
  330. if (i->index) /* Only one INPUT is supported */
  331. return -EINVAL;
  332. strcpy(i->name, "usb");
  333. return 0;
  334. }
  335. static int pwc_g_input(struct file *file, void *fh, unsigned int *i)
  336. {
  337. *i = 0;
  338. return 0;
  339. }
  340. static int pwc_s_input(struct file *file, void *fh, unsigned int i)
  341. {
  342. return i ? -EINVAL : 0;
  343. }
  344. static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
  345. {
  346. int i, idx;
  347. u32 id;
  348. id = c->id;
  349. if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
  350. id &= V4L2_CTRL_ID_MASK;
  351. id++;
  352. idx = -1;
  353. for (i = 0; i < ARRAY_SIZE(pwc_controls); i++) {
  354. if (pwc_controls[i].id < id)
  355. continue;
  356. if (idx >= 0
  357. && pwc_controls[i].id > pwc_controls[idx].id)
  358. continue;
  359. idx = i;
  360. }
  361. if (idx < 0)
  362. return -EINVAL;
  363. memcpy(c, &pwc_controls[idx], sizeof pwc_controls[0]);
  364. return 0;
  365. }
  366. for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) {
  367. if (pwc_controls[i].id == c->id) {
  368. PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
  369. memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl));
  370. return 0;
  371. }
  372. }
  373. return -EINVAL;
  374. }
  375. static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
  376. {
  377. struct pwc_device *pdev = video_drvdata(file);
  378. int ret;
  379. switch (c->id) {
  380. case V4L2_CID_BRIGHTNESS:
  381. c->value = pwc_get_brightness(pdev);
  382. if (c->value < 0)
  383. return -EINVAL;
  384. return 0;
  385. case V4L2_CID_CONTRAST:
  386. c->value = pwc_get_contrast(pdev);
  387. if (c->value < 0)
  388. return -EINVAL;
  389. return 0;
  390. case V4L2_CID_SATURATION:
  391. ret = pwc_get_saturation(pdev, &c->value);
  392. if (ret < 0)
  393. return -EINVAL;
  394. return 0;
  395. case V4L2_CID_GAMMA:
  396. c->value = pwc_get_gamma(pdev);
  397. if (c->value < 0)
  398. return -EINVAL;
  399. return 0;
  400. case V4L2_CID_RED_BALANCE:
  401. ret = pwc_get_red_gain(pdev, &c->value);
  402. if (ret < 0)
  403. return -EINVAL;
  404. c->value >>= 8;
  405. return 0;
  406. case V4L2_CID_BLUE_BALANCE:
  407. ret = pwc_get_blue_gain(pdev, &c->value);
  408. if (ret < 0)
  409. return -EINVAL;
  410. c->value >>= 8;
  411. return 0;
  412. case V4L2_CID_AUTO_WHITE_BALANCE:
  413. ret = pwc_get_awb(pdev);
  414. if (ret < 0)
  415. return -EINVAL;
  416. c->value = (ret == PWC_WB_MANUAL) ? 0 : 1;
  417. return 0;
  418. case V4L2_CID_GAIN:
  419. ret = pwc_get_agc(pdev, &c->value);
  420. if (ret < 0)
  421. return -EINVAL;
  422. c->value >>= 8;
  423. return 0;
  424. case V4L2_CID_AUTOGAIN:
  425. ret = pwc_get_agc(pdev, &c->value);
  426. if (ret < 0)
  427. return -EINVAL;
  428. c->value = (c->value < 0) ? 1 : 0;
  429. return 0;
  430. case V4L2_CID_EXPOSURE:
  431. ret = pwc_get_shutter_speed(pdev, &c->value);
  432. if (ret < 0)
  433. return -EINVAL;
  434. return 0;
  435. case V4L2_CID_PRIVATE_COLOUR_MODE:
  436. ret = pwc_get_colour_mode(pdev, &c->value);
  437. if (ret < 0)
  438. return -EINVAL;
  439. return 0;
  440. case V4L2_CID_PRIVATE_AUTOCONTOUR:
  441. ret = pwc_get_contour(pdev, &c->value);
  442. if (ret < 0)
  443. return -EINVAL;
  444. c->value = (c->value == -1 ? 1 : 0);
  445. return 0;
  446. case V4L2_CID_PRIVATE_CONTOUR:
  447. ret = pwc_get_contour(pdev, &c->value);
  448. if (ret < 0)
  449. return -EINVAL;
  450. c->value >>= 10;
  451. return 0;
  452. case V4L2_CID_PRIVATE_BACKLIGHT:
  453. ret = pwc_get_backlight(pdev, &c->value);
  454. if (ret < 0)
  455. return -EINVAL;
  456. return 0;
  457. case V4L2_CID_PRIVATE_FLICKERLESS:
  458. ret = pwc_get_flicker(pdev, &c->value);
  459. if (ret < 0)
  460. return -EINVAL;
  461. c->value = (c->value ? 1 : 0);
  462. return 0;
  463. case V4L2_CID_PRIVATE_NOISE_REDUCTION:
  464. ret = pwc_get_dynamic_noise(pdev, &c->value);
  465. if (ret < 0)
  466. return -EINVAL;
  467. return 0;
  468. case V4L2_CID_PRIVATE_SAVE_USER:
  469. case V4L2_CID_PRIVATE_RESTORE_USER:
  470. case V4L2_CID_PRIVATE_RESTORE_FACTORY:
  471. return -EINVAL;
  472. }
  473. return -EINVAL;
  474. }
  475. static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
  476. {
  477. struct pwc_device *pdev = video_drvdata(file);
  478. int ret;
  479. switch (c->id) {
  480. case V4L2_CID_BRIGHTNESS:
  481. c->value <<= 9;
  482. ret = pwc_set_brightness(pdev, c->value);
  483. if (ret < 0)
  484. return -EINVAL;
  485. return 0;
  486. case V4L2_CID_CONTRAST:
  487. c->value <<= 10;
  488. ret = pwc_set_contrast(pdev, c->value);
  489. if (ret < 0)
  490. return -EINVAL;
  491. return 0;
  492. case V4L2_CID_SATURATION:
  493. ret = pwc_set_saturation(pdev, c->value);
  494. if (ret < 0)
  495. return -EINVAL;
  496. return 0;
  497. case V4L2_CID_GAMMA:
  498. c->value <<= 11;
  499. ret = pwc_set_gamma(pdev, c->value);
  500. if (ret < 0)
  501. return -EINVAL;
  502. return 0;
  503. case V4L2_CID_RED_BALANCE:
  504. c->value <<= 8;
  505. ret = pwc_set_red_gain(pdev, c->value);
  506. if (ret < 0)
  507. return -EINVAL;
  508. return 0;
  509. case V4L2_CID_BLUE_BALANCE:
  510. c->value <<= 8;
  511. ret = pwc_set_blue_gain(pdev, c->value);
  512. if (ret < 0)
  513. return -EINVAL;
  514. return 0;
  515. case V4L2_CID_AUTO_WHITE_BALANCE:
  516. c->value = (c->value == 0) ? PWC_WB_MANUAL : PWC_WB_AUTO;
  517. ret = pwc_set_awb(pdev, c->value);
  518. if (ret < 0)
  519. return -EINVAL;
  520. return 0;
  521. case V4L2_CID_EXPOSURE:
  522. c->value <<= 8;
  523. ret = pwc_set_shutter_speed(pdev, c->value ? 0 : 1, c->value);
  524. if (ret < 0)
  525. return -EINVAL;
  526. return 0;
  527. case V4L2_CID_AUTOGAIN:
  528. /* autogain off means nothing without a gain */
  529. if (c->value == 0)
  530. return 0;
  531. ret = pwc_set_agc(pdev, c->value, 0);
  532. if (ret < 0)
  533. return -EINVAL;
  534. return 0;
  535. case V4L2_CID_GAIN:
  536. c->value <<= 8;
  537. ret = pwc_set_agc(pdev, 0, c->value);
  538. if (ret < 0)
  539. return -EINVAL;
  540. return 0;
  541. case V4L2_CID_PRIVATE_SAVE_USER:
  542. if (pwc_save_user(pdev))
  543. return -EINVAL;
  544. return 0;
  545. case V4L2_CID_PRIVATE_RESTORE_USER:
  546. if (pwc_restore_user(pdev))
  547. return -EINVAL;
  548. return 0;
  549. case V4L2_CID_PRIVATE_RESTORE_FACTORY:
  550. if (pwc_restore_factory(pdev))
  551. return -EINVAL;
  552. return 0;
  553. case V4L2_CID_PRIVATE_COLOUR_MODE:
  554. ret = pwc_set_colour_mode(pdev, c->value);
  555. if (ret < 0)
  556. return -EINVAL;
  557. return 0;
  558. case V4L2_CID_PRIVATE_AUTOCONTOUR:
  559. c->value = (c->value == 1) ? -1 : 0;
  560. ret = pwc_set_contour(pdev, c->value);
  561. if (ret < 0)
  562. return -EINVAL;
  563. return 0;
  564. case V4L2_CID_PRIVATE_CONTOUR:
  565. c->value <<= 10;
  566. ret = pwc_set_contour(pdev, c->value);
  567. if (ret < 0)
  568. return -EINVAL;
  569. return 0;
  570. case V4L2_CID_PRIVATE_BACKLIGHT:
  571. ret = pwc_set_backlight(pdev, c->value);
  572. if (ret < 0)
  573. return -EINVAL;
  574. return 0;
  575. case V4L2_CID_PRIVATE_FLICKERLESS:
  576. ret = pwc_set_flicker(pdev, c->value);
  577. if (ret < 0)
  578. return -EINVAL;
  579. case V4L2_CID_PRIVATE_NOISE_REDUCTION:
  580. ret = pwc_set_dynamic_noise(pdev, c->value);
  581. if (ret < 0)
  582. return -EINVAL;
  583. return 0;
  584. }
  585. return -EINVAL;
  586. }
  587. static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
  588. {
  589. struct pwc_device *pdev = video_drvdata(file);
  590. /* We only support two format: the raw format, and YUV */
  591. switch (f->index) {
  592. case 0:
  593. /* RAW format */
  594. f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2;
  595. f->flags = V4L2_FMT_FLAG_COMPRESSED;
  596. strlcpy(f->description, "Raw Philips Webcam", sizeof(f->description));
  597. break;
  598. case 1:
  599. f->pixelformat = V4L2_PIX_FMT_YUV420;
  600. strlcpy(f->description, "4:2:0, planar, Y-Cb-Cr", sizeof(f->description));
  601. break;
  602. default:
  603. return -EINVAL;
  604. }
  605. return 0;
  606. }
  607. static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
  608. {
  609. struct pwc_device *pdev = video_drvdata(file);
  610. PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
  611. pdev->image.x, pdev->image.y);
  612. pwc_vidioc_fill_fmt(pdev, f);
  613. return 0;
  614. }
  615. static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
  616. {
  617. struct pwc_device *pdev = video_drvdata(file);
  618. return pwc_vidioc_try_fmt(pdev, f);
  619. }
  620. static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
  621. {
  622. struct pwc_device *pdev = video_drvdata(file);
  623. return pwc_vidioc_set_fmt(pdev, f);
  624. }
  625. static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
  626. {
  627. int nbuffers;
  628. PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count);
  629. if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
  630. return -EINVAL;
  631. if (rb->memory != V4L2_MEMORY_MMAP)
  632. return -EINVAL;
  633. nbuffers = rb->count;
  634. if (nbuffers < 2)
  635. nbuffers = 2;
  636. else if (nbuffers > pwc_mbufs)
  637. nbuffers = pwc_mbufs;
  638. /* Force to use our # of buffers */
  639. rb->count = pwc_mbufs;
  640. return 0;
  641. }
  642. static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
  643. {
  644. struct pwc_device *pdev = video_drvdata(file);
  645. int index;
  646. PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index);
  647. if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
  648. PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
  649. return -EINVAL;
  650. }
  651. index = buf->index;
  652. if (index < 0 || index >= pwc_mbufs) {
  653. PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
  654. return -EINVAL;
  655. }
  656. buf->m.offset = index * pdev->len_per_image;
  657. if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
  658. buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
  659. else
  660. buf->bytesused = pdev->view.size;
  661. buf->field = V4L2_FIELD_NONE;
  662. buf->memory = V4L2_MEMORY_MMAP;
  663. /*buf->flags = V4L2_BUF_FLAG_MAPPED;*/
  664. buf->length = pdev->len_per_image;
  665. PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n", buf->index);
  666. PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n", buf->m.offset);
  667. PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n", buf->bytesused);
  668. return 0;
  669. }
  670. static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
  671. {
  672. PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index);
  673. if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
  674. return -EINVAL;
  675. if (buf->memory != V4L2_MEMORY_MMAP)
  676. return -EINVAL;
  677. if (buf->index >= pwc_mbufs)
  678. return -EINVAL;
  679. buf->flags |= V4L2_BUF_FLAG_QUEUED;
  680. buf->flags &= ~V4L2_BUF_FLAG_DONE;
  681. return 0;
  682. }
  683. static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
  684. {
  685. DECLARE_WAITQUEUE(wait, current);
  686. struct pwc_device *pdev = video_drvdata(file);
  687. int ret;
  688. PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
  689. if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
  690. return -EINVAL;
  691. add_wait_queue(&pdev->frameq, &wait);
  692. while (pdev->full_frames == NULL) {
  693. if (pdev->error_status) {
  694. remove_wait_queue(&pdev->frameq, &wait);
  695. set_current_state(TASK_RUNNING);
  696. return -pdev->error_status;
  697. }
  698. if (signal_pending(current)) {
  699. remove_wait_queue(&pdev->frameq, &wait);
  700. set_current_state(TASK_RUNNING);
  701. return -ERESTARTSYS;
  702. }
  703. mutex_unlock(&pdev->modlock);
  704. schedule();
  705. set_current_state(TASK_INTERRUPTIBLE);
  706. mutex_lock(&pdev->modlock);
  707. }
  708. remove_wait_queue(&pdev->frameq, &wait);
  709. set_current_state(TASK_RUNNING);
  710. PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
  711. /* Decompress data in pdev->images[pdev->fill_image] */
  712. ret = pwc_handle_frame(pdev);
  713. if (ret)
  714. return -EFAULT;
  715. PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
  716. buf->index = pdev->fill_image;
  717. if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
  718. buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
  719. else
  720. buf->bytesused = pdev->view.size;
  721. buf->flags = V4L2_BUF_FLAG_MAPPED;
  722. buf->field = V4L2_FIELD_NONE;
  723. do_gettimeofday(&buf->timestamp);
  724. buf->sequence = 0;
  725. buf->memory = V4L2_MEMORY_MMAP;
  726. buf->m.offset = pdev->fill_image * pdev->len_per_image;
  727. buf->length = pdev->len_per_image;
  728. pwc_next_image(pdev);
  729. PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n", buf->index);
  730. PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n", buf->length);
  731. PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n", buf->m.offset);
  732. PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n", buf->bytesused);
  733. PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
  734. return 0;
  735. }
  736. static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
  737. {
  738. struct pwc_device *pdev = video_drvdata(file);
  739. return pwc_isoc_init(pdev);
  740. }
  741. static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
  742. {
  743. struct pwc_device *pdev = video_drvdata(file);
  744. pwc_isoc_cleanup(pdev);
  745. return 0;
  746. }
  747. static int pwc_enum_framesizes(struct file *file, void *fh,
  748. struct v4l2_frmsizeenum *fsize)
  749. {
  750. struct pwc_device *pdev = video_drvdata(file);
  751. unsigned int i = 0, index = fsize->index;
  752. if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
  753. for (i = 0; i < PSZ_MAX; i++) {
  754. if (pdev->image_mask & (1UL << i)) {
  755. if (!index--) {
  756. fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
  757. fsize->discrete.width = pwc_image_sizes[i].x;
  758. fsize->discrete.height = pwc_image_sizes[i].y;
  759. return 0;
  760. }
  761. }
  762. }
  763. } else if (fsize->index == 0 &&
  764. ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
  765. (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
  766. fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
  767. fsize->discrete.width = pdev->abs_max.x;
  768. fsize->discrete.height = pdev->abs_max.y;
  769. return 0;
  770. }
  771. return -EINVAL;
  772. }
  773. static int pwc_enum_frameintervals(struct file *file, void *fh,
  774. struct v4l2_frmivalenum *fival)
  775. {
  776. struct pwc_device *pdev = video_drvdata(file);
  777. int size = -1;
  778. unsigned int i;
  779. for (i = 0; i < PSZ_MAX; i++) {
  780. if (pwc_image_sizes[i].x == fival->width &&
  781. pwc_image_sizes[i].y == fival->height) {
  782. size = i;
  783. break;
  784. }
  785. }
  786. /* TODO: Support raw format */
  787. if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420)
  788. return -EINVAL;
  789. i = pwc_get_fps(pdev, fival->index, size);
  790. if (!i)
  791. return -EINVAL;
  792. fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
  793. fival->discrete.numerator = 1;
  794. fival->discrete.denominator = i;
  795. return 0;
  796. }
  797. static long pwc_default(struct file *file, void *fh, bool valid_prio,
  798. int cmd, void *arg)
  799. {
  800. struct pwc_device *pdev = video_drvdata(file);
  801. return pwc_ioctl(pdev, cmd, arg);
  802. }
  803. const struct v4l2_ioctl_ops pwc_ioctl_ops = {
  804. .vidioc_querycap = pwc_querycap,
  805. .vidioc_enum_input = pwc_enum_input,
  806. .vidioc_g_input = pwc_g_input,
  807. .vidioc_s_input = pwc_s_input,
  808. .vidioc_enum_fmt_vid_cap = pwc_enum_fmt_vid_cap,
  809. .vidioc_g_fmt_vid_cap = pwc_g_fmt_vid_cap,
  810. .vidioc_s_fmt_vid_cap = pwc_s_fmt_vid_cap,
  811. .vidioc_try_fmt_vid_cap = pwc_try_fmt_vid_cap,
  812. .vidioc_queryctrl = pwc_queryctrl,
  813. .vidioc_g_ctrl = pwc_g_ctrl,
  814. .vidioc_s_ctrl = pwc_s_ctrl,
  815. .vidioc_reqbufs = pwc_reqbufs,
  816. .vidioc_querybuf = pwc_querybuf,
  817. .vidioc_qbuf = pwc_qbuf,
  818. .vidioc_dqbuf = pwc_dqbuf,
  819. .vidioc_streamon = pwc_streamon,
  820. .vidioc_streamoff = pwc_streamoff,
  821. .vidioc_enum_framesizes = pwc_enum_framesizes,
  822. .vidioc_enum_frameintervals = pwc_enum_frameintervals,
  823. .vidioc_default = pwc_default,
  824. };
  825. /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */