cregit-Linux how code gets into the kernel

Release 4.11 drivers/usb/image/mdc800.c

/*
 * copyright (C) 1999/2000 by Henning Zabel <henning@uni-paderborn.de>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


/*
 *      USB-Kernel Driver for the Mustek MDC800 Digital Camera
 *      (c) 1999/2000 Henning Zabel <henning@uni-paderborn.de>
 *
 *
 * The driver brings the USB functions of the MDC800 to Linux.
 * To use the Camera you must support the USB Protocol of the camera
 * to the Kernel Node.
 * The Driver uses a misc device Node. Create it with :
 * mknod /dev/mustek c 180 32
 *
 * The driver supports only one camera.
 * 
 * Fix: mdc800 used sleep_on and slept with io_lock held.
 * Converted sleep_on to waitqueues with schedule_timeout and made io_lock
 * a semaphore from a spinlock.
 * by Oliver Neukum <oliver@neukum.name>
 * (02/12/2001)
 * 
 * Identify version on module load.
 * (08/04/2001) gb
 *
 * version 0.7.5
 * Fixed potential SMP races with Spinlocks.
 * Thanks to Oliver Neukum <oliver@neukum.name> who 
 * noticed the race conditions.
 * (30/10/2000)
 *
 * Fixed: Setting urb->dev before submitting urb.
 * by Greg KH <greg@kroah.com>
 * (13/10/2000)
 *
 * version 0.7.3
 * bugfix : The mdc800->state field gets set to READY after the
 * the disconnect function sets it to NOT_CONNECTED. This makes the
 * driver running like the camera is connected and causes some
 * hang ups.
 *
 * version 0.7.1
 * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload
 * problems when compiled as Module.
 * (04/04/2000)
 *
 * The mdc800 driver gets assigned the USB Minor 32-47. The Registration
 * was updated to use these values.
 * (26/03/2000)
 *
 * The Init und Exit Module Function are updated.
 * (01/03/2000)
 *
 * version 0.7.0
 * Rewrite of the driver : The driver now uses URB's. The old stuff
 * has been removed.
 *
 * version 0.6.0
 * Rewrite of this driver: The Emulation of the rs232 protocoll
 * has been removed from the driver. A special executeCommand function
 * for this driver is included to gphoto.
 * The driver supports two kind of communication to bulk endpoints.
 * Either with the dev->bus->ops->bulk... or with callback function.
 * (09/11/1999)
 *
 * version 0.5.0:
 * first Version that gets a version number. Most of the needed
 * functions work.
 * (20/10/1999)
 */

#include <linux/sched/signal.h>
#include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/wait.h>
#include <linux/mutex.h>

#include <linux/usb.h>
#include <linux/fs.h>

/*
 * Version Information
 */

#define DRIVER_VERSION "v0.7.5 (30/10/2000)"

#define DRIVER_AUTHOR "Henning Zabel <henning@uni-paderborn.de>"

#define DRIVER_DESC "USB Driver for Mustek MDC800 Digital Camera"

/* Vendor and Product Information */

#define MDC800_VENDOR_ID 	0x055f

#define MDC800_PRODUCT_ID	0xa800

/* Timeouts (msec) */

#define TO_DOWNLOAD_GET_READY		1500

#define TO_DOWNLOAD_GET_BUSY		1500

#define TO_WRITE_GET_READY		1000

#define TO_DEFAULT_COMMAND		5000

#define TO_READ_FROM_IRQ 		TO_DEFAULT_COMMAND

#define TO_GET_READY			TO_DEFAULT_COMMAND

/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */

#define MDC800_DEVICE_MINOR_BASE 32


/**************************************************************************
        Data and structs
***************************************************************************/


typedef enum {
	



NOT_CONNECTED, READY, WORKING, DOWNLOAD
} 
mdc800_state;


/* Data for the driver */

struct mdc800_data
{
	
struct usb_device *	dev;			// Device Data
	
mdc800_state 		state;

	
unsigned int		endpoint [4];

	
struct urb *		irq_urb;
	
wait_queue_head_t	irq_wait;
	
int			irq_woken;
	
char*			irq_urb_buffer;

	
int			camera_busy;          // is camera busy ?
	
int 			camera_request_ready; // Status to synchronize with irq
	
char 			camera_response [8];  // last Bytes send after busy

	
struct urb *   		write_urb;
	
char*			write_urb_buffer;
	
wait_queue_head_t	write_wait;
	
int			written;


	
struct urb *   		download_urb;
	
char*			download_urb_buffer;
	
wait_queue_head_t	download_wait;
	
int			downloaded;
	
int			download_left;		// Bytes left to download ?


