at v3.1-rc9 118 lines 2.6 kB view raw
1/* 2 * Load Analog Devices SigmaStudio firmware files 3 * 4 * Copyright 2009-2011 Analog Devices Inc. 5 * 6 * Licensed under the GPL-2 or later. 7 */ 8 9#include <linux/crc32.h> 10#include <linux/delay.h> 11#include <linux/firmware.h> 12#include <linux/kernel.h> 13#include <linux/i2c.h> 14#include <linux/module.h> 15#include <linux/sigma.h> 16 17/* Return: 0==OK, <0==error, =1 ==no more actions */ 18static int 19process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw) 20{ 21 struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos); 22 size_t len = sigma_action_len(sa); 23 int ret = 0; 24 25 pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, 26 sa->instr, sa->addr, len); 27 28 switch (sa->instr) { 29 case SIGMA_ACTION_WRITEXBYTES: 30 case SIGMA_ACTION_WRITESINGLE: 31 case SIGMA_ACTION_WRITESAFELOAD: 32 if (ssfw->fw->size < ssfw->pos + len) 33 return -EINVAL; 34 ret = i2c_master_send(client, (void *)&sa->addr, len); 35 if (ret < 0) 36 return -EINVAL; 37 break; 38 39 case SIGMA_ACTION_DELAY: 40 ret = 0; 41 udelay(len); 42 len = 0; 43 break; 44 45 case SIGMA_ACTION_END: 46 return 1; 47 48 default: 49 return -EINVAL; 50 } 51 52 /* when arrive here ret=0 or sent data */ 53 ssfw->pos += sigma_action_size(sa, len); 54 return ssfw->pos == ssfw->fw->size; 55} 56 57static int 58process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw) 59{ 60 pr_debug("%s: processing %p\n", __func__, ssfw); 61 62 while (1) { 63 int ret = process_sigma_action(client, ssfw); 64 pr_debug("%s: action returned %i\n", __func__, ret); 65 if (ret == 1) 66 return 0; 67 else if (ret) 68 return ret; 69 } 70} 71 72int process_sigma_firmware(struct i2c_client *client, const char *name) 73{ 74 int ret; 75 struct sigma_firmware_header *ssfw_head; 76 struct sigma_firmware ssfw; 77 const struct firmware *fw; 78 u32 crc; 79 80 pr_debug("%s: loading firmware %s\n", __func__, name); 81 82 /* first load the blob */ 83 ret = request_firmware(&fw, name, &client->dev); 84 if (ret) { 85 pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); 86 return ret; 87 } 88 ssfw.fw = fw; 89 90 /* then verify the header */ 91 ret = -EINVAL; 92 if (fw->size < sizeof(*ssfw_head)) 93 goto done; 94 95 ssfw_head = (void *)fw->data; 96 if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) 97 goto done; 98 99 crc = crc32(0, fw->data, fw->size); 100 pr_debug("%s: crc=%x\n", __func__, crc); 101 if (crc != ssfw_head->crc) 102 goto done; 103 104 ssfw.pos = sizeof(*ssfw_head); 105 106 /* finally process all of the actions */ 107 ret = process_sigma_actions(client, &ssfw); 108 109 done: 110 release_firmware(fw); 111 112 pr_debug("%s: loaded %s\n", __func__, name); 113 114 return ret; 115} 116EXPORT_SYMBOL(process_sigma_firmware); 117 118MODULE_LICENSE("GPL");