18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2008 Sensoray Company Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/usb.h> 98c2ecf20Sopenharmony_ci#include <linux/firmware.h> 108c2ecf20Sopenharmony_ci#include <cypress_firmware.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistruct fw_config { 138c2ecf20Sopenharmony_ci u16 vendor; 148c2ecf20Sopenharmony_ci u16 product; 158c2ecf20Sopenharmony_ci const char * const fw_name1; 168c2ecf20Sopenharmony_ci const char * const fw_name2; 178c2ecf20Sopenharmony_ci}; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic struct fw_config fw_configs[] = { 208c2ecf20Sopenharmony_ci { 0x1943, 0xa250, "go7007/s2250-1.fw", "go7007/s2250-2.fw" }, 218c2ecf20Sopenharmony_ci { 0x093b, 0xa002, "go7007/px-m402u.fw", NULL }, 228c2ecf20Sopenharmony_ci { 0x093b, 0xa004, "go7007/px-tv402u.fw", NULL }, 238c2ecf20Sopenharmony_ci { 0x0eb1, 0x6666, "go7007/lr192.fw", NULL }, 248c2ecf20Sopenharmony_ci { 0x0eb1, 0x6668, "go7007/wis-startrek.fw", NULL }, 258c2ecf20Sopenharmony_ci { 0, 0, NULL, NULL } 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ciMODULE_FIRMWARE("go7007/s2250-1.fw"); 288c2ecf20Sopenharmony_ciMODULE_FIRMWARE("go7007/s2250-2.fw"); 298c2ecf20Sopenharmony_ciMODULE_FIRMWARE("go7007/px-m402u.fw"); 308c2ecf20Sopenharmony_ciMODULE_FIRMWARE("go7007/px-tv402u.fw"); 318c2ecf20Sopenharmony_ciMODULE_FIRMWARE("go7007/lr192.fw"); 328c2ecf20Sopenharmony_ciMODULE_FIRMWARE("go7007/wis-startrek.fw"); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int go7007_loader_probe(struct usb_interface *interface, 358c2ecf20Sopenharmony_ci const struct usb_device_id *id) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct usb_device *usbdev; 388c2ecf20Sopenharmony_ci const struct firmware *fw; 398c2ecf20Sopenharmony_ci u16 vendor, product; 408c2ecf20Sopenharmony_ci const char *fw1, *fw2; 418c2ecf20Sopenharmony_ci int ret; 428c2ecf20Sopenharmony_ci int i; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci usbdev = usb_get_dev(interface_to_usbdev(interface)); 458c2ecf20Sopenharmony_ci if (!usbdev) 468c2ecf20Sopenharmony_ci goto failed2; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (usbdev->descriptor.bNumConfigurations != 1) { 498c2ecf20Sopenharmony_ci dev_err(&interface->dev, "can't handle multiple config\n"); 508c2ecf20Sopenharmony_ci goto failed2; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci vendor = le16_to_cpu(usbdev->descriptor.idVendor); 548c2ecf20Sopenharmony_ci product = le16_to_cpu(usbdev->descriptor.idProduct); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci for (i = 0; fw_configs[i].fw_name1; i++) 578c2ecf20Sopenharmony_ci if (fw_configs[i].vendor == vendor && 588c2ecf20Sopenharmony_ci fw_configs[i].product == product) 598c2ecf20Sopenharmony_ci break; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* Should never happen */ 628c2ecf20Sopenharmony_ci if (fw_configs[i].fw_name1 == NULL) 638c2ecf20Sopenharmony_ci goto failed2; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci fw1 = fw_configs[i].fw_name1; 668c2ecf20Sopenharmony_ci fw2 = fw_configs[i].fw_name2; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci dev_info(&interface->dev, "loading firmware %s\n", fw1); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (request_firmware(&fw, fw1, &usbdev->dev)) { 718c2ecf20Sopenharmony_ci dev_err(&interface->dev, 728c2ecf20Sopenharmony_ci "unable to load firmware from file \"%s\"\n", fw1); 738c2ecf20Sopenharmony_ci goto failed2; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci ret = cypress_load_firmware(usbdev, fw, CYPRESS_FX2); 768c2ecf20Sopenharmony_ci release_firmware(fw); 778c2ecf20Sopenharmony_ci if (0 != ret) { 788c2ecf20Sopenharmony_ci dev_err(&interface->dev, "loader download failed\n"); 798c2ecf20Sopenharmony_ci goto failed2; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (fw2 == NULL) 838c2ecf20Sopenharmony_ci return 0; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (request_firmware(&fw, fw2, &usbdev->dev)) { 868c2ecf20Sopenharmony_ci dev_err(&interface->dev, 878c2ecf20Sopenharmony_ci "unable to load firmware from file \"%s\"\n", fw2); 888c2ecf20Sopenharmony_ci goto failed2; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci ret = cypress_load_firmware(usbdev, fw, CYPRESS_FX2); 918c2ecf20Sopenharmony_ci release_firmware(fw); 928c2ecf20Sopenharmony_ci if (0 != ret) { 938c2ecf20Sopenharmony_ci dev_err(&interface->dev, "firmware download failed\n"); 948c2ecf20Sopenharmony_ci goto failed2; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cifailed2: 998c2ecf20Sopenharmony_ci usb_put_dev(usbdev); 1008c2ecf20Sopenharmony_ci dev_err(&interface->dev, "probe failed\n"); 1018c2ecf20Sopenharmony_ci return -ENODEV; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void go7007_loader_disconnect(struct usb_interface *interface) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci dev_info(&interface->dev, "disconnect\n"); 1078c2ecf20Sopenharmony_ci usb_put_dev(interface_to_usbdev(interface)); 1088c2ecf20Sopenharmony_ci usb_set_intfdata(interface, NULL); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const struct usb_device_id go7007_loader_ids[] = { 1128c2ecf20Sopenharmony_ci { USB_DEVICE(0x1943, 0xa250) }, 1138c2ecf20Sopenharmony_ci { USB_DEVICE(0x093b, 0xa002) }, 1148c2ecf20Sopenharmony_ci { USB_DEVICE(0x093b, 0xa004) }, 1158c2ecf20Sopenharmony_ci { USB_DEVICE(0x0eb1, 0x6666) }, 1168c2ecf20Sopenharmony_ci { USB_DEVICE(0x0eb1, 0x6668) }, 1178c2ecf20Sopenharmony_ci {} /* Terminating entry */ 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, go7007_loader_ids); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic struct usb_driver go7007_loader_driver = { 1238c2ecf20Sopenharmony_ci .name = "go7007-loader", 1248c2ecf20Sopenharmony_ci .probe = go7007_loader_probe, 1258c2ecf20Sopenharmony_ci .disconnect = go7007_loader_disconnect, 1268c2ecf20Sopenharmony_ci .id_table = go7007_loader_ids, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cimodule_usb_driver(go7007_loader_driver); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ciMODULE_AUTHOR(""); 1328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("firmware loader for go7007-usb"); 1338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 134