Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 Sensoray Company Inc. |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License (Version 2) as |
| 6 | * published by the Free Software Foundation. |
| 7 | * |
| 8 | * This program is distributed in the hope that it will be useful, |
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * GNU General Public License for more details. |
| 12 | * |
| 13 | * You should have received a copy of the GNU General Public License |
| 14 | * along with this program; if not, write to the Free Software Foundation, |
| 15 | * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. |
| 16 | */ |
| 17 | |
| 18 | #include <linux/module.h> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 19 | #include <linux/slab.h> |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 20 | #include <linux/usb.h> |
Hans Verkuil | c046981 | 2013-03-09 09:35:07 -0300 | [diff] [blame] | 21 | #include <linux/firmware.h> |
| 22 | #include <cypress_firmware.h> |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 23 | |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 24 | struct fw_config { |
| 25 | u16 vendor; |
| 26 | u16 product; |
| 27 | const char * const fw_name1; |
| 28 | const char * const fw_name2; |
| 29 | }; |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 30 | |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 31 | struct fw_config fw_configs[] = { |
| 32 | { 0x1943, 0xa250, "go7007/s2250-1.fw", "go7007/s2250-2.fw" }, |
| 33 | { 0x093b, 0xa002, "go7007/px-m402u.fw", NULL }, |
| 34 | { 0x093b, 0xa004, "go7007/px-tv402u.fw", NULL }, |
| 35 | { 0x0eb1, 0x6666, "go7007/lr192.fw", NULL }, |
| 36 | { 0x0eb1, 0x6668, "go7007/wis-startrek.fw", NULL }, |
| 37 | { 0, 0, NULL, NULL } |
| 38 | }; |
| 39 | MODULE_FIRMWARE("go7007/s2250-1.fw"); |
| 40 | MODULE_FIRMWARE("go7007/s2250-2.fw"); |
| 41 | MODULE_FIRMWARE("go7007/px-m402u.fw"); |
| 42 | MODULE_FIRMWARE("go7007/px-tv402u.fw"); |
| 43 | MODULE_FIRMWARE("go7007/lr192.fw"); |
| 44 | MODULE_FIRMWARE("go7007/wis-startrek.fw"); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 45 | |
Hans Verkuil | e129c97 | 2013-03-09 13:28:39 -0300 | [diff] [blame] | 46 | static int go7007_loader_probe(struct usb_interface *interface, |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 47 | const struct usb_device_id *id) |
| 48 | { |
| 49 | struct usb_device *usbdev; |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 50 | const struct firmware *fw; |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 51 | u16 vendor, product; |
| 52 | const char *fw1, *fw2; |
| 53 | int ret; |
| 54 | int i; |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 55 | |
| 56 | usbdev = usb_get_dev(interface_to_usbdev(interface)); |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 57 | if (!usbdev) |
| 58 | goto failed2; |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 59 | |
| 60 | if (usbdev->descriptor.bNumConfigurations != 1) { |
YAMANE Toshiaki | b11558a | 2012-11-05 07:34:42 -0300 | [diff] [blame] | 61 | dev_err(&interface->dev, "can't handle multiple config\n"); |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 62 | return -ENODEV; |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 63 | } |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 64 | |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 65 | vendor = le16_to_cpu(usbdev->descriptor.idVendor); |
| 66 | product = le16_to_cpu(usbdev->descriptor.idProduct); |
| 67 | |
| 68 | for (i = 0; fw_configs[i].fw_name1; i++) |
| 69 | if (fw_configs[i].vendor == vendor && |
| 70 | fw_configs[i].product == product) |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 71 | break; |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 72 | |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 73 | /* Should never happen */ |
| 74 | if (fw_configs[i].fw_name1 == NULL) |
| 75 | goto failed2; |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 76 | |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 77 | fw1 = fw_configs[i].fw_name1; |
| 78 | fw2 = fw_configs[i].fw_name2; |
Joe Perches | 535ec04 | 2013-02-11 14:38:05 -0300 | [diff] [blame] | 79 | |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 80 | dev_info(&interface->dev, "loading firmware %s\n", fw1); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 81 | |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 82 | if (request_firmware(&fw, fw1, &usbdev->dev)) { |
YAMANE Toshiaki | b11558a | 2012-11-05 07:34:42 -0300 | [diff] [blame] | 83 | dev_err(&interface->dev, |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 84 | "unable to load firmware from file \"%s\"\n", fw1); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 85 | goto failed2; |
| 86 | } |
Hans Verkuil | 79a63c6 | 2013-03-25 06:43:12 -0300 | [diff] [blame] | 87 | ret = cypress_load_firmware(usbdev, fw, CYPRESS_FX2); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 88 | release_firmware(fw); |
| 89 | if (0 != ret) { |
YAMANE Toshiaki | b11558a | 2012-11-05 07:34:42 -0300 | [diff] [blame] | 90 | dev_err(&interface->dev, "loader download failed\n"); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 91 | goto failed2; |
| 92 | } |
| 93 | |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 94 | if (fw2 == NULL) |
| 95 | return 0; |
| 96 | |
| 97 | if (request_firmware(&fw, fw2, &usbdev->dev)) { |
YAMANE Toshiaki | b11558a | 2012-11-05 07:34:42 -0300 | [diff] [blame] | 98 | dev_err(&interface->dev, |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 99 | "unable to load firmware from file \"%s\"\n", fw2); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 100 | goto failed2; |
| 101 | } |
Hans Verkuil | 79a63c6 | 2013-03-25 06:43:12 -0300 | [diff] [blame] | 102 | ret = cypress_load_firmware(usbdev, fw, CYPRESS_FX2); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 103 | release_firmware(fw); |
| 104 | if (0 != ret) { |
Hans Verkuil | e129c97 | 2013-03-09 13:28:39 -0300 | [diff] [blame] | 105 | dev_err(&interface->dev, "firmware download failed\n"); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 106 | goto failed2; |
| 107 | } |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 108 | return 0; |
| 109 | |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 110 | failed2: |
YAMANE Toshiaki | b11558a | 2012-11-05 07:34:42 -0300 | [diff] [blame] | 111 | dev_err(&interface->dev, "probe failed\n"); |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 112 | return -ENODEV; |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 113 | } |
| 114 | |
Hans Verkuil | e129c97 | 2013-03-09 13:28:39 -0300 | [diff] [blame] | 115 | static void go7007_loader_disconnect(struct usb_interface *interface) |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 116 | { |
Hans Verkuil | e129c97 | 2013-03-09 13:28:39 -0300 | [diff] [blame] | 117 | dev_info(&interface->dev, "disconnect\n"); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 118 | usb_set_intfdata(interface, NULL); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 119 | } |
| 120 | |
Hans Verkuil | e129c97 | 2013-03-09 13:28:39 -0300 | [diff] [blame] | 121 | static const struct usb_device_id go7007_loader_ids[] = { |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 122 | { USB_DEVICE(0x1943, 0xa250) }, |
| 123 | { USB_DEVICE(0x093b, 0xa002) }, |
| 124 | { USB_DEVICE(0x093b, 0xa004) }, |
| 125 | { USB_DEVICE(0x0eb1, 0x6666) }, |
| 126 | { USB_DEVICE(0x0eb1, 0x6668) }, |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 127 | {} /* Terminating entry */ |
| 128 | }; |
| 129 | |
Hans Verkuil | e129c97 | 2013-03-09 13:28:39 -0300 | [diff] [blame] | 130 | MODULE_DEVICE_TABLE(usb, go7007_loader_ids); |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 131 | |
Hans Verkuil | e129c97 | 2013-03-09 13:28:39 -0300 | [diff] [blame] | 132 | static struct usb_driver go7007_loader_driver = { |
| 133 | .name = "go7007-loader", |
| 134 | .probe = go7007_loader_probe, |
| 135 | .disconnect = go7007_loader_disconnect, |
| 136 | .id_table = go7007_loader_ids, |
Pete Eberlein | b11869d | 2008-10-30 12:56:41 -0700 | [diff] [blame] | 137 | }; |
| 138 | |
Hans Verkuil | e129c97 | 2013-03-09 13:28:39 -0300 | [diff] [blame] | 139 | module_usb_driver(go7007_loader_driver); |
Pete Eberlein | 832b6a8 | 2009-11-16 15:13:51 -0300 | [diff] [blame] | 140 | |
| 141 | MODULE_AUTHOR(""); |
Hans Verkuil | 0ee3d4d | 2013-03-11 06:45:14 -0300 | [diff] [blame] | 142 | MODULE_DESCRIPTION("firmware loader for go7007-usb"); |
Pete Eberlein | 832b6a8 | 2009-11-16 15:13:51 -0300 | [diff] [blame] | 143 | MODULE_LICENSE("GPL v2"); |