diff options
Diffstat (limited to 'drivers/media/video/gspca/sq905.c')
-rw-r--r-- | drivers/media/video/gspca/sq905.c | 56 |
1 files changed, 26 insertions, 30 deletions
diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c index 715a68f0156e..547d1fd5191d 100644 --- a/drivers/media/video/gspca/sq905.c +++ b/drivers/media/video/gspca/sq905.c | |||
@@ -168,18 +168,22 @@ static int sq905_ack_frame(struct gspca_dev *gspca_dev) | |||
168 | * request and read a block of data - see warning on sq905_command. | 168 | * request and read a block of data - see warning on sq905_command. |
169 | */ | 169 | */ |
170 | static int | 170 | static int |
171 | sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size) | 171 | sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock) |
172 | { | 172 | { |
173 | int ret; | 173 | int ret; |
174 | int act_len; | 174 | int act_len; |
175 | 175 | ||
176 | gspca_dev->usb_buf[0] = '\0'; | 176 | gspca_dev->usb_buf[0] = '\0'; |
177 | if (need_lock) | ||
178 | mutex_lock(&gspca_dev->usb_lock); | ||
177 | ret = usb_control_msg(gspca_dev->dev, | 179 | ret = usb_control_msg(gspca_dev->dev, |
178 | usb_sndctrlpipe(gspca_dev->dev, 0), | 180 | usb_sndctrlpipe(gspca_dev->dev, 0), |
179 | USB_REQ_SYNCH_FRAME, /* request */ | 181 | USB_REQ_SYNCH_FRAME, /* request */ |
180 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 182 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
181 | SQ905_BULK_READ, size, gspca_dev->usb_buf, | 183 | SQ905_BULK_READ, size, gspca_dev->usb_buf, |
182 | 1, SQ905_CMD_TIMEOUT); | 184 | 1, SQ905_CMD_TIMEOUT); |
185 | if (need_lock) | ||
186 | mutex_unlock(&gspca_dev->usb_lock); | ||
183 | if (ret < 0) { | 187 | if (ret < 0) { |
184 | PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret); | 188 | PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret); |
185 | return ret; | 189 | return ret; |
@@ -214,7 +218,6 @@ static void sq905_dostream(struct work_struct *work) | |||
214 | int bytes_left; /* bytes remaining in current frame. */ | 218 | int bytes_left; /* bytes remaining in current frame. */ |
215 | int data_len; /* size to use for the next read. */ | 219 | int data_len; /* size to use for the next read. */ |
216 | int header_read; /* true if we have already read the frame header. */ | 220 | int header_read; /* true if we have already read the frame header. */ |
217 | int discarding; /* true if we failed to get space for frame. */ | ||
218 | int packet_type; | 221 | int packet_type; |
219 | int frame_sz; | 222 | int frame_sz; |
220 | int ret; | 223 | int ret; |
@@ -222,7 +225,6 @@ static void sq905_dostream(struct work_struct *work) | |||
222 | u8 *buffer; | 225 | u8 *buffer; |
223 | 226 | ||
224 | buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); | 227 | buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); |
225 | mutex_lock(&gspca_dev->usb_lock); | ||
226 | if (!buffer) { | 228 | if (!buffer) { |
227 | PDEBUG(D_ERR, "Couldn't allocate USB buffer"); | 229 | PDEBUG(D_ERR, "Couldn't allocate USB buffer"); |
228 | goto quit_stream; | 230 | goto quit_stream; |
@@ -232,28 +234,22 @@ static void sq905_dostream(struct work_struct *work) | |||
232 | + FRAME_HEADER_LEN; | 234 | + FRAME_HEADER_LEN; |
233 | 235 | ||
234 | while (gspca_dev->present && gspca_dev->streaming) { | 236 | while (gspca_dev->present && gspca_dev->streaming) { |
235 | /* Need a short delay to ensure streaming flag was set by | ||
236 | * gspca and to make sure gspca can grab the mutex. */ | ||
237 | mutex_unlock(&gspca_dev->usb_lock); | ||
238 | msleep(1); | ||
239 | |||
240 | /* request some data and then read it until we have | 237 | /* request some data and then read it until we have |
241 | * a complete frame. */ | 238 | * a complete frame. */ |
242 | bytes_left = frame_sz; | 239 | bytes_left = frame_sz; |
243 | header_read = 0; | 240 | header_read = 0; |
244 | discarding = 0; | ||
245 | 241 | ||
246 | while (bytes_left > 0) { | 242 | /* Note we do not check for gspca_dev->streaming here, as |
243 | we must finish reading an entire frame, otherwise the | ||
244 | next time we stream we start reading in the middle of a | ||
245 | frame. */ | ||
246 | while (bytes_left > 0 && gspca_dev->present) { | ||
247 | data_len = bytes_left > SQ905_MAX_TRANSFER ? | 247 | data_len = bytes_left > SQ905_MAX_TRANSFER ? |
248 | SQ905_MAX_TRANSFER : bytes_left; | 248 | SQ905_MAX_TRANSFER : bytes_left; |
249 | mutex_lock(&gspca_dev->usb_lock); | 249 | ret = sq905_read_data(gspca_dev, buffer, data_len, 1); |
250 | if (!gspca_dev->present) | ||
251 | goto quit_stream; | ||
252 | ret = sq905_read_data(gspca_dev, buffer, data_len); | ||
253 | if (ret < 0) | 250 | if (ret < 0) |
254 | goto quit_stream; | 251 | goto quit_stream; |
255 | mutex_unlock(&gspca_dev->usb_lock); | 252 | PDEBUG(D_PACK, |
256 | PDEBUG(D_STREAM, | ||
257 | "Got %d bytes out of %d for frame", | 253 | "Got %d bytes out of %d for frame", |
258 | data_len, bytes_left); | 254 | data_len, bytes_left); |
259 | bytes_left -= data_len; | 255 | bytes_left -= data_len; |
@@ -271,7 +267,7 @@ static void sq905_dostream(struct work_struct *work) | |||
271 | packet_type = INTER_PACKET; | 267 | packet_type = INTER_PACKET; |
272 | } | 268 | } |
273 | frame = gspca_get_i_frame(gspca_dev); | 269 | frame = gspca_get_i_frame(gspca_dev); |
274 | if (frame && !discarding) { | 270 | if (frame) { |
275 | frame = gspca_frame_add(gspca_dev, packet_type, | 271 | frame = gspca_frame_add(gspca_dev, packet_type, |
276 | frame, data, data_len); | 272 | frame, data, data_len); |
277 | /* If entire frame fits in one packet we still | 273 | /* If entire frame fits in one packet we still |
@@ -281,23 +277,23 @@ static void sq905_dostream(struct work_struct *work) | |||
281 | frame = gspca_frame_add(gspca_dev, | 277 | frame = gspca_frame_add(gspca_dev, |
282 | LAST_PACKET, | 278 | LAST_PACKET, |
283 | frame, data, 0); | 279 | frame, data, 0); |
284 | } else { | ||
285 | discarding = 1; | ||
286 | } | 280 | } |
287 | } | 281 | } |
288 | /* acknowledge the frame */ | 282 | if (gspca_dev->present) { |
289 | mutex_lock(&gspca_dev->usb_lock); | 283 | /* acknowledge the frame */ |
290 | if (!gspca_dev->present) | 284 | mutex_lock(&gspca_dev->usb_lock); |
291 | goto quit_stream; | 285 | ret = sq905_ack_frame(gspca_dev); |
292 | ret = sq905_ack_frame(gspca_dev); | 286 | mutex_unlock(&gspca_dev->usb_lock); |
293 | if (ret < 0) | 287 | if (ret < 0) |
294 | goto quit_stream; | 288 | goto quit_stream; |
289 | } | ||
295 | } | 290 | } |
296 | quit_stream: | 291 | quit_stream: |
297 | /* the usb_lock is already acquired */ | 292 | if (gspca_dev->present) { |
298 | if (gspca_dev->present) | 293 | mutex_lock(&gspca_dev->usb_lock); |
299 | sq905_command(gspca_dev, SQ905_CLEAR); | 294 | sq905_command(gspca_dev, SQ905_CLEAR); |
300 | mutex_unlock(&gspca_dev->usb_lock); | 295 | mutex_unlock(&gspca_dev->usb_lock); |
296 | } | ||
301 | kfree(buffer); | 297 | kfree(buffer); |
302 | } | 298 | } |
303 | 299 | ||
@@ -346,7 +342,7 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
346 | ret = sq905_command(gspca_dev, SQ905_ID); | 342 | ret = sq905_command(gspca_dev, SQ905_ID); |
347 | if (ret < 0) | 343 | if (ret < 0) |
348 | return ret; | 344 | return ret; |
349 | ret = sq905_read_data(gspca_dev, gspca_dev->usb_buf, 4); | 345 | ret = sq905_read_data(gspca_dev, gspca_dev->usb_buf, 4, 0); |
350 | if (ret < 0) | 346 | if (ret < 0) |
351 | return ret; | 347 | return ret; |
352 | /* usb_buf is allocated with kmalloc so is aligned. | 348 | /* usb_buf is allocated with kmalloc so is aligned. |