2
0

0031-uvc-add-iPassion-iP2970-support.patch 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. From 975e76214cd2516eb6cfff4c3eec581872645e88 Mon Sep 17 00:00:00 2001
  2. From: John Crispin <blogic@openwrt.org>
  3. Date: Thu, 19 Sep 2013 01:50:59 +0200
  4. Subject: [PATCH 31/53] uvc: add iPassion iP2970 support
  5. Signed-off-by: John Crispin <blogic@openwrt.org>
  6. ---
  7. drivers/media/usb/uvc/uvc_driver.c | 12 +++
  8. drivers/media/usb/uvc/uvc_status.c | 2 +
  9. drivers/media/usb/uvc/uvc_video.c | 147 ++++++++++++++++++++++++++++++++++++
  10. drivers/media/usb/uvc/uvcvideo.h | 5 +-
  11. 4 files changed, 165 insertions(+), 1 deletion(-)
  12. --- a/drivers/media/usb/uvc/uvc_driver.c
  13. +++ b/drivers/media/usb/uvc/uvc_driver.c
  14. @@ -2559,6 +2559,18 @@ static struct usb_device_id uvc_ids[] =
  15. .bInterfaceSubClass = 1,
  16. .bInterfaceProtocol = 0,
  17. .driver_info = UVC_QUIRK_FORCE_Y8 },
  18. + /* iPassion iP2970 */
  19. + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
  20. + | USB_DEVICE_ID_MATCH_INT_INFO,
  21. + .idVendor = 0x1B3B,
  22. + .idProduct = 0x2970,
  23. + .bInterfaceClass = USB_CLASS_VIDEO,
  24. + .bInterfaceSubClass = 1,
  25. + .bInterfaceProtocol = 0,
  26. + .driver_info = UVC_QUIRK_PROBE_MINMAX
  27. + | UVC_QUIRK_STREAM_NO_FID
  28. + | UVC_QUIRK_MOTION
  29. + | UVC_QUIRK_SINGLE_ISO },
  30. /* Generic USB Video Class */
  31. { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
  32. {}
  33. --- a/drivers/media/usb/uvc/uvc_status.c
  34. +++ b/drivers/media/usb/uvc/uvc_status.c
  35. @@ -139,6 +139,7 @@ static void uvc_status_complete(struct u
  36. switch (dev->status[0] & 0x0f) {
  37. case UVC_STATUS_TYPE_CONTROL:
  38. uvc_event_control(dev, dev->status, len);
  39. + dev->motion = 1;
  40. break;
  41. case UVC_STATUS_TYPE_STREAMING:
  42. @@ -182,6 +183,7 @@ int uvc_status_init(struct uvc_device *d
  43. }
  44. pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
  45. + dev->motion = 0;
  46. /* For high-speed interrupt endpoints, the bInterval value is used as
  47. * an exponent of two. Some developers forgot about it.
  48. --- a/drivers/media/usb/uvc/uvc_video.c
  49. +++ b/drivers/media/usb/uvc/uvc_video.c
  50. @@ -21,6 +21,11 @@
  51. #include <linux/wait.h>
  52. #include <linux/atomic.h>
  53. #include <asm/unaligned.h>
  54. +#include <linux/skbuff.h>
  55. +#include <linux/kobject.h>
  56. +#include <linux/netlink.h>
  57. +#include <linux/kobject.h>
  58. +#include <linux/workqueue.h>
  59. #include <media/v4l2-common.h>
  60. @@ -1092,9 +1097,149 @@ static void uvc_video_decode_data(struct
  61. }
  62. }
  63. +struct bh_priv {
  64. + unsigned long seen;
  65. +};
  66. +
  67. +struct bh_event {
  68. + const char *name;
  69. + struct sk_buff *skb;
  70. + struct work_struct work;
  71. +};
  72. +
  73. +#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, "webcam", ##args )
  74. +#define BH_DBG(fmt, args...) do {} while (0)
  75. +#define BH_SKB_SIZE 2048
  76. +
  77. +extern u64 uevent_next_seqnum(void);
  78. +static int seen = 0;
  79. +
  80. +static int bh_event_add_var(struct bh_event *event, int argv,
  81. + const char *format, ...)
  82. +{
  83. + static char buf[128];
  84. + char *s;
  85. + va_list args;
  86. + int len;
  87. +
  88. + if (argv)
  89. + return 0;
  90. +
  91. + va_start(args, format);
  92. + len = vsnprintf(buf, sizeof(buf), format, args);
  93. + va_end(args);
  94. +
  95. + if (len >= sizeof(buf)) {
  96. + BH_ERR("buffer size too small\n");
  97. + WARN_ON(1);
  98. + return -ENOMEM;
  99. + }
  100. +
  101. + s = skb_put(event->skb, len + 1);
  102. + strcpy(s, buf);
  103. +
  104. + BH_DBG("added variable '%s'\n", s);
  105. +
  106. + return 0;
  107. +}
  108. +
  109. +static int motion_hotplug_fill_event(struct bh_event *event)
  110. +{
  111. + int s = jiffies;
  112. + int ret;
  113. +
  114. + if (!seen)
  115. + seen = jiffies;
  116. +
  117. + ret = bh_event_add_var(event, 0, "HOME=%s", "/");
  118. + if (ret)
  119. + return ret;
  120. +
  121. + ret = bh_event_add_var(event, 0, "PATH=%s",
  122. + "/sbin:/bin:/usr/sbin:/usr/bin");
  123. + if (ret)
  124. + return ret;
  125. +
  126. + ret = bh_event_add_var(event, 0, "SUBSYSTEM=usb");
  127. + if (ret)
  128. + return ret;
  129. +
  130. + ret = bh_event_add_var(event, 0, "ACTION=motion");
  131. + if (ret)
  132. + return ret;
  133. +
  134. + ret = bh_event_add_var(event, 0, "SEEN=%d", s - seen);
  135. + if (ret)
  136. + return ret;
  137. + seen = s;
  138. +
  139. + ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
  140. +
  141. + return ret;
  142. +}
  143. +
  144. +static void motion_hotplug_work(struct work_struct *work)
  145. +{
  146. + struct bh_event *event = container_of(work, struct bh_event, work);
  147. + int ret = 0;
  148. +
  149. + event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
  150. + if (!event->skb)
  151. + goto out_free_event;
  152. +
  153. + ret = bh_event_add_var(event, 0, "%s@", "add");
  154. + if (ret)
  155. + goto out_free_skb;
  156. +
  157. + ret = motion_hotplug_fill_event(event);
  158. + if (ret)
  159. + goto out_free_skb;
  160. +
  161. + NETLINK_CB(event->skb).dst_group = 1;
  162. + broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
  163. +
  164. +out_free_skb:
  165. + if (ret) {
  166. + BH_ERR("work error %d\n", ret);
  167. + kfree_skb(event->skb);
  168. + }
  169. +out_free_event:
  170. + kfree(event);
  171. +}
  172. +
  173. +static int motion_hotplug_create_event(void)
  174. +{
  175. + struct bh_event *event;
  176. +
  177. + event = kzalloc(sizeof(*event), GFP_KERNEL);
  178. + if (!event)
  179. + return -ENOMEM;
  180. +
  181. + event->name = "motion";
  182. +
  183. + INIT_WORK(&event->work, (void *)(void *)motion_hotplug_work);
  184. + schedule_work(&event->work);
  185. +
  186. + return 0;
  187. +}
  188. +
  189. +#define MOTION_FLAG_OFFSET 4
  190. static void uvc_video_decode_end(struct uvc_streaming *stream,
  191. struct uvc_buffer *buf, const __u8 *data, int len)
  192. {
  193. + if ((stream->dev->quirks & UVC_QUIRK_MOTION) &&
  194. + (data[len - 2] == 0xff) && (data[len - 1] == 0xd9)) {
  195. + u8 *mem;
  196. + buf->state = UVC_BUF_STATE_READY;
  197. + mem = (u8 *) (buf->mem + MOTION_FLAG_OFFSET);
  198. + if ( stream->dev->motion ) {
  199. + stream->dev->motion = 0;
  200. + motion_hotplug_create_event();
  201. + } else {
  202. + *mem &= 0x7f;
  203. + }
  204. + }
  205. +
  206. /* Mark the buffer as done if the EOF marker is set. */
  207. if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) {
  208. uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
  209. @@ -1507,6 +1652,8 @@ static int uvc_init_video_isoc(struct uv
  210. if (npackets == 0)
  211. return -ENOMEM;
  212. + if (stream->dev->quirks & UVC_QUIRK_SINGLE_ISO)
  213. + npackets = 1;
  214. size = npackets * psize;
  215. for (i = 0; i < UVC_URBS; ++i) {
  216. --- a/drivers/media/usb/uvc/uvcvideo.h
  217. +++ b/drivers/media/usb/uvc/uvcvideo.h
  218. @@ -164,7 +164,9 @@
  219. #define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
  220. #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400
  221. #define UVC_QUIRK_FORCE_Y8 0x00000800
  222. -
  223. +#define UVC_QUIRK_MOTION 0x00001000
  224. +#define UVC_QUIRK_SINGLE_ISO 0x00002000
  225. +
  226. /* Format flags */
  227. #define UVC_FMT_FLAG_COMPRESSED 0x00000001
  228. #define UVC_FMT_FLAG_STREAM 0x00000002
  229. @@ -562,6 +564,7 @@ struct uvc_device {
  230. __u8 *status;
  231. struct input_dev *input;
  232. char input_phys[64];
  233. + int motion;
  234. };
  235. enum uvc_handle_state {