	/* Device Data */
	
char			out [64];	// Answer Buffer
	
int 			out_ptr;	// Index to the first not readen byte
	
int			out_count;	// Bytes in the buffer

	
int			open;		// Camera device open ?
	
struct mutex		io_lock;	// IO -lock

	
char 			in [8];		// Command Input Buffer
	
int  			in_count;

	
int			pic_index;	// Cache for the Imagesize (-1 for nothing cached )
	
int			pic_len;
	
int			minor;
};


/* Specification of the Endpoints */

static struct usb_endpoint_descriptor mdc800_ed [4] =
{
	{ 
		.bLength = 		0,
		.bDescriptorType =	0,
		.bEndpointAddress =	0x01,
		.bmAttributes = 	0x02,
		.wMaxPacketSize =	cpu_to_le16(8),
		.bInterval = 		0,
		.bRefresh = 		0,
		.bSynchAddress = 	0,
        },
	{
		.bLength = 		0,
		.bDescriptorType = 	0,
		.bEndpointAddress = 	0x82,
		.bmAttributes = 	0x03,
		.wMaxPacketSize = 	cpu_to_le16(8),
		.bInterval = 		0,
		.bRefresh = 		0,
		.bSynchAddress = 	0,
        },
	{
		.bLength = 		0,
		.bDescriptorType = 	0,
		.bEndpointAddress = 	0x03,
		.bmAttributes = 	0x02,
		.wMaxPacketSize = 	cpu_to_le16(64),
		.bInterval = 		0,
		.bRefresh = 		0,
		.bSynchAddress = 	0,
        },
	{
		.bLength = 		0,
		.bDescriptorType = 	0,
		.bEndpointAddress = 	0x84,
		.bmAttributes = 	0x02,
		.wMaxPacketSize = 	cpu_to_le16(64),
		.bInterval = 		0,
		.bRefresh = 		0,
		.bSynchAddress = 	0,
        },
};

/* The Variable used by the driver */

static struct mdc800_data* mdc800;


/***************************************************************************
        The USB Part of the driver
****************************************************************************/


static int mdc800_endpoint_equals (struct usb_endpoint_descriptor *a,struct usb_endpoint_descriptor *b) { return ( ( a->bEndpointAddress == b->bEndpointAddress ) && ( a->bmAttributes == b->bmAttributes ) && ( a->wMaxPacketSize == b->wMaxPacketSize ) ); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)49100.00%1100.00%
Total49100.00%1100.00%

/* * Checks whether the camera responds busy */
static int mdc800_isBusy (char* ch) { int i=0; while (i<8) { if (ch [i] != (char)0x99) return 0; i++; } return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)44100.00%1100.00%
Total44100.00%1100.00%

/* * Checks whether the Camera is ready */
static int mdc800_isReady (char *ch) { int i=0; while (i<8) { if (ch [i] != (char)0xbb) return 0; i++; } return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)44100.00%1100.00%
Total44100.00%1100.00%

/* * USB IRQ Handler for InputLine */
static void mdc800_usb_irq (struct urb *urb) { int data_received=0, wake_up; unsigned char* b=urb->transfer_buffer; struct mdc800_data* mdc800=urb->context; struct device *dev = &mdc800->dev->dev; int status = urb->status; if (status >= 0) { if (mdc800_isBusy (b)) { if (!mdc800->camera_busy) { mdc800->camera_busy=1; dev_dbg(dev, "gets busy\n"); } } else { if (mdc800->camera_busy && mdc800_isReady (b)) { mdc800->camera_busy=0; dev_dbg(dev, "gets ready\n"); } } if (!(mdc800_isBusy (b) || mdc800_isReady (b))) { /* Store Data in camera_answer field */ 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]); memcpy (mdc800->camera_response,b,8); data_received=1; } } wake_up= ( mdc800->camera_request_ready > 0 ) && ( ((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy)) || ((mdc800->camera_request_ready == 2) && data_received) || ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy)) || (status < 0) ); if (wake_up) { mdc800->camera_request_ready=0; mdc800->irq_woken=1; wake_up (&mdc800->irq_wait); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)25486.99%120.00%
Greg Kroah-Hartman3110.62%240.00%
Linus Torvalds62.05%120.00%
Nishanth Aravamudan10.34%120.00%
Total292100.00%5100.00%

