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