📄 fps200usb.c
字号:
static void fps200usb_cleanup_memory(pfps200usb_t s){ fdbg("s=%p", s); if (s != NULL) { if (s->read_urb){ fdbg("calling usb_free_urb to read_urb"); usb_free_urb (s->read_urb); } if (s->file_header){ fdbg("calling kfree(s->file_header)"); kfree(s->file_header); } if (s->bulk_in_buffer) { fdbg("calling kfree(s->bulk_in_buffer)"); kfree(s->bulk_in_buffer); } }}/* --------------------------------------------------------------------- *//* \brief configure the image to be grabbed * \param s pointer to the fps200usb_t struct that controls the device * \param file_format the file format that should be used * \param x the starting row * \param y the starting line * \param width the number of rows (musb be a multiple of 64) * \param height the number of lines * \param arg the argument to the command * \return return 0 in case of success or < 0 in case of error */static int fps200usb_configureImage(pfps200usb_t s, int file_format, int x, int y, int width, int height) { WINBMPFILEHEADER *bmp_fileheader; WIN2XBITMAPHEADER *bmp_bitmapheader; WIN2XPALETTEELEMENT *bmp_palette; int palette_entry; fdbg("file_format=%d x=%d y=%d width=%d height=%d", file_format, x, y, width, height); /* a little use of cache doesnt hurt. Does it ? */ if ((s->file_format == file_format) && (s->x == x) && (s->y == y) && (s->width == width) && (s->height == height)) { fdbg("using cached information"); return 0; /* doesnt need any change */ } /* shutdown any bulk writes that might be going on */ if (s->read_urb){ fdbg("calling usb_unlink_urb"); usb_unlink_urb (s->read_urb); } /* file format */ if ((file_format != s->file_format) || (s->width != width) || (s->height != height)){ fdbg("file format changing. Old=%d New=%d", s->file_format, file_format); s->file_format = file_format; switch (s->file_format){ case FPS200_FILEFORMAT_PGM: fdbg("preparing for the pgm file format"); /* pay attention to the maximum header size. It is defined by the constant PGM_HEADER_SIZE. */ sprintf(s->file_header, "P5 %d %d 255 ", width, height); s->header_size = strlen(s->file_header); break; case FPS200_FILEFORMAT_RAW: fdbg("preparing for the raw file format"); /* I will not release the memory in s->file_header. It's too ado for nothing. */ s->header_size = 0; /* no header */ break; case FPS200_FILEFORMAT_BMP: fdbg("preparing for the bmp file format"); s->header_size = BMP_HEADER_SIZE; bmp_fileheader = (WINBMPFILEHEADER*)s->file_header; bmp_bitmapheader = (WIN2XBITMAPHEADER*)(s->file_header + sizeof(WINBMPFILEHEADER)); bmp_palette = (WIN2XPALETTEELEMENT*)(s->file_header + sizeof(WINBMPFILEHEADER) + sizeof(WIN2XBITMAPHEADER)); bmp_fileheader->FileType = 0x4d42; bmp_fileheader->FileSizeLow = (s->header_size+width*height) & 0xffff; bmp_fileheader->FileSizeHigh = (s->header_size+width*height) >> 16; bmp_fileheader->Reserved1 = bmp_fileheader->Reserved2 = 0; bmp_fileheader->BitmapOffsetLow = s->header_size & 0xffff; bmp_fileheader->BitmapOffsetHigh = s->header_size >> 16; bmp_bitmapheader->SizeLow = sizeof(WIN2XBITMAPHEADER) & 0xffff; bmp_bitmapheader->SizeHigh = sizeof(WIN2XBITMAPHEADER) >> 16; bmp_bitmapheader->Width = width; bmp_bitmapheader->Height = -height; bmp_bitmapheader->Planes = 1; bmp_bitmapheader->BitsPerPixel = 8; for(palette_entry=0; palette_entry < 256; palette_entry++) { bmp_palette[palette_entry].Blue = palette_entry; bmp_palette[palette_entry].Green = palette_entry; bmp_palette[palette_entry].Red = palette_entry; } break; default: /* format not supported */ return -1; } } /* if there is a change in the file format */ if ((x < 0) || (y < 0) || (width <= 0) || (height <= 0) || (width > FPS200_WIDTH) || (height > FPS200_HEIGHT)){ ferr("you specified parameters for the image dimension " "out of range: x=%d y=%d width=%d height=%d\n", x, y, width, height); return -1; } if (width % 64){ ferr("width must be a multiple of 64 bytes"); return -1; } if ((x + width) > FPS200_WIDTH) { ferr("the parameters specifies a block outside the sensor area x=%d width=%d", x, width); return -1; } if ((y + height) > FPS200_HEIGHT) { ferr("the parameters specifies a block outside the sensor area y=%d height=%d", y, height); return -1; } /* default for the size of the image */ s->image_size = width*height; s->x = x; s->y = y; s->width = width; s->height = height; /* configure the new size for the bulk transfer */ s->bulk_in_size = s->image_size; fdbg("end sucessfully"); return 0;}#ifdef INTERRUPT_HANDLING/* --------------------------------------------------------------------- *//* \brief configure the interrupt handling routine * \param s pointer to the fps200usb_t struct that controls the device * \return return 0 in case of success or < 0 in case of error */static int fps200usb_configInterrupt(pfps200usb_t s){#if (LINUX_VERSION_CODE >= USB_SUPPORT_KERNEL) usb_fill_int_urb (&s->irq_urb, s->usbdev, usb_rcvintpipe(s->usbdev, FPS200_USB_ENDPOINT_IRQ), &s->irq_status, sizeof(s->irq_status), (usb_complete_t)fps200_interrupt_callback, s, 1000);#else /* for old style compatibility */ FILL_INT_URB (&s->irq_urb, s->usbdev, usb_rcvintpipe(s->usbdev, FPS200_USB_ENDPOINT_IRQ), &s->irq_status, sizeof(s->irq_status), (usb_complete_t)fps200_interrupt_callback, s, 1000);#endif return 0;}#endif /* INTERRUPT_HANDLING *//* --------------------------------------------------------------------- *//* \brief probes the device to check for veridicom's fingerprint sensor * being connected to the usb hub. * \param usbdev handler of the device * \param ifnum the number of the interface * \param id pointer to the device identification struct * \return always return NULL * \note erros are reported through stderr and the device is not registered * in case one occurr. */static void *fps200usb_probe (struct usb_device *usbdev, unsigned int ifnum#if (LINUX_VERSION_CODE >= USB_SUPPORT_KERNEL) , const struct usb_device_id *id#endif ){ int devnum; pfps200usb_t s;#ifdef INTERRUPT_HANDLING#ifdef DEBUG unsigned char isr_status=-1;#endif#endif fdbg("vendor id 0x%x, device id 0x%x ifnum:%d", usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum); /* We don't handle multiple configurations */ if (usbdev->descriptor.bNumConfigurations != 1) return NULL; /* searchs for an empty struct */ devnum = fps200usb_find_struct (); if (devnum == -1) return NULL; s = &fsusb[devnum]; down (&s->mutex); s->remove_pending = 0; s->fatal_error = 0; s->usbdev = usbdev; s->file_format = -1; /* this will clear the cache information */ fdbg("will allocate memory resources now."); /* allocate the memory resources */ s->file_header = kmalloc(BIGGEST_HEADER_SIZE, GFP_KERNEL); if (!s->file_header){ ferr("could not allocate s->file_header"); goto reject; } s->bulk_in_size = FPS200_IMAGESIZE; /* the maximum */ fdbg("allocating the bulk_in_buffer (%d bytes)", s->bulk_in_size); s->bulk_in_buffer = kmalloc(s->bulk_in_size, GFP_KERNEL); if (!s->bulk_in_buffer){ err("Couldn't allocate %d bytes for bulk_in_buffer", s->bulk_in_size); s->fatal_error = 1; goto reject; } fdbg("allocating the read urb (usb_alloc_urb)"); s->read_urb = usb_alloc_urb(0); if (!s->read_urb){ err("No free urbs available to read_urb"); s->fatal_error = 1; goto reject; } if (usb_set_configuration (usbdev, usbdev->config[0].bConfigurationValue) < 0) { err("set_configuration failed"); goto reject; } if (fps200usb_configureImage(s, FPS200_FILEFORMAT_DEFAULT, 0, 0, FPS200_WIDTH, FPS200_HEIGHT) < 0) { goto error; } /* set the default parameters */ if ((fps200_usb_writeRegister(usbdev, FPS200_DTR, dtr)) < 0) goto error; if ((fps200_usb_writeRegister(usbdev, FPS200_DCR, dcr)) < 0) goto error; if ((fps200_usb_writeRegister(usbdev, FPS200_PGC, pgc)) < 0) goto error; if ((fps200_usb_writeRegister(usbdev, FPS200_THR, thr)) < 0) goto error;#ifdef INTERRUPT_HANDLING /* acknowledge any previous interrupt requests */ fps200_usb_writeRegister(s->usbdev, FPS200_ISR, FPS200_ISR_IR0 | FPS200_ISR_IR1);#endif dbg("bound to interface: %d", ifnum); up (&s->mutex);#ifdef LOCKDEVICE /* enabling LOCKDEVICE at compile time makes the driver removable only when no fingerprint sensor is connected */ MOD_INC_USE_COUNT;#endif fdbg("returning sucessfully"); return s; error: reject: fps200usb_cleanup_memory(s); up (&s->mutex); s->usbdev = NULL; return NULL;}/* ---------------------------------------------------------------- *//* \brief called when the device is disconnected from the hub * \param usbdev handler of the device * \param ptr pointer to the fps200usb_t struct of the device */static void fps200usb_disconnect (struct usb_device *usbdev, void *ptr){ pfps200usb_t s = (pfps200usb_t) ptr; fdbg("s=%p", s); s->remove_pending = 1; wake_up (&s->wait); wake_up_interruptible (&s->waitReadCompletion); if (s->state == _started) { sleep_on (&s->remove_ok); } fps200usb_cleanup_memory(s); s->usbdev = NULL;#ifdef LOCKDEVICE /* if the device is disconnected than we can allow the removal of the driver */ MOD_DEC_USE_COUNT;#endif}#if (LINUX_VERSION_CODE >= USB_SUPPORT_KERNEL)/* ---------------------------------------------------------------- */static struct usb_device_id fps200usb_ids [] = { { USB_DEVICE(0x061a, 0x0200) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, fps200usb_ids);#endifstatic struct usb_driver fps200usb_driver = { name: "fps200usb", probe: fps200usb_probe, disconnect: fps200usb_disconnect, fops: &fps200usb_fops, /* minor: FPS200USB_MINOR,*/#if (LINUX_VERSION_CODE >= USB_SUPPORT_KERNEL) id_table: fps200usb_ids,#endif};/* --------------------------------------------------------------------- *//* \brief called when the driver is loaded * \return 0 in case of success or < 0 in case of errors. */static int __init fps200usb_init (void){ unsigned u; int ret; fdbg("will register the device"); /* makes a copy of the specified parameters just in case some program solicit to reset to them by ioctl */ parcopy.dtr = dtr; parcopy.dcr = dcr; parcopy.pgc = pgc; parcopy.thr = thr; /* initialize struct */ for (u = 0; u < NRSENSORS; u++) { pfps200usb_t s = &fsusb[u]; memset (s, 0, sizeof (fps200usb_t)); init_MUTEX (&s->mutex); s->usbdev = NULL; init_waitqueue_head (&s->wait); init_waitqueue_head (&s->remove_ok); init_waitqueue_head (&s->waitReadCompletion); spin_lock_init (&s->lock); } /* use the minor number proposed by the user */ fps200usb_driver.minor = minor; /* register misc device */ if ((ret=usb_register(&fps200usb_driver))){ ferr("Could not register the usb device - error=%d - Maybe the Minor number (%d) is been used - cat /proc/modules to check it out", ret, minor); return -1; } fdbg("driver registered"); info(DRIVER_VERSION ":" DRIVER_DESC); return 0;}/* ---------------------------------------------------------------- *//* \brief called when the driver is unloaded */static void __exit fps200usb_cleanup (void){ fdbg(" "); usb_deregister (&fps200usb_driver);}/* --------------------------------------------------------------------- */MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");MODULE_PARM (minor, "i");MODULE_PARM_DESC (minor, "Minor number for the device (default=240)");MODULE_PARM (dtr, "i");MODULE_PARM_DESC (dtr, "Discharge Time Register (default=10)");MODULE_PARM (dcr, "i");MODULE_PARM_DESC (dcr, "Discharge Current Register (default=6)");MODULE_PARM (pgc, "i");MODULE_PARM_DESC (pgc, "Programmable Gain Control Register (default=8)");MODULE_PARM (thr, "i");MODULE_PARM_DESC (thr, "Threshold Register (default=0)");module_init (fps200usb_init);module_exit (fps200usb_cleanup);/* --------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -