/* * 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 * 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)
*/
/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */ #define MDC800_DEVICE_MINOR_BASE 32
/************************************************************************** Data and structs
***************************************************************************/
/* Data for the driver */ struct mdc800_data
{ struct usb_device * dev; // Device Data
mdc800_state state;
unsignedint 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;
};
/* The Variable used by the driver */ staticstruct mdc800_data* mdc800;
/*************************************************************************** The USB Part of the driver
****************************************************************************/
if (wake_up)
{
mdc800->camera_request_ready=0;
mdc800->irq_woken=1;
wake_up (&mdc800->irq_wait);
}
}
/* * 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
*/ staticint mdc800_usb_waitForIRQ (int mode, int msec)
{
mdc800->camera_request_ready=1+mode;
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;
}
/* * The write_urb callback function
*/ staticvoid mdc800_usb_write_notify (struct urb *urb)
{ struct mdc800_data* mdc800=urb->context; int status = urb->status;
/* * The download_urb callback function
*/ staticvoid 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);
}
/*************************************************************************** Probing for the Camera
***************************************************************************/
/* * Callback to search the Mustek MDC800 on the USB Bus
*/ staticint mdc800_usb_probe (struct usb_interface *intf, conststruct 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;
/* 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;
}
/*************************************************************************** The Misc device Part (file_operations)
****************************************************************************/
/* * This Function calc the Answersize for a command.
*/ staticint mdc800_getAnswerSize (char command)
{ switch ((unsignedchar) 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;
}
}
/* * Init the device: (1) alloc mem (2) Increase MOD Count ..
*/ staticint 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;
}
/* * 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, constchar __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)
{ unsignedchar c; if (signal_pending (current))
{
mutex_unlock(&mdc800->io_lock); return -EINTR;
}
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*(unsignedchar) mdc800->camera_response[0]+256*(unsignedchar) mdc800->camera_response[1]+(unsignedchar) mdc800->camera_response[2];
/*************************************************************************** Init and Cleanup this driver (Structs and types)
****************************************************************************/
MODULE_DEVICE_TABLE (usb, mdc800_table); /* * USB Driver Struct for this device
*/ staticstruct 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)
*************************************************************************/
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.