18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/**************************************************************************** 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Filename: cpia2_usb.c 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2001, STMicrolectronics, Inc. 78c2ecf20Sopenharmony_ci * Contact: steve.miller@st.com 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Description: 108c2ecf20Sopenharmony_ci * This is a USB driver for CPia2 based video cameras. 118c2ecf20Sopenharmony_ci * The infrastructure of this driver is based on the cpia usb driver by 128c2ecf20Sopenharmony_ci * Jochen Scharrlach and Johannes Erdfeldt. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Stripped of 2.4 stuff ready for main kernel submit by 158c2ecf20Sopenharmony_ci * Alan Cox <alan@lxorguk.ukuu.org.uk> 168c2ecf20Sopenharmony_ci ****************************************************************************/ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/usb.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "cpia2.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int frame_sizes[] = { 268c2ecf20Sopenharmony_ci 0, // USBIF_CMDONLY 278c2ecf20Sopenharmony_ci 0, // USBIF_BULK 288c2ecf20Sopenharmony_ci 128, // USBIF_ISO_1 298c2ecf20Sopenharmony_ci 384, // USBIF_ISO_2 308c2ecf20Sopenharmony_ci 640, // USBIF_ISO_3 318c2ecf20Sopenharmony_ci 768, // USBIF_ISO_4 328c2ecf20Sopenharmony_ci 896, // USBIF_ISO_5 338c2ecf20Sopenharmony_ci 1023, // USBIF_ISO_6 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define FRAMES_PER_DESC 10 378c2ecf20Sopenharmony_ci#define FRAME_SIZE_PER_DESC frame_sizes[cam->cur_alt] 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void process_frame(struct camera_data *cam); 408c2ecf20Sopenharmony_cistatic void cpia2_usb_complete(struct urb *urb); 418c2ecf20Sopenharmony_cistatic int cpia2_usb_probe(struct usb_interface *intf, 428c2ecf20Sopenharmony_ci const struct usb_device_id *id); 438c2ecf20Sopenharmony_cistatic void cpia2_usb_disconnect(struct usb_interface *intf); 448c2ecf20Sopenharmony_cistatic int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message); 458c2ecf20Sopenharmony_cistatic int cpia2_usb_resume(struct usb_interface *intf); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void free_sbufs(struct camera_data *cam); 488c2ecf20Sopenharmony_cistatic void add_APPn(struct camera_data *cam); 498c2ecf20Sopenharmony_cistatic void add_COM(struct camera_data *cam); 508c2ecf20Sopenharmony_cistatic int submit_urbs(struct camera_data *cam); 518c2ecf20Sopenharmony_cistatic int set_alternate(struct camera_data *cam, unsigned int alt); 528c2ecf20Sopenharmony_cistatic int configure_transfer_mode(struct camera_data *cam, unsigned int alt); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic const struct usb_device_id cpia2_id_table[] = { 558c2ecf20Sopenharmony_ci {USB_DEVICE(0x0553, 0x0100)}, 568c2ecf20Sopenharmony_ci {USB_DEVICE(0x0553, 0x0140)}, 578c2ecf20Sopenharmony_ci {USB_DEVICE(0x0553, 0x0151)}, /* STV0676 */ 588c2ecf20Sopenharmony_ci {} /* Terminating entry */ 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, cpia2_id_table); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic struct usb_driver cpia2_driver = { 638c2ecf20Sopenharmony_ci .name = "cpia2", 648c2ecf20Sopenharmony_ci .probe = cpia2_usb_probe, 658c2ecf20Sopenharmony_ci .disconnect = cpia2_usb_disconnect, 668c2ecf20Sopenharmony_ci .suspend = cpia2_usb_suspend, 678c2ecf20Sopenharmony_ci .resume = cpia2_usb_resume, 688c2ecf20Sopenharmony_ci .reset_resume = cpia2_usb_resume, 698c2ecf20Sopenharmony_ci .id_table = cpia2_id_table 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/****************************************************************************** 748c2ecf20Sopenharmony_ci * 758c2ecf20Sopenharmony_ci * process_frame 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci *****************************************************************************/ 788c2ecf20Sopenharmony_cistatic void process_frame(struct camera_data *cam) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci static int frame_count; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci unsigned char *inbuff = cam->workbuff->data; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci DBG("Processing frame #%d, current:%d\n", 858c2ecf20Sopenharmony_ci cam->workbuff->num, cam->curbuff->num); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if(cam->workbuff->length > cam->workbuff->max_length) 888c2ecf20Sopenharmony_ci cam->workbuff->max_length = cam->workbuff->length; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) { 918c2ecf20Sopenharmony_ci frame_count++; 928c2ecf20Sopenharmony_ci } else { 938c2ecf20Sopenharmony_ci cam->workbuff->status = FRAME_ERROR; 948c2ecf20Sopenharmony_ci DBG("Start of frame not found\n"); 958c2ecf20Sopenharmony_ci return; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /*** 998c2ecf20Sopenharmony_ci * Now the output buffer should have a JPEG image in it. 1008c2ecf20Sopenharmony_ci ***/ 1018c2ecf20Sopenharmony_ci if(!cam->first_image_seen) { 1028c2ecf20Sopenharmony_ci /* Always skip the first image after streaming 1038c2ecf20Sopenharmony_ci * starts. It is almost certainly corrupt. */ 1048c2ecf20Sopenharmony_ci cam->first_image_seen = 1; 1058c2ecf20Sopenharmony_ci cam->workbuff->status = FRAME_EMPTY; 1068c2ecf20Sopenharmony_ci return; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci if (cam->workbuff->length > 3) { 1098c2ecf20Sopenharmony_ci if(cam->mmapped && 1108c2ecf20Sopenharmony_ci cam->workbuff->length < cam->workbuff->max_length) { 1118c2ecf20Sopenharmony_ci /* No junk in the buffers */ 1128c2ecf20Sopenharmony_ci memset(cam->workbuff->data+cam->workbuff->length, 1138c2ecf20Sopenharmony_ci 0, cam->workbuff->max_length- 1148c2ecf20Sopenharmony_ci cam->workbuff->length); 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci cam->workbuff->max_length = cam->workbuff->length; 1178c2ecf20Sopenharmony_ci cam->workbuff->status = FRAME_READY; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if(!cam->mmapped && cam->num_frames > 2) { 1208c2ecf20Sopenharmony_ci /* During normal reading, the most recent 1218c2ecf20Sopenharmony_ci * frame will be read. If the current frame 1228c2ecf20Sopenharmony_ci * hasn't started reading yet, it will never 1238c2ecf20Sopenharmony_ci * be read, so mark it empty. If the buffer is 1248c2ecf20Sopenharmony_ci * mmapped, or we have few buffers, we need to 1258c2ecf20Sopenharmony_ci * wait for the user to free the buffer. 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * NOTE: This is not entirely foolproof with 3 1288c2ecf20Sopenharmony_ci * buffers, but it would take an EXTREMELY 1298c2ecf20Sopenharmony_ci * overloaded system to cause problems (possible 1308c2ecf20Sopenharmony_ci * image data corruption). Basically, it would 1318c2ecf20Sopenharmony_ci * need to take more time to execute cpia2_read 1328c2ecf20Sopenharmony_ci * than it would for the camera to send 1338c2ecf20Sopenharmony_ci * cam->num_frames-2 frames before problems 1348c2ecf20Sopenharmony_ci * could occur. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci cam->curbuff->status = FRAME_EMPTY; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci cam->curbuff = cam->workbuff; 1398c2ecf20Sopenharmony_ci cam->workbuff = cam->workbuff->next; 1408c2ecf20Sopenharmony_ci DBG("Changed buffers, work:%d, current:%d\n", 1418c2ecf20Sopenharmony_ci cam->workbuff->num, cam->curbuff->num); 1428c2ecf20Sopenharmony_ci return; 1438c2ecf20Sopenharmony_ci } else { 1448c2ecf20Sopenharmony_ci DBG("Not enough data for an image.\n"); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci cam->workbuff->status = FRAME_ERROR; 1488c2ecf20Sopenharmony_ci return; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/****************************************************************************** 1528c2ecf20Sopenharmony_ci * 1538c2ecf20Sopenharmony_ci * add_APPn 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * Adds a user specified APPn record 1568c2ecf20Sopenharmony_ci *****************************************************************************/ 1578c2ecf20Sopenharmony_cistatic void add_APPn(struct camera_data *cam) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci if(cam->APP_len > 0) { 1608c2ecf20Sopenharmony_ci cam->workbuff->data[cam->workbuff->length++] = 0xFF; 1618c2ecf20Sopenharmony_ci cam->workbuff->data[cam->workbuff->length++] = 0xE0+cam->APPn; 1628c2ecf20Sopenharmony_ci cam->workbuff->data[cam->workbuff->length++] = 0; 1638c2ecf20Sopenharmony_ci cam->workbuff->data[cam->workbuff->length++] = cam->APP_len+2; 1648c2ecf20Sopenharmony_ci memcpy(cam->workbuff->data+cam->workbuff->length, 1658c2ecf20Sopenharmony_ci cam->APP_data, cam->APP_len); 1668c2ecf20Sopenharmony_ci cam->workbuff->length += cam->APP_len; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/****************************************************************************** 1718c2ecf20Sopenharmony_ci * 1728c2ecf20Sopenharmony_ci * add_COM 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * Adds a user specified COM record 1758c2ecf20Sopenharmony_ci *****************************************************************************/ 1768c2ecf20Sopenharmony_cistatic void add_COM(struct camera_data *cam) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci if(cam->COM_len > 0) { 1798c2ecf20Sopenharmony_ci cam->workbuff->data[cam->workbuff->length++] = 0xFF; 1808c2ecf20Sopenharmony_ci cam->workbuff->data[cam->workbuff->length++] = 0xFE; 1818c2ecf20Sopenharmony_ci cam->workbuff->data[cam->workbuff->length++] = 0; 1828c2ecf20Sopenharmony_ci cam->workbuff->data[cam->workbuff->length++] = cam->COM_len+2; 1838c2ecf20Sopenharmony_ci memcpy(cam->workbuff->data+cam->workbuff->length, 1848c2ecf20Sopenharmony_ci cam->COM_data, cam->COM_len); 1858c2ecf20Sopenharmony_ci cam->workbuff->length += cam->COM_len; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/****************************************************************************** 1908c2ecf20Sopenharmony_ci * 1918c2ecf20Sopenharmony_ci * cpia2_usb_complete 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * callback when incoming packet is received 1948c2ecf20Sopenharmony_ci *****************************************************************************/ 1958c2ecf20Sopenharmony_cistatic void cpia2_usb_complete(struct urb *urb) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci int i; 1988c2ecf20Sopenharmony_ci unsigned char *cdata; 1998c2ecf20Sopenharmony_ci static bool frame_ready = false; 2008c2ecf20Sopenharmony_ci struct camera_data *cam = (struct camera_data *) urb->context; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (urb->status!=0) { 2038c2ecf20Sopenharmony_ci if (!(urb->status == -ENOENT || 2048c2ecf20Sopenharmony_ci urb->status == -ECONNRESET || 2058c2ecf20Sopenharmony_ci urb->status == -ESHUTDOWN)) 2068c2ecf20Sopenharmony_ci { 2078c2ecf20Sopenharmony_ci DBG("urb->status = %d!\n", urb->status); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci DBG("Stopping streaming\n"); 2108c2ecf20Sopenharmony_ci return; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (!cam->streaming || !video_is_registered(&cam->vdev)) { 2148c2ecf20Sopenharmony_ci LOG("Will now stop the streaming: streaming = %d, present=%d\n", 2158c2ecf20Sopenharmony_ci cam->streaming, video_is_registered(&cam->vdev)); 2168c2ecf20Sopenharmony_ci return; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /*** 2208c2ecf20Sopenharmony_ci * Packet collater 2218c2ecf20Sopenharmony_ci ***/ 2228c2ecf20Sopenharmony_ci //DBG("Collating %d packets\n", urb->number_of_packets); 2238c2ecf20Sopenharmony_ci for (i = 0; i < urb->number_of_packets; i++) { 2248c2ecf20Sopenharmony_ci u16 checksum, iso_checksum; 2258c2ecf20Sopenharmony_ci int j; 2268c2ecf20Sopenharmony_ci int n = urb->iso_frame_desc[i].actual_length; 2278c2ecf20Sopenharmony_ci int st = urb->iso_frame_desc[i].status; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if(cam->workbuff->status == FRAME_READY) { 2308c2ecf20Sopenharmony_ci struct framebuf *ptr; 2318c2ecf20Sopenharmony_ci /* Try to find an available buffer */ 2328c2ecf20Sopenharmony_ci DBG("workbuff full, searching\n"); 2338c2ecf20Sopenharmony_ci for (ptr = cam->workbuff->next; 2348c2ecf20Sopenharmony_ci ptr != cam->workbuff; 2358c2ecf20Sopenharmony_ci ptr = ptr->next) 2368c2ecf20Sopenharmony_ci { 2378c2ecf20Sopenharmony_ci if (ptr->status == FRAME_EMPTY) { 2388c2ecf20Sopenharmony_ci ptr->status = FRAME_READING; 2398c2ecf20Sopenharmony_ci ptr->length = 0; 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci if (ptr == cam->workbuff) 2448c2ecf20Sopenharmony_ci break; /* No READING or EMPTY buffers left */ 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci cam->workbuff = ptr; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (cam->workbuff->status == FRAME_EMPTY || 2508c2ecf20Sopenharmony_ci cam->workbuff->status == FRAME_ERROR) { 2518c2ecf20Sopenharmony_ci cam->workbuff->status = FRAME_READING; 2528c2ecf20Sopenharmony_ci cam->workbuff->length = 0; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci //DBG(" Packet %d length = %d, status = %d\n", i, n, st); 2568c2ecf20Sopenharmony_ci cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (st) { 2598c2ecf20Sopenharmony_ci LOG("cpia2 data error: [%d] len=%d, status = %d\n", 2608c2ecf20Sopenharmony_ci i, n, st); 2618c2ecf20Sopenharmony_ci if(!ALLOW_CORRUPT) 2628c2ecf20Sopenharmony_ci cam->workbuff->status = FRAME_ERROR; 2638c2ecf20Sopenharmony_ci continue; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if(n<=2) 2678c2ecf20Sopenharmony_ci continue; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci checksum = 0; 2708c2ecf20Sopenharmony_ci for(j=0; j<n-2; ++j) 2718c2ecf20Sopenharmony_ci checksum += cdata[j]; 2728c2ecf20Sopenharmony_ci iso_checksum = cdata[j] + cdata[j+1]*256; 2738c2ecf20Sopenharmony_ci if(checksum != iso_checksum) { 2748c2ecf20Sopenharmony_ci LOG("checksum mismatch: [%d] len=%d, calculated = %x, checksum = %x\n", 2758c2ecf20Sopenharmony_ci i, n, (int)checksum, (int)iso_checksum); 2768c2ecf20Sopenharmony_ci if(!ALLOW_CORRUPT) { 2778c2ecf20Sopenharmony_ci cam->workbuff->status = FRAME_ERROR; 2788c2ecf20Sopenharmony_ci continue; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci n -= 2; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if(cam->workbuff->status != FRAME_READING) { 2848c2ecf20Sopenharmony_ci if((0xFF == cdata[0] && 0xD8 == cdata[1]) || 2858c2ecf20Sopenharmony_ci (0xD8 == cdata[0] && 0xFF == cdata[1] && 2868c2ecf20Sopenharmony_ci 0 != cdata[2])) { 2878c2ecf20Sopenharmony_ci /* frame is skipped, but increment total 2888c2ecf20Sopenharmony_ci * frame count anyway */ 2898c2ecf20Sopenharmony_ci cam->frame_count++; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci DBG("workbuff not reading, status=%d\n", 2928c2ecf20Sopenharmony_ci cam->workbuff->status); 2938c2ecf20Sopenharmony_ci continue; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (cam->frame_size < cam->workbuff->length + n) { 2978c2ecf20Sopenharmony_ci ERR("buffer overflow! length: %d, n: %d\n", 2988c2ecf20Sopenharmony_ci cam->workbuff->length, n); 2998c2ecf20Sopenharmony_ci cam->workbuff->status = FRAME_ERROR; 3008c2ecf20Sopenharmony_ci if(cam->workbuff->length > cam->workbuff->max_length) 3018c2ecf20Sopenharmony_ci cam->workbuff->max_length = 3028c2ecf20Sopenharmony_ci cam->workbuff->length; 3038c2ecf20Sopenharmony_ci continue; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (cam->workbuff->length == 0) { 3078c2ecf20Sopenharmony_ci int data_offset; 3088c2ecf20Sopenharmony_ci if ((0xD8 == cdata[0]) && (0xFF == cdata[1])) { 3098c2ecf20Sopenharmony_ci data_offset = 1; 3108c2ecf20Sopenharmony_ci } else if((0xFF == cdata[0]) && (0xD8 == cdata[1]) 3118c2ecf20Sopenharmony_ci && (0xFF == cdata[2])) { 3128c2ecf20Sopenharmony_ci data_offset = 2; 3138c2ecf20Sopenharmony_ci } else { 3148c2ecf20Sopenharmony_ci DBG("Ignoring packet, not beginning!\n"); 3158c2ecf20Sopenharmony_ci continue; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci DBG("Start of frame pattern found\n"); 3188c2ecf20Sopenharmony_ci cam->workbuff->ts = ktime_get_ns(); 3198c2ecf20Sopenharmony_ci cam->workbuff->seq = cam->frame_count++; 3208c2ecf20Sopenharmony_ci cam->workbuff->data[0] = 0xFF; 3218c2ecf20Sopenharmony_ci cam->workbuff->data[1] = 0xD8; 3228c2ecf20Sopenharmony_ci cam->workbuff->length = 2; 3238c2ecf20Sopenharmony_ci add_APPn(cam); 3248c2ecf20Sopenharmony_ci add_COM(cam); 3258c2ecf20Sopenharmony_ci memcpy(cam->workbuff->data+cam->workbuff->length, 3268c2ecf20Sopenharmony_ci cdata+data_offset, n-data_offset); 3278c2ecf20Sopenharmony_ci cam->workbuff->length += n-data_offset; 3288c2ecf20Sopenharmony_ci } else if (cam->workbuff->length > 0) { 3298c2ecf20Sopenharmony_ci memcpy(cam->workbuff->data + cam->workbuff->length, 3308c2ecf20Sopenharmony_ci cdata, n); 3318c2ecf20Sopenharmony_ci cam->workbuff->length += n; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if ((cam->workbuff->length >= 3) && 3358c2ecf20Sopenharmony_ci (cam->workbuff->data[cam->workbuff->length - 3] == 0xFF) && 3368c2ecf20Sopenharmony_ci (cam->workbuff->data[cam->workbuff->length - 2] == 0xD9) && 3378c2ecf20Sopenharmony_ci (cam->workbuff->data[cam->workbuff->length - 1] == 0xFF)) { 3388c2ecf20Sopenharmony_ci frame_ready = true; 3398c2ecf20Sopenharmony_ci cam->workbuff->data[cam->workbuff->length - 1] = 0; 3408c2ecf20Sopenharmony_ci cam->workbuff->length -= 1; 3418c2ecf20Sopenharmony_ci } else if ((cam->workbuff->length >= 2) && 3428c2ecf20Sopenharmony_ci (cam->workbuff->data[cam->workbuff->length - 2] == 0xFF) && 3438c2ecf20Sopenharmony_ci (cam->workbuff->data[cam->workbuff->length - 1] == 0xD9)) { 3448c2ecf20Sopenharmony_ci frame_ready = true; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (frame_ready) { 3488c2ecf20Sopenharmony_ci DBG("Workbuff image size = %d\n",cam->workbuff->length); 3498c2ecf20Sopenharmony_ci process_frame(cam); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci frame_ready = false; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (waitqueue_active(&cam->wq_stream)) 3548c2ecf20Sopenharmony_ci wake_up_interruptible(&cam->wq_stream); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if(cam->streaming) { 3598c2ecf20Sopenharmony_ci /* resubmit */ 3608c2ecf20Sopenharmony_ci urb->dev = cam->dev; 3618c2ecf20Sopenharmony_ci if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) 3628c2ecf20Sopenharmony_ci ERR("%s: usb_submit_urb ret %d!\n", __func__, i); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/****************************************************************************** 3678c2ecf20Sopenharmony_ci * 3688c2ecf20Sopenharmony_ci * configure_transfer_mode 3698c2ecf20Sopenharmony_ci * 3708c2ecf20Sopenharmony_ci *****************************************************************************/ 3718c2ecf20Sopenharmony_cistatic int configure_transfer_mode(struct camera_data *cam, unsigned int alt) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci static unsigned char iso_regs[8][4] = { 3748c2ecf20Sopenharmony_ci {0x00, 0x00, 0x00, 0x00}, 3758c2ecf20Sopenharmony_ci {0x00, 0x00, 0x00, 0x00}, 3768c2ecf20Sopenharmony_ci {0xB9, 0x00, 0x00, 0x7E}, 3778c2ecf20Sopenharmony_ci {0xB9, 0x00, 0x01, 0x7E}, 3788c2ecf20Sopenharmony_ci {0xB9, 0x00, 0x02, 0x7E}, 3798c2ecf20Sopenharmony_ci {0xB9, 0x00, 0x02, 0xFE}, 3808c2ecf20Sopenharmony_ci {0xB9, 0x00, 0x03, 0x7E}, 3818c2ecf20Sopenharmony_ci {0xB9, 0x00, 0x03, 0xFD} 3828c2ecf20Sopenharmony_ci }; 3838c2ecf20Sopenharmony_ci struct cpia2_command cmd; 3848c2ecf20Sopenharmony_ci unsigned char reg; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (!video_is_registered(&cam->vdev)) 3878c2ecf20Sopenharmony_ci return -ENODEV; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /*** 3908c2ecf20Sopenharmony_ci * Write the isoc registers according to the alternate selected 3918c2ecf20Sopenharmony_ci ***/ 3928c2ecf20Sopenharmony_ci cmd.direction = TRANSFER_WRITE; 3938c2ecf20Sopenharmony_ci cmd.buffer.block_data[0] = iso_regs[alt][0]; 3948c2ecf20Sopenharmony_ci cmd.buffer.block_data[1] = iso_regs[alt][1]; 3958c2ecf20Sopenharmony_ci cmd.buffer.block_data[2] = iso_regs[alt][2]; 3968c2ecf20Sopenharmony_ci cmd.buffer.block_data[3] = iso_regs[alt][3]; 3978c2ecf20Sopenharmony_ci cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; 3988c2ecf20Sopenharmony_ci cmd.start = CPIA2_VC_USB_ISOLIM; 3998c2ecf20Sopenharmony_ci cmd.reg_count = 4; 4008c2ecf20Sopenharmony_ci cpia2_send_command(cam, &cmd); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /*** 4038c2ecf20Sopenharmony_ci * Enable relevant streams before starting polling. 4048c2ecf20Sopenharmony_ci * First read USB Stream Config Register. 4058c2ecf20Sopenharmony_ci ***/ 4068c2ecf20Sopenharmony_ci cmd.direction = TRANSFER_READ; 4078c2ecf20Sopenharmony_ci cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; 4088c2ecf20Sopenharmony_ci cmd.start = CPIA2_VC_USB_STRM; 4098c2ecf20Sopenharmony_ci cmd.reg_count = 1; 4108c2ecf20Sopenharmony_ci cpia2_send_command(cam, &cmd); 4118c2ecf20Sopenharmony_ci reg = cmd.buffer.block_data[0]; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* Clear iso, bulk, and int */ 4148c2ecf20Sopenharmony_ci reg &= ~(CPIA2_VC_USB_STRM_BLK_ENABLE | 4158c2ecf20Sopenharmony_ci CPIA2_VC_USB_STRM_ISO_ENABLE | 4168c2ecf20Sopenharmony_ci CPIA2_VC_USB_STRM_INT_ENABLE); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (alt == USBIF_BULK) { 4198c2ecf20Sopenharmony_ci DBG("Enabling bulk xfer\n"); 4208c2ecf20Sopenharmony_ci reg |= CPIA2_VC_USB_STRM_BLK_ENABLE; /* Enable Bulk */ 4218c2ecf20Sopenharmony_ci cam->xfer_mode = XFER_BULK; 4228c2ecf20Sopenharmony_ci } else if (alt >= USBIF_ISO_1) { 4238c2ecf20Sopenharmony_ci DBG("Enabling ISOC xfer\n"); 4248c2ecf20Sopenharmony_ci reg |= CPIA2_VC_USB_STRM_ISO_ENABLE; 4258c2ecf20Sopenharmony_ci cam->xfer_mode = XFER_ISOC; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci cmd.buffer.block_data[0] = reg; 4298c2ecf20Sopenharmony_ci cmd.direction = TRANSFER_WRITE; 4308c2ecf20Sopenharmony_ci cmd.start = CPIA2_VC_USB_STRM; 4318c2ecf20Sopenharmony_ci cmd.reg_count = 1; 4328c2ecf20Sopenharmony_ci cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; 4338c2ecf20Sopenharmony_ci cpia2_send_command(cam, &cmd); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci return 0; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci/****************************************************************************** 4398c2ecf20Sopenharmony_ci * 4408c2ecf20Sopenharmony_ci * cpia2_usb_change_streaming_alternate 4418c2ecf20Sopenharmony_ci * 4428c2ecf20Sopenharmony_ci *****************************************************************************/ 4438c2ecf20Sopenharmony_ciint cpia2_usb_change_streaming_alternate(struct camera_data *cam, 4448c2ecf20Sopenharmony_ci unsigned int alt) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci int ret = 0; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if(alt < USBIF_ISO_1 || alt > USBIF_ISO_6) 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if(alt == cam->params.camera_state.stream_mode) 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci cpia2_usb_stream_pause(cam); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci configure_transfer_mode(cam, alt); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci cam->params.camera_state.stream_mode = alt; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* Reset the camera to prevent image quality degradation */ 4618c2ecf20Sopenharmony_ci cpia2_reset_camera(cam); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci cpia2_usb_stream_resume(cam); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci return ret; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci/****************************************************************************** 4698c2ecf20Sopenharmony_ci * 4708c2ecf20Sopenharmony_ci * set_alternate 4718c2ecf20Sopenharmony_ci * 4728c2ecf20Sopenharmony_ci *****************************************************************************/ 4738c2ecf20Sopenharmony_cistatic int set_alternate(struct camera_data *cam, unsigned int alt) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci int ret = 0; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if(alt == cam->cur_alt) 4788c2ecf20Sopenharmony_ci return 0; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (cam->cur_alt != USBIF_CMDONLY) { 4818c2ecf20Sopenharmony_ci DBG("Changing from alt %d to %d\n", cam->cur_alt, USBIF_CMDONLY); 4828c2ecf20Sopenharmony_ci ret = usb_set_interface(cam->dev, cam->iface, USBIF_CMDONLY); 4838c2ecf20Sopenharmony_ci if (ret != 0) 4848c2ecf20Sopenharmony_ci return ret; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci if (alt != USBIF_CMDONLY) { 4878c2ecf20Sopenharmony_ci DBG("Changing from alt %d to %d\n", USBIF_CMDONLY, alt); 4888c2ecf20Sopenharmony_ci ret = usb_set_interface(cam->dev, cam->iface, alt); 4898c2ecf20Sopenharmony_ci if (ret != 0) 4908c2ecf20Sopenharmony_ci return ret; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci cam->old_alt = cam->cur_alt; 4948c2ecf20Sopenharmony_ci cam->cur_alt = alt; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci/****************************************************************************** 5008c2ecf20Sopenharmony_ci * 5018c2ecf20Sopenharmony_ci * free_sbufs 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * Free all cam->sbuf[]. All non-NULL .data and .urb members that are non-NULL 5048c2ecf20Sopenharmony_ci * are assumed to be allocated. Non-NULL .urb members are also assumed to be 5058c2ecf20Sopenharmony_ci * submitted (and must therefore be killed before they are freed). 5068c2ecf20Sopenharmony_ci *****************************************************************************/ 5078c2ecf20Sopenharmony_cistatic void free_sbufs(struct camera_data *cam) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci int i; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SBUF; i++) { 5128c2ecf20Sopenharmony_ci if(cam->sbuf[i].urb) { 5138c2ecf20Sopenharmony_ci usb_kill_urb(cam->sbuf[i].urb); 5148c2ecf20Sopenharmony_ci usb_free_urb(cam->sbuf[i].urb); 5158c2ecf20Sopenharmony_ci cam->sbuf[i].urb = NULL; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci if(cam->sbuf[i].data) { 5188c2ecf20Sopenharmony_ci kfree(cam->sbuf[i].data); 5198c2ecf20Sopenharmony_ci cam->sbuf[i].data = NULL; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci/******* 5258c2ecf20Sopenharmony_ci* Convenience functions 5268c2ecf20Sopenharmony_ci*******/ 5278c2ecf20Sopenharmony_ci/**************************************************************************** 5288c2ecf20Sopenharmony_ci * 5298c2ecf20Sopenharmony_ci * write_packet 5308c2ecf20Sopenharmony_ci * 5318c2ecf20Sopenharmony_ci ***************************************************************************/ 5328c2ecf20Sopenharmony_cistatic int write_packet(struct usb_device *udev, 5338c2ecf20Sopenharmony_ci u8 request, u8 * registers, u16 start, size_t size) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci unsigned char *buf; 5368c2ecf20Sopenharmony_ci int ret; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (!registers || size <= 0) 5398c2ecf20Sopenharmony_ci return -EINVAL; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci buf = kmemdup(registers, size, GFP_KERNEL); 5428c2ecf20Sopenharmony_ci if (!buf) 5438c2ecf20Sopenharmony_ci return -ENOMEM; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci ret = usb_control_msg(udev, 5468c2ecf20Sopenharmony_ci usb_sndctrlpipe(udev, 0), 5478c2ecf20Sopenharmony_ci request, 5488c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE, 5498c2ecf20Sopenharmony_ci start, /* value */ 5508c2ecf20Sopenharmony_ci 0, /* index */ 5518c2ecf20Sopenharmony_ci buf, /* buffer */ 5528c2ecf20Sopenharmony_ci size, 5538c2ecf20Sopenharmony_ci 1000); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci kfree(buf); 5568c2ecf20Sopenharmony_ci return ret; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/**************************************************************************** 5608c2ecf20Sopenharmony_ci * 5618c2ecf20Sopenharmony_ci * read_packet 5628c2ecf20Sopenharmony_ci * 5638c2ecf20Sopenharmony_ci ***************************************************************************/ 5648c2ecf20Sopenharmony_cistatic int read_packet(struct usb_device *udev, 5658c2ecf20Sopenharmony_ci u8 request, u8 * registers, u16 start, size_t size) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci unsigned char *buf; 5688c2ecf20Sopenharmony_ci int ret; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (!registers || size <= 0) 5718c2ecf20Sopenharmony_ci return -EINVAL; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci buf = kmalloc(size, GFP_KERNEL); 5748c2ecf20Sopenharmony_ci if (!buf) 5758c2ecf20Sopenharmony_ci return -ENOMEM; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci ret = usb_control_msg(udev, 5788c2ecf20Sopenharmony_ci usb_rcvctrlpipe(udev, 0), 5798c2ecf20Sopenharmony_ci request, 5808c2ecf20Sopenharmony_ci USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE, 5818c2ecf20Sopenharmony_ci start, /* value */ 5828c2ecf20Sopenharmony_ci 0, /* index */ 5838c2ecf20Sopenharmony_ci buf, /* buffer */ 5848c2ecf20Sopenharmony_ci size, 5858c2ecf20Sopenharmony_ci 1000); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (ret >= 0) 5888c2ecf20Sopenharmony_ci memcpy(registers, buf, size); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci kfree(buf); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return ret; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci/****************************************************************************** 5968c2ecf20Sopenharmony_ci * 5978c2ecf20Sopenharmony_ci * cpia2_usb_transfer_cmd 5988c2ecf20Sopenharmony_ci * 5998c2ecf20Sopenharmony_ci *****************************************************************************/ 6008c2ecf20Sopenharmony_ciint cpia2_usb_transfer_cmd(struct camera_data *cam, 6018c2ecf20Sopenharmony_ci void *registers, 6028c2ecf20Sopenharmony_ci u8 request, u8 start, u8 count, u8 direction) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci int err = 0; 6058c2ecf20Sopenharmony_ci struct usb_device *udev = cam->dev; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (!udev) { 6088c2ecf20Sopenharmony_ci ERR("%s: Internal driver error: udev is NULL\n", __func__); 6098c2ecf20Sopenharmony_ci return -EINVAL; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (!registers) { 6138c2ecf20Sopenharmony_ci ERR("%s: Internal driver error: register array is NULL\n", __func__); 6148c2ecf20Sopenharmony_ci return -EINVAL; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (direction == TRANSFER_READ) { 6188c2ecf20Sopenharmony_ci err = read_packet(udev, request, (u8 *)registers, start, count); 6198c2ecf20Sopenharmony_ci if (err > 0) 6208c2ecf20Sopenharmony_ci err = 0; 6218c2ecf20Sopenharmony_ci } else if (direction == TRANSFER_WRITE) { 6228c2ecf20Sopenharmony_ci err =write_packet(udev, request, (u8 *)registers, start, count); 6238c2ecf20Sopenharmony_ci if (err < 0) { 6248c2ecf20Sopenharmony_ci LOG("Control message failed, err val = %d\n", err); 6258c2ecf20Sopenharmony_ci LOG("Message: request = 0x%0X, start = 0x%0X\n", 6268c2ecf20Sopenharmony_ci request, start); 6278c2ecf20Sopenharmony_ci LOG("Message: count = %d, register[0] = 0x%0X\n", 6288c2ecf20Sopenharmony_ci count, ((unsigned char *) registers)[0]); 6298c2ecf20Sopenharmony_ci } else 6308c2ecf20Sopenharmony_ci err=0; 6318c2ecf20Sopenharmony_ci } else { 6328c2ecf20Sopenharmony_ci LOG("Unexpected first byte of direction: %d\n", 6338c2ecf20Sopenharmony_ci direction); 6348c2ecf20Sopenharmony_ci return -EINVAL; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if(err != 0) 6388c2ecf20Sopenharmony_ci LOG("Unexpected error: %d\n", err); 6398c2ecf20Sopenharmony_ci return err; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/****************************************************************************** 6448c2ecf20Sopenharmony_ci * 6458c2ecf20Sopenharmony_ci * submit_urbs 6468c2ecf20Sopenharmony_ci * 6478c2ecf20Sopenharmony_ci *****************************************************************************/ 6488c2ecf20Sopenharmony_cistatic int submit_urbs(struct camera_data *cam) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct urb *urb; 6518c2ecf20Sopenharmony_ci int fx, err, i, j; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci for(i=0; i<NUM_SBUF; ++i) { 6548c2ecf20Sopenharmony_ci if (cam->sbuf[i].data) 6558c2ecf20Sopenharmony_ci continue; 6568c2ecf20Sopenharmony_ci cam->sbuf[i].data = 6578c2ecf20Sopenharmony_ci kmalloc_array(FRAME_SIZE_PER_DESC, FRAMES_PER_DESC, 6588c2ecf20Sopenharmony_ci GFP_KERNEL); 6598c2ecf20Sopenharmony_ci if (!cam->sbuf[i].data) { 6608c2ecf20Sopenharmony_ci while (--i >= 0) { 6618c2ecf20Sopenharmony_ci kfree(cam->sbuf[i].data); 6628c2ecf20Sopenharmony_ci cam->sbuf[i].data = NULL; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci return -ENOMEM; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* We double buffer the Isoc lists, and also know the polling 6698c2ecf20Sopenharmony_ci * interval is every frame (1 == (1 << (bInterval -1))). 6708c2ecf20Sopenharmony_ci */ 6718c2ecf20Sopenharmony_ci for(i=0; i<NUM_SBUF; ++i) { 6728c2ecf20Sopenharmony_ci if(cam->sbuf[i].urb) { 6738c2ecf20Sopenharmony_ci continue; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); 6768c2ecf20Sopenharmony_ci if (!urb) { 6778c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 6788c2ecf20Sopenharmony_ci usb_free_urb(cam->sbuf[j].urb); 6798c2ecf20Sopenharmony_ci for (j = 0; j < NUM_SBUF; j++) { 6808c2ecf20Sopenharmony_ci kfree(cam->sbuf[j].data); 6818c2ecf20Sopenharmony_ci cam->sbuf[j].data = NULL; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci return -ENOMEM; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci cam->sbuf[i].urb = urb; 6878c2ecf20Sopenharmony_ci urb->dev = cam->dev; 6888c2ecf20Sopenharmony_ci urb->context = cam; 6898c2ecf20Sopenharmony_ci urb->pipe = usb_rcvisocpipe(cam->dev, 1 /*ISOC endpoint*/); 6908c2ecf20Sopenharmony_ci urb->transfer_flags = URB_ISO_ASAP; 6918c2ecf20Sopenharmony_ci urb->transfer_buffer = cam->sbuf[i].data; 6928c2ecf20Sopenharmony_ci urb->complete = cpia2_usb_complete; 6938c2ecf20Sopenharmony_ci urb->number_of_packets = FRAMES_PER_DESC; 6948c2ecf20Sopenharmony_ci urb->interval = 1; 6958c2ecf20Sopenharmony_ci urb->transfer_buffer_length = 6968c2ecf20Sopenharmony_ci FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci for (fx = 0; fx < FRAMES_PER_DESC; fx++) { 6998c2ecf20Sopenharmony_ci urb->iso_frame_desc[fx].offset = 7008c2ecf20Sopenharmony_ci FRAME_SIZE_PER_DESC * fx; 7018c2ecf20Sopenharmony_ci urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* Queue the ISO urbs, and resubmit in the completion handler */ 7078c2ecf20Sopenharmony_ci for(i=0; i<NUM_SBUF; ++i) { 7088c2ecf20Sopenharmony_ci err = usb_submit_urb(cam->sbuf[i].urb, GFP_KERNEL); 7098c2ecf20Sopenharmony_ci if (err) { 7108c2ecf20Sopenharmony_ci ERR("usb_submit_urb[%d]() = %d\n", i, err); 7118c2ecf20Sopenharmony_ci return err; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return 0; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci/****************************************************************************** 7198c2ecf20Sopenharmony_ci * 7208c2ecf20Sopenharmony_ci * cpia2_usb_stream_start 7218c2ecf20Sopenharmony_ci * 7228c2ecf20Sopenharmony_ci *****************************************************************************/ 7238c2ecf20Sopenharmony_ciint cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci int ret; 7268c2ecf20Sopenharmony_ci int old_alt; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if(cam->streaming) 7298c2ecf20Sopenharmony_ci return 0; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (cam->flush) { 7328c2ecf20Sopenharmony_ci int i; 7338c2ecf20Sopenharmony_ci DBG("Flushing buffers\n"); 7348c2ecf20Sopenharmony_ci for(i=0; i<cam->num_frames; ++i) { 7358c2ecf20Sopenharmony_ci cam->buffers[i].status = FRAME_EMPTY; 7368c2ecf20Sopenharmony_ci cam->buffers[i].length = 0; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci cam->curbuff = &cam->buffers[0]; 7398c2ecf20Sopenharmony_ci cam->workbuff = cam->curbuff->next; 7408c2ecf20Sopenharmony_ci cam->flush = false; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci old_alt = cam->params.camera_state.stream_mode; 7448c2ecf20Sopenharmony_ci cam->params.camera_state.stream_mode = 0; 7458c2ecf20Sopenharmony_ci ret = cpia2_usb_change_streaming_alternate(cam, alternate); 7468c2ecf20Sopenharmony_ci if (ret < 0) { 7478c2ecf20Sopenharmony_ci int ret2; 7488c2ecf20Sopenharmony_ci ERR("cpia2_usb_change_streaming_alternate() = %d!\n", ret); 7498c2ecf20Sopenharmony_ci cam->params.camera_state.stream_mode = old_alt; 7508c2ecf20Sopenharmony_ci ret2 = set_alternate(cam, USBIF_CMDONLY); 7518c2ecf20Sopenharmony_ci if (ret2 < 0) { 7528c2ecf20Sopenharmony_ci ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already failed. Then tried to call set_alternate(USBIF_CMDONLY) = %d.\n", 7538c2ecf20Sopenharmony_ci alternate, ret, ret2); 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci } else { 7568c2ecf20Sopenharmony_ci cam->frame_count = 0; 7578c2ecf20Sopenharmony_ci cam->streaming = 1; 7588c2ecf20Sopenharmony_ci ret = cpia2_usb_stream_resume(cam); 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci return ret; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci/****************************************************************************** 7648c2ecf20Sopenharmony_ci * 7658c2ecf20Sopenharmony_ci * cpia2_usb_stream_pause 7668c2ecf20Sopenharmony_ci * 7678c2ecf20Sopenharmony_ci *****************************************************************************/ 7688c2ecf20Sopenharmony_ciint cpia2_usb_stream_pause(struct camera_data *cam) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci int ret = 0; 7718c2ecf20Sopenharmony_ci if(cam->streaming) { 7728c2ecf20Sopenharmony_ci free_sbufs(cam); 7738c2ecf20Sopenharmony_ci ret = set_alternate(cam, USBIF_CMDONLY); 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci return ret; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci/****************************************************************************** 7798c2ecf20Sopenharmony_ci * 7808c2ecf20Sopenharmony_ci * cpia2_usb_stream_resume 7818c2ecf20Sopenharmony_ci * 7828c2ecf20Sopenharmony_ci *****************************************************************************/ 7838c2ecf20Sopenharmony_ciint cpia2_usb_stream_resume(struct camera_data *cam) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci int ret = 0; 7868c2ecf20Sopenharmony_ci if(cam->streaming) { 7878c2ecf20Sopenharmony_ci cam->first_image_seen = 0; 7888c2ecf20Sopenharmony_ci ret = set_alternate(cam, cam->params.camera_state.stream_mode); 7898c2ecf20Sopenharmony_ci if(ret == 0) { 7908c2ecf20Sopenharmony_ci /* for some reason the user effects need to be set 7918c2ecf20Sopenharmony_ci again when starting streaming. */ 7928c2ecf20Sopenharmony_ci cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, 7938c2ecf20Sopenharmony_ci cam->params.vp_params.user_effects); 7948c2ecf20Sopenharmony_ci ret = submit_urbs(cam); 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci return ret; 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci/****************************************************************************** 8018c2ecf20Sopenharmony_ci * 8028c2ecf20Sopenharmony_ci * cpia2_usb_stream_stop 8038c2ecf20Sopenharmony_ci * 8048c2ecf20Sopenharmony_ci *****************************************************************************/ 8058c2ecf20Sopenharmony_ciint cpia2_usb_stream_stop(struct camera_data *cam) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci int ret; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci ret = cpia2_usb_stream_pause(cam); 8108c2ecf20Sopenharmony_ci cam->streaming = 0; 8118c2ecf20Sopenharmony_ci configure_transfer_mode(cam, 0); 8128c2ecf20Sopenharmony_ci return ret; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci/****************************************************************************** 8168c2ecf20Sopenharmony_ci * 8178c2ecf20Sopenharmony_ci * cpia2_usb_probe 8188c2ecf20Sopenharmony_ci * 8198c2ecf20Sopenharmony_ci * Probe and initialize. 8208c2ecf20Sopenharmony_ci *****************************************************************************/ 8218c2ecf20Sopenharmony_cistatic int cpia2_usb_probe(struct usb_interface *intf, 8228c2ecf20Sopenharmony_ci const struct usb_device_id *id) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 8258c2ecf20Sopenharmony_ci struct usb_interface_descriptor *interface; 8268c2ecf20Sopenharmony_ci struct camera_data *cam; 8278c2ecf20Sopenharmony_ci int ret; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* A multi-config CPiA2 camera? */ 8308c2ecf20Sopenharmony_ci if (udev->descriptor.bNumConfigurations != 1) 8318c2ecf20Sopenharmony_ci return -ENODEV; 8328c2ecf20Sopenharmony_ci interface = &intf->cur_altsetting->desc; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* If we get to this point, we found a CPiA2 camera */ 8358c2ecf20Sopenharmony_ci LOG("CPiA2 USB camera found\n"); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci cam = cpia2_init_camera_struct(intf); 8388c2ecf20Sopenharmony_ci if (cam == NULL) 8398c2ecf20Sopenharmony_ci return -ENOMEM; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci cam->dev = udev; 8428c2ecf20Sopenharmony_ci cam->iface = interface->bInterfaceNumber; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci ret = set_alternate(cam, USBIF_CMDONLY); 8458c2ecf20Sopenharmony_ci if (ret < 0) { 8468c2ecf20Sopenharmony_ci ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret); 8478c2ecf20Sopenharmony_ci goto alt_err; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if((ret = cpia2_init_camera(cam)) < 0) { 8528c2ecf20Sopenharmony_ci ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret); 8538c2ecf20Sopenharmony_ci goto alt_err; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci LOG(" CPiA Version: %d.%02d (%d.%d)\n", 8568c2ecf20Sopenharmony_ci cam->params.version.firmware_revision_hi, 8578c2ecf20Sopenharmony_ci cam->params.version.firmware_revision_lo, 8588c2ecf20Sopenharmony_ci cam->params.version.asic_id, 8598c2ecf20Sopenharmony_ci cam->params.version.asic_rev); 8608c2ecf20Sopenharmony_ci LOG(" CPiA PnP-ID: %04x:%04x:%04x\n", 8618c2ecf20Sopenharmony_ci cam->params.pnp_id.vendor, 8628c2ecf20Sopenharmony_ci cam->params.pnp_id.product, 8638c2ecf20Sopenharmony_ci cam->params.pnp_id.device_revision); 8648c2ecf20Sopenharmony_ci LOG(" SensorID: %d.(version %d)\n", 8658c2ecf20Sopenharmony_ci cam->params.version.sensor_flags, 8668c2ecf20Sopenharmony_ci cam->params.version.sensor_rev); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci usb_set_intfdata(intf, cam); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci ret = cpia2_register_camera(cam); 8718c2ecf20Sopenharmony_ci if (ret < 0) { 8728c2ecf20Sopenharmony_ci ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret); 8738c2ecf20Sopenharmony_ci goto alt_err; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci return 0; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cialt_err: 8798c2ecf20Sopenharmony_ci cpia2_deinit_camera_struct(cam, intf); 8808c2ecf20Sopenharmony_ci return ret; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci/****************************************************************************** 8848c2ecf20Sopenharmony_ci * 8858c2ecf20Sopenharmony_ci * cpia2_disconnect 8868c2ecf20Sopenharmony_ci * 8878c2ecf20Sopenharmony_ci *****************************************************************************/ 8888c2ecf20Sopenharmony_cistatic void cpia2_usb_disconnect(struct usb_interface *intf) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci struct camera_data *cam = usb_get_intfdata(intf); 8918c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci DBG("Stopping stream\n"); 8948c2ecf20Sopenharmony_ci cpia2_usb_stream_stop(cam); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci mutex_lock(&cam->v4l2_lock); 8978c2ecf20Sopenharmony_ci DBG("Unregistering camera\n"); 8988c2ecf20Sopenharmony_ci cpia2_unregister_camera(cam); 8998c2ecf20Sopenharmony_ci v4l2_device_disconnect(&cam->v4l2_dev); 9008c2ecf20Sopenharmony_ci mutex_unlock(&cam->v4l2_lock); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if(cam->buffers) { 9038c2ecf20Sopenharmony_ci DBG("Wakeup waiting processes\n"); 9048c2ecf20Sopenharmony_ci cam->curbuff->status = FRAME_READY; 9058c2ecf20Sopenharmony_ci cam->curbuff->length = 0; 9068c2ecf20Sopenharmony_ci wake_up_interruptible(&cam->wq_stream); 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci v4l2_device_put(&cam->v4l2_dev); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci LOG("CPiA2 camera disconnected.\n"); 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci struct camera_data *cam = usb_get_intfdata(intf); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci mutex_lock(&cam->v4l2_lock); 9198c2ecf20Sopenharmony_ci if (cam->streaming) { 9208c2ecf20Sopenharmony_ci cpia2_usb_stream_stop(cam); 9218c2ecf20Sopenharmony_ci cam->streaming = 1; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci mutex_unlock(&cam->v4l2_lock); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci dev_info(&intf->dev, "going into suspend..\n"); 9268c2ecf20Sopenharmony_ci return 0; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci/* Resume device - start device. */ 9308c2ecf20Sopenharmony_cistatic int cpia2_usb_resume(struct usb_interface *intf) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci struct camera_data *cam = usb_get_intfdata(intf); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci mutex_lock(&cam->v4l2_lock); 9358c2ecf20Sopenharmony_ci v4l2_ctrl_handler_setup(&cam->hdl); 9368c2ecf20Sopenharmony_ci if (cam->streaming) { 9378c2ecf20Sopenharmony_ci cam->streaming = 0; 9388c2ecf20Sopenharmony_ci cpia2_usb_stream_start(cam, 9398c2ecf20Sopenharmony_ci cam->params.camera_state.stream_mode); 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci mutex_unlock(&cam->v4l2_lock); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci dev_info(&intf->dev, "coming out of suspend..\n"); 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci/****************************************************************************** 9488c2ecf20Sopenharmony_ci * 9498c2ecf20Sopenharmony_ci * usb_cpia2_init 9508c2ecf20Sopenharmony_ci * 9518c2ecf20Sopenharmony_ci *****************************************************************************/ 9528c2ecf20Sopenharmony_ciint cpia2_usb_init(void) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci return usb_register(&cpia2_driver); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci/****************************************************************************** 9588c2ecf20Sopenharmony_ci * 9598c2ecf20Sopenharmony_ci * usb_cpia_cleanup 9608c2ecf20Sopenharmony_ci * 9618c2ecf20Sopenharmony_ci *****************************************************************************/ 9628c2ecf20Sopenharmony_civoid cpia2_usb_cleanup(void) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci schedule_timeout(2 * HZ); 9658c2ecf20Sopenharmony_ci usb_deregister(&cpia2_driver); 9668c2ecf20Sopenharmony_ci} 967