PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/media/usb/gspca/dtcs033.c

https://gitlab.com/Skylake/Staging
C | 439 lines | 344 code | 50 blank | 45 comment | 14 complexity | 796a69f3548eb11a1b162212061ca659 MD5 | raw file
  1. /*
  2. * Subdriver for Scopium astro-camera (DTCS033, 0547:7303)
  3. *
  4. * Copyright (C) 2014 Robert Butora (robert.butora.fi@gmail.com)
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  17. #define MODULE_NAME "dtcs033"
  18. #include "gspca.h"
  19. MODULE_AUTHOR("Robert Butora <robert.butora.fi@gmail.com>");
  20. MODULE_DESCRIPTION("Scopium DTCS033 astro-cam USB Camera Driver");
  21. MODULE_LICENSE("GPL");
  22. struct dtcs033_usb_requests {
  23. u8 bRequestType;
  24. u8 bRequest;
  25. u16 wValue;
  26. u16 wIndex;
  27. u16 wLength;
  28. };
  29. /* send a usb request */
  30. static void reg_rw(struct gspca_dev *gspca_dev,
  31. u8 bRequestType, u8 bRequest,
  32. u16 wValue, u16 wIndex, u16 wLength)
  33. {
  34. struct usb_device *udev = gspca_dev->dev;
  35. int ret;
  36. if (gspca_dev->usb_err < 0)
  37. return;
  38. ret = usb_control_msg(udev,
  39. usb_rcvctrlpipe(udev, 0),
  40. bRequest,
  41. bRequestType,
  42. wValue, wIndex,
  43. gspca_dev->usb_buf, wLength, 500);
  44. if (ret < 0) {
  45. gspca_dev->usb_err = ret;
  46. pr_err("usb_control_msg error %d\n", ret);
  47. }
  48. return;
  49. }
  50. /* send several usb in/out requests */
  51. static int reg_reqs(struct gspca_dev *gspca_dev,
  52. const struct dtcs033_usb_requests *preqs, int n_reqs)
  53. {
  54. int i = 0;
  55. const struct dtcs033_usb_requests *preq;
  56. while ((i < n_reqs) && (gspca_dev->usb_err >= 0)) {
  57. preq = &preqs[i];
  58. reg_rw(gspca_dev, preq->bRequestType, preq->bRequest,
  59. preq->wValue, preq->wIndex, preq->wLength);
  60. if (gspca_dev->usb_err < 0) {
  61. gspca_err(gspca_dev, "usb error request no: %d / %d\n",
  62. i, n_reqs);
  63. } else if (preq->bRequestType & USB_DIR_IN) {
  64. gspca_dbg(gspca_dev, D_STREAM,
  65. "USB IN (%d) returned[%d] %3ph %s",
  66. i,
  67. preq->wLength,
  68. gspca_dev->usb_buf,
  69. preq->wLength > 3 ? "...\n" : "\n");
  70. }
  71. i++;
  72. }
  73. return gspca_dev->usb_err;
  74. }
  75. /* -- subdriver interface implementation -- */
  76. #define DT_COLS (640)
  77. static const struct v4l2_pix_format dtcs033_mode[] = {
  78. /* raw Bayer patterned output */
  79. {DT_COLS, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
  80. .bytesperline = DT_COLS,
  81. .sizeimage = DT_COLS*480,
  82. .colorspace = V4L2_COLORSPACE_SRGB,
  83. },
  84. /* this mode will demosaic the Bayer pattern */
  85. {DT_COLS, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
  86. .bytesperline = DT_COLS,
  87. .sizeimage = DT_COLS*480,
  88. .colorspace = V4L2_COLORSPACE_SRGB,
  89. }
  90. };
  91. /* config called at probe time */
  92. static int sd_config(struct gspca_dev *gspca_dev,
  93. const struct usb_device_id *id)
  94. {
  95. gspca_dev->cam.cam_mode = dtcs033_mode;
  96. gspca_dev->cam.nmodes = ARRAY_SIZE(dtcs033_mode);
  97. gspca_dev->cam.bulk = 1;
  98. gspca_dev->cam.bulk_nurbs = 1;
  99. gspca_dev->cam.bulk_size = DT_COLS*512;
  100. return 0;
  101. }
  102. /* init called at probe and resume time */
  103. static int sd_init(struct gspca_dev *gspca_dev)
  104. {
  105. return 0;
  106. }
  107. /* start stop the camera */
  108. static int dtcs033_start(struct gspca_dev *gspca_dev);
  109. static void dtcs033_stopN(struct gspca_dev *gspca_dev);
  110. /* intercept camera image data */
  111. static void dtcs033_pkt_scan(struct gspca_dev *gspca_dev,
  112. u8 *data, /* packet data */
  113. int len) /* packet data length */
  114. {
  115. /* drop incomplete frames */
  116. if (len != DT_COLS*512) {
  117. gspca_dev->last_packet_type = DISCARD_PACKET;
  118. /* gspca.c: discard invalidates the whole frame. */
  119. return;
  120. }
  121. /* forward complete frames */
  122. gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
  123. gspca_frame_add(gspca_dev, INTER_PACKET,
  124. data + 16*DT_COLS,
  125. len - 32*DT_COLS); /* skip first & last 16 lines */
  126. gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
  127. return;
  128. }
  129. /* -- controls: exposure and gain -- */
  130. static void dtcs033_setexposure(struct gspca_dev *gspca_dev,
  131. s32 expo, s32 gain)
  132. {
  133. /* gain [dB] encoding */
  134. u16 sGain = (u16)gain;
  135. u16 gainVal = 224+(sGain-14)*(768-224)/(33-14);
  136. u16 wIndex = 0x0100|(0x00FF&gainVal);
  137. u16 wValue = (0xFF00&gainVal)>>8;
  138. /* exposure time [msec] encoding */
  139. u16 sXTime = (u16)expo;
  140. u16 xtimeVal = (524*(150-(sXTime-1)))/150;
  141. const u8 bRequestType =
  142. USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
  143. const u8 bRequest = 0x18;
  144. reg_rw(gspca_dev,
  145. bRequestType, bRequest, wValue, wIndex, 0);
  146. if (gspca_dev->usb_err < 0)
  147. gspca_err(gspca_dev, "usb error in setexposure(gain) sequence\n");
  148. reg_rw(gspca_dev,
  149. bRequestType, bRequest, (xtimeVal<<4), 0x6300, 0);
  150. if (gspca_dev->usb_err < 0)
  151. gspca_err(gspca_dev, "usb error in setexposure(time) sequence\n");
  152. }
  153. /* specific webcam descriptor */
  154. struct sd {
  155. struct gspca_dev gspca_dev;/* !! must be the first item */
  156. /* exposure & gain controls */
  157. struct {
  158. struct v4l2_ctrl *exposure;
  159. struct v4l2_ctrl *gain;
  160. };
  161. };
  162. static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
  163. {
  164. struct gspca_dev *gspca_dev =
  165. container_of(ctrl->handler,
  166. struct gspca_dev, ctrl_handler);
  167. struct sd *sd = (struct sd *) gspca_dev;
  168. gspca_dev->usb_err = 0;
  169. if (!gspca_dev->streaming)
  170. return 0;
  171. switch (ctrl->id) {
  172. case V4L2_CID_EXPOSURE:
  173. dtcs033_setexposure(gspca_dev,
  174. ctrl->val, sd->gain->val);
  175. break;
  176. case V4L2_CID_GAIN:
  177. dtcs033_setexposure(gspca_dev,
  178. sd->exposure->val, ctrl->val);
  179. break;
  180. }
  181. return gspca_dev->usb_err;
  182. }
  183. static const struct v4l2_ctrl_ops sd_ctrl_ops = {
  184. .s_ctrl = sd_s_ctrl,
  185. };
  186. static int dtcs033_init_controls(struct gspca_dev *gspca_dev)
  187. {
  188. struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
  189. struct sd *sd = (struct sd *) gspca_dev;
  190. gspca_dev->vdev.ctrl_handler = hdl;
  191. v4l2_ctrl_handler_init(hdl, 2);
  192. /* min max step default */
  193. sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
  194. V4L2_CID_EXPOSURE,
  195. 1, 150, 1, 75);/* [msec] */
  196. sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
  197. V4L2_CID_GAIN,
  198. 14, 33, 1, 24);/* [dB] */
  199. if (hdl->error) {
  200. gspca_err(gspca_dev, "Could not initialize controls: %d\n",
  201. hdl->error);
  202. return hdl->error;
  203. }
  204. v4l2_ctrl_cluster(2, &sd->exposure);
  205. return 0;
  206. }
  207. /* sub-driver description */
  208. static const struct sd_desc sd_desc = {
  209. .name = MODULE_NAME,
  210. .config = sd_config,
  211. .init = sd_init,
  212. .start = dtcs033_start,
  213. .stopN = dtcs033_stopN,
  214. .pkt_scan = dtcs033_pkt_scan,
  215. .init_controls = dtcs033_init_controls,
  216. };
  217. /* -- module initialisation -- */
  218. static const struct usb_device_id device_table[] = {
  219. {USB_DEVICE(0x0547, 0x7303)},
  220. {}
  221. };
  222. MODULE_DEVICE_TABLE(usb, device_table);
  223. /* device connect */
  224. static int sd_probe(struct usb_interface *intf,
  225. const struct usb_device_id *id)
  226. {
  227. return gspca_dev_probe(intf, id,
  228. &sd_desc, sizeof(struct sd),
  229. THIS_MODULE);
  230. }
  231. static struct usb_driver sd_driver = {
  232. .name = MODULE_NAME,
  233. .id_table = device_table,
  234. .probe = sd_probe,
  235. .disconnect = gspca_disconnect,
  236. #ifdef CONFIG_PM
  237. .suspend = gspca_suspend,
  238. .resume = gspca_resume,
  239. .reset_resume = gspca_resume,
  240. #endif
  241. };
  242. module_usb_driver(sd_driver);
  243. /* ---------------------------------------------------------
  244. USB requests to start/stop the camera [USB 2.0 spec Ch.9].
  245. bRequestType :
  246. 0x40 = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
  247. 0xC0 = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
  248. */
  249. static const struct dtcs033_usb_requests dtcs033_start_reqs[] = {
  250. /* -- bRequest,wValue,wIndex,wLength */
  251. { 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
  252. { 0x40, 0x01, 0x0000, 0x000F, 0x0000 },
  253. { 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
  254. { 0x40, 0x18, 0x0000, 0x7F00, 0x0000 },
  255. { 0x40, 0x18, 0x0000, 0x1001, 0x0000 },
  256. { 0x40, 0x18, 0x0000, 0x0004, 0x0000 },
  257. { 0x40, 0x18, 0x0000, 0x7F01, 0x0000 },
  258. { 0x40, 0x18, 0x30E0, 0x0009, 0x0000 },
  259. { 0x40, 0x18, 0x0500, 0x012C, 0x0000 },
  260. { 0x40, 0x18, 0x0380, 0x0200, 0x0000 },
  261. { 0x40, 0x18, 0x0000, 0x035C, 0x0000 },
  262. { 0x40, 0x18, 0x05C0, 0x0438, 0x0000 },
  263. { 0x40, 0x18, 0x0440, 0x0500, 0x0000 },
  264. { 0x40, 0x18, 0x0000, 0x0668, 0x0000 },
  265. { 0x40, 0x18, 0x0000, 0x0700, 0x0000 },
  266. { 0x40, 0x18, 0x0000, 0x0800, 0x0000 },
  267. { 0x40, 0x18, 0x0000, 0x0900, 0x0000 },
  268. { 0x40, 0x18, 0x0000, 0x0A00, 0x0000 },
  269. { 0x40, 0x18, 0x0000, 0x0B00, 0x0000 },
  270. { 0x40, 0x18, 0x30E0, 0x6009, 0x0000 },
  271. { 0x40, 0x18, 0x0500, 0x612C, 0x0000 },
  272. { 0x40, 0x18, 0x2090, 0x6274, 0x0000 },
  273. { 0x40, 0x18, 0x05C0, 0x6338, 0x0000 },
  274. { 0x40, 0x18, 0x0000, 0x6400, 0x0000 },
  275. { 0x40, 0x18, 0x05C0, 0x6538, 0x0000 },
  276. { 0x40, 0x18, 0x0000, 0x6600, 0x0000 },
  277. { 0x40, 0x18, 0x0680, 0x6744, 0x0000 },
  278. { 0x40, 0x18, 0x0000, 0x6800, 0x0000 },
  279. { 0x40, 0x18, 0x0000, 0x6900, 0x0000 },
  280. { 0x40, 0x18, 0x0000, 0x6A00, 0x0000 },
  281. { 0x40, 0x18, 0x0000, 0x6B00, 0x0000 },
  282. { 0x40, 0x18, 0x0000, 0x6C00, 0x0000 },
  283. { 0x40, 0x18, 0x0000, 0x6D00, 0x0000 },
  284. { 0x40, 0x18, 0x0000, 0x6E00, 0x0000 },
  285. { 0x40, 0x18, 0x0000, 0x808C, 0x0000 },
  286. { 0x40, 0x18, 0x0010, 0x8101, 0x0000 },
  287. { 0x40, 0x18, 0x30E0, 0x8200, 0x0000 },
  288. { 0x40, 0x18, 0x0810, 0x832C, 0x0000 },
  289. { 0x40, 0x18, 0x0680, 0x842B, 0x0000 },
  290. { 0x40, 0x18, 0x0000, 0x8500, 0x0000 },
  291. { 0x40, 0x18, 0x0000, 0x8600, 0x0000 },
  292. { 0x40, 0x18, 0x0280, 0x8715, 0x0000 },
  293. { 0x40, 0x18, 0x0000, 0x880C, 0x0000 },
  294. { 0x40, 0x18, 0x0010, 0x8901, 0x0000 },
  295. { 0x40, 0x18, 0x30E0, 0x8A00, 0x0000 },
  296. { 0x40, 0x18, 0x0810, 0x8B2C, 0x0000 },
  297. { 0x40, 0x18, 0x0680, 0x8C2B, 0x0000 },
  298. { 0x40, 0x18, 0x0000, 0x8D00, 0x0000 },
  299. { 0x40, 0x18, 0x0000, 0x8E00, 0x0000 },
  300. { 0x40, 0x18, 0x0280, 0x8F15, 0x0000 },
  301. { 0x40, 0x18, 0x0010, 0xD040, 0x0000 },
  302. { 0x40, 0x18, 0x0000, 0xD100, 0x0000 },
  303. { 0x40, 0x18, 0x00B0, 0xD20A, 0x0000 },
  304. { 0x40, 0x18, 0x0000, 0xD300, 0x0000 },
  305. { 0x40, 0x18, 0x30E2, 0xD40D, 0x0000 },
  306. { 0x40, 0x18, 0x0001, 0xD5C0, 0x0000 },
  307. { 0x40, 0x18, 0x00A0, 0xD60A, 0x0000 },
  308. { 0x40, 0x18, 0x0000, 0xD700, 0x0000 },
  309. { 0x40, 0x18, 0x0000, 0x7F00, 0x0000 },
  310. { 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
  311. { 0x40, 0x18, 0x0001, 0x01FF, 0x0000 },
  312. { 0x40, 0x18, 0x0000, 0x0200, 0x0000 },
  313. { 0x40, 0x18, 0x0000, 0x0304, 0x0000 },
  314. { 0x40, 0x18, 0x0000, 0x1101, 0x0000 },
  315. { 0x40, 0x18, 0x0000, 0x1201, 0x0000 },
  316. { 0x40, 0x18, 0x0000, 0x1300, 0x0000 },
  317. { 0x40, 0x18, 0x0000, 0x1400, 0x0000 },
  318. { 0x40, 0x18, 0x0000, 0x1601, 0x0000 },
  319. { 0x40, 0x18, 0x0000, 0x1800, 0x0000 },
  320. { 0x40, 0x18, 0x0000, 0x1900, 0x0000 },
  321. { 0x40, 0x18, 0x0000, 0x1A00, 0x0000 },
  322. { 0x40, 0x18, 0x2000, 0x1B00, 0x0000 },
  323. { 0x40, 0x18, 0x0000, 0x1C00, 0x0000 },
  324. { 0x40, 0x18, 0x0000, 0x2100, 0x0000 },
  325. { 0x40, 0x18, 0x00C0, 0x228E, 0x0000 },
  326. { 0x40, 0x18, 0x0000, 0x3001, 0x0000 },
  327. { 0x40, 0x18, 0x0010, 0x3101, 0x0000 },
  328. { 0x40, 0x18, 0x0008, 0x3301, 0x0000 },
  329. { 0x40, 0x18, 0x0000, 0x3400, 0x0000 },
  330. { 0x40, 0x18, 0x0012, 0x3549, 0x0000 },
  331. { 0x40, 0x18, 0x0000, 0x3620, 0x0000 },
  332. { 0x40, 0x18, 0x0001, 0x3700, 0x0000 },
  333. { 0x40, 0x18, 0x0000, 0x4000, 0x0000 },
  334. { 0x40, 0x18, 0xFFFF, 0x41FF, 0x0000 },
  335. { 0x40, 0x18, 0xFFFF, 0x42FF, 0x0000 },
  336. { 0x40, 0x18, 0x0000, 0x500F, 0x0000 },
  337. { 0x40, 0x18, 0x2272, 0x5108, 0x0000 },
  338. { 0x40, 0x18, 0x2272, 0x5208, 0x0000 },
  339. { 0x40, 0x18, 0xFFFF, 0x53FF, 0x0000 },
  340. { 0x40, 0x18, 0xFFFF, 0x54FF, 0x0000 },
  341. { 0x40, 0x18, 0x0000, 0x6000, 0x0000 },
  342. { 0x40, 0x18, 0x0000, 0x6102, 0x0000 },
  343. { 0x40, 0x18, 0x0010, 0x6214, 0x0000 },
  344. { 0x40, 0x18, 0x0C80, 0x6300, 0x0000 },
  345. { 0x40, 0x18, 0x0000, 0x6401, 0x0000 },
  346. { 0x40, 0x18, 0x0680, 0x6551, 0x0000 },
  347. { 0x40, 0x18, 0xFFFF, 0x66FF, 0x0000 },
  348. { 0x40, 0x18, 0x0000, 0x6702, 0x0000 },
  349. { 0x40, 0x18, 0x0010, 0x6800, 0x0000 },
  350. { 0x40, 0x18, 0x0000, 0x6900, 0x0000 },
  351. { 0x40, 0x18, 0x0000, 0x6A00, 0x0000 },
  352. { 0x40, 0x18, 0x0000, 0x6B00, 0x0000 },
  353. { 0x40, 0x18, 0x0000, 0x6C00, 0x0000 },
  354. { 0x40, 0x18, 0x0000, 0x6D01, 0x0000 },
  355. { 0x40, 0x18, 0x0000, 0x6E00, 0x0000 },
  356. { 0x40, 0x18, 0x0000, 0x6F00, 0x0000 },
  357. { 0x40, 0x18, 0x0000, 0x7000, 0x0000 },
  358. { 0x40, 0x18, 0x0001, 0x7118, 0x0000 },
  359. { 0x40, 0x18, 0x0000, 0x2001, 0x0000 },
  360. { 0x40, 0x18, 0x0000, 0x1101, 0x0000 },
  361. { 0x40, 0x18, 0x0000, 0x1301, 0x0000 },
  362. { 0x40, 0x18, 0x0000, 0x1300, 0x0000 },
  363. { 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
  364. { 0xC0, 0x11, 0x0000, 0x24C0, 0x0003 },
  365. { 0x40, 0x18, 0x0000, 0x3000, 0x0000 },
  366. { 0x40, 0x18, 0x0000, 0x3620, 0x0000 },
  367. { 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
  368. { 0x40, 0x18, 0x0010, 0x6300, 0x0000 },
  369. { 0x40, 0x18, 0x0002, 0x01F0, 0x0000 },
  370. { 0x40, 0x01, 0x0003, 0x000F, 0x0000 }
  371. };
  372. static const struct dtcs033_usb_requests dtcs033_stop_reqs[] = {
  373. /* -- bRequest,wValue,wIndex,wLength */
  374. { 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
  375. { 0x40, 0x01, 0x0000, 0x000F, 0x0000 },
  376. { 0x40, 0x18, 0x0000, 0x0003, 0x0000 }
  377. };
  378. static int dtcs033_start(struct gspca_dev *gspca_dev)
  379. {
  380. return reg_reqs(gspca_dev, dtcs033_start_reqs,
  381. ARRAY_SIZE(dtcs033_start_reqs));
  382. }
  383. static void dtcs033_stopN(struct gspca_dev *gspca_dev)
  384. {
  385. reg_reqs(gspca_dev, dtcs033_stop_reqs,
  386. ARRAY_SIZE(dtcs033_stop_reqs));
  387. return;
  388. }