/* * Waits a while until the irq responds that camera is ready * * mode : 0: Wait for camera gets ready * 1: Wait for receiving data * 2: Wait for camera gets busy * * msec: Time to wait */
static int mdc800_usb_waitForIRQ (int mode, int msec) { mdc800->camera_request_ready=1+mode; wait_event_timeout(mdc800->irq_wait, mdc800->irq_woken, msecs_to_jiffies(msec)); mdc800->irq_woken = 0; if (mdc800->camera_request_ready>0) { mdc800->camera_request_ready=0; dev_err(&mdc800->dev->dev, "timeout waiting for camera.\n"); return -1; } if (mdc800->state == NOT_CONNECTED) { printk(KERN_WARNING "mdc800: Camera gets disconnected " "during waiting for irq.\n"); mdc800->camera_request_ready=0; return -2; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7572.12%228.57%
Greg Kroah-Hartman1312.50%228.57%
Linus Torvalds87.69%114.29%
Nishanth Aravamudan54.81%114.29%
Nicholas Mc Guire32.88%114.29%
Total104100.00%7100.00%

/* * The write_urb callback function */
static void mdc800_usb_write_notify (struct urb *urb) { struct mdc800_data* mdc800=urb->context; int status = urb->status; if (status != 0) dev_err(&mdc800->dev->dev, "writing command fails (status=%i)\n", status); else mdc800->state=READY; mdc800->written = 1; wake_up (&mdc800->write_wait); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4566.18%233.33%
Greg Kroah-Hartman1623.53%233.33%
Linus Torvalds68.82%116.67%
Nishanth Aravamudan11.47%116.67%
Total68100.00%6100.00%

/* * The download_urb callback function */
static void mdc800_usb_download_notify (struct urb *urb) { struct mdc800_data* mdc800=urb->context; int status = urb->status; if (status == 0) { /* Fill output buffer with these data */ memcpy (mdc800->out, urb->transfer_buffer, 64); mdc800->out_count=64; mdc800->out_ptr=0; mdc800->download_left-=64; if (mdc800->download_left == 0) { mdc800->state=READY; } } else { dev_err(&mdc800->dev->dev, "request bytes fails (status:%i)\n", status); } mdc800->downloaded = 1; wake_up (&mdc800->download_wait); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9179.82%120.00%
Greg Kroah-Hartman1614.04%240.00%
Linus Torvalds65.26%120.00%
Nishanth Aravamudan10.88%120.00%
Total114100.00%5100.00%

/*************************************************************************** Probing for the Camera ***************************************************************************/ static struct usb_driver mdc800_usb_driver; static const struct file_operations mdc800_device_ops; static struct usb_class_driver mdc800_class = { .name = "mdc800%d", .fops = &mdc800_device_ops, .minor_base = MDC800_DEVICE_MINOR_BASE, }; /* * Callback to search the Mustek MDC800 on the USB Bus */
static int mdc800_usb_probe (struct usb_interface *intf, const struct usb_device_id *id) { int i,j; struct usb_host_interface *intf_desc; struct usb_device *dev = interface_to_usbdev (intf); int irq_interval=0; int retval; dev_dbg(&intf->dev, "(%s) called.\n", __func__); if (mdc800->dev != NULL) { dev_warn(&intf->dev, "only one Mustek MDC800 is supported.\n"); return -ENODEV; } if (dev->descriptor.bNumConfigurations != 1) { dev_err(&intf->dev, "probe fails -> wrong Number of Configuration\n"); return -ENODEV; } intf_desc = intf->cur_altsetting; if ( ( intf_desc->desc.bInterfaceClass != 0xff ) || ( intf_desc->desc.bInterfaceSubClass != 0 ) || ( intf_desc->desc.bInterfaceProtocol != 0 ) || ( intf_desc->desc.bNumEndpoints != 4) ) { dev_err(&intf->dev, "probe fails -> wrong Interface\n"); return -ENODEV; } /* Check the Endpoints */ for (i=0; i<4; i++) { mdc800->endpoint[i]=-1; for (j=0; j<4; j++) { if (mdc800_endpoint_equals (&intf_desc->endpoint [j].desc,&mdc800_ed [i])) { mdc800->endpoint[i]=intf_desc->endpoint [j].desc.bEndpointAddress ; if (i==1) { irq_interval=intf_desc->endpoint [j].desc.bInterval; } } } if (mdc800->endpoint[i] == -1) { dev_err(&intf->dev, "probe fails -> Wrong Endpoints.\n"); return -ENODEV; } } dev_info(&intf->dev, "Found Mustek MDC800 on USB.\n"); mutex_lock(&mdc800->io_lock); retval = usb_register_dev(intf, &mdc800_class); if (retval) { dev_err(&intf->dev, "Not able to get a minor for this device.\n"); mutex_unlock(&mdc800->io_lock); return -ENODEV; } mdc800->dev=dev; mdc800->open=0; /* Setup URB Structs */ usb_fill_int_urb ( mdc800->irq_urb, mdc800->dev, usb_rcvintpipe (mdc800->dev,mdc800->endpoint [1]), mdc800->irq_urb_buffer, 8, mdc800_usb_irq, mdc800, irq_interval ); usb_fill_bulk_urb ( mdc800->write_urb, mdc800->dev, usb_sndbulkpipe (mdc800->dev, mdc800->endpoint[0]), mdc800->write_urb_buffer, 8, mdc800_usb_write_notify, mdc800 ); usb_fill_bulk_urb ( mdc800->download_urb, mdc800->dev, usb_rcvbulkpipe (mdc800->dev, mdc800->endpoint [3]), mdc800->download_urb_buffer, 64, mdc800_usb_download_notify, mdc800 ); mdc800->state=READY; mutex_unlock(&mdc800->io_lock); usb_set_intfdata(intf, mdc800); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)36572.71%525.00%
Greg Kroah-Hartman10721.31%945.00%
David Brownell152.99%15.00%
Jiri Slaby81.59%15.00%
Josh Myer30.60%15.00%
Arjan van de Ven20.40%15.00%
Alexey Dobriyan10.20%15.00%
Alan Stern10.20%15.00%
Total502100.00%20100.00%

/* * Disconnect USB device (maybe the MDC800) */
static void mdc800_usb_disconnect (struct usb_interface *intf) { struct mdc800_data* mdc800 = usb_get_intfdata(intf); dev_dbg(&intf->dev, "(%s) called\n", __func__); if (mdc800) { if (mdc800->state == NOT_CONNECTED) return; usb_deregister_dev(intf, &mdc800_class); /* must be under lock to make sure no URB is submitted after usb_kill_urb() */ mutex_lock(&mdc800->io_lock); mdc800->state=NOT_CONNECTED; usb_kill_urb(mdc800->irq_urb); usb_kill_urb(mdc800->write_urb); usb_kill_urb(mdc800->download_urb); mutex_unlock(&mdc800->io_lock); mdc800->dev = NULL; usb_set_intfdata(intf, NULL); } dev_info(&intf->dev, "Mustek MDC800 disconnected from USB.\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5947.97%110.00%
Greg Kroah-Hartman4334.96%660.00%
Oliver Neukum1713.82%110.00%
Borislav Petkov32.44%110.00%
Al Viro10.81%110.00%
Total123100.00%10100.00%

/*************************************************************************** The Misc device Part (file_operations) ****************************************************************************/ /* * This Function calc the Answersize for a command. */
static int mdc800_getAnswerSize (char command) { switch ((unsigned char) command) { case 0x2a: case 0x49: case 0x51: case 0x0d: case 0x20: case 0x07: case 0x01: case 0x25: case 0x00: return 8; case 0x05: case 0x3e: return mdc800->pic_len; case 0x09: return 4096; default: return 0; } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)70100.00%1100.00%
Total70100.00%1100.00%

/* * Init the device: (1) alloc mem (2) Increase MOD Count .. */
static int mdc800_device_open (struct inode* inode, struct file *file) { int retval=0; int errn=0; mutex_lock(&mdc800->io_lock); if (mdc800->state == NOT_CONNECTED) { errn=-EBUSY; goto error_out; } if (mdc800->open) { errn=-EBUSY; goto error_out; } mdc800->in_count=0; mdc800->out_count=0; mdc800->out_ptr=0; mdc800->pic_index=0; mdc800->pic_len=-1; mdc800->download_left=0; mdc800->camera_busy=0; mdc800->camera_request_ready=0; retval=0; mdc800->irq_urb->dev = mdc800->dev; retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL); if (retval) { dev_err(&mdc800->dev->dev, "request USB irq fails (submit_retval=%i).\n", retval); errn = -EIO; goto error_out; } mdc800->open=1; dev_dbg(&mdc800->dev->dev, "Mustek MDC800 device opened.\n"); error_out: mutex_unlock(&mdc800->io_lock); return errn; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)17386.07%444.44%
Greg Kroah-Hartman2612.94%444.44%
Arjan van de Ven21.00%111.11%
Total201100.00%9100.00%

/* * Close the Camera and release Memory */
static int mdc800_device_release (struct inode* inode, struct file *file) { int retval=0; mutex_lock(&mdc800->io_lock); if (mdc800->open && (mdc800->state != NOT_CONNECTED)) { usb_kill_urb(mdc800->irq_urb); usb_kill_urb(mdc800->write_urb); usb_kill_urb(mdc800->download_urb); mdc800->open=0; } else { retval=-EIO; } mutex_unlock(&mdc800->io_lock); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7481.32%342.86%
Linus Torvalds1213.19%228.57%
Borislav Petkov33.30%114.29%
Arjan van de Ven22.20%114.29%
Total91100.00%7100.00%

/* * The Device read callback Function */
static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t len, loff_t *pos) { size_t left=len, sts=len; /* single transfer size */ char __user *ptr = buf; int retval; mutex_lock(&mdc800->io_lock); if (mdc800->state == NOT_CONNECTED) { mutex_unlock(&mdc800->io_lock); return -EBUSY; } if (mdc800->state == WORKING) { printk(KERN_WARNING "mdc800: Illegal State \"working\"" "reached during read ?!\n"); mutex_unlock(&mdc800->io_lock); return -EBUSY; } if (!mdc800->open) { mutex_unlock(&mdc800->io_lock); return -EBUSY; } while (left) { if (signal_pending (current)) { mutex_unlock(&mdc800->io_lock); return -EINTR; } sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left; if (sts <= 0) { /* Too less Data in buffer */ if (mdc800->state == DOWNLOAD) { mdc800->out_count=0; mdc800->out_ptr=0; /* Download -> Request new bytes */ mdc800->download_urb->dev = mdc800->dev; retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL); if (retval) { dev_err(&mdc800->dev->dev, "Can't submit download urb " "(retval=%i)\n", retval); mutex_unlock(&mdc800->io_lock); return len-left; } wait_event_timeout(mdc800->download_wait, mdc800->downloaded, msecs_to_jiffies(TO_DOWNLOAD_GET_READY)); mdc800->downloaded = 0; if (mdc800->download_urb->status != 0) { dev_err(&mdc800->dev->dev, "request download-bytes fails " "(status=%i)\n", mdc800->download_urb->status); mutex_unlock(&mdc800->io_lock); return len-left; } } else { /* No more bytes -> that's an error*/ mutex_unlock(&mdc800->io_lock); return -EIO; } } else { /* Copy Bytes */ if (copy_to_user(ptr, &mdc800->out [mdc800->out_ptr], sts)) { mutex_unlock(&mdc800->io_lock); return -EFAULT; } ptr+=sts; left-=sts; mdc800->out_ptr+=sts; } } mutex_unlock(&mdc800->io_lock); return len-left; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)32579.85%426.67%
Greg Kroah-Hartman399.58%640.00%
Andrew Morton174.18%16.67%
Arjan van de Ven102.46%16.67%
Linus Torvalds81.97%16.67%
Nishanth Aravamudan51.23%16.67%
Nicholas Mc Guire30.74%16.67%
Total407100.00%15100.00%

/* * The Device write callback Function * If a 8Byte Command is received, it will be send to the camera. * After this the driver initiates the request for the answer or * just waits until the camera becomes ready. */
static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos) { size_t i=0; int retval; mutex_lock(&mdc800->io_lock); if (mdc800->state != READY) { mutex_unlock(&mdc800->io_lock); return -EBUSY; } if (!mdc800->open ) { mutex_unlock(&mdc800->io_lock); return -EBUSY; } while (i<len) { unsigned char c; if (signal_pending (current)) { mutex_unlock(&mdc800->io_lock); return -EINTR; } if(get_user(c, buf+i)) { mutex_unlock(&mdc800->io_lock); return -EFAULT; } /* check for command start */ if (c == 0x55) { mdc800->in_count=0; mdc800->out_count=0; mdc800->out_ptr=0; mdc800->download_left=0; } /* save command byte */ if (mdc800->in_count < 8) { mdc800->in[mdc800->in_count] = c; mdc800->in_count++; } else { mutex_unlock(&mdc800->io_lock); return -EIO; } /* Command Buffer full ? -> send it to camera */ if (mdc800->in_count == 8) { int answersize; if (mdc800_usb_waitForIRQ (0,TO_GET_READY)) { dev_err(&mdc800->dev->dev, "Camera didn't get ready.\n"); mutex_unlock(&mdc800->io_lock); return -EIO; } answersize=mdc800_getAnswerSize (mdc800->in[1]); mdc800->state=WORKING; memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8); mdc800->write_urb->dev = mdc800->dev; retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL); if (retval) { dev_err(&mdc800->dev->dev, "submitting write urb fails " "(retval=%i)\n", retval); mutex_unlock(&mdc800->io_lock); return -EIO; } wait_event_timeout(mdc800->write_wait, mdc800->written, msecs_to_jiffies(TO_WRITE_GET_READY)); mdc800->written = 0; if (mdc800->state == WORKING) { usb_kill_urb(mdc800->write_urb); mutex_unlock(&mdc800->io_lock); return -EIO; } switch ((unsigned char) mdc800->in[1]) { case 0x05: /* Download Image */ case 0x3e: /* Take shot in Fine Mode (WCam Mode) */ if (mdc800->pic_len < 0) { dev_err(&mdc800->dev->dev, "call 0x07 before " "0x05,0x3e\n"); mdc800->state=READY; mutex_unlock(&mdc800->io_lock); return -EIO; } mdc800->pic_len=-1; case 0x09: /* Download Thumbnail */ mdc800->download_left=answersize+64; mdc800->state=DOWNLOAD; mdc800_usb_waitForIRQ (0,TO_DOWNLOAD_GET_BUSY); break; default: if (answersize) { if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ)) { dev_err(&mdc800->dev->dev, "requesting answer from irq fails\n"); mutex_unlock(&mdc800->io_lock); return -EIO; } /* Write dummy data, (this is ugly but part of the USB Protocol */ /* if you use endpoint 1 as bulk and not as irq) */ memcpy (mdc800->out, mdc800->camera_response,8); /* This is the interpreted answer */ memcpy (&mdc800->out[8], mdc800->camera_response,8); mdc800->out_ptr=0; mdc800->out_count=16; /* Cache the Imagesize, if command was getImageSize */ if (mdc800->in [1] == (char) 0x07) { mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2]; dev_dbg(&mdc800->dev->dev, "cached imagesize = %i\n", mdc800->pic_len); } } else { if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND)) { dev_err(&mdc800->dev->dev, "Command Timeout.\n"); mutex_unlock(&mdc800->io_lock); return -EIO; } } mdc800->state=READY; break; } } i++; } mutex_unlock(&mdc800->io_lock); return i; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)59382.02%529.41%
Greg Kroah-Hartman699.54%635.29%
Andrew Morton314.29%15.88%
Arjan van de Ven131.80%15.88%
Linus Torvalds81.11%15.88%
Nishanth Aravamudan50.69%15.88%
Nicholas Mc Guire30.41%15.88%
Borislav Petkov10.14%15.88%
Total723100.00%17100.00%

