[patch 1/5] Hotplug firmware loader for Keyspan usb-serial driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



A simple Intel HEX format parser/loader.

Signed-off-by: Jan Harkes <[email protected]>


 include/linux/ihex_parser.h |   23 +++++
 lib/Kconfig                 |    8 +
 lib/Makefile                |    2 
 lib/ihex_parser.c           |  181 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 214 insertions(+)

Index: linux/lib/Makefile
===================================================================
--- linux.orig/lib/Makefile	2005-04-05 15:21:30.000000000 -0400
+++ linux/lib/Makefile	2005-04-05 15:21:45.000000000 -0400
@@ -34,6 +34,8 @@ obj-$(CONFIG_ZLIB_INFLATE) += zlib_infla
 obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
 obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
 
+obj-$(CONFIG_IHEX_PARSER) += ihex_parser.o
+
 hostprogs-y	:= gen_crc32table
 clean-files	:= crc32table.h
 
Index: linux/lib/ihex_parser.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/lib/ihex_parser.c	2005-04-05 15:29:55.000000000 -0400
@@ -0,0 +1,181 @@
+/*
+ * Parser/loader for IHEX formatted data.
+ *
+ * Copyright (C) 2005 Jan Harkes <[email protected]>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License version
+ *     2 as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ihex_parser.h>
+
+MODULE_AUTHOR("Jan Harkes <[email protected]>");
+MODULE_DESCRIPTION("IHEX formatted data parser");
+MODULE_LICENSE("GPL");
+
+#ifndef QUIET
+#define dbg(msg, ...) printk(KERN_WARNING "%s: line %d: " msg, __FUNCTION__, line, ## __VA_ARGS__)
+#else
+#define dbg(msg, ...) do {} while(0)
+#endif
+
+/**
+ * nibble/hex are little helpers to parse hexadecimal numbers to a byte value
+ **/
+static __u8 nibble(const __u8 n)
+{
+       if      (n >= '0' && n <= '9') return n - '0';
+       else if (n >= 'A' && n <= 'F') return n - ('A' - 10);
+       else if (n >= 'a' && n <= 'f') return n - ('a' - 10);
+       return 0;
+}
+static __u8 hex(const __u8 *data, __u8 *crc)
+{
+       __u8 val = (nibble(data[0]) << 4) | nibble(data[1]);
+       *crc += val;
+       return val;
+}
+
+/**
+ * load_ihex:
+ *
+ * Description:
+ *     @data  is expected to point at a block of Intel HEX formatted data.
+ *     @size  is the size of the data block.
+ *
+ *     @load will be called for each record that is found in the IHEX data.
+ *
+ *     @context will be passed on to @load.
+ *
+ **/
+int load_ihex(const u8 *data, const size_t size, void *context,
+	      int (*load)(struct ihex_record *record, void *context))
+{
+	struct ihex_record *record;
+	__u32 offset = 0;
+	__u8 type, crc = 0;
+	int i, j, err = 0;
+	int line = 1;
+
+	record = kmalloc(sizeof(*record), GFP_KERNEL);
+	if (!record) {
+		dbg("Allocation failed\n");
+		return -ENOMEM;
+	}
+
+	i = 0;
+next_record:
+	/* search for the start of record character */
+	while (i < size) {
+		if (data[i] == '\n') line++;
+		if (data[i++] == ':') break;
+	}
+
+	/* Minimum record length would be about 10 characters */
+	if (i + 10 > size) {
+		dbg("Can't find valid record\n");
+		err = -EINVAL;
+		goto done;
+	}
+
+	record->len = hex(data + i, &crc);
+	i += 2;
+
+	/* now check if we have enough data to read everything */
+	if (i + 8 + (record->len * 2) > size) {
+		dbg("Not enough data to read complete record\n");
+		err = -EINVAL;
+		goto done;
+	}
+
+	record->address  = hex(data + i, &crc) << 8; i += 2;
+	record->address |= hex(data + i, &crc); i += 2;
+	record->address += offset;
+	type = hex(data + i, &crc); i += 2;
+
+	for (j = 0; j < record->len; j++, i += 2)
+		record->data[j] = hex(data + i, &crc);
+
+	/* check CRC */
+	(void)hex(data + i, &crc); i += 2;
+	if (crc != 0) {
+		dbg("CRC failure\n");
+		err = -EINVAL;
+		goto done;
+	}
+
+	/* Done reading the record */
+	switch (type) {
+	case 0:
+		/* old style EOF record? */
+		if (!record->len)
+			break;
+
+		err = load(record, context);
+		if (err < 0) {
+			dbg("Firmware load failed (err %d)\n", err);
+			break;
+		} else
+		    err = 0;
+		goto next_record;
+
+	case 1: /* End-Of-File Record */
+		if (record->address || record->len) {
+			dbg("Bad EOF record (type 01) format\n");
+			err = -EINVAL;
+		}
+		break;
+
+	case 2: /* Extended Segment Address Record (HEX86) */
+	case 4: /* Extended Linear Address Record (HEX386) */
+		if (record->address || record->len != 2) {
+			dbg("Bad HEX86/HEX386 record (type %02X)\n", type);
+			err = -EINVAL;
+			break;
+		}
+
+		/* We shouldn't really be using the offset for HEX86 because
+		 * the wraparound case is specified quite differently. */
+		offset = record->data[0] << 8 | record->data[1];
+		offset <<= (type == 2 ? 4 : 16);
+		goto next_record;
+
+	case 3: /* Start Segment Address Record */
+	case 5: /* Start Linear Address Record */
+		if (record->address || record->len != 4) {
+			dbg("Bad Start Address record (type %02X)\n", type);
+			err = -EINVAL;
+			break;
+		}
+
+		/* These records contain the CS/IP or EIP where execution
+		 * starts. Don't really know what to do with them. */
+		goto next_record;
+
+	default:
+		dbg("Unknown record (type %02X)\n", type);
+		err = -EINVAL;
+		break; /* unknown record type */
+	}
+done:
+	kfree(record);
+	return err;
+}
+
+static int __init no_init(void)
+{
+	return 0;
+}
+
+static void __exit no_exit(void)
+{
+}
+
+module_init(no_init);
+module_exit(no_exit);
+
+EXPORT_SYMBOL(load_ihex);
+
Index: linux/include/linux/ihex_parser.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/include/linux/ihex_parser.h	2005-04-05 15:21:45.000000000 -0400
@@ -0,0 +1,23 @@
+/*
+ * Definitions for parser/loader for IHEX formatted data.
+ *
+ * Copyright (C) 2005 Jan Harkes <[email protected]>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License version
+ *     2 as published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_IHEX_PARSER_H
+#define _LINUX_IHEX_PARSER_H
+
+struct ihex_record {
+       __u32 address;
+       __u8  len;
+       __u8  data[255];
+};
+
+int load_ihex(const u8 *data, const size_t size, void *context,
+	      int (*load)(struct ihex_record *record, void *context));
+
+#endif
Index: linux/lib/Kconfig
===================================================================
--- linux.orig/lib/Kconfig	2005-04-05 15:08:37.000000000 -0400
+++ linux/lib/Kconfig	2005-04-05 15:21:45.000000000 -0400
@@ -57,5 +57,13 @@ config REED_SOLOMON_ENC16
 config REED_SOLOMON_DEC16
 	boolean
 
+config IHEX_PARSER
+	tristate "Intel HEX formatted data parser"
+	help
+	  This option is provided for the case where no in-kernel-tree
+	  modules require IHEX parsing, but a module built outside the
+	  kernel tree does. Such modules that need to parse Intel HEX
+	  formatted data require M here.
+
 endmenu
 

--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux