firmware.h revision 1.8
11.7Sriastrad/* $NetBSD: firmware.h,v 1.8 2018/08/27 07:24:54 riastradh Exp $ */ 21.2Sriastrad 31.2Sriastrad/*- 41.2Sriastrad * Copyright (c) 2013 The NetBSD Foundation, Inc. 51.2Sriastrad * All rights reserved. 61.2Sriastrad * 71.2Sriastrad * This code is derived from software contributed to The NetBSD Foundation 81.2Sriastrad * by Taylor R. Campbell. 91.2Sriastrad * 101.2Sriastrad * Redistribution and use in source and binary forms, with or without 111.2Sriastrad * modification, are permitted provided that the following conditions 121.2Sriastrad * are met: 131.2Sriastrad * 1. Redistributions of source code must retain the above copyright 141.2Sriastrad * notice, this list of conditions and the following disclaimer. 151.2Sriastrad * 2. Redistributions in binary form must reproduce the above copyright 161.2Sriastrad * notice, this list of conditions and the following disclaimer in the 171.2Sriastrad * documentation and/or other materials provided with the distribution. 181.2Sriastrad * 191.2Sriastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 201.2Sriastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 211.2Sriastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 221.2Sriastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 231.2Sriastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241.2Sriastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251.2Sriastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 261.2Sriastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 271.2Sriastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 281.2Sriastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 291.2Sriastrad * POSSIBILITY OF SUCH DAMAGE. 301.2Sriastrad */ 311.2Sriastrad 321.2Sriastrad#ifndef _LINUX_FIRMWARE_H_ 331.2Sriastrad#define _LINUX_FIRMWARE_H_ 341.2Sriastrad 351.3Sriastrad#include <sys/types.h> 361.3Sriastrad#include <sys/device.h> 371.3Sriastrad#include <sys/kmem.h> 381.8Sriastrad#include <sys/module.h> 391.3Sriastrad#include <sys/systm.h> 401.3Sriastrad 411.3Sriastrad#include <dev/firmload.h> 421.3Sriastrad 431.8Sriastrad#include <linux/slab.h> 441.8Sriastrad#include <linux/string.h> 451.8Sriastrad#include <linux/workqueue.h> 461.8Sriastrad 471.3Sriastradstruct device; 481.3Sriastrad 491.3Sriastradstruct firmware { 501.7Sriastrad char *data; 511.3Sriastrad size_t size; 521.3Sriastrad}; 531.3Sriastrad 541.8Sriastradstruct firmload_work { 551.8Sriastrad char *flw_name; 561.8Sriastrad void (*flw_callback)(const struct firmware *, void *); 571.8Sriastrad void *flw_cookie; 581.8Sriastrad struct device *flw_device; 591.8Sriastrad struct module *flw_module; 601.8Sriastrad struct work_struct flw_work; 611.8Sriastrad}; 621.8Sriastrad 631.3Sriastradstatic inline int 641.3Sriastradrequest_firmware(const struct firmware **fwp, const char *image_name, 651.3Sriastrad struct device *dev) 661.3Sriastrad{ 671.5Sriastrad const char *drvname; 681.3Sriastrad struct firmware *fw; 691.6Sriastrad firmware_handle_t handle; 701.3Sriastrad int ret; 711.3Sriastrad 721.3Sriastrad fw = kmem_alloc(sizeof(*fw), KM_SLEEP); 731.3Sriastrad 741.5Sriastrad /* 751.5Sriastrad * If driver xyz(4) asks for xyz/foo/bar.bin, turn that into 761.5Sriastrad * just foo/bar.bin. This leaves open the possibility of name 771.5Sriastrad * collisions. Let's hope upstream is sensible about this. 781.5Sriastrad */ 791.5Sriastrad drvname = device_cfdriver(dev)->cd_name; 801.5Sriastrad if ((strncmp(drvname, image_name, strlen(drvname)) == 0) && 811.5Sriastrad (image_name[strlen(drvname)] == '/')) 821.5Sriastrad image_name += (strlen(drvname) + 1); 831.5Sriastrad 841.3Sriastrad /* XXX errno NetBSD->Linux */ 851.6Sriastrad ret = -firmware_open(drvname, image_name, &handle); 861.3Sriastrad if (ret) 871.3Sriastrad goto fail0; 881.6Sriastrad fw->size = firmware_get_size(handle); 891.3Sriastrad fw->data = firmware_malloc(fw->size); 901.3Sriastrad 911.3Sriastrad /* XXX errno NetBSD->Linux */ 921.6Sriastrad ret = -firmware_read(handle, 0, fw->data, fw->size); 931.6Sriastrad (void)firmware_close(handle); 941.3Sriastrad if (ret) 951.3Sriastrad goto fail1; 961.3Sriastrad 971.3Sriastrad /* Success! */ 981.3Sriastrad *fwp = fw; 991.3Sriastrad return 0; 1001.3Sriastrad 1011.3Sriastradfail1: firmware_free(fw->data, fw->size); 1021.3Sriastradfail0: KASSERT(ret); 1031.3Sriastrad kmem_free(fw, sizeof(*fw)); 1041.4Sriastrad *fwp = NULL; 1051.3Sriastrad return ret; 1061.3Sriastrad} 1071.3Sriastrad 1081.3Sriastradstatic inline void 1091.8Sriastradrequest_firmware_work(struct work_struct *wk) 1101.8Sriastrad{ 1111.8Sriastrad struct firmload_work *work = container_of(wk, struct firmload_work, 1121.8Sriastrad flw_work); 1131.8Sriastrad const struct firmware *fw; 1141.8Sriastrad int ret; 1151.8Sriastrad 1161.8Sriastrad /* Reqeust the firmware. If it failed, set it to NULL. */ 1171.8Sriastrad ret = request_firmware(&fw, work->flw_name, work->flw_device); 1181.8Sriastrad if (ret) 1191.8Sriastrad fw = NULL; 1201.8Sriastrad 1211.8Sriastrad /* Call the callback. */ 1221.8Sriastrad (*work->flw_callback)(fw, work->flw_cookie); 1231.8Sriastrad 1241.8Sriastrad /* 1251.8Sriastrad * Release the device and module references now that we're 1261.8Sriastrad * done. 1271.8Sriastrad * 1281.8Sriastrad * XXX Heh. What if the module gets unloaded _during_ 1291.8Sriastrad * module_rele because it went to zero? 1301.8Sriastrad */ 1311.8Sriastrad /* XXX device_release */ 1321.8Sriastrad if (work->flw_module) 1331.8Sriastrad module_rele(work->flw_module); 1341.8Sriastrad} 1351.8Sriastrad 1361.8Sriastradstatic inline int 1371.8Sriastradrequest_firmware_nowait(struct module *module, bool uevent, const char *name, 1381.8Sriastrad struct device *device, gfp_t gfp, void *cookie, 1391.8Sriastrad void (*callback)(const struct firmware *, void *)) 1401.8Sriastrad{ 1411.8Sriastrad char *namedup; 1421.8Sriastrad struct firmload_work *work; 1431.8Sriastrad 1441.8Sriastrad /* Allocate memory for it, or fail if we can't. */ 1451.8Sriastrad work = kzalloc(sizeof(*work), gfp); 1461.8Sriastrad if (work == NULL) 1471.8Sriastrad goto fail0; 1481.8Sriastrad 1491.8Sriastrad /* Copy the name just in case. */ 1501.8Sriastrad namedup = kstrdup(name, gfp); 1511.8Sriastrad if (namedup == NULL) 1521.8Sriastrad goto fail1; 1531.8Sriastrad 1541.8Sriastrad /* Hold the module and device so they don't go away before callback. */ 1551.8Sriastrad if (module) 1561.8Sriastrad module_hold(module); 1571.8Sriastrad /* XXX device_acquire(device) */ 1581.8Sriastrad 1591.8Sriastrad /* Initialize the work. */ 1601.8Sriastrad work->flw_name = namedup; 1611.8Sriastrad work->flw_callback = callback; 1621.8Sriastrad work->flw_cookie = callback; 1631.8Sriastrad work->flw_device = device; 1641.8Sriastrad work->flw_module = module; 1651.8Sriastrad INIT_WORK(&work->flw_work, request_firmware_work); 1661.8Sriastrad 1671.8Sriastrad /* Kick it off. */ 1681.8Sriastrad schedule_work(&work->flw_work); 1691.8Sriastrad 1701.8Sriastrad /* Success! */ 1711.8Sriastrad return 0; 1721.8Sriastrad 1731.8Sriastradfail1: kfree(work); 1741.8Sriastradfail0: return -ENOMEM; 1751.8Sriastrad} 1761.8Sriastrad 1771.8Sriastradstatic inline void 1781.3Sriastradrelease_firmware(const struct firmware *fw) 1791.3Sriastrad{ 1801.3Sriastrad 1811.4Sriastrad if (fw != NULL) { 1821.4Sriastrad firmware_free(fw->data, fw->size); 1831.4Sriastrad kmem_free(__UNCONST(fw), sizeof(*fw)); 1841.4Sriastrad } 1851.3Sriastrad} 1861.3Sriastrad 1871.2Sriastrad#endif /* _LINUX_FIRMWARE_H_ */ 188