Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * NCI based driver for Samsung S3FWRN5 NFC chip
  4 *
  5 * Copyright (C) 2015 Samsung Electrnoics
  6 * Robert Baldyga <r.baldyga@samsung.com>
 
 
 
 
 
 
 
 
 
 
 
 
  7 */
  8
  9#include <linux/completion.h>
 10#include <linux/firmware.h>
 11#include <crypto/hash.h>
 12#include <crypto/sha.h>
 13
 14#include "s3fwrn5.h"
 15#include "firmware.h"
 16
 17struct s3fwrn5_fw_version {
 18	__u8 major;
 19	__u8 build1;
 20	__u8 build2;
 21	__u8 target;
 22};
 23
 24static int s3fwrn5_fw_send_msg(struct s3fwrn5_fw_info *fw_info,
 25	struct sk_buff *msg, struct sk_buff **rsp)
 26{
 27	struct s3fwrn5_info *info =
 28		container_of(fw_info, struct s3fwrn5_info, fw_info);
 29	long ret;
 30
 31	reinit_completion(&fw_info->completion);
 32
 33	ret = s3fwrn5_write(info, msg);
 34	if (ret < 0)
 35		return ret;
 36
 37	ret = wait_for_completion_interruptible_timeout(
 38		&fw_info->completion, msecs_to_jiffies(1000));
 39	if (ret < 0)
 40		return ret;
 41	else if (ret == 0)
 42		return -ENXIO;
 43
 44	if (!fw_info->rsp)
 45		return -EINVAL;
 46
 47	*rsp = fw_info->rsp;
 48	fw_info->rsp = NULL;
 49
 50	return 0;
 51}
 52
 53static int s3fwrn5_fw_prep_msg(struct s3fwrn5_fw_info *fw_info,
 54	struct sk_buff **msg, u8 type, u8 code, const void *data, u16 len)
 55{
 56	struct s3fwrn5_fw_header hdr;
 57	struct sk_buff *skb;
 58
 59	hdr.type = type | fw_info->parity;
 60	fw_info->parity ^= 0x80;
 61	hdr.code = code;
 62	hdr.len = len;
 63
 64	skb = alloc_skb(S3FWRN5_FW_HDR_SIZE + len, GFP_KERNEL);
 65	if (!skb)
 66		return -ENOMEM;
 67
 68	skb_put_data(skb, &hdr, S3FWRN5_FW_HDR_SIZE);
 69	if (len)
 70		skb_put_data(skb, data, len);
 71
 72	*msg = skb;
 73
 74	return 0;
 75}
 76
 77static int s3fwrn5_fw_get_bootinfo(struct s3fwrn5_fw_info *fw_info,
 78	struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo)
 79{
 80	struct sk_buff *msg, *rsp = NULL;
 81	struct s3fwrn5_fw_header *hdr;
 82	int ret;
 83
 84	/* Send GET_BOOTINFO command */
 85
 86	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
 87		S3FWRN5_FW_CMD_GET_BOOTINFO, NULL, 0);
 88	if (ret < 0)
 89		return ret;
 90
 91	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
 92	kfree_skb(msg);
 93	if (ret < 0)
 94		return ret;
 95
 96	hdr = (struct s3fwrn5_fw_header *) rsp->data;
 97	if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
 98		ret = -EINVAL;
 99		goto out;
100	}
101
102	memcpy(bootinfo, rsp->data + S3FWRN5_FW_HDR_SIZE, 10);
103
104out:
105	kfree_skb(rsp);
106	return ret;
107}
108
109static int s3fwrn5_fw_enter_update_mode(struct s3fwrn5_fw_info *fw_info,
110	const void *hash_data, u16 hash_size,
111	const void *sig_data, u16 sig_size)
112{
113	struct s3fwrn5_fw_cmd_enter_updatemode args;
114	struct sk_buff *msg, *rsp = NULL;
115	struct s3fwrn5_fw_header *hdr;
116	int ret;
117
118	/* Send ENTER_UPDATE_MODE command */
119
120	args.hashcode_size = hash_size;
121	args.signature_size = sig_size;
122
123	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
124		S3FWRN5_FW_CMD_ENTER_UPDATE_MODE, &args, sizeof(args));
125	if (ret < 0)
126		return ret;
127
128	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
129	kfree_skb(msg);
130	if (ret < 0)
131		return ret;
132
133	hdr = (struct s3fwrn5_fw_header *) rsp->data;
134	if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
135		ret = -EPROTO;
136		goto out;
137	}
138
139	kfree_skb(rsp);
140
141	/* Send hashcode data */
142
143	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0,
144		hash_data, hash_size);
145	if (ret < 0)
146		return ret;
147
148	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
149	kfree_skb(msg);
150	if (ret < 0)
151		return ret;
152
153	hdr = (struct s3fwrn5_fw_header *) rsp->data;
154	if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
155		ret = -EPROTO;
156		goto out;
157	}
158
159	kfree_skb(rsp);
160
161	/* Send signature data */
162
163	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0,
164		sig_data, sig_size);
165	if (ret < 0)
166		return ret;
167
168	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
169	kfree_skb(msg);
170	if (ret < 0)
171		return ret;
172
173	hdr = (struct s3fwrn5_fw_header *) rsp->data;
174	if (hdr->code != S3FWRN5_FW_RET_SUCCESS)
175		ret = -EPROTO;
176
177out:
178	kfree_skb(rsp);
179	return ret;
180}
181
182static int s3fwrn5_fw_update_sector(struct s3fwrn5_fw_info *fw_info,
183	u32 base_addr, const void *data)
184{
185	struct s3fwrn5_fw_cmd_update_sector args;
186	struct sk_buff *msg, *rsp = NULL;
187	struct s3fwrn5_fw_header *hdr;
188	int ret, i;
189
190	/* Send UPDATE_SECTOR command */
191
192	args.base_address = base_addr;
193
194	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
195		S3FWRN5_FW_CMD_UPDATE_SECTOR, &args, sizeof(args));
196	if (ret < 0)
197		return ret;
198
199	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
200	kfree_skb(msg);
201	if (ret < 0)
202		return ret;
203
204	hdr = (struct s3fwrn5_fw_header *) rsp->data;
205	if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
206		ret = -EPROTO;
207		goto err;
208	}
209
210	kfree_skb(rsp);
211
212	/* Send data split into 256-byte packets */
213
214	for (i = 0; i < 16; ++i) {
215		ret = s3fwrn5_fw_prep_msg(fw_info, &msg,
216			S3FWRN5_FW_MSG_DATA, 0, data+256*i, 256);
217		if (ret < 0)
218			break;
219
220		ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
221		kfree_skb(msg);
222		if (ret < 0)
223			break;
224
225		hdr = (struct s3fwrn5_fw_header *) rsp->data;
226		if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
227			ret = -EPROTO;
228			goto err;
229		}
230
231		kfree_skb(rsp);
232	}
233
234	return ret;
235
236err:
237	kfree_skb(rsp);
238	return ret;
239}
240
241static int s3fwrn5_fw_complete_update_mode(struct s3fwrn5_fw_info *fw_info)
242{
243	struct sk_buff *msg, *rsp = NULL;
244	struct s3fwrn5_fw_header *hdr;
245	int ret;
246
247	/* Send COMPLETE_UPDATE_MODE command */
248
249	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
250		S3FWRN5_FW_CMD_COMPLETE_UPDATE_MODE, NULL, 0);
251	if (ret < 0)
252		return ret;
253
254	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
255	kfree_skb(msg);
256	if (ret < 0)
257		return ret;
258
259	hdr = (struct s3fwrn5_fw_header *) rsp->data;
260	if (hdr->code != S3FWRN5_FW_RET_SUCCESS)
261		ret = -EPROTO;
262
263	kfree_skb(rsp);
264
265	return ret;
266}
267
268/*
269 * Firmware header stucture:
270 *
271 * 0x00 - 0x0B : Date and time string (w/o NUL termination)
272 * 0x10 - 0x13 : Firmware version
273 * 0x14 - 0x17 : Signature address
274 * 0x18 - 0x1B : Signature size
275 * 0x1C - 0x1F : Firmware image address
276 * 0x20 - 0x23 : Firmware sectors count
277 * 0x24 - 0x27 : Custom signature address
278 * 0x28 - 0x2B : Custom signature size
279 */
280
281#define S3FWRN5_FW_IMAGE_HEADER_SIZE 44
282
283static int s3fwrn5_fw_request_firmware(struct s3fwrn5_fw_info *fw_info)
284{
285	struct s3fwrn5_fw_image *fw = &fw_info->fw;
286	u32 sig_off;
287	u32 image_off;
288	u32 custom_sig_off;
289	int ret;
290
291	ret = request_firmware(&fw->fw, fw_info->fw_name,
292		&fw_info->ndev->nfc_dev->dev);
293	if (ret < 0)
294		return ret;
295
296	if (fw->fw->size < S3FWRN5_FW_IMAGE_HEADER_SIZE)
297		return -EINVAL;
298
299	memcpy(fw->date, fw->fw->data + 0x00, 12);
300	fw->date[12] = '\0';
301
302	memcpy(&fw->version, fw->fw->data + 0x10, 4);
303
304	memcpy(&sig_off, fw->fw->data + 0x14, 4);
305	fw->sig = fw->fw->data + sig_off;
306	memcpy(&fw->sig_size, fw->fw->data + 0x18, 4);
307
308	memcpy(&image_off, fw->fw->data + 0x1C, 4);
309	fw->image = fw->fw->data + image_off;
310	memcpy(&fw->image_sectors, fw->fw->data + 0x20, 4);
311
312	memcpy(&custom_sig_off, fw->fw->data + 0x24, 4);
313	fw->custom_sig = fw->fw->data + custom_sig_off;
314	memcpy(&fw->custom_sig_size, fw->fw->data + 0x28, 4);
315
316	return 0;
317}
318
319static void s3fwrn5_fw_release_firmware(struct s3fwrn5_fw_info *fw_info)
320{
321	release_firmware(fw_info->fw.fw);
322}
323
324static int s3fwrn5_fw_get_base_addr(
325	struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo, u32 *base_addr)
326{
327	int i;
328	static const struct {
329		u8 version[4];
330		u32 base_addr;
331	} match[] = {
332		{{0x05, 0x00, 0x00, 0x00}, 0x00005000},
333		{{0x05, 0x00, 0x00, 0x01}, 0x00003000},
334		{{0x05, 0x00, 0x00, 0x02}, 0x00003000},
335		{{0x05, 0x00, 0x00, 0x03}, 0x00003000},
336		{{0x05, 0x00, 0x00, 0x05}, 0x00003000}
337	};
338
339	for (i = 0; i < ARRAY_SIZE(match); ++i)
340		if (bootinfo->hw_version[0] == match[i].version[0] &&
341			bootinfo->hw_version[1] == match[i].version[1] &&
342			bootinfo->hw_version[3] == match[i].version[3]) {
343			*base_addr = match[i].base_addr;
344			return 0;
345		}
346
347	return -EINVAL;
348}
349
350static inline bool
351s3fwrn5_fw_is_custom(struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo)
352{
353	return !!bootinfo->hw_version[2];
354}
355
356int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info)
357{
358	struct s3fwrn5_fw_cmd_get_bootinfo_rsp bootinfo;
359	int ret;
360
361	/* Get firmware data */
362
363	ret = s3fwrn5_fw_request_firmware(fw_info);
364	if (ret < 0) {
365		dev_err(&fw_info->ndev->nfc_dev->dev,
366			"Failed to get fw file, ret=%02x\n", ret);
367		return ret;
368	}
369
370	/* Get bootloader info */
371
372	ret = s3fwrn5_fw_get_bootinfo(fw_info, &bootinfo);
373	if (ret < 0) {
374		dev_err(&fw_info->ndev->nfc_dev->dev,
375			"Failed to get bootinfo, ret=%02x\n", ret);
376		goto err;
377	}
378
379	/* Match hardware version to obtain firmware base address */
380
381	ret = s3fwrn5_fw_get_base_addr(&bootinfo, &fw_info->base_addr);
382	if (ret < 0) {
383		dev_err(&fw_info->ndev->nfc_dev->dev,
384			"Unknown hardware version\n");
385		goto err;
386	}
387
388	fw_info->sector_size = bootinfo.sector_size;
389
390	fw_info->sig_size = s3fwrn5_fw_is_custom(&bootinfo) ?
391		fw_info->fw.custom_sig_size : fw_info->fw.sig_size;
392	fw_info->sig = s3fwrn5_fw_is_custom(&bootinfo) ?
393		fw_info->fw.custom_sig : fw_info->fw.sig;
394
395	return 0;
396
397err:
398	s3fwrn5_fw_release_firmware(fw_info);
399	return ret;
400}
401
402bool s3fwrn5_fw_check_version(struct s3fwrn5_fw_info *fw_info, u32 version)
403{
404	struct s3fwrn5_fw_version *new = (void *) &fw_info->fw.version;
405	struct s3fwrn5_fw_version *old = (void *) &version;
406
407	if (new->major > old->major)
408		return true;
409	if (new->build1 > old->build1)
410		return true;
411	if (new->build2 > old->build2)
412		return true;
413
414	return false;
415}
416
417int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info)
418{
419	struct s3fwrn5_fw_image *fw = &fw_info->fw;
420	u8 hash_data[SHA1_DIGEST_SIZE];
421	struct crypto_shash *tfm;
422	u32 image_size, off;
423	int ret;
424
425	image_size = fw_info->sector_size * fw->image_sectors;
426
427	/* Compute SHA of firmware data */
428
429	tfm = crypto_alloc_shash("sha1", 0, 0);
430	if (IS_ERR(tfm)) {
431		ret = PTR_ERR(tfm);
432		dev_err(&fw_info->ndev->nfc_dev->dev,
433			"Cannot allocate shash (code=%d)\n", ret);
434		goto out;
435	}
436
437	ret = crypto_shash_tfm_digest(tfm, fw->image, image_size, hash_data);
 
 
 
 
 
 
 
 
 
438
439	crypto_free_shash(tfm);
440	if (ret) {
441		dev_err(&fw_info->ndev->nfc_dev->dev,
442			"Cannot compute hash (code=%d)\n", ret);
443		goto out;
444	}
445
446	/* Firmware update process */
447
448	dev_info(&fw_info->ndev->nfc_dev->dev,
449		"Firmware update: %s\n", fw_info->fw_name);
450
451	ret = s3fwrn5_fw_enter_update_mode(fw_info, hash_data,
452		SHA1_DIGEST_SIZE, fw_info->sig, fw_info->sig_size);
453	if (ret < 0) {
454		dev_err(&fw_info->ndev->nfc_dev->dev,
455			"Unable to enter update mode\n");
456		goto out;
457	}
458
459	for (off = 0; off < image_size; off += fw_info->sector_size) {
460		ret = s3fwrn5_fw_update_sector(fw_info,
461			fw_info->base_addr + off, fw->image + off);
462		if (ret < 0) {
463			dev_err(&fw_info->ndev->nfc_dev->dev,
464				"Firmware update error (code=%d)\n", ret);
465			goto out;
466		}
467	}
468
469	ret = s3fwrn5_fw_complete_update_mode(fw_info);
470	if (ret < 0) {
471		dev_err(&fw_info->ndev->nfc_dev->dev,
472			"Unable to complete update mode\n");
473		goto out;
474	}
475
476	dev_info(&fw_info->ndev->nfc_dev->dev,
477		"Firmware update: success\n");
478
479out:
480	return ret;
481}
482
483void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name)
484{
485	fw_info->parity = 0x00;
486	fw_info->rsp = NULL;
487	fw_info->fw.fw = NULL;
488	strcpy(fw_info->fw_name, fw_name);
489	init_completion(&fw_info->completion);
490}
491
492void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info)
493{
494	s3fwrn5_fw_release_firmware(fw_info);
495}
496
497int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
498{
499	struct s3fwrn5_info *info = nci_get_drvdata(ndev);
500	struct s3fwrn5_fw_info *fw_info = &info->fw_info;
501
502	if (WARN_ON(fw_info->rsp)) {
503		kfree_skb(skb);
504		return -EINVAL;
505	}
506
507	fw_info->rsp = skb;
508
509	complete(&fw_info->completion);
510
511	return 0;
512}
v4.17
 
  1/*
  2 * NCI based driver for Samsung S3FWRN5 NFC chip
  3 *
  4 * Copyright (C) 2015 Samsung Electrnoics
  5 * Robert Baldyga <r.baldyga@samsung.com>
  6 *
  7 * This program is free software; you can redistribute it and/or modify it
  8 * under the terms and conditions of the GNU General Public License,
  9 * version 2 or later, as published by the Free Software Foundation.
 10 *
 11 * This program is distributed in the hope that it will be useful,
 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 14 * GNU General Public License for more details.
 15 *
 16 * You should have received a copy of the GNU General Public License
 17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 18 */
 19
 20#include <linux/completion.h>
 21#include <linux/firmware.h>
 22#include <crypto/hash.h>
 23#include <crypto/sha.h>
 24
 25#include "s3fwrn5.h"
 26#include "firmware.h"
 27
 28struct s3fwrn5_fw_version {
 29	__u8 major;
 30	__u8 build1;
 31	__u8 build2;
 32	__u8 target;
 33};
 34
 35static int s3fwrn5_fw_send_msg(struct s3fwrn5_fw_info *fw_info,
 36	struct sk_buff *msg, struct sk_buff **rsp)
 37{
 38	struct s3fwrn5_info *info =
 39		container_of(fw_info, struct s3fwrn5_info, fw_info);
 40	long ret;
 41
 42	reinit_completion(&fw_info->completion);
 43
 44	ret = s3fwrn5_write(info, msg);
 45	if (ret < 0)
 46		return ret;
 47
 48	ret = wait_for_completion_interruptible_timeout(
 49		&fw_info->completion, msecs_to_jiffies(1000));
 50	if (ret < 0)
 51		return ret;
 52	else if (ret == 0)
 53		return -ENXIO;
 54
 55	if (!fw_info->rsp)
 56		return -EINVAL;
 57
 58	*rsp = fw_info->rsp;
 59	fw_info->rsp = NULL;
 60
 61	return 0;
 62}
 63
 64static int s3fwrn5_fw_prep_msg(struct s3fwrn5_fw_info *fw_info,
 65	struct sk_buff **msg, u8 type, u8 code, const void *data, u16 len)
 66{
 67	struct s3fwrn5_fw_header hdr;
 68	struct sk_buff *skb;
 69
 70	hdr.type = type | fw_info->parity;
 71	fw_info->parity ^= 0x80;
 72	hdr.code = code;
 73	hdr.len = len;
 74
 75	skb = alloc_skb(S3FWRN5_FW_HDR_SIZE + len, GFP_KERNEL);
 76	if (!skb)
 77		return -ENOMEM;
 78
 79	skb_put_data(skb, &hdr, S3FWRN5_FW_HDR_SIZE);
 80	if (len)
 81		skb_put_data(skb, data, len);
 82
 83	*msg = skb;
 84
 85	return 0;
 86}
 87
 88static int s3fwrn5_fw_get_bootinfo(struct s3fwrn5_fw_info *fw_info,
 89	struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo)
 90{
 91	struct sk_buff *msg, *rsp = NULL;
 92	struct s3fwrn5_fw_header *hdr;
 93	int ret;
 94
 95	/* Send GET_BOOTINFO command */
 96
 97	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
 98		S3FWRN5_FW_CMD_GET_BOOTINFO, NULL, 0);
 99	if (ret < 0)
