/* * Copyright (C) 2008 Sensoray Company Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. * * 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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. */ #include #include #include #include #include #define S2250_LOADER_FIRMWARE "s2250_loader.fw" #define S2250_FIRMWARE "s2250.fw" typedef struct device_extension_s { struct kref kref; int minor; struct usb_device *usbdev; } device_extension_t, *pdevice_extension_t; #define USB_s2250loader_MAJOR 240 #define USB_s2250loader_MINOR_BASE 0 #define MAX_DEVICES 256 static pdevice_extension_t s2250_dev_table[MAX_DEVICES]; static DEFINE_MUTEX(s2250_dev_table_mutex); #define to_s2250loader_dev_common(d) container_of(d, device_extension_t, kref) static void s2250loader_delete(struct kref *kref) { pdevice_extension_t s = to_s2250loader_dev_common(kref); s2250_dev_table[s->minor] = NULL; kfree(s); } static int s2250loader_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *usbdev; int minor, ret; pdevice_extension_t s = NULL; const struct firmware *fw; usbdev = usb_get_dev(interface_to_usbdev(interface)); if (!usbdev) { printk(KERN_ERR "Enter s2250loader_probe failed\n"); return -1; } printk(KERN_INFO "Enter s2250loader_probe 2.6 kernel\n"); printk(KERN_INFO "vendor id 0x%x, device id 0x%x devnum:%d\n", usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, usbdev->devnum); if (usbdev->descriptor.bNumConfigurations != 1) { printk(KERN_ERR "can't handle multiple config\n"); return -1; } mutex_lock(&s2250_dev_table_mutex); for (minor = 0; minor < MAX_DEVICES; minor++) { if (s2250_dev_table[minor] == NULL) break; } if (minor < 0 || minor >= MAX_DEVICES) { printk(KERN_ERR "Invalid minor: %d\n", minor); goto failed; } /* Allocate dev data structure */ s = kmalloc(sizeof(device_extension_t), GFP_KERNEL); if (s == NULL) { printk(KERN_ERR "Out of memory\n"); goto failed; } s2250_dev_table[minor] = s; printk(KERN_INFO "s2250loader_probe: Device %d on Bus %d Minor %d\n", usbdev->devnum, usbdev->bus->busnum, minor); memset(s, 0, sizeof(device_extension_t)); s->usbdev = usbdev; printk(KERN_INFO "loading 2250 loader\n"); kref_init(&(s->kref)); mutex_unlock(&s2250_dev_table_mutex); if (request_firmware(&fw, S2250_LOADER_FIRMWARE, &usbdev->dev)) { printk(KERN_ERR "s2250: unable to load firmware from file \"%s\"\n", S2250_LOADER_FIRMWARE); goto failed2; } ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); release_firmware(fw); if (0 != ret) { printk(KERN_ERR "loader download failed\n"); goto failed2; } if (request_firmware(&fw, S2250_FIRMWARE, &usbdev->dev)) { printk(KERN_ERR "s2250: unable to load firmware from file \"%s\"\n", S2250_FIRMWARE); goto failed2; } ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); release_firmware(fw); if (0 != ret) { printk(KERN_ERR "firmware_s2250 download failed\n"); goto failed2; } usb_set_intfdata(interface, s); return 0; failed: mutex_unlock(&s2250_dev_table_mutex); failed2: if (s) kref_put(&(s->kref), s2250loader_delete); printk(KERN_ERR "probe failed\n"); return -1; } static void s2250loader_disconnect(struct usb_interface *interface) { pdevice_extension_t s; printk(KERN_INFO "s2250: disconnect\n"); s = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); kref_put(&(s->kref), s2250loader_delete); } static const struct usb_device_id s2250loader_ids[] = { {USB_DEVICE(0x1943, 0xa250)}, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, s2250loader_ids); static struct usb_driver s2250loader_driver = { .name = "s2250-loader", .probe = s2250loader_probe, .disconnect = s2250loader_disconnect, .id_table = s2250loader_ids, }; static int __init s2250loader_init(void) { int r; unsigned i = 0; for (i = 0; i < MAX_DEVICES; i++) s2250_dev_table[i] = NULL; r = usb_register(&s2250loader_driver); if (r) { printk(KERN_ERR "usb_register failed. Error number %d\n", r); return -1; } printk(KERN_INFO "s2250loader_init: driver registered\n"); return 0; } module_init(s2250loader_init); static void __exit s2250loader_cleanup(void) { printk(KERN_INFO "s2250loader_cleanup\n"); usb_deregister(&s2250loader_driver); } module_exit(s2250loader_cleanup); MODULE_AUTHOR(""); MODULE_DESCRIPTION("firmware loader for Sensoray 2250/2251"); MODULE_LICENSE("GPL v2");