📄 mdc800.c
字号:
return mdc800;
}
/*
* Disconnect USB device (maybe the MDC800)
*/
static void mdc800_usb_disconnect (struct usb_device *dev,void* ptr)
{
struct mdc800_data* mdc800=(struct mdc800_data*) ptr;
dbg ("(mdc800_usb_disconnect) called");
if (mdc800->state == NOT_CONNECTED)
return;
usb_deregister_dev (&mdc800_usb_driver, 1, mdc800->minor);
mdc800->state=NOT_CONNECTED;
usb_unlink_urb (mdc800->irq_urb);
usb_unlink_urb (mdc800->write_urb);
usb_unlink_urb (mdc800->download_urb);
usb_driver_release_interface (&mdc800_usb_driver, &dev->actconfig->interface[1]);
mdc800->dev=0;
info ("Mustek MDC800 disconnected from USB.");
}
/***************************************************************************
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;
}
}
/*
* 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;
down (&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;
if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
{
err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
errn = -EIO;
goto error_out;
}
mdc800->open=1;
dbg ("Mustek MDC800 device opened.");
error_out:
up (&mdc800->io_lock);
return errn;
}
/*
* Close the Camera and release Memory
*/
static int mdc800_device_release (struct inode* inode, struct file *file)
{
int retval=0;
dbg ("Mustek MDC800 device closed.");
down (&mdc800->io_lock);
if (mdc800->open && (mdc800->state != NOT_CONNECTED))
{
usb_unlink_urb (mdc800->irq_urb);
usb_unlink_urb (mdc800->write_urb);
usb_unlink_urb (mdc800->download_urb);
mdc800->open=0;
}
else
{
retval=-EIO;
}
up(&mdc800->io_lock);
return retval;
}
/*
* The Device read callback Function
*/
static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, loff_t *pos)
{
int left=len, sts=len; /* single transfer size */
char* ptr=buf;
DECLARE_WAITQUEUE(wait, current);
down (&mdc800->io_lock);
if (mdc800->state == NOT_CONNECTED)
{
up (&mdc800->io_lock);
return -EBUSY;
}
if (mdc800->state == WORKING)
{
warn ("Illegal State \"working\" reached during read ?!");
up (&mdc800->io_lock);
return -EBUSY;
}
if (!mdc800->open)
{
up (&mdc800->io_lock);
return -EBUSY;
}
while (left)
{
if (signal_pending (current))
{
up (&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;
if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
{
err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
up (&mdc800->io_lock);
return len-left;
}
add_wait_queue(&mdc800->download_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
if (!mdc800->downloaded)
{
schedule_timeout (TO_DOWNLOAD_GET_READY*HZ/1000);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&mdc800->download_wait, &wait);
mdc800->downloaded = 0;
if (mdc800->download_urb->status != 0)
{
err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
up (&mdc800->io_lock);
return len-left;
}
}
else
{
/* No more bytes -> that's an error*/
up (&mdc800->io_lock);
return -EIO;
}
}
else
{
/* memcpy Bytes */
memcpy (ptr, &mdc800->out [mdc800->out_ptr], sts);
ptr+=sts;
left-=sts;
mdc800->out_ptr+=sts;
}
}
up (&mdc800->io_lock);
return len-left;
}
/*
* 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 *buf, size_t len, loff_t *pos)
{
int i=0;
DECLARE_WAITQUEUE(wait, current);
down (&mdc800->io_lock);
if (mdc800->state != READY)
{
up (&mdc800->io_lock);
return -EBUSY;
}
if (!mdc800->open )
{
up (&mdc800->io_lock);
return -EBUSY;
}
while (i<len)
{
if (signal_pending (current))
{
up (&mdc800->io_lock);
return -EINTR;
}
/* check for command start */
if (buf [i] == (char) 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]=buf[i];
mdc800->in_count++;
}
else
{
err ("Command is to long !\n");
up (&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))
{
err ("Camera didn't get ready.\n");
up (&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;
if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
{
err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
up (&mdc800->io_lock);
return -EIO;
}
add_wait_queue(&mdc800->write_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
if (!mdc800->written)
{
schedule_timeout (TO_WRITE_GET_READY*HZ/1000);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&mdc800->write_wait, &wait);
mdc800->written = 0;
if (mdc800->state == WORKING)
{
usb_unlink_urb (mdc800->write_urb);
up (&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)
{
err ("call 0x07 before 0x05,0x3e");
mdc800->state=READY;
up (&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))
{
err ("requesting answer from irq fails");
up (&mdc800->io_lock);
return -EIO;
}
/* Write dummy data, (this is ugly but part of the USB Protokoll */
/* 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];
dbg ("cached imagesize = %i",mdc800->pic_len);
}
}
else
{
if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
{
err ("Command Timeout.");
up (&mdc800->io_lock);
return -EIO;
}
}
mdc800->state=READY;
break;
}
}
i++;
}
up (&mdc800->io_lock);
return i;
}
/***************************************************************************
Init and Cleanup this driver (Structs and types)
****************************************************************************/
/* File Operations of this drivers */
static 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,
};
static 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,
fops: &mdc800_device_ops,
minor: MDC800_DEVICE_MINOR_BASE,
num_minors: 1,
id_table: mdc800_table
};
/************************************************************************
Init and Cleanup this driver (Main Functions)
*************************************************************************/
#define try(A) if ((A) == 0) goto cleanup_on_fail;
#define try_free_mem(A) if (A != 0) { kfree (A); A=0; }
#define try_free_urb(A) if (A != 0) { usb_free_urb (A); A=0; }
int __init usb_mdc800_init (void)
{
/* Allocate Memory */
try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL));
memset(mdc800, 0, sizeof(struct mdc800_data));
mdc800->dev=0;
mdc800->open=0;
mdc800->state=NOT_CONNECTED;
init_MUTEX (&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;
try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL));
try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL));
try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL));
try (mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL));
try (mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL));
try (mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL));
/* Register the driver */
if (usb_register (&mdc800_usb_driver) < 0)
goto cleanup_on_fail;
info (DRIVER_VERSION ":" DRIVER_DESC);
return 0;
/* Clean driver up, when something fails */
cleanup_on_fail:
if (mdc800 != 0)
{
err ("can't alloc memory!");
try_free_mem (mdc800->download_urb_buffer);
try_free_mem (mdc800->write_urb_buffer);
try_free_mem (mdc800->irq_urb_buffer);
try_free_urb (mdc800->write_urb);
try_free_urb (mdc800->download_urb);
try_free_urb (mdc800->irq_urb);
kfree (mdc800);
}
mdc800=0;
return -1;
}
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=0;
}
module_init (usb_mdc800_init);
module_exit (usb_mdc800_cleanup);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -