162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * copyright (C) 1999/2000 by Henning Zabel <henning@uni-paderborn.de> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci * USB-Kernel Driver for the Mustek MDC800 Digital Camera 962306a36Sopenharmony_ci * (c) 1999/2000 Henning Zabel <henning@uni-paderborn.de> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * The driver brings the USB functions of the MDC800 to Linux. 1362306a36Sopenharmony_ci * To use the Camera you must support the USB Protocol of the camera 1462306a36Sopenharmony_ci * to the Kernel Node. 1562306a36Sopenharmony_ci * The Driver uses a misc device Node. Create it with : 1662306a36Sopenharmony_ci * mknod /dev/mustek c 180 32 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * The driver supports only one camera. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Fix: mdc800 used sleep_on and slept with io_lock held. 2162306a36Sopenharmony_ci * Converted sleep_on to waitqueues with schedule_timeout and made io_lock 2262306a36Sopenharmony_ci * a semaphore from a spinlock. 2362306a36Sopenharmony_ci * by Oliver Neukum <oliver@neukum.name> 2462306a36Sopenharmony_ci * (02/12/2001) 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Identify version on module load. 2762306a36Sopenharmony_ci * (08/04/2001) gb 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * version 0.7.5 3062306a36Sopenharmony_ci * Fixed potential SMP races with Spinlocks. 3162306a36Sopenharmony_ci * Thanks to Oliver Neukum <oliver@neukum.name> who 3262306a36Sopenharmony_ci * noticed the race conditions. 3362306a36Sopenharmony_ci * (30/10/2000) 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * Fixed: Setting urb->dev before submitting urb. 3662306a36Sopenharmony_ci * by Greg KH <greg@kroah.com> 3762306a36Sopenharmony_ci * (13/10/2000) 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * version 0.7.3 4062306a36Sopenharmony_ci * bugfix : The mdc800->state field gets set to READY after the 4162306a36Sopenharmony_ci * disconnect function sets it to NOT_CONNECTED. This makes the 4262306a36Sopenharmony_ci * driver running like the camera is connected and causes some 4362306a36Sopenharmony_ci * hang ups. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * version 0.7.1 4662306a36Sopenharmony_ci * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload 4762306a36Sopenharmony_ci * problems when compiled as Module. 4862306a36Sopenharmony_ci * (04/04/2000) 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * The mdc800 driver gets assigned the USB Minor 32-47. The Registration 5162306a36Sopenharmony_ci * was updated to use these values. 5262306a36Sopenharmony_ci * (26/03/2000) 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * The Init und Exit Module Function are updated. 5562306a36Sopenharmony_ci * (01/03/2000) 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * version 0.7.0 5862306a36Sopenharmony_ci * Rewrite of the driver : The driver now uses URB's. The old stuff 5962306a36Sopenharmony_ci * has been removed. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * version 0.6.0 6262306a36Sopenharmony_ci * Rewrite of this driver: The Emulation of the rs232 protocoll 6362306a36Sopenharmony_ci * has been removed from the driver. A special executeCommand function 6462306a36Sopenharmony_ci * for this driver is included to gphoto. 6562306a36Sopenharmony_ci * The driver supports two kind of communication to bulk endpoints. 6662306a36Sopenharmony_ci * Either with the dev->bus->ops->bulk... or with callback function. 6762306a36Sopenharmony_ci * (09/11/1999) 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * version 0.5.0: 7062306a36Sopenharmony_ci * first Version that gets a version number. Most of the needed 7162306a36Sopenharmony_ci * functions work. 7262306a36Sopenharmony_ci * (20/10/1999) 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#include <linux/sched/signal.h> 7662306a36Sopenharmony_ci#include <linux/signal.h> 7762306a36Sopenharmony_ci#include <linux/spinlock.h> 7862306a36Sopenharmony_ci#include <linux/errno.h> 7962306a36Sopenharmony_ci#include <linux/random.h> 8062306a36Sopenharmony_ci#include <linux/poll.h> 8162306a36Sopenharmony_ci#include <linux/init.h> 8262306a36Sopenharmony_ci#include <linux/slab.h> 8362306a36Sopenharmony_ci#include <linux/module.h> 8462306a36Sopenharmony_ci#include <linux/wait.h> 8562306a36Sopenharmony_ci#include <linux/mutex.h> 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#include <linux/usb.h> 8862306a36Sopenharmony_ci#include <linux/fs.h> 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * Version Information 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci#define DRIVER_VERSION "v0.7.5 (30/10/2000)" 9462306a36Sopenharmony_ci#define DRIVER_AUTHOR "Henning Zabel <henning@uni-paderborn.de>" 9562306a36Sopenharmony_ci#define DRIVER_DESC "USB Driver for Mustek MDC800 Digital Camera" 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* Vendor and Product Information */ 9862306a36Sopenharmony_ci#define MDC800_VENDOR_ID 0x055f 9962306a36Sopenharmony_ci#define MDC800_PRODUCT_ID 0xa800 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* Timeouts (msec) */ 10262306a36Sopenharmony_ci#define TO_DOWNLOAD_GET_READY 1500 10362306a36Sopenharmony_ci#define TO_DOWNLOAD_GET_BUSY 1500 10462306a36Sopenharmony_ci#define TO_WRITE_GET_READY 1000 10562306a36Sopenharmony_ci#define TO_DEFAULT_COMMAND 5000 10662306a36Sopenharmony_ci#define TO_READ_FROM_IRQ TO_DEFAULT_COMMAND 10762306a36Sopenharmony_ci#define TO_GET_READY TO_DEFAULT_COMMAND 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */ 11062306a36Sopenharmony_ci#define MDC800_DEVICE_MINOR_BASE 32 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/************************************************************************** 11462306a36Sopenharmony_ci Data and structs 11562306a36Sopenharmony_ci***************************************************************************/ 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_citypedef enum { 11962306a36Sopenharmony_ci NOT_CONNECTED, READY, WORKING, DOWNLOAD 12062306a36Sopenharmony_ci} mdc800_state; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* Data for the driver */ 12462306a36Sopenharmony_cistruct mdc800_data 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct usb_device * dev; // Device Data 12762306a36Sopenharmony_ci mdc800_state state; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci unsigned int endpoint [4]; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci struct urb * irq_urb; 13262306a36Sopenharmony_ci wait_queue_head_t irq_wait; 13362306a36Sopenharmony_ci int irq_woken; 13462306a36Sopenharmony_ci char* irq_urb_buffer; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci int camera_busy; // is camera busy ? 13762306a36Sopenharmony_ci int camera_request_ready; // Status to synchronize with irq 13862306a36Sopenharmony_ci char camera_response [8]; // last Bytes send after busy 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci struct urb * write_urb; 14162306a36Sopenharmony_ci char* write_urb_buffer; 14262306a36Sopenharmony_ci wait_queue_head_t write_wait; 14362306a36Sopenharmony_ci int written; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci struct urb * download_urb; 14762306a36Sopenharmony_ci char* download_urb_buffer; 14862306a36Sopenharmony_ci wait_queue_head_t download_wait; 14962306a36Sopenharmony_ci int downloaded; 15062306a36Sopenharmony_ci int download_left; // Bytes left to download ? 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Device Data */ 15462306a36Sopenharmony_ci char out [64]; // Answer Buffer 15562306a36Sopenharmony_ci int out_ptr; // Index to the first not readen byte 15662306a36Sopenharmony_ci int out_count; // Bytes in the buffer 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci int open; // Camera device open ? 15962306a36Sopenharmony_ci struct mutex io_lock; // IO -lock 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci char in [8]; // Command Input Buffer 16262306a36Sopenharmony_ci int in_count; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci int pic_index; // Cache for the Imagesize (-1 for nothing cached ) 16562306a36Sopenharmony_ci int pic_len; 16662306a36Sopenharmony_ci int minor; 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* Specification of the Endpoints */ 17162306a36Sopenharmony_cistatic struct usb_endpoint_descriptor mdc800_ed [4] = 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci { 17462306a36Sopenharmony_ci .bLength = 0, 17562306a36Sopenharmony_ci .bDescriptorType = 0, 17662306a36Sopenharmony_ci .bEndpointAddress = 0x01, 17762306a36Sopenharmony_ci .bmAttributes = 0x02, 17862306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(8), 17962306a36Sopenharmony_ci .bInterval = 0, 18062306a36Sopenharmony_ci .bRefresh = 0, 18162306a36Sopenharmony_ci .bSynchAddress = 0, 18262306a36Sopenharmony_ci }, 18362306a36Sopenharmony_ci { 18462306a36Sopenharmony_ci .bLength = 0, 18562306a36Sopenharmony_ci .bDescriptorType = 0, 18662306a36Sopenharmony_ci .bEndpointAddress = 0x82, 18762306a36Sopenharmony_ci .bmAttributes = 0x03, 18862306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(8), 18962306a36Sopenharmony_ci .bInterval = 0, 19062306a36Sopenharmony_ci .bRefresh = 0, 19162306a36Sopenharmony_ci .bSynchAddress = 0, 19262306a36Sopenharmony_ci }, 19362306a36Sopenharmony_ci { 19462306a36Sopenharmony_ci .bLength = 0, 19562306a36Sopenharmony_ci .bDescriptorType = 0, 19662306a36Sopenharmony_ci .bEndpointAddress = 0x03, 19762306a36Sopenharmony_ci .bmAttributes = 0x02, 19862306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(64), 19962306a36Sopenharmony_ci .bInterval = 0, 20062306a36Sopenharmony_ci .bRefresh = 0, 20162306a36Sopenharmony_ci .bSynchAddress = 0, 20262306a36Sopenharmony_ci }, 20362306a36Sopenharmony_ci { 20462306a36Sopenharmony_ci .bLength = 0, 20562306a36Sopenharmony_ci .bDescriptorType = 0, 20662306a36Sopenharmony_ci .bEndpointAddress = 0x84, 20762306a36Sopenharmony_ci .bmAttributes = 0x02, 20862306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(64), 20962306a36Sopenharmony_ci .bInterval = 0, 21062306a36Sopenharmony_ci .bRefresh = 0, 21162306a36Sopenharmony_ci .bSynchAddress = 0, 21262306a36Sopenharmony_ci }, 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/* The Variable used by the driver */ 21662306a36Sopenharmony_cistatic struct mdc800_data* mdc800; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/*************************************************************************** 22062306a36Sopenharmony_ci The USB Part of the driver 22162306a36Sopenharmony_ci****************************************************************************/ 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int mdc800_endpoint_equals (struct usb_endpoint_descriptor *a,struct usb_endpoint_descriptor *b) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci return ( 22662306a36Sopenharmony_ci ( a->bEndpointAddress == b->bEndpointAddress ) 22762306a36Sopenharmony_ci && ( a->bmAttributes == b->bmAttributes ) 22862306a36Sopenharmony_ci && ( a->wMaxPacketSize == b->wMaxPacketSize ) 22962306a36Sopenharmony_ci ); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* 23462306a36Sopenharmony_ci * Checks whether the camera responds busy 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_cistatic int mdc800_isBusy (char* ch) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci int i=0; 23962306a36Sopenharmony_ci while (i<8) 24062306a36Sopenharmony_ci { 24162306a36Sopenharmony_ci if (ch [i] != (char)0x99) 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci i++; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci return 1; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/* 25062306a36Sopenharmony_ci * Checks whether the Camera is ready 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_cistatic int mdc800_isReady (char *ch) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci int i=0; 25562306a36Sopenharmony_ci while (i<8) 25662306a36Sopenharmony_ci { 25762306a36Sopenharmony_ci if (ch [i] != (char)0xbb) 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci i++; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci return 1; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* 26762306a36Sopenharmony_ci * USB IRQ Handler for InputLine 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_cistatic void mdc800_usb_irq (struct urb *urb) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci int data_received=0, wake_up; 27262306a36Sopenharmony_ci unsigned char* b=urb->transfer_buffer; 27362306a36Sopenharmony_ci struct mdc800_data* mdc800=urb->context; 27462306a36Sopenharmony_ci struct device *dev = &mdc800->dev->dev; 27562306a36Sopenharmony_ci int status = urb->status; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (status >= 0) { 27862306a36Sopenharmony_ci if (mdc800_isBusy (b)) 27962306a36Sopenharmony_ci { 28062306a36Sopenharmony_ci if (!mdc800->camera_busy) 28162306a36Sopenharmony_ci { 28262306a36Sopenharmony_ci mdc800->camera_busy=1; 28362306a36Sopenharmony_ci dev_dbg(dev, "gets busy\n"); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci else 28762306a36Sopenharmony_ci { 28862306a36Sopenharmony_ci if (mdc800->camera_busy && mdc800_isReady (b)) 28962306a36Sopenharmony_ci { 29062306a36Sopenharmony_ci mdc800->camera_busy=0; 29162306a36Sopenharmony_ci dev_dbg(dev, "gets ready\n"); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci if (!(mdc800_isBusy (b) || mdc800_isReady (b))) 29562306a36Sopenharmony_ci { 29662306a36Sopenharmony_ci /* Store Data in camera_answer field */ 29762306a36Sopenharmony_ci dev_dbg(dev, "%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci memcpy (mdc800->camera_response,b,8); 30062306a36Sopenharmony_ci data_received=1; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci wake_up= ( mdc800->camera_request_ready > 0 ) 30462306a36Sopenharmony_ci && 30562306a36Sopenharmony_ci ( 30662306a36Sopenharmony_ci ((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy)) 30762306a36Sopenharmony_ci || 30862306a36Sopenharmony_ci ((mdc800->camera_request_ready == 2) && data_received) 30962306a36Sopenharmony_ci || 31062306a36Sopenharmony_ci ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy)) 31162306a36Sopenharmony_ci || 31262306a36Sopenharmony_ci (status < 0) 31362306a36Sopenharmony_ci ); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (wake_up) 31662306a36Sopenharmony_ci { 31762306a36Sopenharmony_ci mdc800->camera_request_ready=0; 31862306a36Sopenharmony_ci mdc800->irq_woken=1; 31962306a36Sopenharmony_ci wake_up (&mdc800->irq_wait); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* 32562306a36Sopenharmony_ci * Waits a while until the irq responds that camera is ready 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci * mode : 0: Wait for camera gets ready 32862306a36Sopenharmony_ci * 1: Wait for receiving data 32962306a36Sopenharmony_ci * 2: Wait for camera gets busy 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci * msec: Time to wait 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_cistatic int mdc800_usb_waitForIRQ (int mode, int msec) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci mdc800->camera_request_ready=1+mode; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci wait_event_timeout(mdc800->irq_wait, mdc800->irq_woken, 33862306a36Sopenharmony_ci msecs_to_jiffies(msec)); 33962306a36Sopenharmony_ci mdc800->irq_woken = 0; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (mdc800->camera_request_ready>0) 34262306a36Sopenharmony_ci { 34362306a36Sopenharmony_ci mdc800->camera_request_ready=0; 34462306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, "timeout waiting for camera.\n"); 34562306a36Sopenharmony_ci return -1; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (mdc800->state == NOT_CONNECTED) 34962306a36Sopenharmony_ci { 35062306a36Sopenharmony_ci printk(KERN_WARNING "mdc800: Camera gets disconnected " 35162306a36Sopenharmony_ci "during waiting for irq.\n"); 35262306a36Sopenharmony_ci mdc800->camera_request_ready=0; 35362306a36Sopenharmony_ci return -2; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/* 36162306a36Sopenharmony_ci * The write_urb callback function 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_cistatic void mdc800_usb_write_notify (struct urb *urb) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci struct mdc800_data* mdc800=urb->context; 36662306a36Sopenharmony_ci int status = urb->status; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (status != 0) 36962306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, 37062306a36Sopenharmony_ci "writing command fails (status=%i)\n", status); 37162306a36Sopenharmony_ci else 37262306a36Sopenharmony_ci mdc800->state=READY; 37362306a36Sopenharmony_ci mdc800->written = 1; 37462306a36Sopenharmony_ci wake_up (&mdc800->write_wait); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/* 37962306a36Sopenharmony_ci * The download_urb callback function 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_cistatic void mdc800_usb_download_notify (struct urb *urb) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct mdc800_data* mdc800=urb->context; 38462306a36Sopenharmony_ci int status = urb->status; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (status == 0) { 38762306a36Sopenharmony_ci /* Fill output buffer with these data */ 38862306a36Sopenharmony_ci memcpy (mdc800->out, urb->transfer_buffer, 64); 38962306a36Sopenharmony_ci mdc800->out_count=64; 39062306a36Sopenharmony_ci mdc800->out_ptr=0; 39162306a36Sopenharmony_ci mdc800->download_left-=64; 39262306a36Sopenharmony_ci if (mdc800->download_left == 0) 39362306a36Sopenharmony_ci { 39462306a36Sopenharmony_ci mdc800->state=READY; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci } else { 39762306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, 39862306a36Sopenharmony_ci "request bytes fails (status:%i)\n", status); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci mdc800->downloaded = 1; 40162306a36Sopenharmony_ci wake_up (&mdc800->download_wait); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/*************************************************************************** 40662306a36Sopenharmony_ci Probing for the Camera 40762306a36Sopenharmony_ci ***************************************************************************/ 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic struct usb_driver mdc800_usb_driver; 41062306a36Sopenharmony_cistatic const struct file_operations mdc800_device_ops; 41162306a36Sopenharmony_cistatic struct usb_class_driver mdc800_class = { 41262306a36Sopenharmony_ci .name = "mdc800%d", 41362306a36Sopenharmony_ci .fops = &mdc800_device_ops, 41462306a36Sopenharmony_ci .minor_base = MDC800_DEVICE_MINOR_BASE, 41562306a36Sopenharmony_ci}; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/* 41962306a36Sopenharmony_ci * Callback to search the Mustek MDC800 on the USB Bus 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_cistatic int mdc800_usb_probe (struct usb_interface *intf, 42262306a36Sopenharmony_ci const struct usb_device_id *id) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci int i,j; 42562306a36Sopenharmony_ci struct usb_host_interface *intf_desc; 42662306a36Sopenharmony_ci struct usb_device *dev = interface_to_usbdev (intf); 42762306a36Sopenharmony_ci int irq_interval=0; 42862306a36Sopenharmony_ci int retval; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci dev_dbg(&intf->dev, "(%s) called.\n", __func__); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (mdc800->dev != NULL) 43462306a36Sopenharmony_ci { 43562306a36Sopenharmony_ci dev_warn(&intf->dev, "only one Mustek MDC800 is supported.\n"); 43662306a36Sopenharmony_ci return -ENODEV; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (dev->descriptor.bNumConfigurations != 1) 44062306a36Sopenharmony_ci { 44162306a36Sopenharmony_ci dev_err(&intf->dev, 44262306a36Sopenharmony_ci "probe fails -> wrong Number of Configuration\n"); 44362306a36Sopenharmony_ci return -ENODEV; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci intf_desc = intf->cur_altsetting; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if ( 44862306a36Sopenharmony_ci ( intf_desc->desc.bInterfaceClass != 0xff ) 44962306a36Sopenharmony_ci || ( intf_desc->desc.bInterfaceSubClass != 0 ) 45062306a36Sopenharmony_ci || ( intf_desc->desc.bInterfaceProtocol != 0 ) 45162306a36Sopenharmony_ci || ( intf_desc->desc.bNumEndpoints != 4) 45262306a36Sopenharmony_ci ) 45362306a36Sopenharmony_ci { 45462306a36Sopenharmony_ci dev_err(&intf->dev, "probe fails -> wrong Interface\n"); 45562306a36Sopenharmony_ci return -ENODEV; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* Check the Endpoints */ 45962306a36Sopenharmony_ci for (i=0; i<4; i++) 46062306a36Sopenharmony_ci { 46162306a36Sopenharmony_ci mdc800->endpoint[i]=-1; 46262306a36Sopenharmony_ci for (j=0; j<4; j++) 46362306a36Sopenharmony_ci { 46462306a36Sopenharmony_ci if (mdc800_endpoint_equals (&intf_desc->endpoint [j].desc,&mdc800_ed [i])) 46562306a36Sopenharmony_ci { 46662306a36Sopenharmony_ci mdc800->endpoint[i]=intf_desc->endpoint [j].desc.bEndpointAddress ; 46762306a36Sopenharmony_ci if (i==1) 46862306a36Sopenharmony_ci { 46962306a36Sopenharmony_ci irq_interval=intf_desc->endpoint [j].desc.bInterval; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci if (mdc800->endpoint[i] == -1) 47462306a36Sopenharmony_ci { 47562306a36Sopenharmony_ci dev_err(&intf->dev, "probe fails -> Wrong Endpoints.\n"); 47662306a36Sopenharmony_ci return -ENODEV; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci dev_info(&intf->dev, "Found Mustek MDC800 on USB.\n"); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci mutex_lock(&mdc800->io_lock); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci retval = usb_register_dev(intf, &mdc800_class); 48662306a36Sopenharmony_ci if (retval) { 48762306a36Sopenharmony_ci dev_err(&intf->dev, "Not able to get a minor for this device.\n"); 48862306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 48962306a36Sopenharmony_ci return -ENODEV; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci mdc800->dev=dev; 49362306a36Sopenharmony_ci mdc800->open=0; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci /* Setup URB Structs */ 49662306a36Sopenharmony_ci usb_fill_int_urb ( 49762306a36Sopenharmony_ci mdc800->irq_urb, 49862306a36Sopenharmony_ci mdc800->dev, 49962306a36Sopenharmony_ci usb_rcvintpipe (mdc800->dev,mdc800->endpoint [1]), 50062306a36Sopenharmony_ci mdc800->irq_urb_buffer, 50162306a36Sopenharmony_ci 8, 50262306a36Sopenharmony_ci mdc800_usb_irq, 50362306a36Sopenharmony_ci mdc800, 50462306a36Sopenharmony_ci irq_interval 50562306a36Sopenharmony_ci ); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci usb_fill_bulk_urb ( 50862306a36Sopenharmony_ci mdc800->write_urb, 50962306a36Sopenharmony_ci mdc800->dev, 51062306a36Sopenharmony_ci usb_sndbulkpipe (mdc800->dev, mdc800->endpoint[0]), 51162306a36Sopenharmony_ci mdc800->write_urb_buffer, 51262306a36Sopenharmony_ci 8, 51362306a36Sopenharmony_ci mdc800_usb_write_notify, 51462306a36Sopenharmony_ci mdc800 51562306a36Sopenharmony_ci ); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci usb_fill_bulk_urb ( 51862306a36Sopenharmony_ci mdc800->download_urb, 51962306a36Sopenharmony_ci mdc800->dev, 52062306a36Sopenharmony_ci usb_rcvbulkpipe (mdc800->dev, mdc800->endpoint [3]), 52162306a36Sopenharmony_ci mdc800->download_urb_buffer, 52262306a36Sopenharmony_ci 64, 52362306a36Sopenharmony_ci mdc800_usb_download_notify, 52462306a36Sopenharmony_ci mdc800 52562306a36Sopenharmony_ci ); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci mdc800->state=READY; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci usb_set_intfdata(intf, mdc800); 53262306a36Sopenharmony_ci return 0; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci/* 53762306a36Sopenharmony_ci * Disconnect USB device (maybe the MDC800) 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_cistatic void mdc800_usb_disconnect (struct usb_interface *intf) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci struct mdc800_data* mdc800 = usb_get_intfdata(intf); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci dev_dbg(&intf->dev, "(%s) called\n", __func__); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (mdc800) { 54662306a36Sopenharmony_ci if (mdc800->state == NOT_CONNECTED) 54762306a36Sopenharmony_ci return; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci usb_deregister_dev(intf, &mdc800_class); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* must be under lock to make sure no URB 55262306a36Sopenharmony_ci is submitted after usb_kill_urb() */ 55362306a36Sopenharmony_ci mutex_lock(&mdc800->io_lock); 55462306a36Sopenharmony_ci mdc800->state=NOT_CONNECTED; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci usb_kill_urb(mdc800->irq_urb); 55762306a36Sopenharmony_ci usb_kill_urb(mdc800->write_urb); 55862306a36Sopenharmony_ci usb_kill_urb(mdc800->download_urb); 55962306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci mdc800->dev = NULL; 56262306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci dev_info(&intf->dev, "Mustek MDC800 disconnected from USB.\n"); 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/*************************************************************************** 56962306a36Sopenharmony_ci The Misc device Part (file_operations) 57062306a36Sopenharmony_ci****************************************************************************/ 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci/* 57362306a36Sopenharmony_ci * This Function calc the Answersize for a command. 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_cistatic int mdc800_getAnswerSize (char command) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci switch ((unsigned char) command) 57862306a36Sopenharmony_ci { 57962306a36Sopenharmony_ci case 0x2a: 58062306a36Sopenharmony_ci case 0x49: 58162306a36Sopenharmony_ci case 0x51: 58262306a36Sopenharmony_ci case 0x0d: 58362306a36Sopenharmony_ci case 0x20: 58462306a36Sopenharmony_ci case 0x07: 58562306a36Sopenharmony_ci case 0x01: 58662306a36Sopenharmony_ci case 0x25: 58762306a36Sopenharmony_ci case 0x00: 58862306a36Sopenharmony_ci return 8; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci case 0x05: 59162306a36Sopenharmony_ci case 0x3e: 59262306a36Sopenharmony_ci return mdc800->pic_len; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci case 0x09: 59562306a36Sopenharmony_ci return 4096; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci default: 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci/* 60462306a36Sopenharmony_ci * Init the device: (1) alloc mem (2) Increase MOD Count .. 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_cistatic int mdc800_device_open (struct inode* inode, struct file *file) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci int retval=0; 60962306a36Sopenharmony_ci int errn=0; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci mutex_lock(&mdc800->io_lock); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (mdc800->state == NOT_CONNECTED) 61462306a36Sopenharmony_ci { 61562306a36Sopenharmony_ci errn=-EBUSY; 61662306a36Sopenharmony_ci goto error_out; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci if (mdc800->open) 61962306a36Sopenharmony_ci { 62062306a36Sopenharmony_ci errn=-EBUSY; 62162306a36Sopenharmony_ci goto error_out; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci mdc800->in_count=0; 62562306a36Sopenharmony_ci mdc800->out_count=0; 62662306a36Sopenharmony_ci mdc800->out_ptr=0; 62762306a36Sopenharmony_ci mdc800->pic_index=0; 62862306a36Sopenharmony_ci mdc800->pic_len=-1; 62962306a36Sopenharmony_ci mdc800->download_left=0; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci mdc800->camera_busy=0; 63262306a36Sopenharmony_ci mdc800->camera_request_ready=0; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci retval=0; 63562306a36Sopenharmony_ci mdc800->irq_urb->dev = mdc800->dev; 63662306a36Sopenharmony_ci retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL); 63762306a36Sopenharmony_ci if (retval) { 63862306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, 63962306a36Sopenharmony_ci "request USB irq fails (submit_retval=%i).\n", retval); 64062306a36Sopenharmony_ci errn = -EIO; 64162306a36Sopenharmony_ci goto error_out; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci mdc800->open=1; 64562306a36Sopenharmony_ci dev_dbg(&mdc800->dev->dev, "Mustek MDC800 device opened.\n"); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cierror_out: 64862306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 64962306a36Sopenharmony_ci return errn; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci/* 65462306a36Sopenharmony_ci * Close the Camera and release Memory 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_cistatic int mdc800_device_release (struct inode* inode, struct file *file) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci int retval=0; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci mutex_lock(&mdc800->io_lock); 66162306a36Sopenharmony_ci if (mdc800->open && (mdc800->state != NOT_CONNECTED)) 66262306a36Sopenharmony_ci { 66362306a36Sopenharmony_ci usb_kill_urb(mdc800->irq_urb); 66462306a36Sopenharmony_ci usb_kill_urb(mdc800->write_urb); 66562306a36Sopenharmony_ci usb_kill_urb(mdc800->download_urb); 66662306a36Sopenharmony_ci mdc800->open=0; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci else 66962306a36Sopenharmony_ci { 67062306a36Sopenharmony_ci retval=-EIO; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 67462306a36Sopenharmony_ci return retval; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/* 67962306a36Sopenharmony_ci * The Device read callback Function 68062306a36Sopenharmony_ci */ 68162306a36Sopenharmony_cistatic ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t len, loff_t *pos) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci size_t left=len, sts=len; /* single transfer size */ 68462306a36Sopenharmony_ci char __user *ptr = buf; 68562306a36Sopenharmony_ci int retval; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci mutex_lock(&mdc800->io_lock); 68862306a36Sopenharmony_ci if (mdc800->state == NOT_CONNECTED) 68962306a36Sopenharmony_ci { 69062306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 69162306a36Sopenharmony_ci return -EBUSY; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci if (mdc800->state == WORKING) 69462306a36Sopenharmony_ci { 69562306a36Sopenharmony_ci printk(KERN_WARNING "mdc800: Illegal State \"working\"" 69662306a36Sopenharmony_ci "reached during read ?!\n"); 69762306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 69862306a36Sopenharmony_ci return -EBUSY; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci if (!mdc800->open) 70162306a36Sopenharmony_ci { 70262306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 70362306a36Sopenharmony_ci return -EBUSY; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci while (left) 70762306a36Sopenharmony_ci { 70862306a36Sopenharmony_ci if (signal_pending (current)) 70962306a36Sopenharmony_ci { 71062306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 71162306a36Sopenharmony_ci return -EINTR; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (sts <= 0) 71762306a36Sopenharmony_ci { 71862306a36Sopenharmony_ci /* Too less Data in buffer */ 71962306a36Sopenharmony_ci if (mdc800->state == DOWNLOAD) 72062306a36Sopenharmony_ci { 72162306a36Sopenharmony_ci mdc800->out_count=0; 72262306a36Sopenharmony_ci mdc800->out_ptr=0; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Download -> Request new bytes */ 72562306a36Sopenharmony_ci mdc800->download_urb->dev = mdc800->dev; 72662306a36Sopenharmony_ci retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL); 72762306a36Sopenharmony_ci if (retval) { 72862306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, 72962306a36Sopenharmony_ci "Can't submit download urb " 73062306a36Sopenharmony_ci "(retval=%i)\n", retval); 73162306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 73262306a36Sopenharmony_ci return len-left; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci wait_event_timeout(mdc800->download_wait, 73562306a36Sopenharmony_ci mdc800->downloaded, 73662306a36Sopenharmony_ci msecs_to_jiffies(TO_DOWNLOAD_GET_READY)); 73762306a36Sopenharmony_ci mdc800->downloaded = 0; 73862306a36Sopenharmony_ci if (mdc800->download_urb->status != 0) 73962306a36Sopenharmony_ci { 74062306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, 74162306a36Sopenharmony_ci "request download-bytes fails " 74262306a36Sopenharmony_ci "(status=%i)\n", 74362306a36Sopenharmony_ci mdc800->download_urb->status); 74462306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 74562306a36Sopenharmony_ci return len-left; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci else 74962306a36Sopenharmony_ci { 75062306a36Sopenharmony_ci /* No more bytes -> that's an error*/ 75162306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 75262306a36Sopenharmony_ci return -EIO; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci else 75662306a36Sopenharmony_ci { 75762306a36Sopenharmony_ci /* Copy Bytes */ 75862306a36Sopenharmony_ci if (copy_to_user(ptr, &mdc800->out [mdc800->out_ptr], 75962306a36Sopenharmony_ci sts)) { 76062306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 76162306a36Sopenharmony_ci return -EFAULT; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci ptr+=sts; 76462306a36Sopenharmony_ci left-=sts; 76562306a36Sopenharmony_ci mdc800->out_ptr+=sts; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 77062306a36Sopenharmony_ci return len-left; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci/* 77562306a36Sopenharmony_ci * The Device write callback Function 77662306a36Sopenharmony_ci * If a 8Byte Command is received, it will be send to the camera. 77762306a36Sopenharmony_ci * After this the driver initiates the request for the answer or 77862306a36Sopenharmony_ci * just waits until the camera becomes ready. 77962306a36Sopenharmony_ci */ 78062306a36Sopenharmony_cistatic ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci size_t i=0; 78362306a36Sopenharmony_ci int retval; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci mutex_lock(&mdc800->io_lock); 78662306a36Sopenharmony_ci if (mdc800->state != READY) 78762306a36Sopenharmony_ci { 78862306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 78962306a36Sopenharmony_ci return -EBUSY; 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci if (!mdc800->open ) 79262306a36Sopenharmony_ci { 79362306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 79462306a36Sopenharmony_ci return -EBUSY; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci while (i<len) 79862306a36Sopenharmony_ci { 79962306a36Sopenharmony_ci unsigned char c; 80062306a36Sopenharmony_ci if (signal_pending (current)) 80162306a36Sopenharmony_ci { 80262306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 80362306a36Sopenharmony_ci return -EINTR; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if(get_user(c, buf+i)) 80762306a36Sopenharmony_ci { 80862306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 80962306a36Sopenharmony_ci return -EFAULT; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* check for command start */ 81362306a36Sopenharmony_ci if (c == 0x55) 81462306a36Sopenharmony_ci { 81562306a36Sopenharmony_ci mdc800->in_count=0; 81662306a36Sopenharmony_ci mdc800->out_count=0; 81762306a36Sopenharmony_ci mdc800->out_ptr=0; 81862306a36Sopenharmony_ci mdc800->download_left=0; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* save command byte */ 82262306a36Sopenharmony_ci if (mdc800->in_count < 8) 82362306a36Sopenharmony_ci { 82462306a36Sopenharmony_ci mdc800->in[mdc800->in_count] = c; 82562306a36Sopenharmony_ci mdc800->in_count++; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci else 82862306a36Sopenharmony_ci { 82962306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 83062306a36Sopenharmony_ci return -EIO; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* Command Buffer full ? -> send it to camera */ 83462306a36Sopenharmony_ci if (mdc800->in_count == 8) 83562306a36Sopenharmony_ci { 83662306a36Sopenharmony_ci int answersize; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (mdc800_usb_waitForIRQ (0,TO_GET_READY)) 83962306a36Sopenharmony_ci { 84062306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, 84162306a36Sopenharmony_ci "Camera didn't get ready.\n"); 84262306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 84362306a36Sopenharmony_ci return -EIO; 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci answersize=mdc800_getAnswerSize (mdc800->in[1]); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci mdc800->state=WORKING; 84962306a36Sopenharmony_ci memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8); 85062306a36Sopenharmony_ci mdc800->write_urb->dev = mdc800->dev; 85162306a36Sopenharmony_ci retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL); 85262306a36Sopenharmony_ci if (retval) { 85362306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, 85462306a36Sopenharmony_ci "submitting write urb fails " 85562306a36Sopenharmony_ci "(retval=%i)\n", retval); 85662306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 85762306a36Sopenharmony_ci return -EIO; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci wait_event_timeout(mdc800->write_wait, mdc800->written, 86062306a36Sopenharmony_ci msecs_to_jiffies(TO_WRITE_GET_READY)); 86162306a36Sopenharmony_ci mdc800->written = 0; 86262306a36Sopenharmony_ci if (mdc800->state == WORKING) 86362306a36Sopenharmony_ci { 86462306a36Sopenharmony_ci usb_kill_urb(mdc800->write_urb); 86562306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 86662306a36Sopenharmony_ci return -EIO; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci switch ((unsigned char) mdc800->in[1]) 87062306a36Sopenharmony_ci { 87162306a36Sopenharmony_ci case 0x05: /* Download Image */ 87262306a36Sopenharmony_ci case 0x3e: /* Take shot in Fine Mode (WCam Mode) */ 87362306a36Sopenharmony_ci if (mdc800->pic_len < 0) 87462306a36Sopenharmony_ci { 87562306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, 87662306a36Sopenharmony_ci "call 0x07 before " 87762306a36Sopenharmony_ci "0x05,0x3e\n"); 87862306a36Sopenharmony_ci mdc800->state=READY; 87962306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 88062306a36Sopenharmony_ci return -EIO; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci mdc800->pic_len=-1; 88362306a36Sopenharmony_ci fallthrough; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci case 0x09: /* Download Thumbnail */ 88662306a36Sopenharmony_ci mdc800->download_left=answersize+64; 88762306a36Sopenharmony_ci mdc800->state=DOWNLOAD; 88862306a36Sopenharmony_ci mdc800_usb_waitForIRQ (0,TO_DOWNLOAD_GET_BUSY); 88962306a36Sopenharmony_ci break; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci default: 89362306a36Sopenharmony_ci if (answersize) 89462306a36Sopenharmony_ci { 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ)) 89762306a36Sopenharmony_ci { 89862306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, "requesting answer from irq fails\n"); 89962306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 90062306a36Sopenharmony_ci return -EIO; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* Write dummy data, (this is ugly but part of the USB Protocol */ 90462306a36Sopenharmony_ci /* if you use endpoint 1 as bulk and not as irq) */ 90562306a36Sopenharmony_ci memcpy (mdc800->out, mdc800->camera_response,8); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* This is the interpreted answer */ 90862306a36Sopenharmony_ci memcpy (&mdc800->out[8], mdc800->camera_response,8); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci mdc800->out_ptr=0; 91162306a36Sopenharmony_ci mdc800->out_count=16; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* Cache the Imagesize, if command was getImageSize */ 91462306a36Sopenharmony_ci if (mdc800->in [1] == (char) 0x07) 91562306a36Sopenharmony_ci { 91662306a36Sopenharmony_ci mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2]; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci dev_dbg(&mdc800->dev->dev, "cached imagesize = %i\n", mdc800->pic_len); 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci else 92362306a36Sopenharmony_ci { 92462306a36Sopenharmony_ci if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND)) 92562306a36Sopenharmony_ci { 92662306a36Sopenharmony_ci dev_err(&mdc800->dev->dev, "Command Timeout.\n"); 92762306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 92862306a36Sopenharmony_ci return -EIO; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci mdc800->state=READY; 93262306a36Sopenharmony_ci break; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci i++; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci mutex_unlock(&mdc800->io_lock); 93862306a36Sopenharmony_ci return i; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci/*************************************************************************** 94362306a36Sopenharmony_ci Init and Cleanup this driver (Structs and types) 94462306a36Sopenharmony_ci****************************************************************************/ 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci/* File Operations of this drivers */ 94762306a36Sopenharmony_cistatic const struct file_operations mdc800_device_ops = 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci .owner = THIS_MODULE, 95062306a36Sopenharmony_ci .read = mdc800_device_read, 95162306a36Sopenharmony_ci .write = mdc800_device_write, 95262306a36Sopenharmony_ci .open = mdc800_device_open, 95362306a36Sopenharmony_ci .release = mdc800_device_release, 95462306a36Sopenharmony_ci .llseek = noop_llseek, 95562306a36Sopenharmony_ci}; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic const struct usb_device_id mdc800_table[] = { 96062306a36Sopenharmony_ci { USB_DEVICE(MDC800_VENDOR_ID, MDC800_PRODUCT_ID) }, 96162306a36Sopenharmony_ci { } /* Terminating entry */ 96262306a36Sopenharmony_ci}; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ciMODULE_DEVICE_TABLE (usb, mdc800_table); 96562306a36Sopenharmony_ci/* 96662306a36Sopenharmony_ci * USB Driver Struct for this device 96762306a36Sopenharmony_ci */ 96862306a36Sopenharmony_cistatic struct usb_driver mdc800_usb_driver = 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci .name = "mdc800", 97162306a36Sopenharmony_ci .probe = mdc800_usb_probe, 97262306a36Sopenharmony_ci .disconnect = mdc800_usb_disconnect, 97362306a36Sopenharmony_ci .id_table = mdc800_table 97462306a36Sopenharmony_ci}; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci/************************************************************************ 97962306a36Sopenharmony_ci Init and Cleanup this driver (Main Functions) 98062306a36Sopenharmony_ci*************************************************************************/ 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic int __init usb_mdc800_init (void) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci int retval = -ENODEV; 98562306a36Sopenharmony_ci /* Allocate Memory */ 98662306a36Sopenharmony_ci mdc800=kzalloc (sizeof (struct mdc800_data), GFP_KERNEL); 98762306a36Sopenharmony_ci if (!mdc800) 98862306a36Sopenharmony_ci goto cleanup_on_fail; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci mdc800->dev = NULL; 99162306a36Sopenharmony_ci mdc800->state=NOT_CONNECTED; 99262306a36Sopenharmony_ci mutex_init (&mdc800->io_lock); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci init_waitqueue_head (&mdc800->irq_wait); 99562306a36Sopenharmony_ci init_waitqueue_head (&mdc800->write_wait); 99662306a36Sopenharmony_ci init_waitqueue_head (&mdc800->download_wait); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci mdc800->irq_woken = 0; 99962306a36Sopenharmony_ci mdc800->downloaded = 0; 100062306a36Sopenharmony_ci mdc800->written = 0; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL); 100362306a36Sopenharmony_ci if (!mdc800->irq_urb_buffer) 100462306a36Sopenharmony_ci goto cleanup_on_fail; 100562306a36Sopenharmony_ci mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL); 100662306a36Sopenharmony_ci if (!mdc800->write_urb_buffer) 100762306a36Sopenharmony_ci goto cleanup_on_fail; 100862306a36Sopenharmony_ci mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL); 100962306a36Sopenharmony_ci if (!mdc800->download_urb_buffer) 101062306a36Sopenharmony_ci goto cleanup_on_fail; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL); 101362306a36Sopenharmony_ci if (!mdc800->irq_urb) 101462306a36Sopenharmony_ci goto cleanup_on_fail; 101562306a36Sopenharmony_ci mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL); 101662306a36Sopenharmony_ci if (!mdc800->download_urb) 101762306a36Sopenharmony_ci goto cleanup_on_fail; 101862306a36Sopenharmony_ci mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL); 101962306a36Sopenharmony_ci if (!mdc800->write_urb) 102062306a36Sopenharmony_ci goto cleanup_on_fail; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* Register the driver */ 102362306a36Sopenharmony_ci retval = usb_register(&mdc800_usb_driver); 102462306a36Sopenharmony_ci if (retval) 102562306a36Sopenharmony_ci goto cleanup_on_fail; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" 102862306a36Sopenharmony_ci DRIVER_DESC "\n"); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci return 0; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci /* Clean driver up, when something fails */ 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cicleanup_on_fail: 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci if (mdc800 != NULL) 103762306a36Sopenharmony_ci { 103862306a36Sopenharmony_ci printk(KERN_ERR "mdc800: can't alloc memory!\n"); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci kfree(mdc800->download_urb_buffer); 104162306a36Sopenharmony_ci kfree(mdc800->write_urb_buffer); 104262306a36Sopenharmony_ci kfree(mdc800->irq_urb_buffer); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci usb_free_urb(mdc800->write_urb); 104562306a36Sopenharmony_ci usb_free_urb(mdc800->download_urb); 104662306a36Sopenharmony_ci usb_free_urb(mdc800->irq_urb); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci kfree (mdc800); 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci mdc800 = NULL; 105162306a36Sopenharmony_ci return retval; 105262306a36Sopenharmony_ci} 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cistatic void __exit usb_mdc800_cleanup (void) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci usb_deregister (&mdc800_usb_driver); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci usb_free_urb (mdc800->irq_urb); 106062306a36Sopenharmony_ci usb_free_urb (mdc800->download_urb); 106162306a36Sopenharmony_ci usb_free_urb (mdc800->write_urb); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci kfree (mdc800->irq_urb_buffer); 106462306a36Sopenharmony_ci kfree (mdc800->write_urb_buffer); 106562306a36Sopenharmony_ci kfree (mdc800->download_urb_buffer); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci kfree (mdc800); 106862306a36Sopenharmony_ci mdc800 = NULL; 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_cimodule_init (usb_mdc800_init); 107262306a36Sopenharmony_cimodule_exit (usb_mdc800_cleanup); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ciMODULE_AUTHOR( DRIVER_AUTHOR ); 107562306a36Sopenharmony_ciMODULE_DESCRIPTION( DRIVER_DESC ); 107662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 107762306a36Sopenharmony_ci 1078