/*************************************************************************** Init and Cleanup this driver (Structs and types) ****************************************************************************/ /* File Operations of this drivers */ static const struct file_operations mdc800_device_ops = { .owner = THIS_MODULE, .read = mdc800_device_read, .write = mdc800_device_write, .open = mdc800_device_open, .release = mdc800_device_release, .llseek = noop_llseek, }; static const struct usb_device_id mdc800_table[] = { { USB_DEVICE(MDC800_VENDOR_ID, MDC800_PRODUCT_ID) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, mdc800_table); /* * USB Driver Struct for this device */ static struct usb_driver mdc800_usb_driver = { .name = "mdc800", .probe = mdc800_usb_probe, .disconnect = mdc800_usb_disconnect, .id_table = mdc800_table }; /************************************************************************ Init and Cleanup this driver (Main Functions) *************************************************************************/
static int __init usb_mdc800_init (void) { int retval = -ENODEV; /* Allocate Memory */ mdc800=kzalloc (sizeof (struct mdc800_data), GFP_KERNEL); if (!mdc800) goto cleanup_on_fail; mdc800->dev = NULL; mdc800->state=NOT_CONNECTED; mutex_init (&mdc800->io_lock); init_waitqueue_head (&mdc800->irq_wait); init_waitqueue_head (&mdc800->write_wait); init_waitqueue_head (&mdc800->download_wait); mdc800->irq_woken = 0; mdc800->downloaded = 0; mdc800->written = 0; mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL); if (!mdc800->irq_urb_buffer) goto cleanup_on_fail; mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL); if (!mdc800->write_urb_buffer) goto cleanup_on_fail; mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL); if (!mdc800->download_urb_buffer) goto cleanup_on_fail; mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL); if (!mdc800->irq_urb) goto cleanup_on_fail; mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL); if (!mdc800->download_urb) goto cleanup_on_fail; mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL); if (!mdc800->write_urb) goto cleanup_on_fail; /* Register the driver */ retval = usb_register(&mdc800_usb_driver); if (retval) goto cleanup_on_fail; printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); return 0; /* Clean driver up, when something fails */ cleanup_on_fail: if (mdc800 != NULL) { printk(KERN_ERR "mdc800: can't alloc memory!\n"); kfree(mdc800->download_urb_buffer); kfree(mdc800->write_urb_buffer); kfree(mdc800->irq_urb_buffer); usb_free_urb(mdc800->write_urb); usb_free_urb(mdc800->download_urb); usb_free_urb(mdc800->irq_urb); kfree (mdc800); } mdc800 = NULL; return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)19760.62%213.33%
Alexey Dobriyan6921.23%213.33%
Greg Kroah-Hartman268.00%533.33%
Linus Torvalds195.85%213.33%
Daniele Bellucci113.38%16.67%
Arjan van de Ven10.31%16.67%
Al Viro10.31%16.67%
Oliver Neukum10.31%16.67%
Total325100.00%15100.00%


