diff options
author | Patrice Chotard <patrice.chotard@sfr.fr> | 2011-04-18 16:37:06 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-05-20 08:27:17 -0400 |
commit | c3d8692758dfaaf0049d6112c94c819de9237577 (patch) | |
tree | 708b552b22f215c370bc79e42a4e8873e6ef1aa9 /drivers/media/video/gspca | |
parent | ec2a0954350098dccd579c945c8bf5cf969c604b (diff) |
[media] gspca - jeilinj: suppress workqueue
Signed-off-by: Patrice CHOTARD <patricechotard@free.fr>
Signed-off-by: Jean-François Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/gspca')
-rw-r--r-- | drivers/media/video/gspca/jeilinj.c | 192 |
1 files changed, 77 insertions, 115 deletions
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index 36dae38b1e3..33de1771b19 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * download raw JPEG data. | 5 | * download raw JPEG data. |
6 | * | 6 | * |
7 | * Copyright (C) 2009 Theodore Kilgore | 7 | * Copyright (C) 2009 Theodore Kilgore |
8 | * Copyright (C) 2011 Patrice Chotard | ||
8 | * | 9 | * |
9 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -23,7 +24,6 @@ | |||
23 | 24 | ||
24 | #define MODULE_NAME "jeilinj" | 25 | #define MODULE_NAME "jeilinj" |
25 | 26 | ||
26 | #include <linux/workqueue.h> | ||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include "gspca.h" | 28 | #include "gspca.h" |
29 | #include "jpeg.h" | 29 | #include "jpeg.h" |
@@ -38,25 +38,23 @@ MODULE_LICENSE("GPL"); | |||
38 | 38 | ||
39 | /* Maximum transfer size to use. */ | 39 | /* Maximum transfer size to use. */ |
40 | #define JEILINJ_MAX_TRANSFER 0x200 | 40 | #define JEILINJ_MAX_TRANSFER 0x200 |
41 | |||
42 | #define FRAME_HEADER_LEN 0x10 | 41 | #define FRAME_HEADER_LEN 0x10 |
42 | #define FRAME_START 0xFFFFFFFF | ||
43 | 43 | ||
44 | /* Structure to hold all of our device specific stuff */ | 44 | /* Structure to hold all of our device specific stuff */ |
45 | struct sd { | 45 | struct sd { |
46 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 46 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
47 | int blocks_left; | ||
47 | const struct v4l2_pix_format *cap_mode; | 48 | const struct v4l2_pix_format *cap_mode; |
48 | /* Driver stuff */ | 49 | /* Driver stuff */ |
49 | struct work_struct work_struct; | ||
50 | struct workqueue_struct *work_thread; | ||
51 | u8 quality; /* image quality */ | 50 | u8 quality; /* image quality */ |
52 | u8 jpegqual; /* webcam quality */ | ||
53 | u8 jpeg_hdr[JPEG_HDR_SZ]; | 51 | u8 jpeg_hdr[JPEG_HDR_SZ]; |
54 | }; | 52 | }; |
55 | 53 | ||
56 | struct jlj_command { | 54 | struct jlj_command { |
57 | unsigned char instruction[2]; | 55 | unsigned char instruction[2]; |
58 | unsigned char ack_wanted; | 56 | unsigned char ack_wanted; |
59 | }; | 57 | }; |
60 | 58 | ||
61 | /* AFAICT these cameras will only do 320x240. */ | 59 | /* AFAICT these cameras will only do 320x240. */ |
62 | static struct v4l2_pix_format jlj_mode[] = { | 60 | static struct v4l2_pix_format jlj_mode[] = { |
@@ -107,6 +105,7 @@ static int jlj_start(struct gspca_dev *gspca_dev) | |||
107 | int i; | 105 | int i; |
108 | int retval = -1; | 106 | int retval = -1; |
109 | u8 response = 0xff; | 107 | u8 response = 0xff; |
108 | struct sd *sd = (struct sd *) gspca_dev; | ||
110 | struct jlj_command start_commands[] = { | 109 | struct jlj_command start_commands[] = { |
111 | {{0x71, 0x81}, 0}, | 110 | {{0x71, 0x81}, 0}, |
112 | {{0x70, 0x05}, 0}, | 111 | {{0x70, 0x05}, 0}, |
@@ -136,6 +135,8 @@ static int jlj_start(struct gspca_dev *gspca_dev) | |||
136 | {{0x71, 0x80}, 0}, | 135 | {{0x71, 0x80}, 0}, |
137 | {{0x70, 0x07}, 0} | 136 | {{0x70, 0x07}, 0} |
138 | }; | 137 | }; |
138 | |||
139 | sd->blocks_left = 0; | ||
139 | for (i = 0; i < ARRAY_SIZE(start_commands); i++) { | 140 | for (i = 0; i < ARRAY_SIZE(start_commands); i++) { |
140 | retval = jlj_write2(gspca_dev, start_commands[i].instruction); | 141 | retval = jlj_write2(gspca_dev, start_commands[i].instruction); |
141 | if (retval < 0) | 142 | if (retval < 0) |
@@ -149,102 +150,47 @@ static int jlj_start(struct gspca_dev *gspca_dev) | |||
149 | return retval; | 150 | return retval; |
150 | } | 151 | } |
151 | 152 | ||
152 | static int jlj_stop(struct gspca_dev *gspca_dev) | 153 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
153 | { | 154 | u8 *data, int len) |
154 | int i; | ||
155 | int retval; | ||
156 | struct jlj_command stop_commands[] = { | ||
157 | {{0x71, 0x00}, 0}, | ||
158 | {{0x70, 0x09}, 0}, | ||
159 | {{0x71, 0x80}, 0}, | ||
160 | {{0x70, 0x05}, 0} | ||
161 | }; | ||
162 | for (i = 0; i < ARRAY_SIZE(stop_commands); i++) { | ||
163 | retval = jlj_write2(gspca_dev, stop_commands[i].instruction); | ||
164 | if (retval < 0) | ||
165 | return retval; | ||
166 | } | ||
167 | return retval; | ||
168 | } | ||
169 | |||
170 | /* This function is called as a workqueue function and runs whenever the camera | ||
171 | * is streaming data. Because it is a workqueue function it is allowed to sleep | ||
172 | * so we can use synchronous USB calls. To avoid possible collisions with other | ||
173 | * threads attempting to use the camera's USB interface the gspca usb_lock is | ||
174 | * used when performing the one USB control operation inside the workqueue, | ||
175 | * which tells the camera to close the stream. In practice the only thing | ||
176 | * which needs to be protected against is the usb_set_interface call that | ||
177 | * gspca makes during stream_off. Otherwise the camera doesn't provide any | ||
178 | * controls that the user could try to change. | ||
179 | */ | ||
180 | |||
181 | static void jlj_dostream(struct work_struct *work) | ||
182 | { | 155 | { |
183 | struct sd *dev = container_of(work, struct sd, work_struct); | 156 | struct sd *sd = (struct sd *) gspca_dev; |
184 | struct gspca_dev *gspca_dev = &dev->gspca_dev; | ||
185 | int blocks_left; /* 0x200-sized blocks remaining in current frame. */ | ||
186 | int act_len; | ||
187 | int packet_type; | 157 | int packet_type; |
188 | int ret; | 158 | u32 header_marker; |
189 | u8 *buffer; | ||
190 | 159 | ||
191 | buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); | 160 | PDEBUG(D_STREAM, "Got %d bytes out of %d for Block 0", |
192 | if (!buffer) { | 161 | len, JEILINJ_MAX_TRANSFER); |
193 | err("Couldn't allocate USB buffer"); | 162 | if (len != JEILINJ_MAX_TRANSFER) { |
194 | goto quit_stream; | 163 | PDEBUG(D_PACK, "bad length"); |
164 | goto discard; | ||
195 | } | 165 | } |
196 | while (gspca_dev->present && gspca_dev->streaming) { | 166 | /* check if it's start of frame */ |
197 | /* | 167 | header_marker = ((u32 *)data)[0]; |
198 | * Now request data block 0. Line 0 reports the size | 168 | if (header_marker == FRAME_START) { |
199 | * to download, in blocks of size 0x200, and also tells the | 169 | sd->blocks_left = data[0x0a] - 1; |
200 | * "actual" data size, in bytes, which seems best to ignore. | 170 | PDEBUG(D_STREAM, "blocks_left = 0x%x", sd->blocks_left); |
201 | */ | ||
202 | ret = usb_bulk_msg(gspca_dev->dev, | ||
203 | usb_rcvbulkpipe(gspca_dev->dev, 0x82), | ||
204 | buffer, JEILINJ_MAX_TRANSFER, &act_len, | ||
205 | JEILINJ_DATA_TIMEOUT); | ||
206 | PDEBUG(D_STREAM, | ||
207 | "Got %d bytes out of %d for Block 0", | ||
208 | act_len, JEILINJ_MAX_TRANSFER); | ||
209 | if (ret < 0 || act_len < FRAME_HEADER_LEN) | ||
210 | goto quit_stream; | ||
211 | blocks_left = buffer[0x0a] - 1; | ||
212 | PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left); | ||
213 | |||
214 | /* Start a new frame, and add the JPEG header, first thing */ | 171 | /* Start a new frame, and add the JPEG header, first thing */ |
215 | gspca_frame_add(gspca_dev, FIRST_PACKET, | 172 | gspca_frame_add(gspca_dev, FIRST_PACKET, |
216 | dev->jpeg_hdr, JPEG_HDR_SZ); | 173 | sd->jpeg_hdr, JPEG_HDR_SZ); |
217 | /* Toss line 0 of data block 0, keep the rest. */ | 174 | /* Toss line 0 of data block 0, keep the rest. */ |
218 | gspca_frame_add(gspca_dev, INTER_PACKET, | 175 | gspca_frame_add(gspca_dev, INTER_PACKET, |
219 | buffer + FRAME_HEADER_LEN, | 176 | data + FRAME_HEADER_LEN, |
220 | JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN); | 177 | JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN); |
221 | 178 | } else if (sd->blocks_left > 0) { | |
222 | while (blocks_left > 0) { | 179 | PDEBUG(D_STREAM, "%d blocks remaining for frame", |
223 | if (!gspca_dev->present) | 180 | sd->blocks_left); |
224 | goto quit_stream; | 181 | sd->blocks_left -= 1; |
225 | ret = usb_bulk_msg(gspca_dev->dev, | 182 | if (sd->blocks_left == 0) |
226 | usb_rcvbulkpipe(gspca_dev->dev, 0x82), | 183 | packet_type = LAST_PACKET; |
227 | buffer, JEILINJ_MAX_TRANSFER, &act_len, | 184 | else |
228 | JEILINJ_DATA_TIMEOUT); | 185 | packet_type = INTER_PACKET; |
229 | if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER) | 186 | gspca_frame_add(gspca_dev, packet_type, |
230 | goto quit_stream; | 187 | data, JEILINJ_MAX_TRANSFER); |
231 | PDEBUG(D_STREAM, | 188 | } else |
232 | "%d blocks remaining for frame", blocks_left); | 189 | goto discard; |
233 | blocks_left -= 1; | 190 | return; |
234 | if (blocks_left == 0) | 191 | discard: |
235 | packet_type = LAST_PACKET; | 192 | /* Discard data until a new frame starts. */ |
236 | else | 193 | gspca_dev->last_packet_type = DISCARD_PACKET; |
237 | packet_type = INTER_PACKET; | ||
238 | gspca_frame_add(gspca_dev, packet_type, | ||
239 | buffer, JEILINJ_MAX_TRANSFER); | ||
240 | } | ||
241 | } | ||
242 | quit_stream: | ||
243 | mutex_lock(&gspca_dev->usb_lock); | ||
244 | if (gspca_dev->present) | ||
245 | jlj_stop(gspca_dev); | ||
246 | mutex_unlock(&gspca_dev->usb_lock); | ||
247 | kfree(buffer); | ||
248 | } | 194 | } |
249 | 195 | ||
250 | /* This function is called at probe time just before sd_init */ | 196 | /* This function is called at probe time just before sd_init */ |
@@ -255,31 +201,50 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
255 | struct sd *dev = (struct sd *) gspca_dev; | 201 | struct sd *dev = (struct sd *) gspca_dev; |
256 | 202 | ||
257 | dev->quality = 85; | 203 | dev->quality = 85; |
258 | dev->jpegqual = 85; | ||
259 | PDEBUG(D_PROBE, | 204 | PDEBUG(D_PROBE, |
260 | "JEILINJ camera detected" | 205 | "JEILINJ camera detected" |
261 | " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 206 | " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
262 | cam->cam_mode = jlj_mode; | 207 | cam->cam_mode = jlj_mode; |
263 | cam->nmodes = 1; | 208 | cam->nmodes = 1; |
264 | cam->bulk = 1; | 209 | cam->bulk = 1; |
265 | /* We don't use the buffer gspca allocates so make it small. */ | 210 | cam->bulk_nurbs = 1; |
266 | cam->bulk_size = 32; | 211 | cam->bulk_size = JEILINJ_MAX_TRANSFER; |
267 | INIT_WORK(&dev->work_struct, jlj_dostream); | ||
268 | return 0; | 212 | return 0; |
269 | } | 213 | } |
270 | 214 | ||
271 | /* called on streamoff with alt==0 and on disconnect */ | 215 | static void sd_stopN(struct gspca_dev *gspca_dev) |
272 | /* the usb_lock is held at entry - restore on exit */ | ||
273 | static void sd_stop0(struct gspca_dev *gspca_dev) | ||
274 | { | 216 | { |
275 | struct sd *dev = (struct sd *) gspca_dev; | 217 | int i; |
218 | u8 *buf; | ||
219 | u8 stop_commands[][2] = { | ||
220 | {0x71, 0x00}, | ||
221 | {0x70, 0x09}, | ||
222 | {0x71, 0x80}, | ||
223 | {0x70, 0x05} | ||
224 | }; | ||
225 | |||
226 | for (;;) { | ||
227 | /* get the image remaining blocks */ | ||
228 | usb_bulk_msg(gspca_dev->dev, | ||
229 | gspca_dev->urb[0]->pipe, | ||
230 | gspca_dev->urb[0]->transfer_buffer, | ||
231 | JEILINJ_MAX_TRANSFER, NULL, | ||
232 | JEILINJ_DATA_TIMEOUT); | ||
276 | 233 | ||
277 | /* wait for the work queue to terminate */ | 234 | /* search for 0xff 0xd9 (EOF for JPEG) */ |
278 | mutex_unlock(&gspca_dev->usb_lock); | 235 | i = 0; |
279 | /* This waits for jlj_dostream to finish */ | 236 | buf = gspca_dev->urb[0]->transfer_buffer; |
280 | destroy_workqueue(dev->work_thread); | 237 | while ((i < (JEILINJ_MAX_TRANSFER - 1)) && |
281 | dev->work_thread = NULL; | 238 | ((buf[i] != 0xff) || (buf[i+1] != 0xd9))) |
282 | mutex_lock(&gspca_dev->usb_lock); | 239 | i++; |
240 | |||
241 | if (i != (JEILINJ_MAX_TRANSFER - 1)) | ||
242 | /* last remaining block found */ | ||
243 | break; | ||
244 | } | ||
245 | |||
246 | for (i = 0; i < ARRAY_SIZE(stop_commands); i++) | ||
247 | jlj_write2(gspca_dev, stop_commands[i]); | ||
283 | } | 248 | } |
284 | 249 | ||
285 | /* this function is called at probe and resume time */ | 250 | /* this function is called at probe and resume time */ |
@@ -304,10 +269,6 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
304 | PDEBUG(D_ERR, "Start streaming command failed"); | 269 | PDEBUG(D_ERR, "Start streaming command failed"); |
305 | return ret; | 270 | return ret; |
306 | } | 271 | } |
307 | /* Start the workqueue function to do the streaming */ | ||
308 | dev->work_thread = create_singlethread_workqueue(MODULE_NAME); | ||
309 | queue_work(dev->work_thread, &dev->work_struct); | ||
310 | |||
311 | return 0; | 272 | return 0; |
312 | } | 273 | } |
313 | 274 | ||
@@ -325,7 +286,8 @@ static const struct sd_desc sd_desc = { | |||
325 | .config = sd_config, | 286 | .config = sd_config, |
326 | .init = sd_init, | 287 | .init = sd_init, |
327 | .start = sd_start, | 288 | .start = sd_start, |
328 | .stop0 = sd_stop0, | 289 | .stopN = sd_stopN, |
290 | .pkt_scan = sd_pkt_scan, | ||
329 | }; | 291 | }; |
330 | 292 | ||
331 | /* -- device connect -- */ | 293 | /* -- device connect -- */ |