1b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein/* 2b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein * Copyright (C) 2008 Sensoray Company Inc. 3b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein * 4b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein * This program is free software; you can redistribute it and/or modify 5b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein * it under the terms of the GNU General Public License (Version 2) as 6b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein * published by the Free Software Foundation. 7b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein * 8b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein * This program is distributed in the hope that it will be useful, 9b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein * but WITHOUT ANY WARRANTY; without even the implied warranty of 10b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein * GNU General Public License for more details. 12b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein */ 13b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 14b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein#include <linux/module.h> 155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 16b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein#include <linux/usb.h> 17c046981f1aa0e1e1345e6ec43f6bea611e575351Hans Verkuil#include <linux/firmware.h> 18c046981f1aa0e1e1345e6ec43f6bea611e575351Hans Verkuil#include <cypress_firmware.h> 19b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 200ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuilstruct fw_config { 210ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil u16 vendor; 220ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil u16 product; 230ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil const char * const fw_name1; 240ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil const char * const fw_name2; 250ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil}; 26b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 2704ad3a644e4040a68054a0f97bda27972444ea89Ebru Akagunduzstatic struct fw_config fw_configs[] = { 280ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { 0x1943, 0xa250, "go7007/s2250-1.fw", "go7007/s2250-2.fw" }, 290ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { 0x093b, 0xa002, "go7007/px-m402u.fw", NULL }, 300ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { 0x093b, 0xa004, "go7007/px-tv402u.fw", NULL }, 310ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { 0x0eb1, 0x6666, "go7007/lr192.fw", NULL }, 320ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { 0x0eb1, 0x6668, "go7007/wis-startrek.fw", NULL }, 330ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { 0, 0, NULL, NULL } 340ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil}; 350ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans VerkuilMODULE_FIRMWARE("go7007/s2250-1.fw"); 360ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans VerkuilMODULE_FIRMWARE("go7007/s2250-2.fw"); 370ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans VerkuilMODULE_FIRMWARE("go7007/px-m402u.fw"); 380ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans VerkuilMODULE_FIRMWARE("go7007/px-tv402u.fw"); 390ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans VerkuilMODULE_FIRMWARE("go7007/lr192.fw"); 400ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans VerkuilMODULE_FIRMWARE("go7007/wis-startrek.fw"); 41b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 42e129c97494096fbda451619d746d661a05abba64Hans Verkuilstatic int go7007_loader_probe(struct usb_interface *interface, 43b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein const struct usb_device_id *id) 44b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein{ 45b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein struct usb_device *usbdev; 46b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein const struct firmware *fw; 470ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil u16 vendor, product; 480ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil const char *fw1, *fw2; 490ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil int ret; 500ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil int i; 51b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 52b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein usbdev = usb_get_dev(interface_to_usbdev(interface)); 530ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil if (!usbdev) 540ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil goto failed2; 55b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 56b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein if (usbdev->descriptor.bNumConfigurations != 1) { 57b11558a3026bd01436d08b7b8f92da301116c669YAMANE Toshiaki dev_err(&interface->dev, "can't handle multiple config\n"); 5850c88544d225baadd6de1c4365d4ed16cc942a37Alexey Khoroshilov goto failed2; 59b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein } 60b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 610ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil vendor = le16_to_cpu(usbdev->descriptor.idVendor); 620ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil product = le16_to_cpu(usbdev->descriptor.idProduct); 63b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 640ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil for (i = 0; fw_configs[i].fw_name1; i++) 650ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil if (fw_configs[i].vendor == vendor && 660ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil fw_configs[i].product == product) 670ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil break; 68b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 690ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil /* Should never happen */ 700ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil if (fw_configs[i].fw_name1 == NULL) 710ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil goto failed2; 72b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 730ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil fw1 = fw_configs[i].fw_name1; 740ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil fw2 = fw_configs[i].fw_name2; 75b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 760ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil dev_info(&interface->dev, "loading firmware %s\n", fw1); 77b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 780ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil if (request_firmware(&fw, fw1, &usbdev->dev)) { 79b11558a3026bd01436d08b7b8f92da301116c669YAMANE Toshiaki dev_err(&interface->dev, 800ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil "unable to load firmware from file \"%s\"\n", fw1); 81b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein goto failed2; 82b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein } 8379a63c60a6a2ae589e44529401e0ab1150e9408aHans Verkuil ret = cypress_load_firmware(usbdev, fw, CYPRESS_FX2); 84b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein release_firmware(fw); 85b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein if (0 != ret) { 86b11558a3026bd01436d08b7b8f92da301116c669YAMANE Toshiaki dev_err(&interface->dev, "loader download failed\n"); 87b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein goto failed2; 88b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein } 89b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 900ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil if (fw2 == NULL) 910ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil return 0; 920ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil 930ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil if (request_firmware(&fw, fw2, &usbdev->dev)) { 94b11558a3026bd01436d08b7b8f92da301116c669YAMANE Toshiaki dev_err(&interface->dev, 950ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil "unable to load firmware from file \"%s\"\n", fw2); 96b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein goto failed2; 97b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein } 9879a63c60a6a2ae589e44529401e0ab1150e9408aHans Verkuil ret = cypress_load_firmware(usbdev, fw, CYPRESS_FX2); 99b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein release_firmware(fw); 100b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein if (0 != ret) { 101e129c97494096fbda451619d746d661a05abba64Hans Verkuil dev_err(&interface->dev, "firmware download failed\n"); 102b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein goto failed2; 103b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein } 104b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein return 0; 105b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 106b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberleinfailed2: 10750c88544d225baadd6de1c4365d4ed16cc942a37Alexey Khoroshilov usb_put_dev(usbdev); 108b11558a3026bd01436d08b7b8f92da301116c669YAMANE Toshiaki dev_err(&interface->dev, "probe failed\n"); 1090ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil return -ENODEV; 110b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein} 111b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 112e129c97494096fbda451619d746d661a05abba64Hans Verkuilstatic void go7007_loader_disconnect(struct usb_interface *interface) 113b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein{ 114e129c97494096fbda451619d746d661a05abba64Hans Verkuil dev_info(&interface->dev, "disconnect\n"); 11550c88544d225baadd6de1c4365d4ed16cc942a37Alexey Khoroshilov usb_put_dev(interface_to_usbdev(interface)); 116b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein usb_set_intfdata(interface, NULL); 117b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein} 118b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 119e129c97494096fbda451619d746d661a05abba64Hans Verkuilstatic const struct usb_device_id go7007_loader_ids[] = { 1200ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { USB_DEVICE(0x1943, 0xa250) }, 1210ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { USB_DEVICE(0x093b, 0xa002) }, 1220ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { USB_DEVICE(0x093b, 0xa004) }, 1230ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { USB_DEVICE(0x0eb1, 0x6666) }, 1240ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans Verkuil { USB_DEVICE(0x0eb1, 0x6668) }, 125b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein {} /* Terminating entry */ 126b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein}; 127b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 128e129c97494096fbda451619d746d661a05abba64Hans VerkuilMODULE_DEVICE_TABLE(usb, go7007_loader_ids); 129b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 130e129c97494096fbda451619d746d661a05abba64Hans Verkuilstatic struct usb_driver go7007_loader_driver = { 131e129c97494096fbda451619d746d661a05abba64Hans Verkuil .name = "go7007-loader", 132e129c97494096fbda451619d746d661a05abba64Hans Verkuil .probe = go7007_loader_probe, 133e129c97494096fbda451619d746d661a05abba64Hans Verkuil .disconnect = go7007_loader_disconnect, 134e129c97494096fbda451619d746d661a05abba64Hans Verkuil .id_table = go7007_loader_ids, 135b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein}; 136b11869dbb6cc4b4de8da302f758866d0a167a277Pete Eberlein 137e129c97494096fbda451619d746d661a05abba64Hans Verkuilmodule_usb_driver(go7007_loader_driver); 138832b6a8917f050a9cbeeb69e080733128d562f59Pete Eberlein 139832b6a8917f050a9cbeeb69e080733128d562f59Pete EberleinMODULE_AUTHOR(""); 1400ee3d4d53e4e170e9a9a70214de54b9f5d18d30cHans VerkuilMODULE_DESCRIPTION("firmware loader for go7007-usb"); 141832b6a8917f050a9cbeeb69e080733128d562f59Pete EberleinMODULE_LICENSE("GPL v2"); 142