webcam.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. #include "shared.h"
  2. #include "webcam.h"
  3. #include "wdm.h"
  4. #include "urb.h"
  5. /****************************
  6. * UTILS *
  7. ****************************/
  8. int r5u870_control_msg( struct driverInstance* this, int write, int class, u8 request, u16 value, u16 index, void* data, u16 size ){
  9. char* dbuf = NULL;
  10. int res;
  11. if( size ){
  12. dbuf = kmalloc( size, GFP_KERNEL );
  13. if ( !dbuf )return -ENOMEM;
  14. if ( write ) memcpy( dbuf, data, size );
  15. }
  16. //int usb_control_msg(struct usb_device * dev, unsigned int pipe, __u8 request,__u8 requesttype, __u16 value, __u16 index, void * data, __u16 size, int timeout );
  17. res = usb_control_msg(
  18. this->usbDevice,
  19. write ? usb_sndctrlpipe( this->usbDevice, 0 ) : usb_rcvctrlpipe( this->usbDevice, 0 ),
  20. request,
  21. ( write ? USB_DIR_OUT : USB_DIR_IN ) | ( class ? (USB_TYPE_CLASS | USB_RECIP_INTERFACE) : (USB_TYPE_VENDOR | USB_RECIP_DEVICE) ),
  22. value,
  23. index,
  24. dbuf,
  25. size,
  26. 1000
  27. );
  28. if( dbuf ) {
  29. if( !write ) memcpy( data, dbuf, size );
  30. kfree( dbuf );
  31. }
  32. return res;
  33. }
  34. static int r5u870_set_gen_reg( struct driverInstance* this, int cmd, int reg, int val ){
  35. int res = r5u870_control_msg( this, 1, 0, cmd, val, reg, NULL, 0 );
  36. if( res < 0 ){
  37. printk( KERN_ERR "[%s] %s %04x/%04x/%04x failed: %d\n", KBUILD_MODNAME, __FUNCTION__, cmd, reg, val, res);
  38. return res;
  39. }
  40. return 0;
  41. }
  42. static int r5u870_set_reg_wdm( struct driverInstance* this, int reg, int val ){
  43. return r5u870_set_gen_reg( this, 0xc2, reg, val);
  44. }
  45. /****************************
  46. * MICROCODE *
  47. ****************************/
  48. static int r5u870_microcode_get_state( struct driverInstance* this ){
  49. char buf[1];
  50. int res;
  51. res = r5u870_control_msg( this, 0, 0, 0xa4, 0, 0, buf, 1 );
  52. if ((res != 1) || ((buf[0] != 0) && (buf[0] != 1))) {
  53. printk( KERN_ERR "[%s] command 0xa4 failed: %d", KBUILD_MODNAME, res);
  54. return res < 0 ? res : -EIO;
  55. }
  56. printk( KERN_NOTICE "[%s] camera reports %s microcode state\n", KBUILD_MODNAME, buf[0] ? "positive" : "negative" );
  57. return (buf[0] == 0) ? -ENOENT : 0;
  58. }
  59. static int r5u870_microcode_get_ver( struct driverInstance* this, int *verp ){
  60. char buf[2];
  61. int res;
  62. res = r5u870_control_msg( this, 0, 0, 0xc3, 0, 0x0e, buf, 2 );
  63. if (res != 2) {
  64. printk( KERN_ERR "[%s] command 0xa3 failed: %d\n", KBUILD_MODNAME, res );
  65. return res < 0 ? res : -EIO;
  66. }
  67. res = le16_to_cpup((__le16 *) buf);
  68. printk( KERN_NOTICE "[%s] camera reports version %04x\n", KBUILD_MODNAME, res );
  69. *verp = res;
  70. return 0;
  71. }
  72. static int r5u870_microcode_reset( struct driverInstance* this ){
  73. int res;
  74. printk( KERN_NOTICE "[%s] sending microcode reset command\n", KBUILD_MODNAME );
  75. msleep( 100 );// The Windows driver waits 1sec
  76. res = r5u870_set_gen_reg( this, 0xa6, 0, 0 );
  77. if ( !res ) msleep(200);
  78. return res;
  79. }
  80. static int r5u870_microcode_upload( struct driverInstance* this ){
  81. const struct firmware *fws;
  82. char *pgbuf;
  83. const u8 *dptr;
  84. int tolerance = 3;
  85. int i, rem, addr, len, res = 0;
  86. pgbuf = (char *) kmalloc(64, GFP_KERNEL);
  87. if( !pgbuf ) return -ENOMEM;
  88. printk( KERN_NOTICE "[%s] loading microcode file \"%s\"\n", KBUILD_MODNAME, this->webcamModel->ucodeFile );
  89. res = request_firmware( &fws, this->webcamModel->ucodeFile, &this->usbDevice->dev );
  90. if( res ) {
  91. printk( KERN_ERR "[%s] Microcode file \"%s\" is missing\n", KBUILD_MODNAME, this->webcamModel->ucodeFile );
  92. kfree( pgbuf );
  93. return res;
  94. }
  95. i = 0;
  96. dptr = fws->data;
  97. rem = fws->size;
  98. while( rem ){
  99. if( rem < 3 ){
  100. printk( KERN_ERR "[%s] Microcode file msg %d is incomplete", KBUILD_MODNAME, i );
  101. res = -EINVAL;
  102. break;
  103. }
  104. len = dptr[0];
  105. addr = dptr[1] | (dptr[2] << 8);
  106. dptr += 3;
  107. rem -= 3;
  108. if ((rem < len) || (len > 64)) {
  109. printk( KERN_ERR "[%s] Microcode file msg %d has bad length %d\n", KBUILD_MODNAME, i, len );
  110. res = -EINVAL;
  111. break;
  112. }
  113. /*
  114. * The USB stack has issues with the initseq data if
  115. * initseq points into the vmalloc arena. This is
  116. * the case for microcode embedded in a module, or
  117. * data loaded by request_firmware().
  118. *
  119. * As a workaround, we memcpy() into a kmalloc page.
  120. */
  121. memcpy(pgbuf, dptr, len);
  122. dptr += len;
  123. rem -= len;
  124. retry:
  125. // TODO: Maybe make this use r5u870_control_msg or similar?
  126. res = usb_control_msg(
  127. this->usbDevice,
  128. usb_sndctrlpipe( this->usbDevice, 0 ),
  129. 0xa0,
  130. USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
  131. addr,
  132. 0,
  133. pgbuf,
  134. len,
  135. 1000
  136. );
  137. if (res < 0) {
  138. if (tolerance--) goto retry;
  139. printk( KERN_ERR "[%s] command a0[%d] failed: %d\n", KBUILD_MODNAME, i, res);
  140. break;
  141. }
  142. if (res != len) {
  143. printk( KERN_ERR "[%s] command a0[%d] failed: %d (exp %d)\n", KBUILD_MODNAME, i, res, len);
  144. res = -EIO;
  145. break;
  146. }
  147. i++;
  148. }
  149. release_firmware( fws );
  150. kfree( pgbuf );
  151. return res;
  152. }
  153. static int r5u870_microcode_enable( struct driverInstance* this ){
  154. char buf[1];
  155. int res;
  156. buf[0] = 1;
  157. res = r5u870_control_msg( this, 1, 0, 0xa1, 0, 0, buf, 1 );
  158. if( res != 1 ) {
  159. printk( KERN_ERR "[%s] command 0xa1 failed: %d\n", KBUILD_MODNAME, res );
  160. return res < 0 ? res : -EIO;
  161. }
  162. return 0;
  163. }
  164. static int webcamMicrocode( struct driverInstance* this ){//r5u870_dev_init
  165. int mcver;
  166. int res;
  167. if ( !this->webcamModel->ucodeFile ) return 0;
  168. res = r5u870_microcode_get_state( this );
  169. if ( res && (res != -ENOENT) ) return res;
  170. if( !res ){
  171. res = r5u870_microcode_get_ver( this, &mcver );
  172. if ( res ) return res;
  173. if ( mcver != this->webcamModel->ucodeVersion ){
  174. res = r5u870_microcode_reset( this );
  175. if( res ) return res;
  176. res = -ENOENT;
  177. }
  178. }
  179. if( res == -ENOENT ){
  180. res = r5u870_microcode_upload( this );
  181. if( res < 0 ) return res;
  182. res = r5u870_microcode_enable( this );
  183. if( res ) return res;
  184. res = r5u870_microcode_get_ver( this, &mcver );
  185. if( res ) return res;
  186. }
  187. if( mcver != this->webcamModel->ucodeVersion ){
  188. printk( KERN_ERR "[%s] Unexpected microcode version (exp:%04x got:%04x)\n", KBUILD_MODNAME, this->webcamModel->ucodeVersion, mcver);
  189. }
  190. //Halt capture in case it's running (broken driver?)
  191. res = this->vh_cap_stop( this );
  192. if (res < 0) return res;
  193. return 0;
  194. }
  195. /****************************
  196. * FORMAT *
  197. ****************************/
  198. int webcamTryFormat( struct driverInstance* this, struct v4l2_pix_format* requestedFormat, char setFlag ){
  199. const struct r5u870_pixelformat* format;
  200. const struct r5u870_resolution* resolutionTable;
  201. const struct r5u870_resolution* resolution;
  202. int i;
  203. format = NULL;
  204. for ( i = 0; i < this->webcamFormatsCount; i++ ) {
  205. if ( this->webcamFormats[i].pixelformat == requestedFormat->pixelformat ) {
  206. format = &this->webcamFormats[i];
  207. break;
  208. }
  209. }
  210. if ( format == NULL ) return -EINVAL;
  211. resolutionTable = format->resolutionTable;
  212. if ( !resolutionTable || !resolutionTable[0].width ){
  213. printk( KERN_ERR "[%s] invalid resolution table\n", KBUILD_MODNAME );
  214. return -EINVAL;
  215. }
  216. //Find the most acceptable resolution
  217. resolution = NULL;
  218. for( i = 0; resolutionTable[i].width > 0; i++ ){
  219. if ( !resolution ){
  220. resolution = &resolutionTable[i];
  221. }else if( resolution->width > requestedFormat->width ){
  222. if( resolutionTable[i].width < resolution->width ) resolution = &resolutionTable[i];
  223. }else if( resolution->height > requestedFormat->height ){
  224. if( resolutionTable[i].width <= requestedFormat->width && resolutionTable[i].height < resolution->height ) resolution = &resolutionTable[i];
  225. }else if( resolutionTable[i].width <= requestedFormat->width && resolutionTable[i].height <= requestedFormat->height &&
  226. ( resolutionTable[i].width > resolution->width || ( resolutionTable[i].width == resolution->width && resolutionTable[i].height > resolution->height ) ) ){
  227. resolution = &resolutionTable[i];
  228. }
  229. }
  230. if( (requestedFormat->width > 1) && (requestedFormat->height > 1) ){
  231. if ( (resolution->width > requestedFormat->width) || (resolution->height > requestedFormat->height) ) {
  232. printk( KERN_WARNING "[%s] Bad size request. Returning -EINVAL.\n", KBUILD_MODNAME );
  233. return -EINVAL;
  234. }
  235. }
  236. printk( KERN_NOTICE "[%s] Requested %s %dx%d. Using %dx%d.\n",
  237. KBUILD_MODNAME,
  238. format->description,
  239. requestedFormat->width,
  240. requestedFormat->height,
  241. resolution->width,
  242. resolution->height
  243. );
  244. memset( requestedFormat, 0, sizeof(*requestedFormat) );
  245. requestedFormat->width = resolution->width;
  246. requestedFormat->height = resolution->height;
  247. requestedFormat->pixelformat = format->pixelformat;
  248. requestedFormat->bytesperline = requestedFormat->width * 2;
  249. requestedFormat->sizeimage = requestedFormat->width * requestedFormat->height * 2;
  250. requestedFormat->field = V4L2_FIELD_INTERLACED;
  251. requestedFormat->colorspace = V4L2_COLORSPACE_SMPTE170M;
  252. if( !setFlag ) return 0;
  253. if( (this->webcamCurrentPixelformat.width != requestedFormat->width) ||
  254. (this->webcamCurrentPixelformat.height != requestedFormat->height) ||
  255. (this->webcamCurrentPixelformat.pixelformat != requestedFormat->pixelformat) ||
  256. (this->webcamCurrentPixelformat.sizeimage != requestedFormat->sizeimage) ){
  257. this->vh_configured = 0;
  258. }
  259. this->webcamCurrentPixelformat = *requestedFormat;
  260. this->webcamCurrentFormat = format;
  261. this->webcamCurrentResolution = resolution;
  262. return 0;
  263. }
  264. /****************************
  265. * WDM *
  266. ****************************/
  267. //Set the frame size and data format.
  268. //Do not call this function with the isochronous stream active.
  269. //r5u870_set_fmt_wdm
  270. static int webcamApplyFormat_wdm( struct driverInstance* this ){
  271. int res;
  272. msleep(1);
  273. res = r5u870_set_gen_reg( this, 0xc5, 2, this->webcamCurrentFormat->formatId );
  274. if( res ) return res;
  275. msleep(1);
  276. res = r5u870_set_gen_reg( this, 0xc5, 0, this->webcamCurrentResolution->width );
  277. if( res ) return res;
  278. msleep(1);
  279. res = r5u870_set_gen_reg( this, 0xc5, 1, this->webcamCurrentResolution->height );
  280. if( res ) return res;
  281. msleep(5);
  282. return 0;
  283. }
  284. //Turn frame grabbing on or off (WDM).
  285. //This will also turn on or off the LED.
  286. static inline int webcamSetCaptureState_wdm( struct driverInstance* this, int val ){
  287. return r5u870_set_gen_reg( this, 0xc4, val, 0 );
  288. }
  289. static int r5u870_cap_stop_wdm( struct driverInstance* this ){
  290. return webcamSetCaptureState_wdm( this, 0 );
  291. }
  292. static int webcamSetControlCallback_wdm( struct v4l2_ctrl* control ){
  293. struct driverInstance* this = container_of( control->handler, struct driverInstance, webcamControlHandler );
  294. struct webcam_control* webcamControl;
  295. int err = 0;
  296. if( atomic_read( &this->webcamControlRegisterIsEnabled ) ){
  297. if( !control->priv ){
  298. printk( KERN_ERR "[%s] %s err: control->priv == NULL\n", KBUILD_MODNAME, __FUNCTION__ );
  299. return -EINVAL;
  300. }
  301. webcamControl = control->priv;
  302. err = r5u870_set_reg_wdm( this, webcamControl->reg, control->val );
  303. if( err )printk( KERN_ERR "[%s](%s) id: %u, val: %i, err: %i\n", KBUILD_MODNAME, __FUNCTION__, control->id, control->val, err );
  304. }else err = -EBUSY;
  305. return err;
  306. }
  307. static int webcamAddControls_wdm( struct driverInstance* this ){
  308. int err = 0;
  309. int i;
  310. //TODO: Find a beautiful way to calculate the number of controls
  311. v4l2_ctrl_handler_init( &this->webcamControlHandler, 19 );
  312. for( i = 0; this->webcamModel->controls_wdm[i] != R5U870_WDM_CTRL_LAST; i++ ){
  313. v4l2_ctrl_new_custom(
  314. &this->webcamControlHandler,
  315. &r5u870_wdm_ctrls[ this->webcamModel->controls_wdm[i] ].control,
  316. &r5u870_wdm_ctrls[ this->webcamModel->controls_wdm[i] ]
  317. );
  318. if( this->webcamControlHandler.error )break;
  319. }
  320. if( this->webcamControlHandler.error ){
  321. err = this->webcamControlHandler.error;
  322. v4l2_ctrl_handler_free( &this->webcamControlHandler );
  323. }else this->v4l2Device.ctrl_handler = &this->webcamControlHandler;
  324. return err;
  325. }
  326. /*
  327. * r5u870_decide_pkt_wdm
  328. *
  329. * Based on the size of an isochronous data packet, this function
  330. * decides whether to copy the packet into the frame buffer and possibly
  331. * complete the frame, or to discard both the packet and the frame.
  332. *
  333. * Returns:
  334. * 0 Frame is done
  335. * -EAGAIN Append packet to frame, frame is not done
  336. * -EPIPE Discard frame and packet
  337. * -EIO The device is nonresponsive, abort
  338. */
  339. static int r5u870_decide_pkt_wdm( struct driverInstance* this, int pktstatus, int pktlen, const u8* pktdata, int* start ){
  340. int ret = -EAGAIN;
  341. *start = 0;
  342. if( pktstatus ){//Abort current frame
  343. if( printk_ratelimit() )printk( KERN_NOTICE "[%s] frame abort: packet status %d\n", KBUILD_MODNAME, pktstatus );
  344. this->vh_frame_accum = -1;
  345. this->vh_emptypkts = 0;
  346. ret = -EPIPE;
  347. }else if( !pktlen ){
  348. if( ++this->vh_emptypkts == R5U870_EMPTYPKT_FRAME_DELIM ){
  349. if(this->vh_frame_accum == -1) ret = -EPIPE;//Frame was previously aborted
  350. else if( this->vh_frame_accum == this->webcamCurrentPixelformat.sizeimage ) ret = 0;//Complete frame
  351. else{//Not enough data in frame sequence
  352. if( printk_ratelimit() ) printk( KERN_NOTICE "[%s] frame abort: Frame seq too short (exp:%d got:%d)\n", KBUILD_MODNAME, this->webcamCurrentPixelformat.sizeimage, this->vh_frame_accum );
  353. ret = -EPIPE;
  354. }
  355. if( !this->vh_firstframe ){//Always reject the first frame
  356. this->vh_firstframe = 1;
  357. this->vh_frame_accum = -1;
  358. ret = -EPIPE;
  359. }else this->vh_frame_accum = 0;
  360. }else if( this->vh_emptypkts >= R5U870_EMPTYPKT_GIVE_UP ){
  361. if( printk_ratelimit() ) printk( KERN_NOTICE "[%s] %d empty packets, giving up\n", KBUILD_MODNAME, this->vh_emptypkts );
  362. ret = -EIO;
  363. }
  364. }else{
  365. this->vh_emptypkts = 0;
  366. if( this->vh_frame_accum == -1 ) ret = -EPIPE;//Frame was previously aborted
  367. else if( (this->vh_frame_accum + pktlen) <= this->webcamCurrentPixelformat.sizeimage ) this->vh_frame_accum += pktlen;//Append this data
  368. else{//Oversized frame, abort
  369. if( printk_ratelimit() ) printk( KERN_NOTICE "[%s] frame abort: Frame seq too long\n", KBUILD_MODNAME );
  370. this->vh_frame_accum = -1;
  371. ret = -EPIPE;
  372. }
  373. }
  374. return ret;
  375. }
  376. /****************************
  377. * CAPTURE *
  378. ****************************/
  379. //r5u870_config_iso_ep
  380. static int webcamConfigInterface( struct driverInstance* this ){
  381. int res;
  382. if( !this->vh_configured ){
  383. this->vh_ctrl_sync = 0;
  384. res = usbcam_choose_altsetting( this );
  385. if( res ){
  386. printk( KERN_ERR "[%s] need %d B/s, no altsetting provides\n", KBUILD_MODNAME, this->webcamCurrentResolution->requiredBandwidth );
  387. return res;
  388. }
  389. printk( KERN_NOTICE "[%s] using altsetting %d\n", KBUILD_MODNAME, this->usbCurrentAltsetting );
  390. }
  391. res = usb_set_interface( this->usbDevice, this->urbstreamInterfaceNumber, this->usbCurrentAltsetting );
  392. if( res ){
  393. printk( KERN_ERR "[%s] could not set altsetting: %d\n", KBUILD_MODNAME, res );
  394. return res;
  395. }
  396. return 0;
  397. }
  398. int webcamCaptureStart( struct driverInstance* this ){
  399. int res;
  400. if( atomic_read( &this->webcamIsCaptuing ) )return 0;
  401. if( !this->webcamModel->isUvc ){
  402. res = webcamConfigInterface( this );
  403. if( res )return res;
  404. }
  405. atomic_set( &this->webcamControlRegisterIsEnabled, 1 );
  406. if( !this->vh_configured ){
  407. v4l2_ctrl_handler_setup( &this->webcamControlHandler );
  408. res = this->webcamApplyFormat( this );
  409. if( res ){
  410. printk( KERN_ERR "[%s] could not configure capture: %d\n", KBUILD_MODNAME, res );
  411. goto out_set_idle;
  412. }
  413. if( this->webcamModel->rm_no_ctrl_reload ) this->vh_ctrl_sync = 1;
  414. }
  415. if( this->webcamModel->isUvc ){
  416. res = webcamConfigInterface( this );
  417. if( res ) goto out_set_idle;
  418. }
  419. this->vh_configured = 1;
  420. res = usbcam_urbstream_config_iso( this );
  421. if( res < 0 ) {
  422. printk( KERN_ERR "[%s] urbstream init failed: %d\n", KBUILD_MODNAME, res );
  423. goto out_set_idle;
  424. }
  425. atomic_set( &this->webcamIsCaptuing, 1 );
  426. if( !this->webcamModel->isUvc ){
  427. res = webcamSetCaptureState_wdm( this, 1 );
  428. if( res )goto out_cleanup_urbstream;
  429. }
  430. if( !this->vh_ctrl_sync ){
  431. //Reload the control values after changing res/format
  432. v4l2_ctrl_handler_setup( &this->webcamControlHandler );
  433. this->vh_ctrl_sync = 1;
  434. }
  435. printk( KERN_NOTICE "[%s] starting capture\n", KBUILD_MODNAME );
  436. this->vh_firstframe = 0;
  437. this->vh_frame_accum = -1;
  438. this->vh_framebuf_offset = 0;
  439. this->vh_emptypkts = R5U870_EMPTYPKT_FRAME_DELIM - 1;
  440. res = usbcam_urbstream_start( this );
  441. if(res) goto out_stop_capture;
  442. return 0;
  443. out_stop_capture:
  444. (void) this->vh_cap_stop( this );
  445. out_cleanup_urbstream:
  446. usbcam_urbstream_cleanup( this );
  447. out_set_idle:
  448. usb_set_interface( this->usbDevice, this->urbstreamInterfaceNumber, 0 );
  449. atomic_set( &this->webcamControlRegisterIsEnabled, 0 );
  450. atomic_set( &this->webcamIsCaptuing, 0 );
  451. return res;
  452. }
  453. void webcamCaptureStop( struct driverInstance* this ){//r5u870_do_stop
  454. struct videobuffer_capsule* cursor;
  455. struct videobuffer_capsule* tmp;
  456. unsigned long flags = 0;
  457. if( atomic_read( &this->webcamIsCaptuing ) ){
  458. atomic_set( &this->webcamIsCaptuing, 0 );
  459. atomic_set( &this->webcamControlRegisterIsEnabled, 0 );
  460. usbcam_urbstream_stop( this );
  461. spin_lock_irqsave( &this->buflistSpinlock, flags );
  462. atomic_set( &this->buflistIsDisabled, 1 );
  463. list_for_each_entry_safe( cursor, tmp, &this->buflist, listItem ){
  464. list_del( &cursor->listItem );
  465. vb2_buffer_done( &cursor->videobuffer, VB2_BUF_STATE_ERROR );
  466. }
  467. spin_unlock_irqrestore( &this->buflistSpinlock, flags );
  468. if( !atomic_read( &this->usbDeviceIsDisconnected ) ){
  469. usb_set_interface( this->usbDevice, this->urbstreamInterfaceNumber, 0);
  470. this->vh_cap_stop( this );
  471. }
  472. usbcam_urbstream_cleanup( this );
  473. printk( KERN_NOTICE "[%s] Webcam capture stopped\n", KBUILD_MODNAME );
  474. }
  475. }
  476. /****************************
  477. * PACKET PROCESSING *
  478. ****************************/
  479. static inline struct videobuffer_capsule* usbcam_capture_curframe( struct driverInstance* this ){
  480. return list_empty( &this->buflist ) ? NULL : list_entry( this->buflist.next, struct videobuffer_capsule, listItem );
  481. }
  482. static void usbcam_curframe_complete( struct driverInstance* this, enum vb2_buffer_state bufstate ){
  483. struct videobuffer_capsule* curframe;
  484. unsigned long flags = 0;
  485. spin_lock_irqsave( &this->buflistSpinlock, flags );
  486. curframe = usbcam_capture_curframe( this );
  487. if( !curframe ){
  488. spin_unlock_irqrestore( &this->buflistSpinlock, flags );
  489. if( printk_ratelimit() ) printk( KERN_WARNING "[%s] No videobuffers in queue.\n", KBUILD_MODNAME );
  490. return;
  491. }
  492. list_del( &curframe->listItem );
  493. spin_unlock_irqrestore( &this->buflistSpinlock, flags );
  494. curframe->videobuffer.timestamp = ktime_get_ns();
  495. vb2_buffer_done( &curframe->videobuffer, bufstate );
  496. }
  497. //#define EAGAIN 11
  498. //#define EPIPE 32
  499. //#define EPROTO 71
  500. //#define EOVERFLOW 75
  501. //static void r5u870_iso_packet_done(struct usbcam_dev *udp, struct usbcam_urbstream *usp, const uint8_t *pktdata, int pktlen, int pktstatus)
  502. void r5u870_iso_packet_done( struct driverInstance* this, const uint8_t *pktdata, int pktlen, int pktstatus ) {
  503. struct videobuffer_capsule* currentVideobuffer;
  504. int res, start = 0;
  505. unsigned long flags = 0;
  506. res = this->vh_decide_pkt( this, pktstatus, pktlen, (u8 *) pktdata, &start );
  507. switch( res ) {
  508. case -EPIPE:
  509. if( this->vh_framebuf_offset ){
  510. this->vh_framebuf_offset = 0;
  511. usbcam_curframe_complete( this, VB2_BUF_STATE_ERROR );
  512. }
  513. break;
  514. case 0:
  515. case -EAGAIN:
  516. if( pktlen ) {
  517. spin_lock_irqsave( &this->buflistSpinlock, flags );
  518. currentVideobuffer = usbcam_capture_curframe( this );
  519. if( !currentVideobuffer ){
  520. spin_unlock_irqrestore( &this->buflistSpinlock, flags );
  521. //Some programs get stupid when starting the capture and do not have time
  522. //to queue videobuffers, so we just display a warning and continue working.
  523. if( printk_ratelimit() ) printk( KERN_WARNING "[%s] Running out of videobuffers.\n", KBUILD_MODNAME );
  524. //webcamCaptureStop( this );
  525. break;
  526. }
  527. BUG_ON( pktlen - start + this->vh_framebuf_offset > vb2_plane_size( &currentVideobuffer->videobuffer, 0 ) );
  528. //This is our one and only memcpy. It's kind of hard to get around doing this, as we
  529. //cannot predict into which isochronous packets the camera will choose to return data.
  530. memcpy( vb2_plane_vaddr( &currentVideobuffer->videobuffer, 0 ) + this->vh_framebuf_offset, pktdata + start, pktlen - start );
  531. this->vh_framebuf_offset += (pktlen - start);
  532. //printk( KERN_NOTICE "(%s) offset now: %d\n", __FUNCTION__, this->vh_framebuf_offset );
  533. spin_unlock_irqrestore( &this->buflistSpinlock, flags );
  534. }
  535. if( !res ) {
  536. this->vh_framebuf_offset = 0;
  537. usbcam_curframe_complete( this, VB2_BUF_STATE_DONE );
  538. }
  539. break;
  540. case -EIO:
  541. webcamCaptureStop( this );
  542. break;
  543. default:
  544. BUG();
  545. }
  546. }
  547. /****************************
  548. * INIT *
  549. ****************************/
  550. void webcamRelease( struct driverInstance* this ){//r5u870_usbcam_release
  551. struct claimed_interface* interfaceTemp;
  552. struct claimed_interface* interfaceCursor;
  553. webcamCaptureStop( this );
  554. v4l2_ctrl_handler_free( &this->webcamControlHandler );
  555. list_for_each_entry_safe( interfaceCursor, interfaceTemp, &this->claimedInterfacesList, listItem ){
  556. usb_set_intfdata( interfaceCursor->interface, NULL );
  557. usb_put_intf( interfaceCursor->interface );
  558. usb_driver_release_interface( this->usbDeviceDriver, interfaceCursor->interface );
  559. list_del( &interfaceCursor->listItem );
  560. }
  561. }
  562. /*
  563. * Someone clever at HP decided to use 05ca:1870 for two distinct devices.
  564. * The Pavilion dv1xxx machines all seem to have the less common of the
  565. * two. There is no known, working method to distinguish the devices
  566. * using USB commands only. We resort to reading the model number out
  567. * of DMI.
  568. */
  569. static int dv1000 = 2;
  570. module_param( dv1000, int, S_IRUGO | S_IWUSR );
  571. MODULE_PARM_DESC( dv1000, "HP dv1000 detect mode (0=no,1=yes,2=DMI)" );
  572. static int r5u870_check_hp_dv1000( void ){
  573. const char *prod_name;
  574. if ( !dv1000 ) return 0;
  575. if ( dv1000 == 1 ) return 1;
  576. prod_name = dmi_get_system_info( DMI_PRODUCT_NAME );
  577. if ( !prod_name ) printk( KERN_INFO "[%s] No DMI model found\n", KBUILD_MODNAME );
  578. else {
  579. printk( KERN_INFO "[%s] Found DMI model: \"%s\"\n", KBUILD_MODNAME, prod_name );
  580. if ( !strncmp( prod_name, "HP Pavilion dv1000", 18 ) && !isdigit( prod_name[18] ) ) return 1;
  581. }
  582. return 0;
  583. }
  584. static const struct r5u870_model* r5u870_find_model( int driver_info ){
  585. if ( driver_info == R5U870_DI_HP_PAVWC_WDM ) {
  586. if ( r5u870_check_hp_dv1000() ) driver_info = R5U870_DI_HP_WEBCAM1K;
  587. }
  588. if ( ( driver_info <= R5U870_DI_INVALID ) || ( driver_info >= ARRAY_SIZE(r5u870_models) ) ) return NULL;
  589. if ( !r5u870_models[driver_info].modelName ) return NULL;
  590. return &r5u870_models[driver_info];
  591. }
  592. int webcamInit( struct driverInstance* this, const struct usb_device_id* devid ){
  593. int res = 0;
  594. this->vh_ctrl_ifnum = -1;
  595. this->urbstreamInterfaceNumber = -1;
  596. this->urbstreamMinPacketSize = -1;
  597. this->webcamModel = r5u870_find_model( devid->driver_info );
  598. if( !this->webcamModel ){
  599. printk( KERN_ERR "[%s] no suitable model descriptor for %04x:%04x\n",
  600. KBUILD_MODNAME, le16_to_cpu( this->usbDevice->descriptor.idVendor ), le16_to_cpu( this->usbDevice->descriptor.idProduct ) );
  601. return -ENODEV;
  602. }
  603. this->webcamFormats = this->webcamModel->pixelformats;
  604. this->webcamFormatsCount = this->webcamModel->pixelformatsCount;
  605. if( this->webcamModel->isUvc ) {
  606. this->webcamApplyFormat = webcamApplyFormat_uvc;
  607. this->vh_cap_stop = r5u870_cap_stop_uvc;
  608. this->vh_decide_pkt = r5u870_decide_pkt_uvc;
  609. }else{
  610. this->webcamApplyFormat = webcamApplyFormat_wdm;
  611. this->vh_cap_stop = r5u870_cap_stop_wdm;
  612. this->vh_decide_pkt = r5u870_decide_pkt_wdm;
  613. }
  614. printk( KERN_INFO "[%s] Detected %s\n", KBUILD_MODNAME, this->webcamModel->modelName );
  615. snprintf( this->videoDevice.name, sizeof( this->videoDevice.name ), "%s", this->webcamModel->modelName );
  616. res = webcamMicrocode( this );
  617. if(res < 0){
  618. printk( KERN_ERR "[%s] webcamMicrocode failed: %d\n", KBUILD_MODNAME, res );
  619. goto out_failed;
  620. }
  621. if ( this->webcamModel->isUvc ) {//This appears to be a UVC VideoControl interface.
  622. res = r5u870_uvc_parse_vc( this );
  623. if (res < 0) {
  624. printk( KERN_ERR "[%s] UVC setup failed: %d \n", KBUILD_MODNAME, res );
  625. goto out_failed;
  626. }
  627. } else {//We are looking at a proprietary Ricoh interface
  628. this->urbstreamInterfaceNumber = this->usbInterface->altsetting->desc.bInterfaceNumber;
  629. this->urbstreamEndpoint = 6;
  630. }
  631. if( this->webcamModel->controls_wdm ){
  632. res = webcamAddControls_wdm( this );
  633. if ( res ) {
  634. printk( KERN_ERR "[%s] Vendor control setup failed: %d\n", KBUILD_MODNAME, res );
  635. goto out_failed;
  636. }
  637. }
  638. //Configure the usbcam pixel format and control arrays
  639. if( !this->webcamFormatsCount ){
  640. printk( KERN_ERR "[%s] No pixel formats detected\n", KBUILD_MODNAME );
  641. res = -ENODEV;
  642. goto out_failed;
  643. }
  644. /* Set the default format */
  645. this->webcamCurrentFormat = &this->webcamFormats[0];
  646. this->webcamCurrentResolution = &this->webcamCurrentFormat->resolutionTable[0];
  647. this->webcamCurrentPixelformat.width = this->webcamCurrentResolution->width;
  648. this->webcamCurrentPixelformat.height = this->webcamCurrentResolution->height;
  649. this->webcamCurrentPixelformat.pixelformat = this->webcamCurrentFormat->pixelformat;
  650. this->webcamCurrentPixelformat.bytesperline = this->webcamCurrentPixelformat.width * 2;
  651. this->webcamCurrentPixelformat.sizeimage = this->webcamCurrentPixelformat.width * this->webcamCurrentPixelformat.height * 2;
  652. this->webcamCurrentPixelformat.colorspace = V4L2_COLORSPACE_SMPTE170M;
  653. this->webcamCurrentPixelformat.field = V4L2_FIELD_INTERLACED;
  654. return 0;
  655. out_failed:
  656. webcamRelease( this );
  657. return res;
  658. }