static void __exit usb_mdc800_cleanup (void) { usb_deregister (&mdc800_usb_driver); usb_free_urb (mdc800->irq_urb); usb_free_urb (mdc800->download_urb); usb_free_urb (mdc800->write_urb); kfree (mdc800->irq_urb_buffer); kfree (mdc800->write_urb_buffer); kfree (mdc800->download_urb_buffer); kfree (mdc800); mdc800 = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6496.97%133.33%
Greg Kroah-Hartman11.52%133.33%
Daniele Bellucci11.52%133.33%
Total66100.00%3100.00%

module_init (usb_mdc800_init); module_exit (usb_mdc800_cleanup); MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)290475.80%1117.74%
Greg Kroah-Hartman52713.76%1930.65%
Linus Torvalds1153.00%711.29%
Alexey Dobriyan701.83%23.23%
Andrew Morton481.25%11.61%
Arjan van de Ven340.89%11.61%
Nishanth Aravamudan210.55%23.23%
Oliver Neukum180.47%23.23%
Rusty Russell180.47%11.61%
David Brownell150.39%11.61%
Daniele Bellucci120.31%11.61%
Nicholas Mc Guire90.23%11.61%
Jiri Slaby80.21%11.61%
Borislav Petkov70.18%11.61%
Arnd Bergmann50.13%11.61%
Harvey Harrison40.10%11.61%
Dave Jones30.08%11.61%
Josh Myer30.08%11.61%
Al Viro20.05%11.61%
Michael Hayes20.05%11.61%
Luiz Fernando N. Capitulino20.05%11.61%
Alan Stern10.03%11.61%
Ingo Molnar10.03%11.61%
Rahul Bedarkar10.03%11.61%
Márton Németh10.03%11.61%
Total3831100.00%62100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.