📄 mdc800.c
字号:
{ struct mdc800_data* mdc800=(struct mdc800_data*) ptr; dbg ("(mdc800_usb_disconnect) called"); if (mdc800->state == NOT_CONNECTED) return; 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)) { 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){ size_t 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)) { 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 */ copy_to_user(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){ size_t 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) { unsigned char c; if (signal_pending (current)) { up (&mdc800->io_lock); return -EINTR; } if(get_user(c, buf+i)) { up(&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 { 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)) { 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 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]; 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, 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)); try (mdc800->download_urb=usb_alloc_urb (0)); try (mdc800->write_urb=usb_alloc_urb (0)); /* 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 + -