100		return ret;
101
102	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
103	kfree_skb(msg);
104	if (ret < 0)
105		return ret;
106
107	hdr = (struct s3fwrn5_fw_header *) rsp->data;
108	if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
109		ret = -EINVAL;
110		goto out;
111	}
112
113	memcpy(bootinfo, rsp->data + S3FWRN5_FW_HDR_SIZE, 10);
114
115out:
116	kfree_skb(rsp);
117	return ret;
118}
119
120static int s3fwrn5_fw_enter_update_mode(struct s3fwrn5_fw_info *fw_info,
121	const void *hash_data, u16 hash_size,
122	const void *sig_data, u16 sig_size)
123{
124	struct s3fwrn5_fw_cmd_enter_updatemode args;
125	struct sk_buff *msg, *rsp = NULL;
126	struct s3fwrn5_fw_header *hdr;
127	int ret;
128
129	/* Send ENTER_UPDATE_MODE command */
130
131	args.hashcode_size = hash_size;
132	args.signature_size = sig_size;
133
134	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
135		S3FWRN5_FW_CMD_ENTER_UPDATE_MODE, &args, sizeof(args));
136	if (ret < 0)
137		return ret;
138
139	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
140	kfree_skb(msg);
141	if (ret < 0)
142		return ret;
143
144	hdr = (struct s3fwrn5_fw_header *) rsp->data;
145	if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
146		ret = -EPROTO;
147		goto out;
148	}
149
150	kfree_skb(rsp);
151
152	/* Send hashcode data */
153
154	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0,
155		hash_data, hash_size);
156	if (ret < 0)
157		return ret;
158
159	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
160	kfree_skb(msg);
161	if (ret < 0)
162		return ret;
163
164	hdr = (struct s3fwrn5_fw_header *) rsp->data;
165	if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
166		ret = -EPROTO;
167		goto out;
168	}
169
170	kfree_skb(rsp);
171
172	/* Send signature data */
173
174	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0,
175		sig_data, sig_size);
176	if (ret < 0)
177		return ret;
178
179	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
180	kfree_skb(msg);
181	if (ret < 0)
182		return ret;
183
184	hdr = (struct s3fwrn5_fw_header *) rsp->data;
185	if (hdr->code != S3FWRN5_FW_RET_SUCCESS)
186		ret = -EPROTO;
187
188out:
189	kfree_skb(rsp);
190	return ret;
191}
192
193static int s3fwrn5_fw_update_sector(struct s3fwrn5_fw_info *fw_info,
194	u32 base_addr, const void *data)
195{
196	struct s3fwrn5_fw_cmd_update_sector args;
197	struct sk_buff *msg, *rsp = NULL;
198	struct s3fwrn5_fw_header *hdr;
199	int ret, i;
200
201	/* Send UPDATE_SECTOR command */
202
203	args.base_address = base_addr;
204
205	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
206		S3FWRN5_FW_CMD_UPDATE_SECTOR, &args, sizeof(args));
207	if (ret < 0)
208		return ret;
209
210	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
211	kfree_skb(msg);
212	if (ret < 0)
213		return ret;
214
215	hdr = (struct s3fwrn5_fw_header *) rsp->data;
216	if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
217		ret = -EPROTO;
218		goto err;
219	}
220
221	kfree_skb(rsp);
222
223	/* Send data split into 256-byte packets */
224
225	for (i = 0; i < 16; ++i) {
226		ret = s3fwrn5_fw_prep_msg(fw_info, &msg,
227			S3FWRN5_FW_MSG_DATA, 0, data+256*i, 256);
228		if (ret < 0)
229			break;
230
231		ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
232		kfree_skb(msg);
233		if (ret < 0)
234			break;
235
236		hdr = (struct s3fwrn5_fw_header *) rsp->data;
237		if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
238			ret = -EPROTO;
239			goto err;
240		}
241
242		kfree_skb(rsp);
243	}
244
245	return ret;
246
247err:
248	kfree_skb(rsp);
249	return ret;
250}
251
252static int s3fwrn5_fw_complete_update_mode(struct s3fwrn5_fw_info *fw_info)
253{
254	struct sk_buff *msg, *rsp = NULL;
255	struct s3fwrn5_fw_header *hdr;
256	int ret;
257
258	/* Send COMPLETE_UPDATE_MODE command */
259
260	ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
261		S3FWRN5_FW_CMD_COMPLETE_UPDATE_MODE, NULL, 0);
262	if (ret < 0)
263		return ret;
264
265	ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
266	kfree_skb(msg);
267	if (ret < 0)
268		return ret;
269
270	hdr = (struct s3fwrn5_fw_header *) rsp->data;
271	if (hdr->code != S3FWRN5_FW_RET_SUCCESS)
272		ret = -EPROTO;
273
274	kfree_skb(rsp);
275
276	return ret;
277}
278
279/*
280 * Firmware header stucture:
281 *
282 * 0x00 - 0x0B : Date and time string (w/o NUL termination)
283 * 0x10 - 0x13 : Firmware version
284 * 0x14 - 0x17 : Signature address
285 * 0x18 - 0x1B : Signature size
286 * 0x1C - 0x1F : Firmware image address
287 * 0x20 - 0x23 : Firmware sectors count
288 * 0x24 - 0x27 : Custom signature address
289 * 0x28 - 0x2B : Custom signature size
290 */
291
292#define S3FWRN5_FW_IMAGE_HEADER_SIZE 44
293
294static int s3fwrn5_fw_request_firmware(struct s3fwrn5_fw_info *fw_info)
295{
296	struct s3fwrn5_fw_image *fw = &fw_info->fw;
297	u32 sig_off;
298	u32 image_off;
299	u32 custom_sig_off;
300	int ret;
301
302	ret = request_firmware(&fw->fw, fw_info->fw_name,
303		&fw_info->ndev->nfc_dev->dev);
304	if (ret < 0)
305		return ret;
306
307	if (fw->fw->size < S3FWRN5_FW_IMAGE_HEADER_SIZE)
308		return -EINVAL;
309
310	memcpy(fw->date, fw->fw->data + 0x00, 12);
311	fw->date[12] = '\0';
312
313	memcpy(&fw->version, fw->fw->data + 0x10, 4);
314
315	memcpy(&sig_off, fw->fw->data + 0x14, 4);
316	fw->sig = fw->fw->data + sig_off;
317	memcpy(&fw->sig_size, fw->fw->data + 0x18, 4);
318
319	memcpy(&image_off, fw->fw->data + 0x1C, 4);
320	fw->image = fw->fw->data + image_off;
321	memcpy(&fw->image_sectors, fw->fw->data + 0x20, 4);
322
323	memcpy(&custom_sig_off, fw->fw->data + 0x24, 4);
324	fw->custom_sig = fw->fw->data + custom_sig_off;
325	memcpy(&fw->custom_sig_size, fw->fw->data + 0x28, 4);
326
327	return 0;
328}
329
330static void s3fwrn5_fw_release_firmware(struct s3fwrn5_fw_info *fw_info)
331{
332	release_firmware(fw_info->fw.fw);
333}
334
335static int s3fwrn5_fw_get_base_addr(
336	struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo, u32 *base_addr)
337{
338	int i;
339	static const struct {
340		u8 version[4];
341		u32 base_addr;
342	} match[] = {
343		{{0x05, 0x00, 0x00, 0x00}, 0x00005000},
344		{{0x05, 0x00, 0x00, 0x01}, 0x00003000},
345		{{0x05, 0x00, 0x00, 0x02}, 0x00003000},
346		{{0x05, 0x00, 0x00, 0x03}, 0x00003000},
347		{{0x05, 0x00, 0x00, 0x05}, 0x00003000}
348	};
349
350	for (i = 0; i < ARRAY_SIZE(match); ++i)
351		if (bootinfo->hw_version[0] == match[i].version[0] &&
352			bootinfo->hw_version[1] == match[i].version[1] &&
353			bootinfo->hw_version[3] == match[i].version[3]) {
354			*base_addr = match[i].base_addr;
355			return 0;
356		}
357
358	return -EINVAL;
359}
360
361static inline bool
362s3fwrn5_fw_is_custom(struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo)
363{
364	return !!bootinfo->hw_version[2];
365}
366
367int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info)
368{
369	struct s3fwrn5_fw_cmd_get_bootinfo_rsp bootinfo;
370	int ret;
371
372	/* Get firmware data */
373
374	ret = s3fwrn5_fw_request_firmware(fw_info);
375	if (ret < 0) {
376		dev_err(&fw_info->ndev->nfc_dev->dev,
377			"Failed to get fw file, ret=%02x\n", ret);
378		return ret;
379	}
380
381	/* Get bootloader info */
382
383	ret = s3fwrn5_fw_get_bootinfo(fw_info, &bootinfo);
384	if (ret < 0) {
385		dev_err(&fw_info->ndev->nfc_dev->dev,
386			"Failed to get bootinfo, ret=%02x\n", ret);
387		goto err;
388	}
389
390	/* Match hardware version to obtain firmware base address */
391
392	ret = s3fwrn5_fw_get_base_addr(&bootinfo, &fw_info->base_addr);
393	if (ret < 0) {
394		dev_err(&fw_info->ndev->nfc_dev->dev,
395			"Unknown hardware version\n");
396		goto err;
397	}
398
399	fw_info->sector_size = bootinfo.sector_size;
400
401	fw_info->sig_size = s3fwrn5_fw_is_custom(&bootinfo) ?
402		fw_info->fw.custom_sig_size : fw_info->fw.sig_size;
403	fw_info->sig = s3fwrn5_fw_is_custom(&bootinfo) ?
404		fw_info->fw.custom_sig : fw_info->fw.sig;
405
406	return 0;
407
408err:
409	s3fwrn5_fw_release_firmware(fw_info);
410	return ret;
411}
412
413bool s3fwrn5_fw_check_version(struct s3fwrn5_fw_info *fw_info, u32 version)
414{
415	struct s3fwrn5_fw_version *new = (void *) &fw_info->fw.version;
416	struct s3fwrn5_fw_version *old = (void *) &version;
417
418	if (new->major > old->major)
419		return true;
420	if (new->build1 > old->build1)
421		return true;
422	if (new->build2 > old->build2)
423		return true;
424
425	return false;
426}
427
428int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info)
429{
430	struct s3fwrn5_fw_image *fw = &fw_info->fw;
431	u8 hash_data[SHA1_DIGEST_SIZE];
432	struct crypto_shash *tfm;
433	u32 image_size, off;
434	int ret;
435
436	image_size = fw_info->sector_size * fw->image_sectors;
437
438	/* Compute SHA of firmware data */
439
440	tfm = crypto_alloc_shash("sha1", 0, 0);
441	if (IS_ERR(tfm)) {
442		ret = PTR_ERR(tfm);
443		dev_err(&fw_info->ndev->nfc_dev->dev,
444			"Cannot allocate shash (code=%d)\n", ret);
445		goto out;
446	}
447
448	{
449		SHASH_DESC_ON_STACK(desc, tfm);
450
451		desc->tfm = tfm;
452		desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
453
454		ret = crypto_shash_digest(desc, fw->image, image_size,
455					  hash_data);
456		shash_desc_zero(desc);
457	}
458
459	crypto_free_shash(tfm);
460	if (ret) {
461		dev_err(&fw_info->ndev->nfc_dev->dev,
462			"Cannot compute hash (code=%d)\n", ret);
463		goto out;
464	}
465
466	/* Firmware update process */
467
468	dev_info(&fw_info->ndev->nfc_dev->dev,
469		"Firmware update: %s\n", fw_info->fw_name);
470
471	ret = s3fwrn5_fw_enter_update_mode(fw_info, hash_data,
472		SHA1_DIGEST_SIZE, fw_info->sig, fw_info->sig_size);
473	if (ret < 0) {
474		dev_err(&fw_info->ndev->nfc_dev->dev,
475			"Unable to enter update mode\n");
476		goto out;
477	}
478
479	for (off = 0; off < image_size; off += fw_info->sector_size) {
480		ret = s3fwrn5_fw_update_sector(fw_info,
481			fw_info->base_addr + off, fw->image + off);
482		if (ret < 0) {
483			dev_err(&fw_info->ndev->nfc_dev->dev,
484				"Firmware update error (code=%d)\n", ret);
485			goto out;
486		}
487	}
488
489	ret = s3fwrn5_fw_complete_update_mode(fw_info);
490	if (ret < 0) {
491		dev_err(&fw_info->ndev->nfc_dev->dev,
492			"Unable to complete update mode\n");
493		goto out;
494	}
495
496	dev_info(&fw_info->ndev->nfc_dev->dev,
497		"Firmware update: success\n");
498
499out:
500	return ret;
501}
502
503void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name)
504{
505	fw_info->parity = 0x00;
506	fw_info->rsp = NULL;
507	fw_info->fw.fw = NULL;
508	strcpy(fw_info->fw_name, fw_name);
509	init_completion(&fw_info->completion);
510}
511
512void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info)
513{
514	s3fwrn5_fw_release_firmware(fw_info);
515}
516
517int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
518{
519	struct s3fwrn5_info *info = nci_get_drvdata(ndev);
520	struct s3fwrn5_fw_info *fw_info = &info->fw_info;
521
522	BUG_ON(fw_info->rsp);
 
 
 
523
524	fw_info->rsp = skb;
525
526	complete(&fw_info->completion);
527
528	return 0;
529}