[RFC][PATCH] Oops messages transfer using QR codes
From: Murtaza Alexandru
Date: Fri Oct 30 2015 - 11:01:23 EST
This patch is continued from this previous RFC:
https://lkml.org/lkml/2014/3/17/525
If the config option for this feature is enabled, then when an Oops is
in progress, the printk() calls' strings are buffered. When the Oops
finishes, the buffer is split into multiple packets, compressed, encoded
into QRs and then displayed in console. The compression is done using
DEFLATE (from lib/zlib/). The user can issue commands writing to the sysfs.
For scanning and automatic reporting Bug Koops (Android application) is
needed [0].
Problems with the previous patch:
1. Even if the specifications says you can encode up to 2980 bytes into a
QR code, in reality, you can only encode about 200 bytes if you want to
scan it with a smartphone. Using DEFLATE, we can compress 300 bytes so that
the output is less than 200 bytes almost all the time. From what I saw, an
Oops message is on average about 1.7kb. So the conclusion is: one QR is not
enough.
2. If there are multiple Oopses occurring on different CPUs there is no way
to draw both QRs. Even if we would take not to overlap them, we would be
left with even less space to draw which results in less info we are able
to send.
3. Another problem in the previous RFC was that there is no way (or at
least I didn't figured it out) of knowing if what we write in the
framebuffer actually gets to the screen and also there is no simple way
to guarantee that what we draw is always on top of the text.
Proposed solution for the above stated problems:
When we finish capturing an Oops, split the message into multiple chunks,
compress them and encode into some format so we will be able to get the
initial message again no matter in what order we scan the QRs. For drawing,
we are going to make a kthread and continuously draw. This will guarantee
the QR is always on top. Also this will enable rendering an "animation".
The way data is encoded into a packet is described here [1] but TL;DR:
We are 100% sure the QR code is scanned correctly so we don't need error
correction, we are only in a 1-way "communication" so we have to run the
animation indefinitely anyway. The things we care about is being able
to distinguish between different messages, for one message to be able
to reorder the packets and sanity check of the message (check if the user
is not scanning normal QRs). For more detailed information and explanation
please see [1].
For this patch to work properly you need to have framebuffer enabled.
Anyway, if you do not have one, ASCII art will be used as a fallback.
>From BugKoops to QR module communication we have to use the user (tell him
what to do). For user to QR module we use sysfs. Current implementation
supports stop, pause, resume, clear queue and print packets ids, print
messages ids, delete packet, delete message, which are all useful in
case you want to speed up the scanning process a little bit.
Current issues:
* screen flush and console acquisition is forced with a printk
* not tested for Oops messages issued from several CPUs
* all values and data presented here are empirical and finer tuning should
be done
I hope this will give an impulse to the community to search a way
and extend this for panics too, which would be much more useful.
Also, right now you have to compile Bug Koops on your own (latest Android
Studio) if anyone would like to test it out please reply and I will upload
an apk.
[0]: https://github.com/links234/BugKoops
[1]: https://github.com/links234/BugKoops/blob/master/docs/FORMAT.md
Cc: Teodora Baluta <teodora.baluta@xxxxxxxxx>
Cc: Levente Kurusa <levex@xxxxxxxxx>
Cc: Dirk Hohndel <dirk.hohndel@xxxxxxxxx>
Cc: H. Peter Anvin <h.peter.anvin@xxxxxxxxx>
Signed-off-by: Murtaza Alexandru <alexandru.murtaza@xxxxxxxxx>
---
MAINTAINERS | 10 +
include/linux/print_oops.h | 11 +
include/linux/qrencode.h | 504 +++++++++++++++
kernel/Makefile | 1 +
kernel/panic.c | 5 +
kernel/print_oops.c | 693 ++++++++++++++++++++
kernel/printk/printk.c | 15 +-
lib/Kconfig | 6 +
lib/Kconfig.debug | 17 +
lib/Makefile | 3 +
lib/qr/Makefile | 6 +
lib/qr/bitstream.c | 203 ++++++
lib/qr/bitstream.h | 41 ++
lib/qr/mask.c | 311 +++++++++
lib/qr/mask.h | 28 +
lib/qr/mmask.h | 28 +
lib/qr/qrencode.c | 668 +++++++++++++++++++
lib/qr/qrencode.h | 546 ++++++++++++++++
lib/qr/qrinput.c | 1515 ++++++++++++++++++++++++++++++++++++++++++++
lib/qr/qrinput.h | 115 ++++
lib/qr/qrspec.c | 542 ++++++++++++++++
lib/qr/qrspec.h | 177 ++++++
lib/qr/split.c | 283 +++++++++
lib/qr/split.h | 48 ++
25 files changed, 5776 insertions(+), 1 deletion(-)
create mode 100644 include/linux/print_oops.h
create mode 100644 include/linux/qrencode.h
create mode 100644 kernel/print_oops.c
create mode 100644 lib/qr/Makefile
create mode 100644 lib/qr/bitstream.c
create mode 100644 lib/qr/bitstream.h
create mode 100644 lib/qr/mask.c
create mode 100644 lib/qr/mask.h
create mode 100644 lib/qr/mmask.h
create mode 100644 lib/qr/qrencode.c
create mode 100644 lib/qr/qrencode.h
create mode 100644 lib/qr/qrinput.c
create mode 100644 lib/qr/qrinput.h
create mode 100644 lib/qr/qrspec.c
create mode 100644 lib/qr/qrspec.h
create mode 100644 lib/qr/split.c
create mode 100644 lib/qr/split.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 9f6685f..5275fff 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8527,6 +8527,16 @@ F: fs/qnx4/
F: include/uapi/linux/qnx4_fs.h
F: include/uapi/linux/qnxtypes.h
+QR ENCODING LIBRARY
+M: Murtaza Alexandru <alexandru.murtaza@xxxxxxxxx>
+M: Teodora Baluta <teobaluta@xxxxxxxxx>
+M: Levente Kurusa <levex@xxxxxxxxx>
+S: Maintained
+F: lib/qr/
+F: kernel/print_oops.c
+F: include/linux/print_oops.h
+F: include/linux/qrencode.h
+
QT1010 MEDIA DRIVER
M: Antti Palosaari <crope@xxxxxx>
L: linux-media@xxxxxxxxxxxxxxx
diff --git a/include/linux/print_oops.h b/include/linux/print_oops.h
new file mode 100644
index 0000000..9f53d1a
--- /dev/null
+++ b/include/linux/print_oops.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_X86_PRINT_OOPS_H
+#define _ASM_X86_PRINT_OOPS_H
+
+#include <linux/module.h>
+
+#define MESSAGE_BUFSIZE 4096
+
+void qr_append(char *text);
+void print_qr_err(void);
+
+#endif /* _PRINT_OOPS_H */
diff --git a/include/linux/qrencode.h b/include/linux/qrencode.h
new file mode 100644
index 0000000..112c4bf
--- /dev/null
+++ b/include/linux/qrencode.h
@@ -0,0 +1,504 @@
+/**
+ * qrencode - QR Code encoder
+ *
+ * Copyright (C) 2006-2012 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+/** \mainpage
+ * Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D
+ * symbology.
+ *
+ * \section encoding Encoding
+ *
+ * There are two methods to encode data: <b>encoding a string/data</b> or
+ * <b>encoding a structured data</b>.
+ *
+ * \subsection encoding-string Encoding a string/data
+ * You can encode a string by calling qrcode_encode_string().
+ * The given string is parsed automatically and encoded. If you want to encode
+ * data that can be represented as a C string style (NUL terminated), you can
+ * simply use this way.
+ *
+ * If the input data contains Kanji (Shift-JIS) characters and you want to
+ * encode them as Kanji in QR Code, you should give QR_MODE_KANJI as a hint.
+ * Otherwise, all of non-alphanumeric characters are encoded as 8 bit data.
+ * If you want to encode a whole string in 8 bit mode, you can use
+ * qrcode_encode_string_8bit() instead.
+ *
+ * Please note that a C string can not contain NUL characters. If your data
+ * contains NUL, you must use qrcode_encode_data().
+ *
+ * \subsection encoding-input Encoding a structured data
+ * You can construct a structured input data manually. If the structure of the
+ * input data is known, you can use this way.
+ * At first, create a ::qrinput object by qrinput_new(). Then add input data
+ * to the qrinput object by qrinput_append(). Finally call qrcode_encode_input()
+ * to encode the qrinput data.
+ * You can reuse the qrinput data again to encode it in other symbols with
+ * different parameters.
+ *
+ * \section result Result
+ * The encoded symbol is resulted as a ::qrcode object. It will contain
+ * its version number, width of the symbol and an array represents the symbol.
+ * See ::qrcode for the details. You can free the object by qrcode_free().
+ *
+ * Please note that the version of the result may be larger than specified.
+ * In such cases, the input data would be too large to be encoded in a
+ * symbol of the specified version.
+ *
+ * \section structured Structured append
+ * Libqrencode can generate "Structured-appended" symbols that enables to split
+ * a large data set into mulitple QR codes. A QR code reader concatenates
+ * multiple QR code symbols into a string.
+ * Just like qrcode_encode_string(), you can use
+ * qrcode_encode_string_structured() to generate structured-appended symbols.
+ * This functions returns an instance of ::qrcode_list. The returned list is a
+ * singly-linked list of qrcode: you
+ * can retrieve each QR code in this way:
+ *
+ * \code
+ * qrcode_list *qrcodes;
+ * qrcode_list *entry;
+ * qrcode *qrcode;
+ *
+ * qrcodes = qrcode_encode_string_structured(...);
+ * entry = qrcodes;
+ * while(entry != NULL) {
+ * qrcode = entry->code;
+ * // do something
+ * entry = entry->next;
+ * }
+ * qrcode_list_free(entry);
+ * \endcode
+ *
+ * Instead of using auto-parsing functions, you can construct your own
+ * structured input. At first, instantiate an object of ::qrinput_struct
+ * by calling qrinput_struct_new(). This object can hold multiple ::qrinput,
+ * and one QR code is generated for a ::qrinput.
+ * qrinput_struct_append_input() appends a ::qrinput to a ::qrinput_struct
+ * object. In order to generate structured-appended symbols, it is required to
+ * embed headers to each symbol. You can use
+ * qrinput_struct_insert_structured_append_headers() to insert appropriate
+ * headers to each symbol. You should call this function just once before
+ * encoding symbols.
+ */
+
+#ifndef __QRENCODE_H__
+#define __QRENCODE_H__
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * Encoding mode.
+ */
+enum qrencode_mode {
+ QR_MODE_NUL = -1, /* Terminator (NUL character). Internal use only */
+ QR_MODE_NUM = 0, /* Numeric mode */
+ QR_MODE_AN, /* Alphabet-numeric mode */
+ QR_MODE_8, /* 8-bit data mode */
+ QR_MODE_STRUCTURE, /* Internal use only */
+ QR_MODE_ECI, /* ECI mode */
+ QR_MODE_FNC1FIRST, /* FNC1, first position */
+ QR_MODE_FNC1SECOND, /* FNC1, second position */
+};
+
+/**
+ * Level of error correction.
+ */
+enum qrec_level {
+ QR_ECLEVEL_L = 0, /* lowest */
+ QR_ECLEVEL_M,
+ QR_ECLEVEL_Q,
+ QR_ECLEVEL_H /* highest */
+};
+
+/**
+ * Maximum version (size) of QR-code symbol.
+ */
+#define QRSPEC_VERSION_MAX 40
+
+/******************************************************************************
+ * Input data (qrinput.c)
+ *****************************************************************************/
+/**
+ * Instantiate an input data object. The version is set to 0 (auto-select)
+ * and the error correction level is set to QR_ECLEVEL_L.
+ * @return an input object (initialized). On error, NULL is returned and errno
+ * is set to indicate the error.
+ * @throw ENOMEM unable to allocate memory.
+ */
+struct qrinput *qrinput_new(void);
+
+/**
+ * Instantiate an input data object.
+ * @param version version number.
+ * @param level Error correction level.
+ * @return an input object (initialized). On error, NULL is returned and errno
+ * is set to indicate the error.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ * @throw EINVAL invalid arguments.
+ */
+struct qrinput *qrinput_new2(int version, enum qrec_level level);
+
+/**
+ * Append data to an input object.
+ * The data is copied and appended to the input object.
+ * @param input input object.
+ * @param mode encoding mode.
+ * @param size size of data (byte).
+ * @param data a pointer to the memory area of the input data.
+ * @retval 0 success.
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ * @throw EINVAL input data is invalid.
+ *
+ */
+int qrinput_append(struct qrinput *input, enum qrencode_mode mode,
+ int size, const unsigned char *data);
+
+/**
+ * Append ECI header.
+ * @param input input object.
+ * @param ecinum ECI indicator number (0 - 999999)
+ * @retval 0 success.
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ * @throw EINVAL input data is invalid.
+ *
+ */
+int qrinput_append_eci_header(struct qrinput *input, unsigned int ecinum);
+
+/**
+ * Get current version.
+ * @param input input object.
+ * @return current version.
+ */
+int qrinput_get_version(struct qrinput *input);
+
+/**
+ * Set version of the QR code that is to be encoded.
+ * This function cannot be applied to Micro QR Code.
+ * @param input input object.
+ * @param version version number (0 = auto)
+ * @retval 0 success.
+ * @retval -1 invalid argument.
+ */
+int qrinput_set_version(struct qrinput *input, int version);
+
+/**
+ * Get current error correction level.
+ * @param input input object.
+ * @return Current error correcntion level.
+ */
+enum qrec_level qrinput_get_error_correction_level(struct qrinput *input);
+
+/**
+ * Set error correction level of the QR code that is to be encoded.
+ * This function cannot be applied to Micro QR Code.
+ * @param input input object.
+ * @param level Error correction level.
+ * @retval 0 success.
+ * @retval -1 invalid argument.
+ */
+int qrinput_set_error_correction_level(struct qrinput *input,
+ enum qrec_level level);
+
+/**
+ * Set version and error correction level of the QR code at once.
+ * This function is recommened for Micro QR Code.
+ * @param input input object.
+ * @param version version number (0 = auto)
+ * @param level Error correction level.
+ * @retval 0 success.
+ * @retval -1 invalid argument.
+ */
+int qrinput_set_version_and_error_correction_level(struct qrinput *input,
+ int version,
+ enum qrec_level level);
+
+/**
+ * Free the input object.
+ * All of data chunks in the input object are freed too.
+ * @param input input object.
+ */
+void qrinput_free(struct qrinput *input);
+
+/**
+ * Validate the input data.
+ * @param mode encoding mode.
+ * @param size size of data (byte).
+ * @param data a pointer to the memory area of the input data.
+ * @retval 0 success.
+ * @retval -1 invalid arguments.
+ */
+int qrinput_check(enum qrencode_mode mode, int size,
+ const unsigned char *data);
+
+/**
+ * Instantiate a set of input data object.
+ * @return an instance of qrinput_struct. On error, NULL is returned and errno
+ * is set to indicate the error.
+ * @throw ENOMEM unable to allocate memory.
+ */
+struct qrinput_struct *qrinput_struct_new(void);
+
+/**
+ * Set parity of structured symbols.
+ * @param s structured input object.
+ * @param parity parity of s.
+ */
+void qrinput_struct_set_parity(struct qrinput_struct *s,
+ unsigned char parity);
+
+/**
+ * Append a qrinput object to the set. qrinput created by qrinput_new_micro()
+ * will be rejected.
+ * @warning never append the same qrinput object twice or more.
+ * @param s structured input object.
+ * @param input an input object.
+ * @retval >0 number of input objects in the structure.
+ * @retval -1 an error occurred. See Exceptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ * @throw EINVAL invalid arguments.
+ */
+int qrinput_struct_append_input(struct qrinput_struct *s,
+ struct qrinput *input);
+
+/**
+ * Free all of qrinput in the set.
+ * @param s a structured input object.
+ */
+void qrinput_struct_free(struct qrinput_struct *s);
+
+/**
+ * Split a qrinput to qrinput_struct. It calculates a parity, set it, then
+ * insert structured-append headers. qrinput created by qrinput_new_micro() will
+ * be rejected.
+ * @param input input object. Version number and error correction level must be
+ * set.
+ * @return a set of input data. On error, NULL is returned, and errno is set
+ * to indicate the error. See Exceptions for the details.
+ * @throw ERANGE input data is too large.
+ * @throw EINVAL invalid input data.
+ * @throw ENOMEM unable to allocate memory.
+ */
+struct qrinput_struct
+*qrinput_split_qrinput_to_struct(struct qrinput *input);
+
+/**
+ * Insert structured-append headers to the input structure. It calculates
+ * a parity and set it if the parity is not set yet.
+ * @param s input structure
+ * @retval 0 success.
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory.
+ */
+int qrinput_struct_insert_structured_append_headers(struct qrinput_struct *s);
+
+/**
+ * Set FNC1-1st position flag.
+ */
+int qrinput_set_fnc1_first(struct qrinput *input);
+
+/**
+ * Set FNC1-2nd position flag and application identifier.
+ */
+int qrinput_set_fnc1_second(struct qrinput *input, unsigned char appid);
+
+/******************************************************************************
+ * qrcode output (qrencode.c)
+ *****************************************************************************/
+
+/**
+ * qrcode class.
+ * Symbol data is represented as an array contains width*width uchars.
+ * Each uchar represents a module (dot). If the less significant bit of
+ * the uchar is 1, the corresponding module is black. The other bits are
+ * meaningless for usual applications, but here its specification is described.
+ *
+ * <pre>
+ * MSB 76543210 LSB
+ * |||||||`- 1=black/0=white
+ * ||||||`-- data and ecc code area
+ * |||||`--- format information
+ * ||||`---- version information
+ * |||`----- timing pattern
+ * ||`------ alignment pattern
+ * |`------- finder pattern and separator
+ * `-------- non-data modules (format, timing, etc.)
+ * </pre>
+ */
+struct qrcode {
+ int version; /* version of the symbol */
+ int width; /* width of the symbol */
+ unsigned char *data; /* symbol data */
+};
+
+/**
+ * Singly-linked list of qrcode. Used to represent a structured symbols.
+ * A list is terminated with NULL.
+ */
+struct qrcode_list {
+ struct qrcode *code;
+ struct qrcode_list *next;
+};
+
+/**
+ * Create a symbol from the input data.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param input input data.
+ * @return an instance of qrcode class. The version of the result qrcode may
+ * be larger than the designated version. On error, NULL is returned,
+ * and errno is set to indicate the error. See Exceptions for the
+ * details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ */
+struct qrcode *qrcode_encode_input(struct qrinput *input);
+
+/**
+ * Create a symbol from the string. The library automatically parses the input
+ * string and encodes in a QR Code symbol.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param string input string. It must be NUL terminated.
+ * @param version version of the symbol. If 0, the library chooses the minimum
+ * version for the given input data.
+ * @param level error correction level.
+ * @param hint tell the library how Japanese Kanji characters should be
+ * encoded. If QR_MODE_KANJI is given, the library assumes that the
+ * given string contains Shift-JIS characters and encodes them in
+ * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical
+ * characters will be encoded as is. If you want to embed UTF-8
+ * string, choose this. Other mode will cause EINVAL error.
+ * @param casesensitive case-sensitive(1) or not(0).
+ * @return an instance of qrcode class. The version of the result qrcode may
+ * be larger than the designated version. On error, NULL is returned,
+ * and errno is set to indicate the error. See Exceptions for the
+ * details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ * @throw ERANGE input data is too large.
+ */
+struct qrcode
+*qrcode_encode_string(const char *string, int version,
+ enum qrec_level level, enum qrencode_mode hint,
+ int casesensitive);
+
+/**
+ * Same to qrcode_encode_string(), but encode whole data in 8-bit mode.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ */
+struct qrcode
+*qrcode_encode_string_8bit(const char *string, int version,
+ enum qrec_level level);
+
+/**
+ * Encode byte stream (may include '\0') in 8-bit mode.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param size size of the input data.
+ * @param data input data.
+ * @param version version of the symbol. If 0, the library chooses the minimum
+ * version for the given input data.
+ * @param level error correction level.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ * @throw ERANGE input data is too large.
+ */
+struct qrcode
+*qrcode_encode_data(int size, const unsigned char *data,
+ int version, enum qrec_level level);
+
+/**
+ * Free the instance of qrcode class.
+ * @param qrcode an instance of qrcode class.
+ */
+void qrcode_free(struct qrcode *qrcode);
+
+/**
+ * Create structured symbols from the input data.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param s
+ * @return a singly-linked list of qrcode.
+ */
+struct qrcode_list
+*qrcode_encode_input_structured(struct qrinput_struct *s);
+
+/**
+ * Create structured symbols from the string. The library automatically parses
+ * the input string and encodes in a QR Code symbol.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param string input string. It must be NUL terminated.
+ * @param version version of the symbol.
+ * @param level error correction level.
+ * @param hint tell the library how Japanese Kanji characters should be
+ * encoded. If QR_MODE_KANJI is given, the library assumes that the
+ * given string contains Shift-JIS characters and encodes them in
+ * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical
+ * characters will be encoded as is. If you want to embed UTF-8
+ * string, choose this. Other mode will cause EINVAL error.
+ * @param casesensitive case-sensitive(1) or not(0).
+ * @return a singly-linked list of qrcode. On error, NULL is returned, and
+ * errno is set to indicate the error. See Exceptions for the details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ */
+struct qrcode_list
+*qrcode_encode_string_structured(const char *string, int version,
+ enum qrec_level level, enum qrencode_mode hint,
+ int casesensitive);
+
+/**
+ * Same to qrcode_encode_string_structured(), but encode whole data in 8-bit
+ * mode.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ */
+struct qrcode_list
+*qrcode_encode_string_8bit_structured(const char *string, int version,
+ enum qrec_level level);
+
+/**
+ * Create structured symbols from byte stream (may include '\0'). Wholde data
+ * are encoded in 8-bit mode.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param size size of the input data.
+ * @param data input dat.
+ * @param version version of the symbol.
+ * @param level error correction level.
+ * @return a singly-linked list of qrcode. On error, NULL is returned, and
+ * errno is set to indicate the error. See Exceptions for the details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ */
+struct qrcode_list
+*qrcode_encode_data_structured(int size, const unsigned char *data,
+ int version, enum qrec_level level);
+
+/**
+ * Return the number of symbols included in a qrcode_list.
+ * @param qrlist a head entry of a qrcode_list.
+ * @return number of symbols in the list.
+ */
+int qrcode_list_size(struct qrcode_list *qrlist);
+
+/**
+ * Free the qrcode_list.
+ * @param qrlist a head entry of a qrcode_list.
+ */
+void qrcode_list_free(struct qrcode_list *qrlist);
+
+#endif /* __QRENCODE_H__ */
diff --git a/kernel/Makefile b/kernel/Makefile
index 53abf00..7202ac0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -30,6 +30,7 @@ obj-y += irq/
obj-y += rcu/
obj-y += livepatch/
+obj-$(CONFIG_QR_OOPS) += print_oops.o
obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o
obj-$(CONFIG_FREEZER) += freezer.o
obj-$(CONFIG_PROFILING) += profile.o
diff --git a/kernel/panic.c b/kernel/panic.c
index 04e91ff..3caf749 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -24,6 +24,8 @@
#include <linux/init.h>
#include <linux/nmi.h>
+#include <linux/print_oops.h>
+
#define PANIC_TIMER_STEP 100
#define PANIC_BLINK_SPD 18
@@ -401,6 +403,9 @@ void print_oops_end_marker(void)
{
init_oops_id();
pr_warn("---[ end trace %016llx ]---\n", (unsigned long long)oops_id);
+#ifdef CONFIG_QR_OOPS
+ print_qr_err();
+#endif
}
/*
diff --git a/kernel/print_oops.c b/kernel/print_oops.c
new file mode 100644
index 0000000..e367228
--- /dev/null
+++ b/kernel/print_oops.c
@@ -0,0 +1,693 @@
+/*
+ *
+ * Copyright (C) 2015 Murtaza Alexandru <alexandru.murtaza@xxxxxxxxx>
+ * Copyright (C) 2014 Teodora Baluta <teobaluta@xxxxxxxxx>
+ * Copyright (C) 2014 Levente Kurusa <levex@xxxxxxxxx>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ */
+#include <linux/print_oops.h>
+#include <linux/kdebug.h>
+#include <linux/bug.h>
+#include <linux/qrencode.h>
+#include <linux/fb.h>
+#include <linux/zlib.h>
+#include <linux/vmalloc.h>
+#include <linux/semaphore.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/list.h>
+#include <linux/jiffies.h>
+
+#define COMPR_LEVEL 9
+#define QQQ_WHITE 0x0F
+#define QQQ_BLACK 0x00
+
+static int qr_oops_cmd;
+core_param(qr_oops_cmd, qr_oops_cmd, int, 0644);
+
+static int qr_oops_param0;
+core_param(qr_oops_param0, qr_oops_param0, int, 0644);
+
+static int qr_oops_param1;
+core_param(qr_oops_param1, qr_oops_param1, int, 0644);
+
+static char qr_buffer[MESSAGE_BUFSIZE];
+static int buf_pos;
+
+static DEFINE_MUTEX(compr_mutex);
+static DEFINE_MUTEX(qr_list_mutex);
+static struct z_stream_s stream;
+
+static int compr_init(void)
+{
+ size_t size = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
+ zlib_inflate_workspacesize());
+
+ stream.workspace = vmalloc(size);
+ if (!stream.workspace)
+ return -ENOMEM;
+ return 0;
+}
+
+static void compr_exit(void)
+{
+ vfree(stream.workspace);
+}
+
+static int compress(void *in, void *out, size_t inlen, size_t outlen)
+{
+ int ret;
+
+ ret = compr_init();
+ if (ret != 0)
+ goto error;
+
+ mutex_lock(&compr_mutex);
+ ret = zlib_deflateInit(&stream, COMPR_LEVEL);
+ if (ret != Z_OK) {
+ pr_emerg("qr_compress: zlib_deflateInit failed with ret = %d\n",
+ ret);
+ goto error;
+ }
+
+ stream.next_in = in;
+ stream.avail_in = inlen;
+ stream.total_in = 0;
+ stream.next_out = out;
+ stream.avail_out = outlen;
+ stream.total_out = 0;
+
+ ret = zlib_deflate(&stream, Z_FINISH);
+ if (ret != Z_STREAM_END) {
+ pr_emerg("qr_compress: zlib_deflate failed with ret = %d\n",
+ ret);
+ goto error;
+ }
+
+ ret = zlib_deflateEnd(&stream);
+ if (ret != Z_OK) {
+ pr_emerg("qr_compress: zlib_deflateEnd failed with ret = %d\n",
+ ret);
+ goto error;
+ }
+
+ if (stream.total_out >= stream.total_in)
+ pr_emerg("qr_compress: total_out > total_in\n");
+
+ ret = stream.total_out;
+error:
+ mutex_unlock(&compr_mutex);
+ return ret;
+}
+
+static inline int compute_w(struct fb_info *info, int qrw)
+{
+ int xres = info->var.xres;
+ int yres = info->var.yres;
+ int minxy = (xres < yres) ? xres : yres;
+ int ret = minxy - minxy / 4;
+
+ return ret / qrw;
+}
+
+static inline void draw_qr(struct fb_info *info, struct qrcode *qr,
+ int pos_x, int pos_y,
+ int cell_width, int cell_height,
+ int border)
+{
+ int i, j;
+ int is_black;
+ struct fb_fillrect rect;
+
+ rect.width = cell_width;
+ rect.height = cell_height;
+ rect.rop = 0;
+
+ if (border) {
+ /* Print borders: */
+ rect.color = QQQ_WHITE;
+ for (i = 0; i < qr->width + 2; i++) {
+ /* Top */
+ rect.dx = 0 + pos_x;
+ rect.dy = i * cell_height + pos_y;
+ cfb_fillrect(info, &rect);
+
+ /* Bottom */
+ rect.dx = (qr->width + 1) * cell_width + pos_x;
+ rect.dy = i * cell_height + pos_y;
+ cfb_fillrect(info, &rect);
+
+ /* Left */
+ rect.dx = i * cell_width + pos_x;
+ rect.dy = pos_y;
+ cfb_fillrect(info, &rect);
+
+ /* Right */
+ rect.dx = i * cell_width + pos_x;
+ rect.dy = (qr->width + 1) * cell_height + pos_y;
+ cfb_fillrect(info, &rect);
+ }
+ }
+
+ /* Print actual QR matrix: */
+ for (i = 0; i < qr->width; i++) {
+ for (j = 0; j < qr->width; j++) {
+ rect.dx = (j + 1) * cell_width + pos_x;
+ rect.dy = (i + 1) * cell_height + pos_y;
+ is_black = qr->data[i * qr->width + j] & 1;
+ rect.color = is_black ? QQQ_BLACK : QQQ_WHITE;
+ cfb_fillrect(info, &rect);
+ }
+ }
+}
+
+#define ASCII_BLACK " "
+#define ASCII_BLOCK "%c", 219
+#define ASCII_HALFBLOCK_TOP "%c", 223
+#define ASCII_HALFBLOCK_BOTTOM "%c", 220
+
+static inline int qr_is_black(struct qrcode *qr, int x, int y)
+{
+ if (x < 0 || y < 0 || x >= qr->width || y >= qr->width)
+ return 0;
+ return qr->data[x * qr->width + y] & 1;
+}
+
+static inline void draw_ascii_qr(struct qrcode *qr)
+{
+ int i, j;
+ int up, down;
+
+ /* Print actual QR matrix: */
+ for (i = -1; i < qr->width + 1; i += 2) {
+ for (j = -1; j < qr->width + 1; j++) {
+ up = 1 - qr_is_black(qr, i, j);
+ down = 1 - qr_is_black(qr, i + 1, j);
+ if (up)
+ if (down)
+ printk(ASCII_BLOCK);
+ else
+ printk(ASCII_HALFBLOCK_TOP);
+ else
+ if (down)
+ printk(ASCII_HALFBLOCK_BOTTOM);
+ else
+ printk(ASCII_BLACK);
+ }
+ printk("\n");
+ }
+}
+
+struct qr_chunk {
+ struct list_head list;
+
+ struct qrcode *qr;
+ int message_id;
+ int packet_id;
+};
+
+static LIST_HEAD(qr_list_head);
+
+static struct task_struct *qr_thread;
+
+#define BUFFER_SIZE (4 * 1024)
+
+static inline void qr_list_delete(struct qr_chunk *element)
+{
+ list_del(&element->list);
+ vfree(element);
+}
+
+static void qr_list_delete_message(int message_id)
+{
+ struct list_head *it, *n;
+ struct qr_chunk *qr_entry;
+
+ mutex_lock(&qr_list_mutex);
+ list_for_each_safe(it, n, &qr_list_head) {
+ qr_entry = list_entry(it, struct qr_chunk, list);
+ if (qr_entry->message_id == message_id)
+ qr_list_delete(qr_entry);
+ }
+ mutex_unlock(&qr_list_mutex);
+}
+
+static void qr_list_clear(void)
+{
+ struct list_head *it, *n;
+
+ mutex_lock(&qr_list_mutex);
+ list_for_each_safe(it, n, &qr_list_head)
+ qr_list_delete(list_entry(it, struct qr_chunk, list));
+ mutex_unlock(&qr_list_mutex);
+}
+
+static void qr_list_delete_packet(int message_id, int packet_id)
+{
+ struct list_head *it, *n;
+ struct qr_chunk *qr_entry;
+
+ mutex_lock(&qr_list_mutex);
+ list_for_each_safe(it, n, &qr_list_head) {
+ qr_entry = list_entry(it, struct qr_chunk, list);
+ if (qr_entry->message_id == message_id &&
+ qr_entry->packet_id == packet_id)
+ qr_list_delete(qr_entry);
+ }
+ mutex_unlock(&qr_list_mutex);
+}
+
+#define BK1_MAGIC_FIRSTBYTE 222
+#define BK1_MAGIC_SECONDBYTE 173
+
+#define BK1_ENCODE_NONE 0
+#define BK1_ENCODE_DEFLATE 1
+
+#define BK1_VERSION 0
+
+static void make_bk1_packet(char *start, int len, int message_id,
+ int packet_id, int packet_count)
+{
+ struct qr_chunk *element;
+ int header_size;
+ ssize_t packet_len;
+ char compr_packet_buffer[BUFFER_SIZE];
+ char checksum;
+
+ element = vmalloc(sizeof(*element));
+ element->message_id = message_id;
+ element->packet_id = packet_id;
+
+ header_size = 0;
+
+ checksum = BK1_VERSION ^ message_id ^ packet_count ^ packet_id ^
+ BK1_ENCODE_DEFLATE;
+
+ compr_packet_buffer[header_size] = BK1_MAGIC_FIRSTBYTE;
+ ++header_size;
+ compr_packet_buffer[header_size] = BK1_MAGIC_SECONDBYTE;
+ ++header_size;
+ compr_packet_buffer[header_size] = BK1_VERSION;
+ ++header_size;
+ compr_packet_buffer[header_size] = message_id;
+ ++header_size;
+ compr_packet_buffer[header_size] = packet_count;
+ ++header_size;
+ compr_packet_buffer[header_size] = packet_id;
+ ++header_size;
+ compr_packet_buffer[header_size] = BK1_ENCODE_DEFLATE;
+ ++header_size;
+ compr_packet_buffer[header_size] = checksum;
+ ++header_size;
+ compr_packet_buffer[header_size] = (len >> 8) & 0xFF;
+ ++header_size;
+ compr_packet_buffer[header_size] = len & 0xFF;
+ ++header_size;
+
+ packet_len = compress(start, compr_packet_buffer + header_size, len,
+ BUFFER_SIZE - header_size);
+ if (packet_len < 0) {
+ pr_emerg("QR: Compression of QR code failed packet_len=%zd\n",
+ packet_len);
+ goto ERROR;
+ }
+ compr_exit();
+
+ packet_len += header_size;
+
+ element->qr = qrcode_encode_data(packet_len, compr_packet_buffer, 0,
+ QR_ECLEVEL_H);
+ if (!element->qr) {
+ pr_emerg("QR: Failed to encode data as a QR code!\n");
+ goto ERROR;
+ }
+
+ mutex_lock(&qr_list_mutex);
+ list_add(&element->list, &qr_list_head);
+ mutex_unlock(&qr_list_mutex);
+
+ return;
+ERROR:
+ pr_emerg("QR: Failed to make QR message packet!\n");
+}
+
+struct qr_chunk *tar_slow, *tar_fast, *tar_current;
+int tar_step;
+
+static struct qr_chunk *list_circular_next_entry(struct qr_chunk *it)
+{
+ it = list_next_entry(it, list);
+ if (it == &qr_list_head)
+ it = list_next_entry(it, list);
+
+ return it;
+}
+
+static inline void tar_strategy_next_step(void)
+{
+ ++tar_step;
+ if (tar_step == 4)
+ tar_step = 0;
+
+ if (tar_step == 0) {
+ mutex_lock(&qr_list_mutex);
+ tar_slow = list_circular_next_entry(tar_slow);
+ mutex_unlock(&qr_list_mutex);
+ tar_current = tar_slow;
+ } else if (tar_step == 1) {
+ tar_current = tar_slow;
+ } else if (tar_step == 2) {
+ mutex_lock(&qr_list_mutex);
+ tar_fast = list_circular_next_entry(tar_fast);
+ mutex_unlock(&qr_list_mutex);
+ tar_current = tar_fast;
+ } else if (tar_step == 3) {
+ mutex_lock(&qr_list_mutex);
+ tar_fast = list_circular_next_entry(tar_fast);
+ mutex_unlock(&qr_list_mutex);
+ tar_current = tar_fast;
+ }
+}
+
+static inline void tar_strategy_init(void)
+{
+ tar_step = 0;
+ tar_slow = list_first_entry(&qr_list_head, struct qr_chunk, list);
+ tar_fast = list_first_entry(&qr_list_head, struct qr_chunk, list);
+ tar_current = list_first_entry(&qr_list_head, struct qr_chunk, list);
+}
+
+static inline struct qrcode *tar_strategy_get_qrcode(void)
+{
+ if (tar_current != &qr_list_head)
+ return tar_current->qr;
+ return 0;
+}
+
+#define MESSAGE_DEFAULT_PACKET_SIZE 300
+
+static DEFINE_MUTEX(message_count_mutex);
+
+static int message_count;
+
+static void make_bk1_message(void)
+{
+ int remaining_bytes;
+ int packet_length;
+ int left;
+ int packet_count;
+ int packet_id;
+ int message_id;
+
+ mutex_lock(&message_count_mutex);
+ ++message_count;
+ message_id = message_count;
+ mutex_unlock(&message_count_mutex);
+
+ packet_count = buf_pos / MESSAGE_DEFAULT_PACKET_SIZE;
+ if (buf_pos % MESSAGE_DEFAULT_PACKET_SIZE)
+ ++packet_count;
+
+ left = 0;
+ packet_id = 0;
+ while (left < buf_pos) {
+ remaining_bytes = buf_pos - left;
+ packet_length = MESSAGE_DEFAULT_PACKET_SIZE;
+ if (packet_length > remaining_bytes)
+ packet_length = remaining_bytes;
+ ++packet_id;
+ make_bk1_packet(qr_buffer + left, packet_length, message_id,
+ packet_id, packet_count);
+ left += packet_length;
+ }
+}
+
+static void print_messages(void)
+{
+ struct qr_chunk *it;
+ int last_message_id = -1;
+
+ pr_info("QR: ids of messages in queue: ");
+ list_for_each_entry(it, &qr_list_head, list)
+ if (it->message_id != last_message_id) {
+ last_message_id = it->message_id;
+ pr_cont("%d ", last_message_id);
+ }
+ pr_cont("\n");
+}
+
+static void print_packets(void)
+{
+ struct qr_chunk *it;
+
+ pr_info("QR: packets in queue <message, packet>: ");
+ list_for_each_entry(it, &qr_list_head, list)
+ pr_cont("<%d, %d> ", it->message_id, it->packet_id);
+ pr_cont("\n");
+}
+
+static void print_packets_by_msg(int message_id)
+{
+ struct qr_chunk *it;
+
+ pr_info("QR: packets in queue for message id %d: ", message_id);
+ list_for_each_entry(it, &qr_list_head, list)
+ if (it->message_id == message_id)
+ pr_cont("%d ", it->packet_id);
+ pr_cont("\n");
+}
+
+static struct fb_info *info;
+static struct fb_fillrect rect;
+static int qr_total_width;
+static int qr_offset_x;
+static int qr_offset_y;
+
+static void clear_last_qr(void)
+{
+ if (info) {
+ pr_emerg("QR: framebuffer clear\n");
+
+ console_lock();
+
+ rect.width = qr_total_width;
+ rect.height = qr_total_width;
+ rect.dx = qr_offset_x;
+ rect.dy = qr_offset_y;
+ rect.rop = 0;
+ rect.color = QQQ_BLACK;
+ cfb_fillrect(info, &rect);
+
+ console_unlock();
+ }
+}
+
+#define QR_OOPS_CMD_NOTHING 0
+#define QR_OOPS_CMD_PRINT_MESSAGES 1
+#define QR_OOPS_CMD_PRINT_PACKETS 2
+#define QR_OOPS_CMD_DELETE_MESSAGE 3
+#define QR_OOPS_CMD_DELETE_PACKET 4
+#define QR_OOPS_CMD_PAUSE 5
+#define QR_OOPS_CMD_RESUME 6
+#define QR_OOPS_CMD_CLEAR_QUEUE 7
+#define QR_OOPS_CMD_STOP 8
+#define QR_THREAD_TIME_STEP (750 * 1000)
+
+int qr_thread_func(void *data)
+{
+ struct qrcode *curr_qr = 0;
+ int w;
+ int last_time;
+ int time_accumulator;
+ int time_now;
+ int elapsed_time;
+ int paused = 0;
+ int changed = 0;
+ int cmd = 0;
+ int param0 = 0;
+ int param1 = 0;
+
+ qr_total_width = 0;
+ qr_offset_x = 0;
+ qr_offset_y = 0;
+
+ info = registered_fb[0];
+ if (!info)
+ pr_emerg("QR: Unable to get hand of a framebuffer!\n");
+
+ tar_strategy_init();
+
+ qr_oops_cmd = QR_OOPS_CMD_NOTHING;
+ qr_oops_param0 = 0;
+ qr_oops_param1 = 0;
+
+ last_time = jiffies_to_usecs(get_jiffies_64());
+ time_accumulator = 0;
+
+ while (true) {
+ msleep(100);
+
+ time_now = jiffies_to_usecs(get_jiffies_64());
+ elapsed_time = time_now - last_time;
+ last_time = time_now;
+
+ cmd = qr_oops_cmd;
+ qr_oops_cmd = QR_OOPS_CMD_NOTHING;
+ param0 = qr_oops_param0;
+ param1 = qr_oops_param1;
+
+ if (cmd != QR_OOPS_CMD_NOTHING) {
+ qr_oops_param0 = 0;
+ qr_oops_param1 = 0;
+ }
+
+ switch (cmd) {
+ case QR_OOPS_CMD_NOTHING:
+ break;
+ case QR_OOPS_CMD_PRINT_MESSAGES:
+ print_messages();
+ break;
+ case QR_OOPS_CMD_PRINT_PACKETS:
+ if (param0)
+ print_packets_by_msg(param0);
+ else
+ print_packets();
+ break;
+ case QR_OOPS_CMD_DELETE_MESSAGE:
+ qr_list_delete_message(param0);
+ tar_strategy_init();
+ break;
+ case QR_OOPS_CMD_DELETE_PACKET:
+ qr_list_delete_packet(param0, param1);
+ tar_strategy_init();
+ break;
+ case QR_OOPS_CMD_PAUSE:
+ if (!paused) {
+ paused = 1;
+ clear_last_qr();
+ }
+ break;
+ case QR_OOPS_CMD_RESUME:
+ paused = 0;
+ break;
+ case QR_OOPS_CMD_CLEAR_QUEUE:
+ qr_list_clear();
+ tar_strategy_init();
+ break;
+ case QR_OOPS_CMD_STOP:
+ /*
+ * Not implemented
+ */
+ break;
+ default:
+ pr_emerg("QR: invalid command: %d\n", qr_oops_cmd);
+ break;
+ }
+
+ if (paused)
+ continue;
+
+ changed = 0;
+ time_accumulator += elapsed_time;
+ if (time_accumulator > QR_THREAD_TIME_STEP) {
+ time_accumulator -= QR_THREAD_TIME_STEP;
+
+ tar_strategy_next_step();
+ if (curr_qr != tar_strategy_get_qrcode()) {
+ curr_qr = tar_strategy_get_qrcode();
+ changed = 1;
+ }
+
+ if (changed && info)
+ pr_emerg("QR: force console flush\n");
+ }
+
+ if (!curr_qr) {
+ if (changed)
+ clear_last_qr();
+ continue;
+ }
+
+ if (info) {
+ console_lock();
+
+ rect.width = qr_total_width;
+ rect.height = qr_total_width;
+ rect.dx = qr_offset_x;
+ rect.dy = qr_offset_y;
+ rect.rop = 0;
+ rect.color = QQQ_BLACK;
+ cfb_fillrect(info, &rect);
+
+ w = compute_w(info, curr_qr->width);
+ qr_total_width = (curr_qr->width + 2) * w;
+ qr_offset_x = info->var.xres - qr_total_width;
+ qr_offset_y = 0;
+
+ draw_qr(info, curr_qr, qr_offset_x, qr_offset_y,
+ w, w, 1);
+
+ console_unlock();
+ } else if (changed) {
+ draw_ascii_qr(curr_qr);
+ }
+ }
+
+ return 0;
+}
+
+int qr_thread_init(void)
+{
+ char qr_thread_name[] = "qr_message_thread";
+
+ qr_thread = kthread_create(qr_thread_func, NULL, qr_thread_name);
+ if (qr_thread)
+ wake_up_process(qr_thread);
+
+ return 0;
+}
+
+void qr_thread_cleanup(void)
+{
+ int ret;
+
+ ret = kthread_stop(qr_thread);
+ if (!ret)
+ pr_emerg("QR thread stopped");
+}
+
+void qr_append(char *text)
+{
+ size_t len;
+
+ len = strlen(text);
+ if (len + buf_pos >= MESSAGE_BUFSIZE - 1) {
+ len = MESSAGE_BUFSIZE - 1 - buf_pos;
+ qr_buffer[MESSAGE_BUFSIZE - 1] = '\0';
+ }
+ memcpy(&qr_buffer[buf_pos], text, len);
+ buf_pos += len;
+}
+
+void print_qr_err(void)
+{
+ make_bk1_message();
+
+ buf_pos = 0;
+
+ if (!qr_thread)
+ qr_thread_init();
+}
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 8f0324e..916f3ed 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -46,6 +46,7 @@
#include <linux/utsname.h>
#include <linux/ctype.h>
#include <linux/uio.h>
+#include <linux/print_oops.h>
#include <asm/uaccess.h>
@@ -1750,6 +1751,11 @@ asmlinkage int vprintk_emit(int facility, int level,
}
}
+#ifdef CONFIG_QR_OOPS
+ if (oops_in_progress)
+ qr_append(text);
+#endif
+
if (level == LOGLEVEL_DEFAULT)
level = default_message_loglevel;
@@ -1898,6 +1904,14 @@ asmlinkage __visible int printk(const char *fmt, ...)
va_list args;
int r;
+#ifdef CONFIG_KGDB_KDB
+ if (unlikely(kdb_trap_printk)) {
+ va_start(args, fmt);
+ r = vkdb_printf(KDB_MSGSRC_PRINTK, fmt, args);
+ va_end(args);
+ return r;
+ }
+#endif
va_start(args, fmt);
/*
@@ -1910,7 +1924,6 @@ asmlinkage __visible int printk(const char *fmt, ...)
r = vprintk_func(fmt, args);
va_end(args);
-
return r;
}
EXPORT_SYMBOL(printk);
diff --git a/lib/Kconfig b/lib/Kconfig
index 2e491ac..c782919 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -492,6 +492,12 @@ config SIGNATURE
Digital signature verification. Currently only RSA is supported.
Implementation is done using GnuPG MPI library
+config QRLIB
+ bool "QR encoding library"
+ select ZLIB_DEFLATE
+ help
+ QR encoding library
+
#
# libfdt files, only selected if needed.
#
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ab76b99..822fe7d 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -15,6 +15,23 @@ config PRINTK_TIME
The behavior is also controlled by the kernel command line
parameter printk.time=1. See Documentation/kernel-parameters.txt
+config QR_OOPS
+ bool "Display QR barcode for Oops messages for debugging purposes"
+ depends on PRINTK && FB
+ select QRLIB
+ select ZLIB_DEFLATE
+ select ZLIB_INFLATE
+ select FB_CFB_FILLRECT
+ select REED_SOLOMON
+ select REED_SOLOMON_ENC8
+ help
+ Selecting this option makes printk() calls to accumulate
+ the Oops messages in a buffer, compresses the message
+ and prints the OR to the frame buffer device.
+
+ This is an experimental feature at the moment.
+
+
config MESSAGE_LOGLEVEL_DEFAULT
int "Default message log level (1-7)"
range 1 7
diff --git a/lib/Makefile b/lib/Makefile
index 13a7c6a..97da07e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -50,6 +50,9 @@ endif
obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o
CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any)
+# QR lib
+obj-$(CONFIG_QRLIB) += qr/
+
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
obj-$(CONFIG_GENERIC_PCI_IOMAP) += pci_iomap.o
obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
diff --git a/lib/qr/Makefile b/lib/qr/Makefile
new file mode 100644
index 0000000..d0c0f13
--- /dev/null
+++ b/lib/qr/Makefile
@@ -0,0 +1,6 @@
+#
+# QR encoding library
+#
+
+EXTRA_FLAGS = -g
+obj-$(CONFIG_QRLIB) = bitstream.o mask.o qrencode.o qrinput.o qrspec.o split.o
diff --git a/lib/qr/bitstream.c b/lib/qr/bitstream.c
new file mode 100644
index 0000000..a2f02e9
--- /dev/null
+++ b/lib/qr/bitstream.c
@@ -0,0 +1,203 @@
+/*
+ * bit_stream - storage of bits to which you can append
+ *
+ * Copyright (C) 2014 Levente Kurusa <levex@xxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "bitstream.h"
+
+#define BITS_TO_BYTES(x) (((x) % 8) ? ((x) / 8 + 1) : ((x) / 8))
+
+u8 *__bit_stream_alloc_data(int len, gfp_t gfp)
+{
+ return kzalloc(BITS_TO_BYTES(len), gfp);
+}
+
+struct bit_stream *bit_stream_allocate(int space, gfp_t gfp)
+{
+ struct bit_stream *bstr;
+ u8 *bitmap;
+
+ /* XXX */
+ gfp = GFP_ATOMIC;
+
+ bstr = kzalloc(sizeof(*bstr), gfp);
+ if (!bstr)
+ return NULL;
+
+ bstr->gfp = gfp;
+
+ if (space == 0)
+ return bstr;
+
+ bitmap = __bit_stream_alloc_data(space, gfp);
+ if (!bitmap) {
+ kfree(bstr);
+ return NULL;
+ }
+
+ bstr->data = bitmap;
+ bstr->space = space;
+ bstr->length = 0;
+ return bstr;
+}
+
+struct bit_stream *bit_stream_new(void)
+{
+ return bit_stream_allocate(128, GFP_ATOMIC);
+}
+
+void bit_stream_free(struct bit_stream *bstr)
+{
+ if (!bstr)
+ return;
+ kfree(bstr->data);
+ kfree(bstr);
+}
+
+int bit_stream_resize(struct bit_stream *bstr, int nspace)
+{
+ unsigned char *data;
+
+ if (nspace == 0)
+ return -EINVAL;
+
+ if (bstr->length >= nspace)
+ return -ENOSPC;
+
+ data = kzalloc(BITS_TO_BYTES(nspace), bstr->gfp);
+ if (!data)
+ return -ENOMEM;
+
+ if (bstr->data) {
+ memcpy(data, bstr->data, BITS_TO_BYTES(bstr->length));
+ kfree(bstr->data);
+ }
+
+ bstr->data = data;
+ bstr->space = nspace;
+ return 0;
+}
+
+int __bit_stream_get_bit(struct bit_stream *bstr, int no)
+{
+ if (WARN_ON(no > bstr->length))
+ return 0;
+
+ return (bstr->data[no / 8] & (1 << (no % 8))) ? 1 : 0;
+}
+
+int __bit_stream_append_bit(struct bit_stream *bstr, u8 bit)
+{
+ int rc;
+
+ if (!bstr->data || bstr->length + 1 >= bstr->space) {
+ rc = bit_stream_resize(bstr, bstr->space + 256);
+ if (rc)
+ return rc;
+ }
+
+ if (bit != 0)
+ bstr->data[bstr->length / 8] |= (1UL << (bstr->length % 8));
+ else
+ bstr->data[bstr->length / 8] &= ~(1UL << (bstr->length % 8));
+
+ bstr->length++;
+
+ return 0;
+}
+
+int bit_stream_append_bytes(struct bit_stream *bstr, int bytes, u8 *data)
+{
+ int rc;
+ int i, j;
+ unsigned char mask;
+
+ for (i = 0; i < bytes; i++) {
+ mask = 0x80;
+ for (j = 0; j < 8; j++) {
+ rc = __bit_stream_append_bit(bstr, data[i] & mask);
+ if (rc)
+ return rc;
+ mask = mask >> 1;
+ }
+ }
+
+ return 0;
+}
+
+int bit_stream_append_num(struct bit_stream *bstr, int bits, int num)
+{
+ int rc;
+ int i;
+ unsigned int mask;
+
+ mask = 1 << (bits - 1);
+ for (i = 0; i < bits; i++) {
+ rc = __bit_stream_append_bit(bstr, num & mask);
+ if (rc)
+ return rc;
+ mask = mask >> 1;
+ }
+
+ return 0;
+}
+
+int bit_stream_append(struct bit_stream *dst, struct bit_stream *src)
+{
+ int rc, i;
+
+ for (i = 0; i < src->length; i++) {
+ rc = __bit_stream_append_bit(dst, __bit_stream_get_bit(src, i));
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+unsigned char *bit_stream_to_byte(struct bit_stream *bstr)
+{
+ unsigned char *data, v;
+ int i, j, size, bytes, p;
+
+ data = kzalloc((bstr->length + 7) / 8, bstr->gfp);
+ if (!data)
+ return NULL;
+ size = bit_stream_size(bstr);
+ bytes = size / 8;
+ p = 0;
+ for (i = 0; i < bytes; i++) {
+ v = 0;
+ for (j = 0; j < 8; j++) {
+ v = v << 1;
+ v |= __bit_stream_get_bit(bstr, p);
+ p++;
+ }
+ data[i] = v;
+ }
+ if (size & 7) {
+ v = 0;
+ for (j = 0; j < (size & 7); j++) {
+ v = v << 1;
+ v |= __bit_stream_get_bit(bstr, p);
+ p++;
+ }
+ data[bytes] = v;
+ }
+
+ return data;
+}
diff --git a/lib/qr/bitstream.h b/lib/qr/bitstream.h
new file mode 100644
index 0000000..9217ae4
--- /dev/null
+++ b/lib/qr/bitstream.h
@@ -0,0 +1,41 @@
+/*
+ * bit_stream - storage of bits to which you can append
+ *
+ * Copyright (C) 2014 Levente Kurusa <levex@xxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __BITSTREAM_H
+#define __BITSTREAM_H
+
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/spinlock.h>
+
+struct bit_stream {
+ u8 *data;
+ int length;
+ int space;
+ gfp_t gfp;
+};
+
+struct bit_stream *bit_stream_allocate(int length, gfp_t gfp);
+struct bit_stream *bit_stream_new(void);
+void bit_stream_free(struct bit_stream *bstr);
+int bit_stream_append_bytes(struct bit_stream *bstr, int len, u8 *data);
+int bit_stream_append_num(struct bit_stream *bstr, int bits, int num);
+int bit_stream_append(struct bit_stream *dst, struct bit_stream *src);
+unsigned char *bit_stream_to_byte(struct bit_stream *bstr);
+
+#define bit_stream_size(b) (b->length)
+
+#endif /* __BITSTREAM_H */
diff --git a/lib/qr/mask.c b/lib/qr/mask.c
new file mode 100644
index 0000000..95bce5e
--- /dev/null
+++ b/lib/qr/mask.c
@@ -0,0 +1,311 @@
+/*
+ * qrencode - QR Code encoder
+ *
+ * Masking.
+ * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/qrencode.h>
+#include "qrspec.h"
+#include "mask.h"
+
+static int mask_write_format_information(int width, unsigned char *frame,
+ int mask, enum qrec_level level)
+{
+ unsigned int format;
+ unsigned char v;
+ int i;
+ int blacks = 0;
+
+ format = qrspec_get_format_info(mask, level);
+
+ for (i = 0; i < 8; i++) {
+ if (format & 1) {
+ blacks += 2;
+ v = 0x85;
+ } else {
+ v = 0x84;
+ }
+ frame[width * 8 + width - 1 - i] = v;
+ if (i < 6)
+ frame[width * i + 8] = v;
+ else
+ frame[width * (i + 1) + 8] = v;
+
+ format = format >> 1;
+ }
+ for (i = 0; i < 7; i++) {
+ if (format & 1) {
+ blacks += 2;
+ v = 0x85;
+ } else {
+ v = 0x84;
+ }
+ frame[width * (width - 7 + i) + 8] = v;
+ if (i == 0)
+ frame[width * 8 + 7] = v;
+ else
+ frame[width * 8 + 6 - i] = v;
+
+ format = format >> 1;
+ }
+
+ return blacks;
+}
+
+/**
+ * Demerit coefficients.
+ * See Section 8.8.2, pp.45, JIS X0510:2004.
+ */
+#define N1 (3)
+#define N2 (3)
+#define N3 (40)
+#define N4 (10)
+
+#define MASKMAKER(__exp__) \
+ int x, y;\
+ int b = 0;\
+\
+ for (y = 0; y < width; y++) {\
+ for (x = 0; x < width; x++) {\
+ if (*s & 0x80) {\
+ *d = *s;\
+ } else {\
+ *d = *s ^ ((__exp__) == 0);\
+ } \
+ b += (int)(*d & 1);\
+ s++; d++;\
+ } \
+ }
+
+static int mask_mask0(int width, const unsigned char *s, unsigned char *d)
+{
+ MASKMAKER((x + y) & 1)
+ return b;
+}
+
+static int mask_mask1(int width, const unsigned char *s, unsigned char *d)
+{
+ MASKMAKER(y & 1)
+ return b;
+}
+
+static int mask_mask2(int width, const unsigned char *s, unsigned char *d)
+{
+ MASKMAKER(x % 3)
+ return b;
+}
+
+static int mask_mask3(int width, const unsigned char *s, unsigned char *d)
+{
+ MASKMAKER((x + y) % 3)
+ return b;
+}
+
+static int mask_mask4(int width, const unsigned char *s, unsigned char *d)
+{
+ MASKMAKER(((y / 2) + (x / 3)) & 1)
+ return b;
+}
+
+static int mask_mask5(int width, const unsigned char *s, unsigned char *d)
+{
+ MASKMAKER(((x * y) & 1) + (x * y) % 3)
+ return b;
+}
+
+static int mask_mask6(int width, const unsigned char *s, unsigned char *d)
+{
+ MASKMAKER((((x * y) & 1) + (x * y) % 3) & 1)
+ return b;
+}
+
+static int mask_mask7(int width, const unsigned char *s, unsigned char *d)
+{
+ MASKMAKER((((x * y) % 3) + ((x + y) & 1)) & 1)
+ return b;
+}
+
+#define MASKNUM (8)
+typedef int mask_maker(int, const unsigned char *, unsigned char *);
+static mask_maker *mask_makers[MASKNUM] = {
+ mask_mask0, mask_mask1, mask_mask2, mask_mask3,
+ mask_mask4, mask_mask5, mask_mask6, mask_mask7
+};
+
+unsigned char *mask_make_mask(int width, unsigned char *frame, int mask,
+ enum qrec_level level)
+{
+ unsigned char *masked;
+
+ if (mask < 0 || mask >= MASKNUM)
+ return NULL;
+
+ masked = kmalloc(width * width, GFP_ATOMIC);
+ if (!masked)
+ return NULL;
+
+ mask_makers[mask] (width, frame, masked);
+ mask_write_format_information(width, masked, mask, level);
+
+ return masked;
+}
+
+static int calc_n1_n3(int length, int *run_length)
+{
+ int i;
+ int demerit = 0;
+ int fact;
+
+ for (i = 0; i < length; i++) {
+ if (run_length[i] >= 5)
+ demerit += N1 + (run_length[i] - 5);
+ if ((i & 1)) {
+ if (i >= 3 && i < length - 2 &&
+ (run_length[i] % 3) == 0) {
+ fact = run_length[i] / 3;
+ if (run_length[i - 2] == fact &&
+ run_length[i - 1] == fact &&
+ run_length[i + 1] == fact &&
+ run_length[i + 2] == fact) {
+ if (i == 3 ||
+ run_length[i - 3] >= 4 * fact) {
+ demerit += N3;
+ } else if (i + 4 >= length ||
+ run_length[i + 3] >=
+ 4 * fact) {
+ demerit += N3;
+ }
+ }
+ }
+ }
+ }
+
+ return demerit;
+}
+
+static int mask_calc_n2(int width, unsigned char *frame)
+{
+ int x, y;
+ unsigned char *p;
+ unsigned char b22, w22;
+ int demerit = 0;
+
+ p = frame + width + 1;
+ for (y = 1; y < width; y++) {
+ for (x = 1; x < width; x++) {
+ b22 = p[0] & p[-1] & p[-width] & p[-width - 1];
+ w22 = p[0] | p[-1] | p[-width] | p[-width - 1];
+ if ((b22 | (w22 ^ 1)) & 1)
+ demerit += N2;
+ p++;
+ }
+ p++;
+ }
+
+ return demerit;
+}
+
+static int mask_calc_run_length(int width, unsigned char *frame, int dir,
+ int *run_length)
+{
+ int head;
+ int i;
+ unsigned char *p;
+ int pitch;
+
+ pitch = (dir == 0) ? 1 : width;
+ if (frame[0] & 1) {
+ run_length[0] = -1;
+ head = 1;
+ } else {
+ head = 0;
+ }
+ run_length[head] = 1;
+ p = frame + pitch;
+
+ for (i = 1; i < width; i++) {
+ if ((p[0] ^ p[-pitch]) & 1) {
+ head++;
+ run_length[head] = 1;
+ } else {
+ run_length[head]++;
+ }
+ p += pitch;
+ }
+
+ return head + 1;
+}
+
+static int mask_evaluate_symbol(int width, unsigned char *frame)
+{
+ int x, y;
+ int demerit = 0;
+ int run_length[QRSPEC_WIDTH_MAX + 1];
+ int length;
+
+ demerit += mask_calc_n2(width, frame);
+
+ for (y = 0; y < width; y++) {
+ length = mask_calc_run_length(width, frame + y * width, 0,
+ run_length);
+ demerit += calc_n1_n3(length, run_length);
+ }
+
+ for (x = 0; x < width; x++) {
+ length = mask_calc_run_length(width, frame + x, 1, run_length);
+ demerit += calc_n1_n3(length, run_length);
+ }
+
+ return demerit;
+}
+
+unsigned char *mask_mask(int width, unsigned char *frame, enum qrec_level level)
+{
+ int i;
+ unsigned char *mask, *best_mask;
+ int min_demerit = INT_MAX;
+ int blacks;
+ int bratio;
+ int demerit;
+ int w2 = width * width;
+
+ mask = kmalloc(w2, GFP_ATOMIC);
+ if (!mask)
+ return NULL;
+ best_mask = NULL;
+
+ for (i = 0; i < MASKNUM; i++) {
+ demerit = 0;
+ blacks = mask_makers[i] (width, frame, mask);
+ blacks += mask_write_format_information(width, mask, i, level);
+ bratio = (200 * blacks + w2) / w2 / 2;
+ demerit = (abs(bratio - 50) / 5) * N4;
+ demerit += mask_evaluate_symbol(width, mask);
+ if (demerit < min_demerit) {
+ min_demerit = demerit;
+ kfree(best_mask);
+ best_mask = mask;
+ mask = kmalloc(w2, GFP_ATOMIC);
+ if (!mask)
+ break;
+ }
+ }
+ kfree(mask);
+ return best_mask;
+}
diff --git a/lib/qr/mask.h b/lib/qr/mask.h
new file mode 100644
index 0000000..57817a6
--- /dev/null
+++ b/lib/qr/mask.h
@@ -0,0 +1,28 @@
+/*
+ * qrencode - QR Code encoder
+ *
+ * Masking.
+ * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MASK_H__
+#define __MASK_H__
+
+unsigned char *mask_make_mask(int width, unsigned char *frame,
+ int mask, enum qrec_level level);
+
+unsigned char *mask_mask(int width, unsigned char *frame,
+ enum qrec_level level);
+
+#endif /* __MASK_H__ */
diff --git a/lib/qr/mmask.h b/lib/qr/mmask.h
new file mode 100644
index 0000000..fc08df6
--- /dev/null
+++ b/lib/qr/mmask.h
@@ -0,0 +1,28 @@
+/*
+ * qrencode - QR Code encoder
+ *
+ * Masking for Micro QR Code.
+ * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MMASK_H__
+#define __MMASK_H__
+
+unsigned char *mmask_make_mask(int version, unsigned char *frame,
+ int mask, enum qrec_level level);
+
+unsigned char *mmask_mask(int version, unsigned char *frame,
+ enum qrec_level level);
+
+#endif /* __MMASK_H__ */
diff --git a/lib/qr/qrencode.c b/lib/qr/qrencode.c
new file mode 100644
index 0000000..c7c849d
--- /dev/null
+++ b/lib/qr/qrencode.c
@@ -0,0 +1,668 @@
+/*
+ * qrencode - QR Code encoder
+ *
+ * Copyright (C) 2014 Levente Kurusa <levex@xxxxxxxxx>
+ * Copyright (C) 2006-2012 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/qrencode.h>
+#include <linux/rslib.h>
+
+#include "qrencode.h"
+#include "qrspec.h"
+#include "bitstream.h"
+#include "qrinput.h"
+#include "split.h"
+#include "mask.h"
+#include "mmask.h"
+
+/******************************************************************************
+ * Raw code
+ *****************************************************************************/
+
+struct rsblock {
+ int data_length;
+ unsigned char *data;
+ int ecc_length;
+ unsigned char *ecc;
+};
+
+struct qrraw_code {
+ int version;
+ int data_length;
+ int ecc_length;
+ unsigned char *datacode;
+ unsigned char *ecccode;
+ int b1;
+ int blocks;
+ struct rsblock *rsblock;
+ int count;
+};
+
+static void rsblock_init_block(struct rsblock *block,
+ int dl,
+ unsigned char *data,
+ int el,
+ unsigned char *ecc,
+ struct rs_control *rs)
+{
+ int i;
+ u16 par[el];
+
+ block->data_length = dl;
+ block->data = data;
+ block->ecc_length = el;
+ block->ecc = ecc;
+
+ memset(par, 0, sizeof(par));
+ encode_rs8(rs, data, dl, par, 0x0000);
+
+ for (i = 0; i < el; i++)
+ ecc[i] = par[i];
+}
+
+static int rsblock_init(struct rsblock *blocks, int spec[5],
+ unsigned char *data,
+ unsigned char *ecc)
+{
+ int i;
+ struct rsblock *block;
+ unsigned char *dp, *ep;
+ struct rs_control *rs;
+ int el, dl;
+
+ dl = qrspec_rs_data_codes1(spec);
+ el = qrspec_rs_ecc_codes1(spec);
+ rs = init_rs(8, 0x11d, 0, 1, el);
+ if (!rs)
+ return -1;
+
+ block = blocks;
+ dp = data;
+ ep = ecc;
+ for (i = 0; i < qrspec_rs_block_num1(spec); i++) {
+ rsblock_init_block(block, dl, dp, el, ep, rs);
+ dp += dl;
+ ep += el;
+ block++;
+ }
+
+ if (qrspec_rs_block_num2(spec) == 0)
+ return 0;
+
+ dl = qrspec_rs_data_codes2(spec);
+ el = qrspec_rs_ecc_codes2(spec);
+ rs = init_rs(8, 0x11d, 0, 1, el);
+ if (!rs)
+ return -1;
+ for (i = 0; i < qrspec_rs_block_num2(spec); i++) {
+ rsblock_init_block(block, dl, dp, el, ep, rs);
+ dp += dl;
+ ep += el;
+ block++;
+ }
+
+ return 0;
+}
+
+static void qrraw_free(struct qrraw_code *raw);
+static struct qrraw_code *qrraw_new(struct qrinput *input)
+{
+ struct qrraw_code *raw;
+ int spec[5], ret;
+
+ raw = kmalloc(sizeof(*raw), GFP_ATOMIC);
+ if (!raw)
+ return NULL;
+
+ raw->datacode = qrinput_get_byte_stream(input);
+ if (!raw->datacode) {
+ kfree(raw);
+ return NULL;
+ }
+
+ qrspec_get_ecc_spec(input->version, input->level, spec);
+
+ raw->version = input->version;
+ raw->b1 = qrspec_rs_block_num1(spec);
+ raw->data_length = qrspec_rs_data_length(spec);
+ raw->ecc_length = qrspec_rs_ecc_length(spec);
+ raw->ecccode = kmalloc(raw->ecc_length, GFP_ATOMIC);
+ if (!raw->ecccode) {
+ kfree(raw->datacode);
+ kfree(raw);
+ return NULL;
+ }
+
+ raw->blocks = qrspec_rs_block_num(spec);
+ raw->rsblock = kcalloc(raw->blocks, sizeof(struct rsblock), GFP_ATOMIC);
+ if (!raw->rsblock) {
+ qrraw_free(raw);
+ return NULL;
+ }
+ ret = rsblock_init(raw->rsblock, spec, raw->datacode, raw->ecccode);
+ if (ret < 0) {
+ qrraw_free(raw);
+ return NULL;
+ }
+
+ raw->count = 0;
+
+ return raw;
+}
+
+/**
+ * Return a code (byte).
+ * This function can be called iteratively.
+ * @param raw raw code.
+ * @return code
+ */
+static unsigned char qrraw_get_code(struct qrraw_code *raw)
+{
+ int col, row;
+ unsigned char ret;
+
+ if (raw->count < raw->data_length) {
+ row = raw->count % raw->blocks;
+ col = raw->count / raw->blocks;
+ if (col >= raw->rsblock[0].data_length)
+ row += raw->b1;
+ ret = raw->rsblock[row].data[col];
+ } else if (raw->count < raw->data_length + raw->ecc_length) {
+ row = (raw->count - raw->data_length) % raw->blocks;
+ col = (raw->count - raw->data_length) / raw->blocks;
+ ret = raw->rsblock[row].ecc[col];
+ } else {
+ return 0;
+ }
+ raw->count++;
+ return ret;
+}
+
+static void qrraw_free(struct qrraw_code *raw)
+{
+ if (raw) {
+ kfree(raw->datacode);
+ kfree(raw->ecccode);
+ kfree(raw->rsblock);
+ kfree(raw);
+ }
+}
+
+/******************************************************************************
+ * Frame filling
+ *****************************************************************************/
+
+struct frame_filler {
+ int width;
+ unsigned char *frame;
+ int x, y;
+ int dir;
+ int bit;
+};
+
+static struct frame_filler *frame_filler_new(int width, unsigned char *frame)
+{
+ struct frame_filler *filler;
+
+ filler = kmalloc(sizeof(*filler), GFP_ATOMIC);
+ if (!filler)
+ return NULL;
+ filler->width = width;
+ filler->frame = frame;
+ filler->x = width - 1;
+ filler->y = width - 1;
+ filler->dir = -1;
+ filler->bit = -1;
+
+ return filler;
+}
+
+static unsigned char *frame_filler_next(struct frame_filler *filler)
+{
+ unsigned char *p;
+ int x, y, w;
+
+ if (filler->bit == -1) {
+ filler->bit = 0;
+ return filler->frame + filler->y * filler->width + filler->x;
+ }
+
+ x = filler->x;
+ y = filler->y;
+ p = filler->frame;
+ w = filler->width;
+
+ if (filler->bit == 0) {
+ x--;
+ filler->bit++;
+ } else {
+ x++;
+ y += filler->dir;
+ filler->bit--;
+ }
+
+ if (filler->dir < 0) {
+ if (y < 0) {
+ y = 0;
+ x -= 2;
+ filler->dir = 1;
+ if (x == 6) {
+ x--;
+ y = 9;
+ }
+ }
+ } else {
+ if (y == w) {
+ y = w - 1;
+ x -= 2;
+ filler->dir = -1;
+ if (x == 6) {
+ x--;
+ y -= 8;
+ }
+ }
+ }
+ if (x < 0 || y < 0)
+ return NULL;
+
+ filler->x = x;
+ filler->y = y;
+
+ if (p[y * w + x] & 0x80) {
+ /* This tail recursion could be optimized. */
+ return frame_filler_next(filler);
+ }
+ return &p[y * w + x];
+}
+
+/******************************************************************************
+ * QR-code encoding
+ *****************************************************************************/
+
+static struct qrcode *qrcode_new(int version, int width, unsigned char *data)
+{
+ struct qrcode *qrcode;
+
+ qrcode = kmalloc(sizeof(*qrcode), GFP_ATOMIC);
+ if (!qrcode)
+ return NULL;
+
+ qrcode->version = version;
+ qrcode->width = width;
+ qrcode->data = data;
+
+ return qrcode;
+}
+
+void qrcode_free(struct qrcode *qrcode)
+{
+ if (!qrcode) {
+ kfree(qrcode->data);
+ kfree(qrcode);
+ }
+}
+EXPORT_SYMBOL_GPL(qrcode_free);
+
+static struct qrcode *qrcode_encode_mask(struct qrinput *input, int mask)
+{
+ int width, version;
+ struct qrraw_code *raw;
+ unsigned char *frame, *masked, *p, code, bit;
+ struct frame_filler *filler;
+ int i, j;
+ struct qrcode *qrcode = NULL;
+
+ if (input->version < 0 || input->version > QRSPEC_VERSION_MAX)
+ return NULL;
+
+ if (input->level > QR_ECLEVEL_H)
+ return NULL;
+
+ raw = qrraw_new(input);
+ if (!raw)
+ return NULL;
+
+ version = raw->version;
+ width = qrspec_get_width(version);
+ frame = qrspec_new_frame(version);
+ if (!frame) {
+ qrraw_free(raw);
+ return NULL;
+ }
+ filler = frame_filler_new(width, frame);
+ if (!filler) {
+ qrraw_free(raw);
+ kfree(frame);
+ return NULL;
+ }
+
+ /* inteleaved data and ecc codes */
+ for (i = 0; i < raw->data_length + raw->ecc_length; i++) {
+ code = qrraw_get_code(raw);
+ bit = 0x80;
+ for (j = 0; j < 8; j++) {
+ p = frame_filler_next(filler);
+ if (!p)
+ goto EXIT;
+ *p = 0x02 | ((bit & code) != 0);
+ bit = bit >> 1;
+ }
+ }
+ qrraw_free(raw);
+ raw = NULL;
+ /* remainder bits */
+ j = qrspec_get_remainder(version);
+ for (i = 0; i < j; i++) {
+ p = frame_filler_next(filler);
+ if (!p)
+ goto EXIT;
+ *p = 0x02;
+ }
+
+ /* masking */
+ if (mask < 0)
+ masked = mask_mask(width, frame, input->level);
+ else
+ masked = mask_make_mask(width, frame, mask, input->level);
+
+ if (!masked)
+ goto EXIT;
+
+ qrcode = qrcode_new(version, width, masked);
+
+EXIT:
+ qrraw_free(raw);
+ kfree(filler);
+ kfree(frame);
+ return qrcode;
+}
+
+struct qrcode *qrcode_encode_input(struct qrinput *input)
+{
+ return qrcode_encode_mask(input, -1);
+}
+EXPORT_SYMBOL_GPL(qrcode_encode_input);
+
+static struct qrcode *qrcode_encode_string_real(const char *string, int version,
+ enum qrec_level level,
+ enum qrencode_mode hint,
+ int casesensitive)
+{
+ struct qrinput *input;
+ struct qrcode *code;
+ int ret;
+
+ if (!string)
+ return NULL;
+
+ if (hint != QR_MODE_8)
+ return NULL;
+
+ input = qrinput_new2(version, level);
+
+ if (!input)
+ return NULL;
+
+ ret = split_split_string_to_qrinput(string, input, hint, casesensitive);
+ if (ret < 0) {
+ qrinput_free(input);
+ return NULL;
+ }
+ code = qrcode_encode_input(input);
+ qrinput_free(input);
+
+ return code;
+}
+
+struct qrcode *qrcode_encode_string(const char *string,
+ int version,
+ enum qrec_level level,
+ enum qrencode_mode hint,
+ int casesensitive)
+{
+ return qrcode_encode_string_real(string, version, level, hint,
+ casesensitive);
+}
+EXPORT_SYMBOL_GPL(qrcode_encode_string);
+
+static struct qrcode *qrcode_encode_data_real(const unsigned char *data,
+ int length, int version,
+ enum qrec_level level)
+{
+ struct qrinput *input;
+ struct qrcode *code;
+ int ret;
+
+ if (!data || length == 0)
+ return NULL;
+
+ input = qrinput_new2(version, level);
+
+ if (!input)
+ return NULL;
+
+ ret = qrinput_append(input, QR_MODE_8, length, data);
+ if (ret < 0) {
+ qrinput_free(input);
+ return NULL;
+ }
+ code = qrcode_encode_input(input);
+ qrinput_free(input);
+
+ return code;
+}
+
+struct qrcode *qrcode_encode_data(int size, const unsigned char *data,
+ int version, enum qrec_level level)
+{
+ return qrcode_encode_data_real(data, size, version, level);
+}
+EXPORT_SYMBOL_GPL(qrcode_encode_data);
+
+struct qrcode *qrcode_encode_string_8bit(const char *string, int version,
+ enum qrec_level level)
+{
+ if (!string)
+ return NULL;
+
+ return qrcode_encode_data_real((unsigned char *)string, strlen(string),
+ version, level);
+}
+EXPORT_SYMBOL_GPL(qrcode_encode_string_8bit);
+
+/******************************************************************************
+ * Structured QR-code encoding
+ *****************************************************************************/
+
+static struct qrcode_list *qrcode_list_new_entry(void)
+{
+ struct qrcode_list *entry;
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry)
+ return NULL;
+
+ entry->next = NULL;
+ entry->code = NULL;
+
+ return entry;
+}
+
+static void qrcode_list_free_entry(struct qrcode_list *entry)
+{
+ if (entry) {
+ qrcode_free(entry->code);
+ kfree(entry);
+ }
+}
+
+void qrcode_list_free(struct qrcode_list *qrlist)
+{
+ struct qrcode_list *list = qrlist, *next;
+
+ while (list) {
+ next = list->next;
+ qrcode_list_free_entry(list);
+ list = next;
+ }
+}
+EXPORT_SYMBOL_GPL(qrcode_list_free);
+
+int qrcode_list_size(struct qrcode_list *qrlist)
+{
+ struct qrcode_list *list = qrlist;
+ int size = 0;
+
+ while (list) {
+ size++;
+ list = list->next;
+ }
+
+ return size;
+}
+EXPORT_SYMBOL_GPL(qrcode_list_size);
+
+struct qrcode_list *qrcode_encode_input_structured(struct qrinput_struct *s)
+{
+ struct qrcode_list *head = NULL;
+ struct qrcode_list *tail = NULL;
+ struct qrcode_list *entry;
+ struct qrinput_input_list *list = s->head;
+
+ while (list) {
+ if (!head) {
+ entry = qrcode_list_new_entry();
+ if (!entry)
+ goto ABORT;
+ head = entry;
+ tail = head;
+ } else {
+ entry = qrcode_list_new_entry();
+ if (!entry)
+ goto ABORT;
+ tail->next = entry;
+ tail = tail->next;
+ }
+ tail->code = qrcode_encode_input(list->input);
+ if (!tail->code)
+ goto ABORT;
+ list = list->next;
+ }
+
+ return head;
+ABORT:
+ qrcode_list_free(head);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(qrcode_encode_input_structured);
+
+static
+struct qrcode_list *qrcode_encode_input_to_structured(struct qrinput *input)
+{
+ struct qrinput_struct *s;
+ struct qrcode_list *codes;
+
+ s = qrinput_split_qrinput_to_struct(input);
+ if (!s)
+ return NULL;
+
+ codes = qrcode_encode_input_structured(s);
+ qrinput_struct_free(s);
+
+ return codes;
+}
+
+static struct qrcode_list *qrcode_encode_data_structured_real
+ (int size,
+ const unsigned char *data,
+ int version,
+ enum qrec_level level,
+ int eightbit,
+ enum qrencode_mode hint,
+ int casesensitive)
+{
+ struct qrinput *input;
+ struct qrcode_list *codes;
+ int ret;
+
+ if (version <= 0)
+ return NULL;
+
+ if (!eightbit && hint != QR_MODE_8)
+ return NULL;
+
+ input = qrinput_new2(version, level);
+ if (!input)
+ return NULL;
+
+ if (eightbit) {
+ ret = qrinput_append(input, QR_MODE_8, size, data);
+ } else {
+ ret =
+ split_split_string_to_qrinput((char *)data, input, hint,
+ casesensitive);
+ }
+ if (ret < 0) {
+ qrinput_free(input);
+ return NULL;
+ }
+ codes = qrcode_encode_input_to_structured(input);
+ qrinput_free(input);
+
+ return codes;
+}
+
+struct qrcode_list *qrcode_encode_data_structured(int size,
+ const unsigned char *data,
+ int version,
+ enum qrec_level level)
+{
+ return qrcode_encode_data_structured_real(size, data, version, level, 1,
+ QR_MODE_NUL, 0);
+}
+EXPORT_SYMBOL_GPL(qrcode_encode_data_structured);
+
+struct qrcode_list *qrcode_encode_string_8bit_structured
+ (const char *string,
+ int version,
+ enum qrec_level level)
+{
+ if (!string)
+ return NULL;
+
+ return qrcode_encode_data_structured(strlen(string),
+ (unsigned char *)string, version,
+ level);
+}
+EXPORT_SYMBOL_GPL(qrcode_encode_string_8bit_structured);
+
+struct qrcode_list
+*qrcode_encode_string_structured(const char *string, int version,
+ enum qrec_level level, enum qrencode_mode hint,
+ int casesensitive)
+{
+ if (!string)
+ return NULL;
+
+ return qrcode_encode_data_structured_real(strlen(string),
+ (unsigned char *)string,
+ version,
+ level, 0,
+ hint, casesensitive);
+}
+EXPORT_SYMBOL_GPL(qrcode_encode_string_structured);
diff --git a/lib/qr/qrencode.h b/lib/qr/qrencode.h
new file mode 100644
index 0000000..d28087f
--- /dev/null
+++ b/lib/qr/qrencode.h
@@ -0,0 +1,546 @@
+/**
+ * qrencode - QR Code encoder
+ *
+ * Copyright (C) 2006-2012 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+/** \mainpage
+ * Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D
+ * symbology.
+ *
+ * \section encoding Encoding
+ *
+ * There are two methods to encode data: <b>encoding a string/data</b> or
+ * <b>encoding a structured data</b>.
+ *
+ * \subsection encoding-string Encoding a string/data
+ * You can encode a string by calling qrcode_encode_string().
+ * The given string is parsed automatically and encoded. If you want to encode
+ * data that can be represented as a C string style (NUL terminated), you can
+ * simply use this way.
+ *
+ * If the input data contains Kanji (Shift-JIS) characters and you want to
+ * encode them as Kanji in QR Code, you should give QR_MODE_KANJI as a hint.
+ * Otherwise, all of non-alphanumeric characters are encoded as 8 bit data.
+ * If you want to encode a whole string in 8 bit mode, you can use
+ * qrcode_encode_string_8bit() instead.
+ *
+ * Please note that a C string can not contain NUL characters. If your data
+ * contains NUL, you must use qrcode_encode_data().
+ *
+ * \subsection encoding-input Encoding a structured data
+ * You can construct a structured input data manually. If the structure of the
+ * input data is known, you can use this way.
+ * At first, create a ::qrinput object by qrinput_new(). Then add input data
+ * to the qrinput object by qrinput_append(). Finally call qrcode_encode_input()
+ * to encode the qrinput data.
+ * You can reuse the qrinput data again to encode it in other symbols with
+ * different parameters.
+ *
+ * \section result Result
+ * The encoded symbol is resulted as a ::qrcode object. It will contain
+ * its version number, width of the symbol and an array represents the symbol.
+ * See ::qrcode for the details. You can free the object by qrcode_free().
+ *
+ * Please note that the version of the result may be larger than specified.
+ * In such cases, the input data would be too large to be encoded in a
+ * symbol of the specified version.
+ *
+ * \section structured Structured append
+ * Libqrencode can generate "Structured-appended" symbols that enables to split
+ * a large data set into mulitple QR codes. A QR code reader concatenates
+ * multiple QR code symbols into a string.
+ * Just like qrcode_encode_string(), you can use
+ * qrcode_encode_string_structured() to generate structured-appended symbols.
+ * This functions returns an instance of ::qrcode_list. The returned list is a
+ * singly-linked list of qrcode: you
+ * can retrieve each QR code in this way:
+ *
+ * \code
+ * qrcode_list *qrcodes;
+ * qrcode_list *entry;
+ * qrcode *qrcode;
+ *
+ * qrcodes = qrcode_encode_string_structured(...);
+ * entry = qrcodes;
+ * while(entry != NULL) {
+ * qrcode = entry->code;
+ * // do something
+ * entry = entry->next;
+ * }
+ * qrcode_list_free(entry);
+ * \endcode
+ *
+ * Instead of using auto-parsing functions, you can construct your own
+ * structured input. At first, instantiate an object of ::qrinput_struct
+ * by calling qrinput_struct_new(). This object can hold multiple ::qrinput,
+ * and one QR code is generated for a ::qrinput.
+ * qrinput_struct_append_input() appends a ::qrinput to a ::qrinput_struct
+ * object. In order to generate structured-appended symbols, it is required to
+ * embed headers to each symbol. You can use
+ * qrinput_struct_insert_structured_append_headers() to insert appropriate
+ * headers to each symbol. You should call this function just once before
+ * encoding symbols.
+ */
+
+#ifndef __QRENCODE_H__
+#define __QRENCODE_H__
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * Encoding mode.
+ */
+enum qrencode_mode {
+ QR_MODE_NUL = -1, /* Terminator (NUL character). Internal use only */
+ QR_MODE_NUM = 0, /* Numeric mode */
+ QR_MODE_AN, /* Alphabet-numeric mode */
+ QR_MODE_8, /* 8-bit data mode */
+ QR_MODE_STRUCTURE, /* Internal use only */
+ QR_MODE_ECI, /* ECI mode */
+ QR_MODE_FNC1FIRST, /* FNC1, first position */
+ QR_MODE_FNC1SECOND, /* FNC1, second position */
+};
+
+/**
+ * Level of error correction.
+ */
+enum qrec_level {
+ QR_ECLEVEL_L = 0, /* lowest */
+ QR_ECLEVEL_M,
+ QR_ECLEVEL_Q,
+ QR_ECLEVEL_H /* highest */
+};
+
+/**
+ * Maximum version (size) of QR-code symbol.
+ */
+#define QRSPEC_VERSION_MAX 40
+
+/**
+ * Maximum version (size) of QR-code symbol.
+ */
+#define MQRSPEC_VERSION_MAX 4
+
+/******************************************************************************
+ * Input data (qrinput.c)
+ *****************************************************************************/
+/**
+ * Instantiate an input data object. The version is set to 0 (auto-select)
+ * and the error correction level is set to QR_ECLEVEL_L.
+ * @return an input object (initialized). On error, NULL is returned and errno
+ * is set to indicate the error.
+ * @throw ENOMEM unable to allocate memory.
+ */
+struct qrinput *qrinput_new(void);
+
+/**
+ * Instantiate an input data object.
+ * @param version version number.
+ * @param level Error correction level.
+ * @return an input object (initialized). On error, NULL is returned and errno
+ * is set to indicate the error.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ * @throw EINVAL invalid arguments.
+ */
+struct qrinput *qrinput_new2(int version, enum qrec_level level);
+
+/**
+ * Instantiate an input data object. Object's Micro QR Code flag is set.
+ * Unlike with full-sized QR Code, version number must be specified (>0).
+ * @param version version number (1--4).
+ * @param level Error correction level.
+ * @return an input object (initialized). On error, NULL is returned and errno
+ * is set to indicate the error.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ * @throw EINVAL invalid arguments.
+ */
+struct qrinput *qrinput_new_micro(int version, enum qrec_level level);
+
+/**
+ * Append data to an input object.
+ * The data is copied and appended to the input object.
+ * @param input input object.
+ * @param mode encoding mode.
+ * @param size size of data (byte).
+ * @param data a pointer to the memory area of the input data.
+ * @retval 0 success.
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ * @throw EINVAL input data is invalid.
+ *
+ */
+int qrinput_append(struct qrinput *input, enum qrencode_mode mode,
+ int size, const unsigned char *data);
+
+/**
+ * Append ECI header.
+ * @param input input object.
+ * @param ecinum ECI indicator number (0 - 999999)
+ * @retval 0 success.
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ * @throw EINVAL input data is invalid.
+ *
+ */
+int qrinput_append_eci_header(struct qrinput *input, unsigned int ecinum);
+
+/**
+ * Get current version.
+ * @param input input object.
+ * @return current version.
+ */
+int qrinput_get_version(struct qrinput *input);
+
+/**
+ * Set version of the QR code that is to be encoded.
+ * This function cannot be applied to Micro QR Code.
+ * @param input input object.
+ * @param version version number (0 = auto)
+ * @retval 0 success.
+ * @retval -1 invalid argument.
+ */
+int qrinput_set_version(struct qrinput *input, int version);
+
+/**
+ * Get current error correction level.
+ * @param input input object.
+ * @return Current error correcntion level.
+ */
+enum qrec_level qrinput_get_error_correction_level(struct qrinput *input);
+
+/**
+ * Set error correction level of the QR code that is to be encoded.
+ * This function cannot be applied to Micro QR Code.
+ * @param input input object.
+ * @param level Error correction level.
+ * @retval 0 success.
+ * @retval -1 invalid argument.
+ */
+int qrinput_set_error_correction_level(struct qrinput *input,
+ enum qrec_level level);
+
+/**
+ * Set version and error correction level of the QR code at once.
+ * This function is recommened for Micro QR Code.
+ * @param input input object.
+ * @param version version number (0 = auto)
+ * @param level Error correction level.
+ * @retval 0 success.
+ * @retval -1 invalid argument.
+ */
+int
+qrinput_set_version_and_error_correction_level(struct qrinput *input,
+ int version,
+ enum qrec_level level);
+
+/**
+ * Free the input object.
+ * All of data chunks in the input object are freed too.
+ * @param input input object.
+ */
+void qrinput_free(struct qrinput *input);
+
+/**
+ * Validate the input data.
+ * @param mode encoding mode.
+ * @param size size of data (byte).
+ * @param data a pointer to the memory area of the input data.
+ * @retval 0 success.
+ * @retval -1 invalid arguments.
+ */
+int qrinput_check(enum qrencode_mode mode, int size,
+ const unsigned char *data);
+
+/**
+ * Instantiate a set of input data object.
+ * @return an instance of qrinput_struct. On error, NULL is returned and errno
+ * is set to indicate the error.
+ * @throw ENOMEM unable to allocate memory.
+ */
+struct qrinput_struct *qrinput_struct_new(void);
+
+/**
+ * Set parity of structured symbols.
+ * @param s structured input object.
+ * @param parity parity of s.
+ */
+void qrinput_struct_set_parity(struct qrinput_struct *s,
+ unsigned char parity);
+
+/**
+ * Append a qrinput object to the set. qrinput created by qrinput_new_micro()
+ * will be rejected.
+ * @warning never append the same qrinput object twice or more.
+ * @param s structured input object.
+ * @param input an input object.
+ * @retval >0 number of input objects in the structure.
+ * @retval -1 an error occurred. See Exceptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ * @throw EINVAL invalid arguments.
+ */
+int qrinput_struct_append_input(struct qrinput_struct *s,
+ struct qrinput *input);
+
+/**
+ * Free all of qrinput in the set.
+ * @param s a structured input object.
+ */
+void qrinput_struct_free(struct qrinput_struct *s);
+
+/**
+ * Split a qrinput to qrinput_struct. It calculates a parity, set it, then
+ * insert structured-append headers. qrinput created by qrinput_new_micro() will
+ * be rejected.
+ * @param input input object. Version number and error correction level must be
+ * set.
+ * @return a set of input data. On error, NULL is returned, and errno is set
+ * to indicate the error. See Exceptions for the details.
+ * @throw ERANGE input data is too large.
+ * @throw EINVAL invalid input data.
+ * @throw ENOMEM unable to allocate memory.
+ */
+struct qrinput_struct *qrinput_split_qrinput_to_struct(struct qrinput *input);
+
+/**
+ * Insert structured-append headers to the input structure. It calculates
+ * a parity and set it if the parity is not set yet.
+ * @param s input structure
+ * @retval 0 success.
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory.
+ */
+int qrinput_struct_insert_structured_append_headers(struct qrinput_struct *s);
+
+/**
+ * Set FNC1-1st position flag.
+ */
+int qrinput_set_fnc1_first(struct qrinput *input);
+
+/**
+ * Set FNC1-2nd position flag and application identifier.
+ */
+int qrinput_set_fnc1_second(struct qrinput *input, unsigned char appid);
+
+/******************************************************************************
+ * qrcode output (qrencode.c)
+ *****************************************************************************/
+
+/**
+ * qrcode class.
+ * Symbol data is represented as an array contains width*width uchars.
+ * Each uchar represents a module (dot). If the less significant bit of
+ * the uchar is 1, the corresponding module is black. The other bits are
+ * meaningless for usual applications, but here its specification is described.
+ *
+ * <pre>
+ * MSB 76543210 LSB
+ * |||||||`- 1=black/0=white
+ * ||||||`-- data and ecc code area
+ * |||||`--- format information
+ * ||||`---- version information
+ * |||`----- timing pattern
+ * ||`------ alignment pattern
+ * |`------- finder pattern and separator
+ * `-------- non-data modules (format, timing, etc.)
+ * </pre>
+ */
+struct qrcode {
+ int version; /* version of the symbol */
+ int width; /* width of the symbol */
+ unsigned char *data; /* symbol data */
+};
+
+/**
+ * Singly-linked list of qrcode. Used to represent a structured symbols.
+ * A list is terminated with NULL.
+ */
+struct qrcode_list {
+ struct qrcode *code;
+ struct qrcode_list *next;
+};
+
+/**
+ * Create a symbol from the input data.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param input input data.
+ * @return an instance of qrcode class. The version of the result qrcode may
+ * be larger than the designated version. On error, NULL is returned,
+ * and errno is set to indicate the error. See Exceptions for the
+ * details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ */
+struct qrcode *qrcode_encode_input(struct qrinput *input);
+
+/**
+ * Create a symbol from the string. The library automatically parses the input
+ * string and encodes in a QR Code symbol.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param string input string. It must be NUL terminated.
+ * @param version version of the symbol. If 0, the library chooses the minimum
+ * version for the given input data.
+ * @param level error correction level.
+ * @param hint tell the library how Japanese Kanji characters should be
+ * encoded. If QR_MODE_KANJI is given, the library assumes that the
+ * given string contains Shift-JIS characters and encodes them in
+ * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical
+ * characters will be encoded as is. If you want to embed UTF-8
+ * string, choose this. Other mode will cause EINVAL error.
+ * @param casesensitive case-sensitive(1) or not(0).
+ * @return an instance of qrcode class. The version of the result qrcode may
+ * be larger than the designated version. On error, NULL is returned,
+ * and errno is set to indicate the error. See Exceptions for the
+ * details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ * @throw ERANGE input data is too large.
+ */
+struct qrcode
+*qrcode_encode_string(const char *string, int version,
+ enum qrec_level level, enum qrencode_mode hint,
+ int casesensitive);
+
+/**
+ * Same to qrcode_encode_string(), but encode whole data in 8-bit mode.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ */
+struct qrcode
+*qrcode_encode_string_8bit(const char *string, int version,
+ enum qrec_level level);
+
+/**
+ * Micro QR Code version of qrcode_encode_string().
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ */
+struct qrcode
+*qrcode_encode_string_micro(const char *string,
+ int version, enum qrec_level level,
+ enum qrencode_mode hint, int casesensitive);
+
+/**
+ * Micro QR Code version of qrcode_encode_string_8bit().
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ */
+struct qrcode
+*qrcode_encode_string_8bit_micro(const char *string, int version,
+ enum qrec_level level);
+
+/**
+ * Encode byte stream (may include '\0') in 8-bit mode.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param size size of the input data.
+ * @param data input data.
+ * @param version version of the symbol. If 0, the library chooses the minimum
+ * version for the given input data.
+ * @param level error correction level.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ * @throw ERANGE input data is too large.
+ */
+struct qrcode
+*qrcode_encode_data(int size, const unsigned char *data,
+ int version, enum qrec_level level);
+
+/**
+ * Micro QR Code version of qrcode_encode_data().
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ */
+struct qrcode
+*qrcode_encode_data_micro(int size, const unsigned char *data,
+ int version, enum qrec_level level);
+
+/**
+ * Free the instance of qrcode class.
+ * @param qrcode an instance of qrcode class.
+ */
+void qrcode_free(struct qrcode *qrcode);
+
+/**
+ * Create structured symbols from the input data.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param s
+ * @return a singly-linked list of qrcode.
+ */
+struct qrcode_list
+*qrcode_encode_input_structured(struct qrinput_struct *s);
+
+/**
+ * Create structured symbols from the string. The library automatically parses
+ * the input string and encodes in a QR Code symbol.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param string input string. It must be NUL terminated.
+ * @param version version of the symbol.
+ * @param level error correction level.
+ * @param hint tell the library how Japanese Kanji characters should be
+ * encoded. If QR_MODE_KANJI is given, the library assumes that the
+ * given string contains Shift-JIS characters and encodes them in
+ * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical
+ * characters will be encoded as is. If you want to embed UTF-8
+ * string, choose this. Other mode will cause EINVAL error.
+ * @param casesensitive case-sensitive(1) or not(0).
+ * @return a singly-linked list of qrcode. On error, NULL is returned, and
+ * errno is set to indicate the error. See Exceptions for the details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ */
+struct qrcode_list
+*qrcode_encode_string_structured(const char *string, int version,
+ enum qrec_level level, enum qrencode_mode hint,
+ int casesensitive);
+
+/**
+ * Same to qrcode_encode_string_structured(), but encode whole data in 8-bit
+ * mode.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ */
+struct qrcode_list
+*qrcode_encode_string_8bit_structured(const char *string, int version,
+ enum qrec_level level);
+
+/**
+ * Create structured symbols from byte stream (may include '\0'). Wholde data
+ * are encoded in 8-bit mode.
+ * @warning This function is THREAD UNSAFE when pthread is disabled.
+ * @param size size of the input data.
+ * @param data input dat.
+ * @param version version of the symbol.
+ * @param level error correction level.
+ * @return a singly-linked list of qrcode. On error, NULL is returned, and
+ * errno is set to indicate the error. See Exceptions for the details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ */
+struct qrcode_list
+*qrcode_encode_data_structured(int size, const unsigned char *data,
+ int version, enum qrec_level level);
+
+/**
+ * Return the number of symbols included in a qrcode_list.
+ * @param qrlist a head entry of a qrcode_list.
+ * @return number of symbols in the list.
+ */
+int qrcode_list_size(struct qrcode_list *qrlist);
+
+/**
+ * Free the qrcode_list.
+ * @param qrlist a head entry of a qrcode_list.
+ */
+void qrcode_list_free(struct qrcode_list *qrlist);
+
+#endif /* __QRENCODE_H__ */
diff --git a/lib/qr/qrinput.c b/lib/qr/qrinput.c
new file mode 100644
index 0000000..a7d9779
--- /dev/null
+++ b/lib/qr/qrinput.c
@@ -0,0 +1,1515 @@
+/*
+ * qrencode - QR Code encoder
+ *
+ * Input data chunk class
+ * Copyright (C) 2014 Levente Kurusa <levex@xxxxxxxxx>
+ * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/qrencode.h>
+#include "qrspec.h"
+#include "bitstream.h"
+#include "qrinput.h"
+
+/******************************************************************************
+ * Utilities
+ *****************************************************************************/
+int qrinput_is_splittable_mode(enum qrencode_mode mode)
+{
+ return mode >= QR_MODE_NUM;
+}
+
+/******************************************************************************
+ * Entry of input data
+ *****************************************************************************/
+
+static
+struct qrinput_list *qrinput_list_new_entry(enum qrencode_mode mode,
+ int size,
+ const unsigned char *data)
+{
+ struct qrinput_list *entry;
+
+ if (qrinput_check(mode, size, data))
+ return NULL;
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry)
+ return NULL;
+
+ entry->mode = mode;
+ entry->size = size;
+ if (size > 0) {
+ entry->data = kmalloc(size, GFP_ATOMIC);
+ if (!entry->data) {
+ kfree(entry);
+ return NULL;
+ }
+ memcpy(entry->data, data, size);
+ }
+ entry->bstream = NULL;
+ entry->next = NULL;
+
+ return entry;
+}
+
+static void qrinput_list_free_entry(struct qrinput_list *entry)
+{
+ if (!entry) {
+ kfree(entry->data);
+ bit_stream_free(entry->bstream);
+ kfree(entry);
+ }
+}
+
+static struct qrinput_list *qrinput_list_dup(struct qrinput_list *entry)
+{
+ struct qrinput_list *n;
+
+ n = kmalloc(sizeof(*n), GFP_ATOMIC);
+ if (!n)
+ return NULL;
+
+ n->mode = entry->mode;
+ n->size = entry->size;
+ n->data = kmalloc(n->size, GFP_ATOMIC);
+ if (!n->data) {
+ kfree(n);
+ return NULL;
+ }
+ memcpy(n->data, entry->data, entry->size);
+ n->bstream = NULL;
+ n->next = NULL;
+
+ return n;
+}
+
+/******************************************************************************
+ * Input Data
+ *****************************************************************************/
+
+struct qrinput *qrinput_new(void)
+{
+ return qrinput_new2(0, QR_ECLEVEL_L);
+}
+
+struct qrinput *qrinput_new2(int version, enum qrec_level level)
+{
+ struct qrinput *input;
+
+ if (version < 0 || version > QRSPEC_VERSION_MAX || level > QR_ECLEVEL_H)
+ return NULL;
+
+ input = kmalloc(sizeof(*input), GFP_ATOMIC);
+ if (!input)
+ return NULL;
+
+ input->head = NULL;
+ input->tail = NULL;
+ input->version = version;
+ input->level = level;
+ input->fnc1 = 0;
+
+ return input;
+}
+
+int qrinput_get_version(struct qrinput *input)
+{
+ return input->version;
+}
+
+int qrinput_set_version(struct qrinput *input, int version)
+{
+ if (version < 0 || version > QRSPEC_VERSION_MAX)
+ return -1;
+
+ input->version = version;
+
+ return 0;
+}
+
+enum qrec_level qrinput_get_error_correction_level(struct qrinput *input)
+{
+ return input->level;
+}
+
+int qrinput_set_error_correction_level(struct qrinput *input,
+ enum qrec_level level)
+{
+ if (level > QR_ECLEVEL_H)
+ return -1;
+
+ input->level = level;
+
+ return 0;
+}
+
+int qrinput_set_version_and_error_correction_level(struct qrinput *input,
+ int version,
+ enum qrec_level level)
+{
+ if (version < 0 || version > QRSPEC_VERSION_MAX)
+ goto INVALID;
+ if (level > QR_ECLEVEL_H)
+ goto INVALID;
+
+ input->version = version;
+ input->level = level;
+
+ return 0;
+
+INVALID:
+ return -1;
+}
+
+static void qrinput_append_entry(struct qrinput *input,
+ struct qrinput_list *entry)
+{
+ if (!input->tail) {
+ input->head = entry;
+ input->tail = entry;
+ } else {
+ input->tail->next = entry;
+ input->tail = entry;
+ }
+ entry->next = NULL;
+}
+
+int qrinput_append(struct qrinput *input, enum qrencode_mode mode, int size,
+ const unsigned char *data)
+{
+ struct qrinput_list *entry;
+
+ entry = qrinput_list_new_entry(mode, size, data);
+ if (!entry)
+ return -1;
+
+ qrinput_append_entry(input, entry);
+
+ return 0;
+}
+
+/**
+ * Insert a structured-append header to the head of the input data.
+ * @param input input data.
+ * @param size number of structured symbols.
+ * @param number index number of the symbol. (1 <= number <= size)
+ * @param parity parity among input data. (NOTE: each symbol of a set of
+ * structured symbols has the same parity data)
+ * @retval 0 success.
+ * @retval -1 error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw EINVAL invalid parameter.
+ * @throw ENOMEM unable to allocate memory.
+ */
+static int qrinput_insert_structured_append_header(struct qrinput *input,
+ int size,
+ int number,
+ unsigned char parity)
+{
+ struct qrinput_list *entry;
+ unsigned char buf[3];
+
+ if (size > MAX_STRUCTURED_SYMBOLS)
+ return -1;
+ if (number <= 0 || number > size)
+ return -1;
+
+ buf[0] = (unsigned char)size;
+ buf[1] = (unsigned char)number;
+ buf[2] = parity;
+ entry = qrinput_list_new_entry(QR_MODE_STRUCTURE, 3, buf);
+ if (!entry)
+ return -1;
+
+ entry->next = input->head;
+ input->head = entry;
+
+ return 0;
+}
+
+int qrinput_append_eci_header(struct qrinput *input, unsigned int ecinum)
+{
+ unsigned char data[4];
+
+ if (ecinum > 999999)
+ return -1;
+
+ /*
+ * We manually create byte array of ecinum because
+ * (unsigned char *)&ecinum may cause bus error on
+ * some architectures.
+ */
+ data[0] = ecinum & 0xff;
+ data[1] = (ecinum >> 8) & 0xff;
+ data[2] = (ecinum >> 16) & 0xff;
+ data[3] = (ecinum >> 24) & 0xff;
+ return qrinput_append(input, QR_MODE_ECI, 4, data);
+}
+
+void qrinput_free(struct qrinput *input)
+{
+ struct qrinput_list *list, *next;
+
+ if (!input) {
+ list = input->head;
+ while (!list) {
+ next = list->next;
+ qrinput_list_free_entry(list);
+ list = next;
+ }
+ kfree(input);
+ }
+}
+
+static unsigned char qrinput_calc_parity(struct qrinput *input)
+{
+ unsigned char parity = 0;
+ struct qrinput_list *list;
+ int i;
+
+ list = input->head;
+ while (!list) {
+ if (list->mode != QR_MODE_STRUCTURE) {
+ for (i = list->size - 1; i >= 0; i--)
+ parity ^= list->data[i];
+ }
+ list = list->next;
+ }
+
+ return parity;
+}
+
+struct qrinput *qrinput_dup(struct qrinput *input)
+{
+ struct qrinput *n;
+ struct qrinput_list *list, *e;
+
+ n = qrinput_new2(input->version, input->level);
+ if (!n)
+ return NULL;
+
+ list = input->head;
+ while (list) {
+ e = qrinput_list_dup(list);
+ if (!e) {
+ qrinput_free(n);
+ return NULL;
+ }
+ qrinput_append_entry(n, e);
+ list = list->next;
+ }
+
+ return n;
+}
+
+/******************************************************************************
+ * Numeric data
+ *****************************************************************************/
+
+/**
+ * Check the input data.
+ * @param size
+ * @param data
+ * @return result
+ */
+static int qrinput_check_mode_num(int size, const char *data)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (data[i] < '0' || data[i] > '9')
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Estimates the length of the encoded bit stream of numeric data.
+ * @param size
+ * @return number of bits
+ */
+int qrinput_estimate_bits_mode_num(int size)
+{
+ int w;
+ int bits;
+
+ w = size / 3;
+ bits = w * 10;
+ switch (size - w * 3) {
+ case 1:
+ bits += 4;
+ break;
+ case 2:
+ bits += 7;
+ break;
+ default:
+ break;
+ }
+
+ return bits;
+}
+
+/**
+ * Convert the number data to a bit stream.
+ * @param entry
+ * @retval 0 success
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ */
+static int qrinput_encode_mode_num(struct qrinput_list *entry, int version)
+{
+ int words, i, ret;
+ unsigned int val;
+
+ entry->bstream = bit_stream_new();
+ if (!entry->bstream)
+ return -1;
+
+ ret = bit_stream_append_num(entry->bstream, 4, QRSPEC_MODEID_NUM);
+ if (ret < 0)
+ goto ABORT;
+
+ ret = bit_stream_append_num(entry->bstream,
+ qrspec_length_indicator(QR_MODE_NUM,
+ version),
+ entry->size);
+ if (ret < 0)
+ goto ABORT;
+
+ words = entry->size / 3;
+ for (i = 0; i < words; i++) {
+ val = (entry->data[i * 3] - '0') * 100;
+ val += (entry->data[i * 3 + 1] - '0') * 10;
+ val += (entry->data[i * 3 + 2] - '0');
+
+ ret = bit_stream_append_num(entry->bstream, 10, val);
+ if (ret < 0)
+ goto ABORT;
+ }
+
+ if (entry->size - words * 3 == 1) {
+ val = entry->data[words * 3] - '0';
+ ret = bit_stream_append_num(entry->bstream, 4, val);
+ if (ret < 0)
+ goto ABORT;
+ } else if (entry->size - words * 3 == 2) {
+ val = (entry->data[words * 3] - '0') * 10;
+ val += (entry->data[words * 3 + 1] - '0');
+ bit_stream_append_num(entry->bstream, 7, val);
+ if (ret < 0)
+ goto ABORT;
+ }
+
+ return 0;
+ABORT:
+ bit_stream_free(entry->bstream);
+ entry->bstream = NULL;
+ return -1;
+}
+
+/******************************************************************************
+ * Alphabet-numeric data
+ *****************************************************************************/
+
+const signed char qrinput_an_table[128] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+/**
+ * Check the input data.
+ * @param size
+ * @param data
+ * @return result
+ */
+static int qrinput_check_mode_an(int size, const char *data)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (qrinput_look_an_table(data[i]) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Estimates the length of the encoded bit stream of alphabet-numeric data.
+ * @param size
+ * @return number of bits
+ */
+int qrinput_estimate_bits_mode_an(int size)
+{
+ int w;
+ int bits;
+
+ w = size / 2;
+ bits = w * 11;
+ if (size & 1)
+ bits += 6;
+
+ return bits;
+}
+
+/**
+ * Convert the alphabet-numeric data to a bit stream.
+ * @param entry
+ * @retval 0 success
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ * @throw EINVAL invalid version.
+ */
+static int qrinput_encode_mode_an(struct qrinput_list *entry, int version)
+{
+ int words, i, ret;
+ unsigned int val;
+
+ entry->bstream = bit_stream_new();
+ if (!entry->bstream)
+ return -1;
+
+ ret = bit_stream_append_num(entry->bstream, 4, QRSPEC_MODEID_AN);
+ if (ret < 0)
+ goto ABORT;
+ ret =
+ bit_stream_append_num(entry->bstream,
+ qrspec_length_indicator(QR_MODE_AN,
+ version),
+ entry->size);
+ if (ret < 0)
+ goto ABORT;
+
+ words = entry->size / 2;
+ for (i = 0; i < words; i++) {
+ val = qrinput_look_an_table(entry->data[i * 2]) * 45;
+ val += qrinput_look_an_table(entry->data[i * 2 + 1]);
+
+ ret = bit_stream_append_num(entry->bstream, 11, val);
+ if (ret < 0)
+ goto ABORT;
+ }
+
+ if (entry->size & 1) {
+ val = qrinput_look_an_table(entry->data[words * 2]);
+
+ ret = bit_stream_append_num(entry->bstream, 6, val);
+ if (ret < 0)
+ goto ABORT;
+ }
+
+ return 0;
+ABORT:
+ bit_stream_free(entry->bstream);
+ entry->bstream = NULL;
+ return -1;
+}
+
+/******************************************************************************
+ * 8 bit data
+ *****************************************************************************/
+
+/**
+ * Estimates the length of the encoded bit stream of 8 bit data.
+ * @param size
+ * @return number of bits
+ */
+int qrinput_estimate_bits_mode8(int size)
+{
+ return size * 8;
+}
+
+/**
+ * Convert the 8bits data to a bit stream.
+ * @param entry
+ * @retval 0 success
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ */
+static int qrinput_encode_mode8(struct qrinput_list *entry, int version)
+{
+ int ret;
+
+ entry->bstream = bit_stream_new();
+ if (!entry->bstream)
+ return -1;
+
+ ret = bit_stream_append_num(entry->bstream, 4, QRSPEC_MODEID_8);
+ if (ret < 0)
+ goto ABORT;
+ ret =
+ bit_stream_append_num(entry->bstream,
+ qrspec_length_indicator(QR_MODE_8,
+ version),
+ entry->size);
+ if (ret < 0)
+ goto ABORT;
+
+ ret = bit_stream_append_bytes(entry->bstream, entry->size, entry->data);
+ if (ret < 0)
+ goto ABORT;
+
+ return 0;
+ABORT:
+ bit_stream_free(entry->bstream);
+ entry->bstream = NULL;
+ return -1;
+}
+
+/******************************************************************************
+ * Structured Symbol
+ *****************************************************************************/
+
+/**
+ * Convert a structure symbol code to a bit stream.
+ * @param entry
+ * @retval 0 success
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ * @throw EINVAL invalid entry.
+ */
+static int qrinput_encode_mode_structure(struct qrinput_list *entry)
+{
+ int ret;
+
+ entry->bstream = bit_stream_new();
+ if (!entry->bstream)
+ return -1;
+
+ ret = bit_stream_append_num(entry->bstream, 4, QRSPEC_MODEID_STRUCTURE);
+ if (ret < 0)
+ goto ABORT;
+ ret = bit_stream_append_num(entry->bstream, 4, entry->data[1] - 1);
+ if (ret < 0)
+ goto ABORT;
+ ret = bit_stream_append_num(entry->bstream, 4, entry->data[0] - 1);
+ if (ret < 0)
+ goto ABORT;
+ ret = bit_stream_append_num(entry->bstream, 8, entry->data[2]);
+ if (ret < 0)
+ goto ABORT;
+
+ return 0;
+ABORT:
+ bit_stream_free(entry->bstream);
+ entry->bstream = NULL;
+ return -1;
+}
+
+/******************************************************************************
+ * FNC1
+ *****************************************************************************/
+
+static int qrinput_check_mode_fnc1_second(int size, const unsigned char *data)
+{
+ if (size != 1)
+ return -1;
+
+ return 0;
+}
+
+static int qrinput_encode_mode_fnc1_second(struct qrinput_list *entry,
+ int version)
+{
+ int ret;
+
+ entry->bstream = bit_stream_new();
+ if (!entry->bstream)
+ return -1;
+
+ ret = bit_stream_append_num(entry->bstream, 4,
+ QRSPEC_MODEID_FNC1SECOND);
+ if (ret < 0)
+ goto ABORT;
+
+ ret = bit_stream_append_bytes(entry->bstream, 1, entry->data);
+ if (ret < 0)
+ goto ABORT;
+
+ return 0;
+ABORT:
+ bit_stream_free(entry->bstream);
+ entry->bstream = NULL;
+ return -1;
+}
+
+/******************************************************************************
+ * ECI header
+ *****************************************************************************/
+static unsigned int qrinput_decode_eci_from_byte_array(unsigned char *data)
+{
+ int i;
+ unsigned int ecinum;
+
+ ecinum = 0;
+ for (i = 0; i < 4; i++) {
+ ecinum = ecinum << 8;
+ ecinum |= data[3 - i];
+ }
+
+ return ecinum;
+}
+
+int qrinput_estimate_bits_mode_eci(unsigned char *data)
+{
+ unsigned int ecinum;
+
+ ecinum = qrinput_decode_eci_from_byte_array(data);
+
+ /* See Table 4 of JISX 0510:2004 pp.17. */
+ if (ecinum < 128)
+ return MODE_INDICATOR_SIZE + 8;
+ else if (ecinum < 16384)
+ return MODE_INDICATOR_SIZE + 16;
+ else
+ return MODE_INDICATOR_SIZE + 24;
+}
+
+static int qrinput_encode_mode_eci(struct qrinput_list *entry, int version)
+{
+ int ret, words;
+ unsigned int ecinum, code;
+
+ entry->bstream = bit_stream_new();
+ if (!entry->bstream)
+ return -1;
+
+ ecinum = qrinput_decode_eci_from_byte_array(entry->data);
+
+ /* See Table 4 of JISX 0510:2004 pp.17. */
+ if (ecinum < 128) {
+ words = 1;
+ code = ecinum;
+ } else if (ecinum < 16384) {
+ words = 2;
+ code = 0x8000 + ecinum;
+ } else {
+ words = 3;
+ code = 0xc0000 + ecinum;
+ }
+
+ ret = bit_stream_append_num(entry->bstream, 4, QRSPEC_MODEID_ECI);
+ if (ret < 0)
+ goto ABORT;
+
+ ret = bit_stream_append_num(entry->bstream, words * 8, code);
+ if (ret < 0)
+ goto ABORT;
+
+ return 0;
+ABORT:
+ bit_stream_free(entry->bstream);
+ entry->bstream = NULL;
+ return -1;
+}
+
+/******************************************************************************
+ * Validation
+ *****************************************************************************/
+
+int qrinput_check(enum qrencode_mode mode, int size, const unsigned char *data)
+{
+ if ((mode == QR_MODE_FNC1FIRST && size < 0) || size <= 0)
+ return -1;
+
+ switch (mode) {
+ case QR_MODE_NUM:
+ return qrinput_check_mode_num(size, (const char *)data);
+ case QR_MODE_AN:
+ return qrinput_check_mode_an(size, (const char *)data);
+ case QR_MODE_8:
+ return 0;
+ case QR_MODE_STRUCTURE:
+ return 0;
+ case QR_MODE_ECI:
+ return 0;
+ case QR_MODE_FNC1FIRST:
+ return 0;
+ case QR_MODE_FNC1SECOND:
+ return qrinput_check_mode_fnc1_second(size, data);
+ case QR_MODE_NUL:
+ break;
+ }
+
+ return -1;
+}
+
+/******************************************************************************
+ * Estimation of the bit length
+ *****************************************************************************/
+
+/**
+ * Estimates the length of the encoded bit stream on the current version.
+ * @param entry
+ * @param version version of the symbol
+ * @return number of bits
+ */
+static int qrinput_estimate_bit_stream_size_of_entry(struct qrinput_list *entry,
+ int version)
+{
+ int bits = 0;
+ int l, m;
+ int num;
+
+ if (version == 0)
+ version = 1;
+
+ switch (entry->mode) {
+ case QR_MODE_NUM:
+ bits = qrinput_estimate_bits_mode_num(entry->size);
+ break;
+ case QR_MODE_AN:
+ bits = qrinput_estimate_bits_mode_an(entry->size);
+ break;
+ case QR_MODE_8:
+ bits = qrinput_estimate_bits_mode8(entry->size);
+ break;
+ case QR_MODE_STRUCTURE:
+ return STRUCTURE_HEADER_SIZE;
+ case QR_MODE_ECI:
+ bits = qrinput_estimate_bits_mode_eci(entry->data);
+ break;
+ case QR_MODE_FNC1FIRST:
+ return MODE_INDICATOR_SIZE;
+ case QR_MODE_FNC1SECOND:
+ return MODE_INDICATOR_SIZE + 8;
+ default:
+ return 0;
+ }
+
+ l = qrspec_length_indicator(entry->mode, version);
+ m = 1 << l;
+ num = (entry->size + m - 1) / m;
+
+ bits += num * (MODE_INDICATOR_SIZE + l);
+
+ return bits;
+}
+
+/**
+ * Estimates the length of the encoded bit stream of the data.
+ * @param input input data
+ * @param version version of the symbol
+ * @return number of bits
+ */
+static int qrinput_estimate_bit_stream_size(struct qrinput *input, int version)
+{
+ struct qrinput_list *list;
+ int bits = 0;
+
+ list = input->head;
+ while (list) {
+ bits +=
+ qrinput_estimate_bit_stream_size_of_entry(list, version);
+ list = list->next;
+ }
+
+ return bits;
+}
+
+/**
+ * Estimates the required version number of the symbol.
+ * @param input input data
+ * @return required version number
+ */
+static int qrinput_estimate_version(struct qrinput *input)
+{
+ int bits;
+ int version, prev;
+
+ version = 0;
+ do {
+ prev = version;
+ bits = qrinput_estimate_bit_stream_size(input, prev);
+ version =
+ qrspec_get_minimum_version((bits + 7) / 8, input->level);
+ if (version < 0)
+ return -1;
+ } while (version > prev);
+
+ return version;
+}
+
+/**
+ * Returns required length in bytes for specified mode, version and bits.
+ * @param mode
+ * @param version
+ * @param bits
+ * @return required length of code words in bytes.
+ */
+static int qrinput_length_of_code(enum qrencode_mode mode, int version,
+ int bits)
+{
+ int payload, size, chunks, remain, maxsize;
+
+ payload = bits - 4 - qrspec_length_indicator(mode, version);
+ switch (mode) {
+ case QR_MODE_NUM:
+ chunks = payload / 10;
+ remain = payload - chunks * 10;
+ size = chunks * 3;
+ if (remain >= 7)
+ size += 2;
+ else if (remain >= 4)
+ size += 1;
+ break;
+ case QR_MODE_AN:
+ chunks = payload / 11;
+ remain = payload - chunks * 11;
+ size = chunks * 2;
+ if (remain >= 6)
+ size++;
+ break;
+ case QR_MODE_8:
+ size = payload / 8;
+ break;
+ case QR_MODE_STRUCTURE:
+ size = payload / 8;
+ break;
+ default:
+ size = 0;
+ break;
+ }
+ maxsize = qrspec_maximum_words(mode, version);
+ if (size < 0)
+ size = 0;
+ if (maxsize > 0 && size > maxsize)
+ size = maxsize;
+
+ return size;
+}
+
+/******************************************************************************
+ * Data conversion
+ *****************************************************************************/
+
+/**
+ * Convert the input data in the data chunk to a bit stream.
+ * @param entry
+ * @return number of bits (>0) or -1 for failure.
+ */
+static int qrinput_encode_bit_stream(struct qrinput_list *entry, int version)
+{
+ int words, ret;
+ struct qrinput_list *st1 = NULL, *st2 = NULL;
+
+ if (entry->bstream) {
+ bit_stream_free(entry->bstream);
+ entry->bstream = NULL;
+ }
+
+ words = qrspec_maximum_words(entry->mode, version);
+ if (words != 0 && entry->size > words) {
+ st1 = qrinput_list_new_entry(entry->mode, words, entry->data);
+ if (!st1)
+ goto ABORT;
+ st2 =
+ qrinput_list_new_entry(entry->mode, entry->size - words,
+ &entry->data[words]);
+ if (!st2)
+ goto ABORT;
+
+ ret = qrinput_encode_bit_stream(st1, version);
+ if (ret < 0)
+ goto ABORT;
+ ret = qrinput_encode_bit_stream(st2, version);
+ if (ret < 0)
+ goto ABORT;
+ entry->bstream = bit_stream_new();
+ if (!entry->bstream)
+ goto ABORT;
+ ret = bit_stream_append(entry->bstream, st1->bstream);
+ if (ret < 0)
+ goto ABORT;
+ ret = bit_stream_append(entry->bstream, st2->bstream);
+ if (ret < 0)
+ goto ABORT;
+ qrinput_list_free_entry(st1);
+ qrinput_list_free_entry(st2);
+ } else {
+ ret = 0;
+ switch (entry->mode) {
+ case QR_MODE_NUM:
+ ret = qrinput_encode_mode_num(entry, version);
+ break;
+ case QR_MODE_AN:
+ ret = qrinput_encode_mode_an(entry, version);
+ break;
+ case QR_MODE_8:
+ ret = qrinput_encode_mode8(entry, version);
+ break;
+ case QR_MODE_STRUCTURE:
+ ret = qrinput_encode_mode_structure(entry);
+ break;
+ case QR_MODE_ECI:
+ ret = qrinput_encode_mode_eci(entry, version);
+ break;
+ case QR_MODE_FNC1SECOND:
+ ret = qrinput_encode_mode_fnc1_second(entry, version);
+ break;
+ default:
+ break;
+ }
+ if (ret < 0)
+ return -1;
+ }
+
+ return bit_stream_size(entry->bstream);
+ABORT:
+ qrinput_list_free_entry(st1);
+ qrinput_list_free_entry(st2);
+ return -1;
+}
+
+/**
+ * Convert the input data to a bit stream.
+ * @param input input data.
+ * @retval 0 success
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ */
+static int qrinput_create_bit_stream(struct qrinput *input)
+{
+ struct qrinput_list *list;
+ int bits, total = 0;
+
+ list = input->head;
+ while (list) {
+ bits =
+ qrinput_encode_bit_stream(list, input->version);
+ if (bits < 0)
+ return -1;
+ total += bits;
+ list = list->next;
+ }
+
+ return total;
+}
+
+/**
+ * Convert the input data to a bit stream.
+ * When the version number is given and that is not sufficient, it is increased
+ * automatically.
+ * @param input input data.
+ * @retval 0 success
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ENOMEM unable to allocate memory.
+ * @throw ERANGE input is too large.
+ */
+static int qrinput_convert_data(struct qrinput *input)
+{
+ int bits;
+ int ver;
+
+ ver = qrinput_estimate_version(input);
+ if (ver > qrinput_get_version(input))
+ qrinput_set_version(input, ver);
+
+ for (;;) {
+ bits = qrinput_create_bit_stream(input);
+ if (bits < 0)
+ return -1;
+ ver = qrspec_get_minimum_version((bits + 7) / 8, input->level);
+ if (ver < 0)
+ return -1;
+ else if (ver > qrinput_get_version(input))
+ qrinput_set_version(input, ver);
+ else
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * Append padding bits for the input data.
+ * @param bstream Bitstream to be appended.
+ * @param input input data.
+ * @retval 0 success
+ * @retval -1 an error occurred and errno is set to indeicate the error.
+ * See Execptions for the details.
+ * @throw ERANGE input data is too large.
+ * @throw ENOMEM unable to allocate memory.
+ */
+static int qrinput_append_padding_bit(struct bit_stream *bstream,
+ struct qrinput *input)
+{
+ int bits, maxbits, words, maxwords, i, ret;
+ struct bit_stream *padding = NULL;
+ unsigned char *padbuf;
+ int padlen;
+
+ bits = bit_stream_size(bstream);
+ maxwords = qrspec_get_data_length(input->version, input->level);
+ maxbits = maxwords * 8;
+
+ if (maxbits < bits)
+ return -1;
+
+ if (maxbits == bits)
+ return 0;
+
+ if (maxbits - bits <= 4) {
+ ret = bit_stream_append_num(bstream, maxbits - bits, 0);
+ goto DONE;
+ }
+
+ words = (bits + 4 + 7) / 8;
+
+ padding = bit_stream_new();
+ if (!padding)
+ return -1;
+ ret = bit_stream_append_num(padding, words * 8 - bits, 0);
+ if (ret < 0)
+ goto DONE;
+
+ padlen = maxwords - words;
+ if (padlen > 0) {
+ padbuf = kmalloc(padlen, GFP_ATOMIC);
+ if (!padbuf) {
+ ret = -1;
+ goto DONE;
+ }
+ for (i = 0; i < padlen; i++)
+ padbuf[i] = (i & 1) ? 0x11 : 0xec;
+ ret = bit_stream_append_bytes(padding, padlen, padbuf);
+ kfree(padbuf);
+ if (ret < 0)
+ goto DONE;
+ }
+
+ ret = bit_stream_append(bstream, padding);
+
+DONE:
+ bit_stream_free(padding);
+ return ret;
+}
+
+static int qrinput_insert_fnc1_header(struct qrinput *input)
+{
+ struct qrinput_list *entry = NULL;
+
+ if (input->fnc1 == 1) {
+ entry = qrinput_list_new_entry(QR_MODE_FNC1FIRST, 0, NULL);
+ } else if (input->fnc1 == 2) {
+ entry =
+ qrinput_list_new_entry(QR_MODE_FNC1SECOND, 1,
+ &input->appid);
+ }
+ if (!entry)
+ return -1;
+
+ if (input->head->mode != QR_MODE_STRUCTURE ||
+ input->head->mode != QR_MODE_ECI) {
+ entry->next = input->head;
+ input->head = entry;
+ } else {
+ entry->next = input->head->next;
+ input->head->next = entry;
+ }
+
+ return 0;
+}
+
+/**
+ * Merge all bit streams in the input data.
+ * @param input input data.
+ * @return merged bit stream
+ */
+
+static struct bit_stream *qrinput_merge_bit_stream(struct qrinput *input)
+{
+ struct bit_stream *bstream;
+ struct qrinput_list *list;
+ int ret;
+
+ if (input->fnc1) {
+ if (qrinput_insert_fnc1_header(input) < 0)
+ return NULL;
+ }
+ if (qrinput_convert_data(input) < 0)
+ return NULL;
+
+ bstream = bit_stream_new();
+ if (!bstream)
+ return NULL;
+
+ list = input->head;
+ while (list) {
+ ret = bit_stream_append(bstream, list->bstream);
+ if (ret < 0) {
+ bit_stream_free(bstream);
+ return NULL;
+ }
+ list = list->next;
+ }
+
+ return bstream;
+}
+
+/**
+ * Merge all bit streams in the input data and append padding bits
+ * @param input input data.
+ * @return padded merged bit stream
+ */
+
+static struct bit_stream *qrinput_get_bit_stream(struct qrinput *input)
+{
+ struct bit_stream *bstream;
+ int ret;
+
+ bstream = qrinput_merge_bit_stream(input);
+ if (!bstream)
+ return NULL;
+
+ ret = qrinput_append_padding_bit(bstream, input);
+
+ if (ret < 0) {
+ bit_stream_free(bstream);
+ return NULL;
+ }
+
+ return bstream;
+}
+
+/**
+ * Pack all bit streams padding bits into a byte array.
+ * @param input input data.
+ * @return padded merged byte stream
+ */
+
+unsigned char *qrinput_get_byte_stream(struct qrinput *input)
+{
+ struct bit_stream *bstream;
+ unsigned char *array;
+
+ bstream = qrinput_get_bit_stream(input);
+ if (!bstream)
+ return NULL;
+
+ array = bit_stream_to_byte(bstream);
+ bit_stream_free(bstream);
+
+ return array;
+}
+
+/******************************************************************************
+ * Structured input data
+ *****************************************************************************/
+
+static struct qrinput_input_list *qrinput_input_list_new_entry(struct qrinput
+ *input)
+{
+ struct qrinput_input_list *entry;
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry)
+ return NULL;
+
+ entry->input = input;
+ entry->next = NULL;
+
+ return entry;
+}
+
+static void qrinput_input_list_free_entry(struct qrinput_input_list *entry)
+{
+ if (entry) {
+ qrinput_free(entry->input);
+ kfree(entry);
+ }
+}
+
+struct qrinput_struct *qrinput_struct_new(void)
+{
+ struct qrinput_struct *s;
+
+ s = kmalloc(sizeof(*s), GFP_ATOMIC);
+ if (!s)
+ return NULL;
+
+ s->size = 0;
+ s->parity = -1;
+ s->head = NULL;
+ s->tail = NULL;
+
+ return s;
+}
+
+void qrinput_struct_set_parity(struct qrinput_struct *s, unsigned char parity)
+{
+ s->parity = (int)parity;
+}
+
+int qrinput_struct_append_input(struct qrinput_struct *s, struct qrinput *input)
+{
+ struct qrinput_input_list *e;
+
+ e = qrinput_input_list_new_entry(input);
+ if (!e)
+ return -1;
+
+ s->size++;
+ if (!s->tail) {
+ s->head = e;
+ s->tail = e;
+ } else {
+ s->tail->next = e;
+ s->tail = e;
+ }
+
+ return s->size;
+}
+
+void qrinput_struct_free(struct qrinput_struct *s)
+{
+ struct qrinput_input_list *list, *next;
+
+ if (s) {
+ list = s->head;
+ while (list) {
+ next = list->next;
+ qrinput_input_list_free_entry(list);
+ list = next;
+ }
+ kfree(s);
+ }
+}
+
+static unsigned char qrinput_struct_calc_parity(struct qrinput_struct *s)
+{
+ struct qrinput_input_list *list;
+ unsigned char parity = 0;
+
+ list = s->head;
+ while (list) {
+ parity ^= qrinput_calc_parity(list->input);
+ list = list->next;
+ }
+
+ qrinput_struct_set_parity(s, parity);
+
+ return parity;
+}
+
+static int qrinput_list_shrink_entry(struct qrinput_list *entry, int bytes)
+{
+ unsigned char *data;
+
+ data = kmalloc(bytes, GFP_ATOMIC);
+ if (!data)
+ return -1;
+
+ memcpy(data, entry->data, bytes);
+ kfree(entry->data);
+ entry->data = data;
+ entry->size = bytes;
+
+ return 0;
+}
+
+static int qrinput_split_entry(struct qrinput_list *entry, int bytes)
+{
+ struct qrinput_list *e;
+ int ret;
+
+ e = qrinput_list_new_entry(entry->mode, entry->size - bytes,
+ entry->data + bytes);
+ if (!e)
+ return -1;
+
+ ret = qrinput_list_shrink_entry(entry, bytes);
+ if (ret < 0) {
+ qrinput_list_free_entry(e);
+ return -1;
+ }
+
+ e->next = entry->next;
+ entry->next = e;
+
+ return 0;
+}
+
+struct qrinput_struct *qrinput_split_qrinput_to_struct(struct qrinput *input)
+{
+ struct qrinput *p;
+ struct qrinput_struct *s;
+ int bits, maxbits, nextbits, bytes, ret;
+ struct qrinput_list *list, *next, *prev;
+
+ s = qrinput_struct_new();
+ if (!s)
+ return NULL;
+
+ input = qrinput_dup(input);
+ if (!input) {
+ qrinput_struct_free(s);
+ return NULL;
+ }
+
+ qrinput_struct_set_parity(s, qrinput_calc_parity(input));
+ maxbits =
+ qrspec_get_data_length(input->version,
+ input->level) * 8 - STRUCTURE_HEADER_SIZE;
+
+ if (maxbits <= 0) {
+ qrinput_struct_free(s);
+ qrinput_free(input);
+ return NULL;
+ }
+
+ bits = 0;
+ list = input->head;
+ prev = NULL;
+ while (list) {
+ nextbits = qrinput_estimate_bit_stream_size_of_entry
+ (list, input->version);
+ if (bits + nextbits <= maxbits) {
+ ret =
+ qrinput_encode_bit_stream(list, input->version);
+ if (ret < 0)
+ goto ABORT;
+ bits += ret;
+ prev = list;
+ list = list->next;
+ } else {
+ bytes =
+ qrinput_length_of_code(list->mode, input->version,
+ maxbits - bits);
+ p = qrinput_new2(input->version, input->level);
+ if (!p)
+ goto ABORT;
+ if (bytes > 0) {
+ /* Splits this entry into 2 entries. */
+ ret = qrinput_split_entry(list, bytes);
+ if (ret < 0) {
+ qrinput_free(p);
+ goto ABORT;
+ }
+ /*
+ * First half is the tail
+ * of the current input.
+ */
+ next = list->next;
+ list->next = NULL;
+ /*
+ * Second half is the head
+ * of the next input, p.
+ */
+ p->head = next;
+ /* Renew qrinput.tail. */
+ p->tail = input->tail;
+ input->tail = list;
+ /* Point to the next entry. */
+ prev = list;
+ list = next;
+ } else {
+ /* Current entry will go to the next input. */
+ prev->next = NULL;
+ p->head = list;
+ p->tail = input->tail;
+ input->tail = prev;
+ }
+ ret = qrinput_struct_append_input(s, input);
+ if (ret < 0) {
+ qrinput_free(p);
+ goto ABORT;
+ }
+ input = p;
+ bits = 0;
+ }
+ }
+ ret = qrinput_struct_append_input(s, input);
+ if (ret < 0)
+ goto ABORT;
+ if (s->size > MAX_STRUCTURED_SYMBOLS) {
+ qrinput_struct_free(s);
+ return NULL;
+ }
+ ret = qrinput_struct_insert_structured_append_headers(s);
+ if (ret < 0) {
+ qrinput_struct_free(s);
+ return NULL;
+ }
+
+ return s;
+
+ABORT:
+ qrinput_free(input);
+ qrinput_struct_free(s);
+ return NULL;
+}
+
+int qrinput_struct_insert_structured_append_headers(struct qrinput_struct *s)
+{
+ int num, i;
+ struct qrinput_input_list *list;
+
+ if (s->parity < 0)
+ qrinput_struct_calc_parity(s);
+ num = 0;
+ list = s->head;
+ while (list) {
+ num++;
+ list = list->next;
+ }
+ i = 1;
+ list = s->head;
+ while (list) {
+ if (qrinput_insert_structured_append_header
+ (list->input, num, i, s->parity))
+ return -1;
+ i++;
+ list = list->next;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ * Extended encoding mode (FNC1 and ECI)
+ *****************************************************************************/
+
+int qrinput_set_fnc1_first(struct qrinput *input)
+{
+ input->fnc1 = 1;
+
+ return 0;
+}
+
+int qrinput_set_fnc1_second(struct qrinput *input, unsigned char appid)
+{
+ input->fnc1 = 2;
+ input->appid = appid;
+
+ return 0;
+}
diff --git a/lib/qr/qrinput.h b/lib/qr/qrinput.h
new file mode 100644
index 0000000..37896ff
--- /dev/null
+++ b/lib/qr/qrinput.h
@@ -0,0 +1,115 @@
+/*
+ * qrencode - QR Code encoder
+ *
+ * Input data chunk class
+ * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __QRINPUT_H__
+#define __QRINPUT_H__
+
+#include <linux/qrencode.h>
+#include "bitstream.h"
+
+int qrinput_is_splittable_mode(enum qrencode_mode mode);
+
+/******************************************************************************
+ * Entry of input data
+ *****************************************************************************/
+struct qrinput_list {
+ enum qrencode_mode mode;
+ int size; /* Size of data chunk (byte). */
+ unsigned char *data; /* Data chunk. */
+ struct bit_stream *bstream;
+ struct qrinput_list *next;
+};
+
+/******************************************************************************
+ * Input Data
+ *****************************************************************************/
+
+/**
+ * Singly linked list to contain input strings. An instance of this class
+ * contains its version and error correction level too. It is required to
+ * set them by qrinput_set_version() and qrinput_set_error_correction_level(),
+ * or use qrinput_new2() to instantiate an object.
+ */
+struct qrinput {
+ int version;
+ enum qrec_level level;
+ struct qrinput_list *head;
+ struct qrinput_list *tail;
+ int fnc1;
+ unsigned char appid;
+};
+
+/******************************************************************************
+ * Structured append input data
+ *****************************************************************************/
+
+struct qrinput_input_list {
+ struct qrinput *input;
+ struct qrinput_input_list *next;
+};
+
+/**
+ * Set of qrinput for structured symbols.
+ */
+struct qrinput_struct {
+ int size; /* number of structured symbols */
+ int parity;
+ struct qrinput_input_list *head;
+ struct qrinput_input_list *tail;
+};
+
+/**
+ * Pack all bit streams padding bits into a byte array.
+ * @param input input data.
+ * @return padded merged byte stream
+ */
+unsigned char *qrinput_get_byte_stream(struct qrinput *input);
+
+int qrinput_estimate_bits_mode_num(int size);
+int qrinput_estimate_bits_mode_an(int size);
+int qrinput_estimate_bits_mode8(int size);
+int qrinput_estimate_bits_mode_kanji(int size);
+
+struct qrinput *qrinput_dup(struct qrinput *input);
+
+extern const signed char qrinput_an_table[128];
+
+/**
+ * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
+ * @param __c__ character
+ * @return value
+ */
+#define qrinput_look_an_table(__c__) \
+ ((__c__ & 0x80) ? -1 : qrinput_an_table[(int)__c__])
+
+/**
+ * Length of a standard mode indicator in bits.
+ */
+#define MODE_INDICATOR_SIZE 4
+
+/**
+ * Length of a segment of structured-append header.
+ */
+#define STRUCTURE_HEADER_SIZE 20
+
+/**
+ * Maximum number of symbols in a set of structured-appended symbols.
+ */
+#define MAX_STRUCTURED_SYMBOLS 16
+
+#endif /* __QRINPUT_H__ */
diff --git a/lib/qr/qrspec.c b/lib/qr/qrspec.c
new file mode 100644
index 0000000..ed753af
--- /dev/null
+++ b/lib/qr/qrspec.c
@@ -0,0 +1,542 @@
+/*
+ * qrencode - QR Code encoder
+ *
+ * QR Code specification in convenient format.
+ * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ *
+ * The following data / specifications are taken from
+ * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
+ * or
+ * "Automatic identification and data capture techniques --
+ * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "qrspec.h"
+#include "qrinput.h"
+
+/******************************************************************************
+ * Version and capacity
+ *****************************************************************************/
+
+struct qrspec_capacity {
+ int width; /* Edge length of the symbol */
+ int words; /* Data capacity (bytes) */
+ int remainder; /* Remainder bit (bits) */
+ int ec[4]; /* Number of ECC code (bytes) */
+};
+
+/**
+ * Table of the capacity of symbols
+ * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
+ */
+static
+const struct qrspec_capacity qrspec_capacities[QRSPEC_VERSION_MAX + 1] = {
+ {0, 0, 0, {0, 0, 0, 0} },
+ {21, 26, 0, {7, 10, 13, 17} }, /* 1 */
+ {25, 44, 7, {10, 16, 22, 28} },
+ {29, 70, 7, {15, 26, 36, 44} },
+ {33, 100, 7, {20, 36, 52, 64} },
+ {37, 134, 7, {26, 48, 72, 88} }, /* 5 */
+ {41, 172, 7, {36, 64, 96, 112} },
+ {45, 196, 0, {40, 72, 108, 130} },
+ {49, 242, 0, {48, 88, 132, 156} },
+ {53, 292, 0, {60, 110, 160, 192} },
+ {57, 346, 0, {72, 130, 192, 224} }, /* 10 */
+ {61, 404, 0, {80, 150, 224, 264} },
+ {65, 466, 0, {96, 176, 260, 308} },
+ {69, 532, 0, {104, 198, 288, 352} },
+ {73, 581, 3, {120, 216, 320, 384} },
+ {77, 655, 3, {132, 240, 360, 432} }, /* 15 */
+ {81, 733, 3, {144, 280, 408, 480} },
+ {85, 815, 3, {168, 308, 448, 532} },
+ {89, 901, 3, {180, 338, 504, 588} },
+ {93, 991, 3, {196, 364, 546, 650} },
+ {97, 1085, 3, {224, 416, 600, 700} }, /* 20 */
+ {101, 1156, 4, {224, 442, 644, 750} },
+ {105, 1258, 4, {252, 476, 690, 816} },
+ {109, 1364, 4, {270, 504, 750, 900} },
+ {113, 1474, 4, {300, 560, 810, 960} },
+ {117, 1588, 4, {312, 588, 870, 1050} }, /* 25 */
+ {121, 1706, 4, {336, 644, 952, 1110} },
+ {125, 1828, 4, {360, 700, 1020, 1200} },
+ {129, 1921, 3, {390, 728, 1050, 1260} },
+ {133, 2051, 3, {420, 784, 1140, 1350} },
+ {137, 2185, 3, {450, 812, 1200, 1440} }, /* 30 */
+ {141, 2323, 3, {480, 868, 1290, 1530} },
+ {145, 2465, 3, {510, 924, 1350, 1620} },
+ {149, 2611, 3, {540, 980, 1440, 1710} },
+ {153, 2761, 3, {570, 1036, 1530, 1800} },
+ {157, 2876, 0, {570, 1064, 1590, 1890} }, /*35 */
+ {161, 3034, 0, {600, 1120, 1680, 1980} },
+ {165, 3196, 0, {630, 1204, 1770, 2100} },
+ {169, 3362, 0, {660, 1260, 1860, 2220} },
+ {173, 3532, 0, {720, 1316, 1950, 2310} },
+ {177, 3706, 0, {750, 1372, 2040, 2430} } /* 40 */
+};
+
+int qrspec_get_data_length(int version, enum qrec_level level)
+{
+ return qrspec_capacities[version].words -
+ qrspec_capacities[version].ec[level];
+}
+
+int qrspec_get_ecc_length(int version, enum qrec_level level)
+{
+ return qrspec_capacities[version].ec[level];
+}
+
+int qrspec_get_minimum_version(int size, enum qrec_level level)
+{
+ int i;
+ int words;
+
+ for (i = 1; i <= QRSPEC_VERSION_MAX; i++) {
+ words = qrspec_capacities[i].words -
+ qrspec_capacities[i].ec[level];
+ if (words >= size)
+ return i;
+ }
+
+ return -1;
+}
+
+int qrspec_get_width(int version)
+{
+ return qrspec_capacities[version].width;
+}
+
+int qrspec_get_remainder(int version)
+{
+ return qrspec_capacities[version].remainder;
+}
+
+/******************************************************************************
+ * Length indicator
+ *****************************************************************************/
+
+static const int length_table_bits[4][3] = {
+ {10, 12, 14},
+ {9, 11, 13},
+ {8, 16, 16},
+ {8, 10, 12}
+};
+
+int qrspec_length_indicator(enum qrencode_mode mode, int version)
+{
+ int l;
+
+ if (!qrinput_is_splittable_mode(mode))
+ return 0;
+ if (version <= 9)
+ l = 0;
+ else if (version <= 26)
+ l = 1;
+ else
+ l = 2;
+
+ return length_table_bits[mode][l];
+}
+
+int qrspec_maximum_words(enum qrencode_mode mode, int version)
+{
+ int l;
+ int bits;
+ int words;
+
+ if (!qrinput_is_splittable_mode(mode))
+ return 0;
+ if (version <= 9)
+ l = 0;
+ else if (version <= 26)
+ l = 1;
+ else
+ l = 2;
+
+ bits = length_table_bits[mode][l];
+ words = (1 << bits) - 1;
+
+ return words;
+}
+
+/******************************************************************************
+ * Error correction code
+ *****************************************************************************/
+
+/**
+ * Table of the error correction code (Reed-Solomon block)
+ * See Table 12-16 (pp.30-36), JIS X0510:2004.
+ */
+static const int ecc_table[QRSPEC_VERSION_MAX + 1][4][2] = {
+ {{0, 0}, {0, 0}, {0, 0}, {0, 0} },
+ {{1, 0}, {1, 0}, {1, 0}, {1, 0} }, /* 1 */
+ {{1, 0}, {1, 0}, {1, 0}, {1, 0} },
+ {{1, 0}, {1, 0}, {2, 0}, {2, 0} },
+ {{1, 0}, {2, 0}, {2, 0}, {4, 0} },
+ {{1, 0}, {2, 0}, {2, 2}, {2, 2} }, /* 5 */
+ {{2, 0}, {4, 0}, {4, 0}, {4, 0} },
+ {{2, 0}, {4, 0}, {2, 4}, {4, 1} },
+ {{2, 0}, {2, 2}, {4, 2}, {4, 2} },
+ {{2, 0}, {3, 2}, {4, 4}, {4, 4} },
+ {{2, 2}, {4, 1}, {6, 2}, {6, 2} }, /* 10 */
+ {{4, 0}, {1, 4}, {4, 4}, {3, 8} },
+ {{2, 2}, {6, 2}, {4, 6}, {7, 4} },
+ {{4, 0}, {8, 1}, {8, 4}, {12, 4} },
+ {{3, 1}, {4, 5}, {11, 5}, {11, 5} },
+ {{5, 1}, {5, 5}, {5, 7}, {11, 7} }, /* 15 */
+ {{5, 1}, {7, 3}, {15, 2}, {3, 13} },
+ {{1, 5}, {10, 1}, {1, 15}, {2, 17} },
+ {{5, 1}, {9, 4}, {17, 1}, {2, 19} },
+ {{3, 4}, {3, 11}, {17, 4}, {9, 16} },
+ {{3, 5}, {3, 13}, {15, 5}, {15, 10} }, /* 20 */
+ {{4, 4}, {17, 0}, {17, 6}, {19, 6} },
+ {{2, 7}, {17, 0}, {7, 16}, {34, 0} },
+ {{4, 5}, {4, 14}, {11, 14}, {16, 14} },
+ {{6, 4}, {6, 14}, {11, 16}, {30, 2} },
+ {{8, 4}, {8, 13}, {7, 22}, {22, 13} }, /* 25 */
+ {{10, 2}, {19, 4}, {28, 6}, {33, 4} },
+ {{8, 4}, {22, 3}, {8, 26}, {12, 28} },
+ {{3, 10}, {3, 23}, {4, 31}, {11, 31} },
+ {{7, 7}, {21, 7}, {1, 37}, {19, 26} },
+ {{5, 10}, {19, 10}, {15, 25}, {23, 25} }, /* 30 */
+ {{13, 3}, {2, 29}, {42, 1}, {23, 28} },
+ {{17, 0}, {10, 23}, {10, 35}, {19, 35} },
+ {{17, 1}, {14, 21}, {29, 19}, {11, 46} },
+ {{13, 6}, {14, 23}, {44, 7}, {59, 1} },
+ {{12, 7}, {12, 26}, {39, 14}, {22, 41} }, /* 35 */
+ {{6, 14}, {6, 34}, {46, 10}, {2, 64} },
+ {{17, 4}, {29, 14}, {49, 10}, {24, 46} },
+ {{4, 18}, {13, 32}, {48, 14}, {42, 32} },
+ {{20, 4}, {40, 7}, {43, 22}, {10, 67} },
+ {{19, 6}, {18, 31}, {34, 34}, {20, 61} }, /* 40 */
+};
+
+void qrspec_get_ecc_spec(int version, enum qrec_level level, int spec[5])
+{
+ int b1, b2;
+ int data, ecc;
+
+ b1 = ecc_table[version][level][0];
+ b2 = ecc_table[version][level][1];
+ data = qrspec_get_data_length(version, level);
+ ecc = qrspec_get_ecc_length(version, level);
+
+ if (b2 == 0) {
+ spec[0] = b1;
+ spec[1] = data / b1;
+ spec[2] = ecc / b1;
+ spec[3] = 0;
+ spec[4] = 0;
+ } else {
+ spec[0] = b1;
+ spec[1] = data / (b1 + b2);
+ spec[2] = ecc / (b1 + b2);
+ spec[3] = b2;
+ spec[4] = spec[1] + 1;
+ }
+}
+
+/******************************************************************************
+ * Alignment pattern
+ *****************************************************************************/
+
+/**
+ * Positions of alignment patterns.
+ * This array includes only the second and the third position of the alignment
+ * patterns. Rest of them can be calculated from the distance between them.
+ *
+ * See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
+ */
+static const int alignment_pattern[QRSPEC_VERSION_MAX + 1][2] = {
+ {0, 0},
+ {0, 0}, {18, 0}, {22, 0}, {26, 0}, {30, 0}, /* 1-5 */
+ {34, 0}, {22, 38}, {24, 42}, {26, 46}, {28, 50}, /* 6-10 */
+ {30, 54}, {32, 58}, {34, 62}, {26, 46}, {26, 48}, /* 11-15 */
+ {26, 50}, {30, 54}, {30, 56}, {30, 58}, {34, 62}, /* 16-20 */
+ {28, 50}, {26, 50}, {30, 54}, {28, 54}, {32, 58}, /* 21-25 */
+ {30, 58}, {34, 62}, {26, 50}, {30, 54}, {26, 52}, /* 26-30 */
+ {30, 56}, {34, 60}, {30, 58}, {34, 62}, {30, 54}, /* 31-35 */
+ {24, 50}, {28, 54}, {32, 58}, {26, 54}, {30, 58}, /* 35-40 */
+};
+
+/**
+ * Put an alignment marker.
+ * @param frame
+ * @param width
+ * @param ox,oy center coordinate of the pattern
+ */
+static void qrspec_put_alignment_marker(unsigned char *frame, int width, int ox,
+ int oy)
+{
+ static const unsigned char finder[] = {
+ 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+ 0xa1, 0xa0, 0xa0, 0xa0, 0xa1,
+ 0xa1, 0xa0, 0xa1, 0xa0, 0xa1,
+ 0xa1, 0xa0, 0xa0, 0xa0, 0xa1,
+ 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+ };
+ int x, y;
+ const unsigned char *s;
+
+ frame += (oy - 2) * width + ox - 2;
+ s = finder;
+ for (y = 0; y < 5; y++) {
+ for (x = 0; x < 5; x++)
+ frame[x] = s[x];
+ frame += width;
+ s += 5;
+ }
+}
+
+static void qrspec_put_alignment_pattern(int version, unsigned char *frame,
+ int width)
+{
+ int d, w, x, y, cx, cy;
+
+ if (version < 2)
+ return;
+
+ d = alignment_pattern[version][1] - alignment_pattern[version][0];
+ if (d < 0)
+ w = 2;
+ else
+ w = (width - alignment_pattern[version][0]) / d + 2;
+
+ if (w * w - 3 == 1) {
+ x = alignment_pattern[version][0];
+ y = alignment_pattern[version][0];
+ qrspec_put_alignment_marker(frame, width, x, y);
+ return;
+ }
+
+ cx = alignment_pattern[version][0];
+ for (x = 1; x < w - 1; x++) {
+ qrspec_put_alignment_marker(frame, width, 6, cx);
+ qrspec_put_alignment_marker(frame, width, cx, 6);
+ cx += d;
+ }
+
+ cy = alignment_pattern[version][0];
+ for (y = 0; y < w - 1; y++) {
+ cx = alignment_pattern[version][0];
+ for (x = 0; x < w - 1; x++) {
+ qrspec_put_alignment_marker(frame, width, cx, cy);
+ cx += d;
+ }
+ cy += d;
+ }
+}
+
+/******************************************************************************
+ * Version information pattern
+ *****************************************************************************/
+
+/**
+ * Version information pattern (BCH coded).
+ * See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
+ */
+static const unsigned int version_pattern[QRSPEC_VERSION_MAX - 6] = {
+ 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,
+ 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,
+ 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
+ 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,
+ 0x27541, 0x28c69
+};
+
+unsigned int qrspec_get_version_pattern(int version)
+{
+ if (version < 7 || version > QRSPEC_VERSION_MAX)
+ return 0;
+
+ return version_pattern[version - 7];
+}
+
+/******************************************************************************
+ * Format information
+ *****************************************************************************/
+
+/* See calcFormatInfo in tests/test_qrspec.c */
+static const unsigned int format_info[4][8] = {
+ {0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976},
+ {0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0},
+ {0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed},
+ {0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b}
+};
+
+unsigned int qrspec_get_format_info(int mask, enum qrec_level level)
+{
+ if (mask < 0 || mask > 7)
+ return 0;
+
+ return format_info[level][mask];
+}
+
+/******************************************************************************
+ * Frame
+ *****************************************************************************/
+
+/**
+ * Cache of initial frames.
+ */
+/* C99 says that static storage shall be initialized to a null pointer
+ * by compiler. */
+static unsigned char *frames[QRSPEC_VERSION_MAX + 1];
+
+/**
+ * Put a finder pattern.
+ * @param frame
+ * @param width
+ * @param ox,oy upper-left coordinate of the pattern
+ */
+static void put_finder_pattern(unsigned char *frame, int width, int ox, int oy)
+{
+ static const unsigned char finder[] = {
+ 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
+ 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
+ 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
+ 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
+ 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1,
+ 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1,
+ 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
+ };
+ int x, y;
+ const unsigned char *s;
+
+ frame += oy * width + ox;
+ s = finder;
+ for (y = 0; y < 7; y++) {
+ for (x = 0; x < 7; x++)
+ frame[x] = s[x];
+ frame += width;
+ s += 7;
+ }
+}
+
+static unsigned char *qrspec_create_frame(int version)
+{
+ unsigned char *frame, *p, *q;
+ int width;
+ int x, y;
+ unsigned int verinfo, v;
+
+ width = qrspec_capacities[version].width;
+ frame = kzalloc(width * width, GFP_ATOMIC);
+ if (!frame)
+ return NULL;
+
+ /* Finder pattern */
+ put_finder_pattern(frame, width, 0, 0);
+ put_finder_pattern(frame, width, width - 7, 0);
+ put_finder_pattern(frame, width, 0, width - 7);
+ /* Separator */
+ p = frame;
+ q = frame + width * (width - 7);
+ for (y = 0; y < 7; y++) {
+ p[7] = 0xc0;
+ p[width - 8] = 0xc0;
+ q[7] = 0xc0;
+ p += width;
+ q += width;
+ }
+ memset(frame + width * 7, 0xc0, 8);
+ memset(frame + width * 8 - 8, 0xc0, 8);
+ memset(frame + width * (width - 8), 0xc0, 8);
+ /* Mask format information area */
+ memset(frame + width * 8, 0x84, 9);
+ memset(frame + width * 9 - 8, 0x84, 8);
+ p = frame + 8;
+ for (y = 0; y < 8; y++) {
+ *p = 0x84;
+ p += width;
+ }
+ p = frame + width * (width - 7) + 8;
+ for (y = 0; y < 7; y++) {
+ *p = 0x84;
+ p += width;
+ }
+ /* Timing pattern */
+ p = frame + width * 6 + 8;
+ q = frame + width * 8 + 6;
+ for (x = 1; x < width - 15; x++) {
+ *p = 0x90 | (x & 1);
+ *q = 0x90 | (x & 1);
+ p++;
+ q += width;
+ }
+ /* Alignment pattern */
+ qrspec_put_alignment_pattern(version, frame, width);
+
+ /* Version information */
+ if (version >= 7) {
+ verinfo = qrspec_get_version_pattern(version);
+
+ p = frame + width * (width - 11);
+ v = verinfo;
+ for (x = 0; x < 6; x++) {
+ for (y = 0; y < 3; y++) {
+ p[width * y + x] = 0x88 | (v & 1);
+ v = v >> 1;
+ }
+ }
+
+ p = frame + width - 11;
+ v = verinfo;
+ for (y = 0; y < 6; y++) {
+ for (x = 0; x < 3; x++) {
+ p[x] = 0x88 | (v & 1);
+ v = v >> 1;
+ }
+ p += width;
+ }
+ }
+ /* and a little bit... */
+ frame[width * (width - 8) + 8] = 0x81;
+
+ return frame;
+}
+
+unsigned char *qrspec_new_frame(int version)
+{
+ unsigned char *frame;
+ int width;
+
+ if (version < 1 || version > QRSPEC_VERSION_MAX)
+ return NULL;
+
+ if (!frames[version])
+ frames[version] = qrspec_create_frame(version);
+ if (!frames[version])
+ return NULL;
+
+ width = qrspec_capacities[version].width;
+ frame = kmalloc(width * width, GFP_ATOMIC);
+ if (!frame)
+ return NULL;
+ memcpy(frame, frames[version], width * width);
+
+ return frame;
+}
+
+void qrspec_clear_cache(void)
+{
+ int i;
+
+ for (i = 1; i <= QRSPEC_VERSION_MAX; i++) {
+ kfree(frames[i]);
+ frames[i] = NULL;
+ }
+}
diff --git a/lib/qr/qrspec.h b/lib/qr/qrspec.h
new file mode 100644
index 0000000..84e08c9
--- /dev/null
+++ b/lib/qr/qrspec.h
@@ -0,0 +1,177 @@
+/*
+ * qrencode - QR Code encoder
+ *
+ * QR Code specification in convenient format.
+ * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __QRSPEC_H__
+#define __QRSPEC_H__
+
+#include <linux/qrencode.h>
+
+/******************************************************************************
+ * Version and capacity
+ *****************************************************************************/
+
+/**
+ * Maximum width of a symbol
+ */
+#define QRSPEC_WIDTH_MAX 177
+
+/**
+ * Return maximum data code length (bytes) for the version.
+ * @param version
+ * @param level
+ * @return maximum size (bytes)
+ */
+int qrspec_get_data_length(int version, enum qrec_level level);
+
+/**
+ * Return maximum error correction code length (bytes) for the version.
+ * @param version
+ * @param level
+ * @return ECC size (bytes)
+ */
+int qrspec_get_ecc_length(int version, enum qrec_level level);
+
+/**
+ * Return a version number that satisfies the input code length.
+ * @param size input code length (byte)
+ * @param level
+ * @return version number
+ */
+int qrspec_get_minimum_version(int size, enum qrec_level level);
+
+/**
+ * Return the width of the symbol for the version.
+ * @param version
+ * @return width
+ */
+int qrspec_get_width(int version);
+
+/**
+ * Return the numer of remainder bits.
+ * @param version
+ * @return number of remainder bits
+ */
+int qrspec_get_remainder(int version);
+
+/******************************************************************************
+ * Length indicator
+ *****************************************************************************/
+
+/**
+ * Return the size of length indicator for the mode and version.
+ * @param mode
+ * @param version
+ * @return the size of the appropriate length indicator (bits).
+ */
+int qrspec_length_indicator(enum qrencode_mode mode, int version);
+
+/**
+ * Return the maximum length for the mode and version.
+ * @param mode
+ * @param version
+ * @return the maximum length (bytes)
+ */
+int qrspec_maximum_words(enum qrencode_mode mode, int version);
+
+/******************************************************************************
+ * Error correction code
+ *****************************************************************************/
+
+/**
+ * Return an array of ECC specification.
+ * @param version
+ * @param level
+ * @param spec an array of ECC specification contains as following:
+ * {# of type1 blocks, # of data code, # of ecc code,
+ * # of type2 blocks, # of data code}
+ */
+void qrspec_get_ecc_spec(int version, enum qrec_level level, int spec[5]);
+
+#define qrspec_rs_block_num(__spec__) (__spec__[0] + __spec__[3])
+#define qrspec_rs_block_num1(__spec__) (__spec__[0])
+#define qrspec_rs_data_codes1(__spec__) (__spec__[1])
+#define qrspec_rs_ecc_codes1(__spec__) (__spec__[2])
+#define qrspec_rs_block_num2(__spec__) (__spec__[3])
+#define qrspec_rs_data_codes2(__spec__) (__spec__[4])
+#define qrspec_rs_ecc_codes2(__spec__) (__spec__[2])
+
+#define qrspec_rs_data_length(__spec__) \
+ ((qrspec_rs_block_num1(__spec__) * qrspec_rs_data_codes1(__spec__)) + \
+ (qrspec_rs_block_num2(__spec__) * qrspec_rs_data_codes2(__spec__)))
+#define qrspec_rs_ecc_length(__spec__) \
+ (qrspec_rs_block_num(__spec__) * qrspec_rs_ecc_codes1(__spec__))
+
+/******************************************************************************
+ * Version information pattern
+ *****************************************************************************/
+
+/**
+ * Return BCH encoded version information pattern that is used for the symbol
+ * of version 7 or greater. Use lower 18 bits.
+ * @param version
+ * @return BCH encoded version information pattern
+ */
+unsigned int qrspec_get_version_pattern(int version);
+
+/******************************************************************************
+ * Format information
+ *****************************************************************************/
+
+/**
+ * Return BCH encoded format information pattern.
+ * @param mask
+ * @param level
+ * @return BCH encoded format information pattern
+ */
+unsigned int qrspec_get_format_info(int mask, enum qrec_level level);
+
+/******************************************************************************
+ * Frame
+ *****************************************************************************/
+
+/**
+ * Return a copy of initialized frame.
+ * When the same version is requested twice or more, a copy of cached frame
+ * is returned.
+ * @param version
+ * @return Array of unsigned char. You can free it by free().
+ */
+unsigned char *qrspec_new_frame(int version);
+
+/**
+ * Clear the frame cache. Typically for debug.
+ */
+void qrspec_clear_cache(void);
+
+/******************************************************************************
+ * Mode indicator
+ *****************************************************************************/
+
+/**
+ * Mode indicator. See Table 2 of JIS X0510:2004, pp.16.
+ */
+#define QRSPEC_MODEID_ECI 7
+#define QRSPEC_MODEID_NUM 1
+#define QRSPEC_MODEID_AN 2
+#define QRSPEC_MODEID_8 4
+#define QRSPEC_MODEID_FNC1FIRST 5
+#define QRSPEC_MODEID_FNC1SECOND 9
+#define QRSPEC_MODEID_STRUCTURE 3
+#define QRSPEC_MODEID_TERMINATOR 0
+
+#endif /* __QRSPEC_H__ */
diff --git a/lib/qr/split.c b/lib/qr/split.c
new file mode 100644
index 0000000..922f9a0
--- /dev/null
+++ b/lib/qr/split.c
@@ -0,0 +1,283 @@
+/*
+ * qrencode - QR Code encoder
+ *
+ * Input data splitter.
+ * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ *
+ * The following data / specifications are taken from
+ * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
+ * or
+ * "Automatic identification and data capture techniques --
+ * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/qrencode.h>
+#include "qrinput.h"
+#include "qrspec.h"
+#include "split.h"
+
+#define isdigit(__c__) ((unsigned char)((signed char)(__c__) - '0') < 10)
+#define isalnum(__c__) (qrinput_look_an_table(__c__) >= 0)
+
+static enum qrencode_mode split_identify_mode(const char *string,
+ enum qrencode_mode hint)
+{
+ unsigned char c;
+
+ c = string[0];
+
+ if (c == '\0')
+ return QR_MODE_NUL;
+ if (isdigit(c))
+ return QR_MODE_NUM;
+ else if (isalnum(c))
+ return QR_MODE_AN;
+ return QR_MODE_8;
+}
+
+static int split_eat_num(const char *string, struct qrinput *input,
+ enum qrencode_mode hint);
+
+static int split_eat_an(const char *string, struct qrinput *input,
+ enum qrencode_mode hint);
+
+static int split_eat8(const char *string, struct qrinput *input,
+ enum qrencode_mode hint);
+
+static int split_eat_num(const char *string, struct qrinput *input,
+ enum qrencode_mode hint)
+{
+ const char *p;
+ int ret;
+ int run;
+ int dif;
+ int ln;
+ enum qrencode_mode mode;
+
+ ln = qrspec_length_indicator(QR_MODE_NUM, input->version);
+
+ p = string;
+ while (isdigit(*p))
+ p++;
+ run = p - string;
+ mode = split_identify_mode(p, hint);
+ if (mode == QR_MODE_8) {
+ dif = qrinput_estimate_bits_mode_num(run) + 4 + ln
+ + qrinput_estimate_bits_mode8(1) /* + 4 + l8 */
+ - qrinput_estimate_bits_mode8(run + 1); /* - 4 - l8 */
+ if (dif > 0)
+ return split_eat8(string, input, hint);
+ }
+ if (mode == QR_MODE_AN) {
+ dif = qrinput_estimate_bits_mode_num(run) + 4 + ln
+ + qrinput_estimate_bits_mode_an(1) /* + 4 + la */
+ - qrinput_estimate_bits_mode_an(run + 1); /* - 4 - la */
+ if (dif > 0)
+ return split_eat_an(string, input, hint);
+ }
+
+ ret = qrinput_append(input, QR_MODE_NUM, run, (unsigned char *)string);
+ if (ret < 0)
+ return -1;
+
+ return run;
+}
+
+static int split_eat_an(const char *string, struct qrinput *input,
+ enum qrencode_mode hint)
+{
+ const char *p, *q;
+ int ret;
+ int run;
+ int dif;
+ int la, ln;
+
+ la = qrspec_length_indicator(QR_MODE_AN, input->version);
+ ln = qrspec_length_indicator(QR_MODE_NUM, input->version);
+
+ p = string;
+ while (isalnum(*p)) {
+ if (isdigit(*p)) {
+ q = p;
+ while (isdigit(*q))
+ q++;
+ dif = qrinput_estimate_bits_mode_an(p - string)
+ /* + 4 + la */
+ + qrinput_estimate_bits_mode_num(q - p) + 4 + ln
+ + (isalnum(*q) ? (4 + ln) : 0)
+ - qrinput_estimate_bits_mode_an(q - string)
+ /* - 4 - la */
+ ;
+ if (dif >= 0)
+ p = q;
+ else
+ break;
+ } else {
+ p++;
+ }
+ }
+
+ run = p - string;
+
+ if (*p && !isalnum(*p)) {
+ dif = qrinput_estimate_bits_mode_an(run) + 4 + la
+ + qrinput_estimate_bits_mode8(1) /* + 4 + l8 */
+ - qrinput_estimate_bits_mode8(run + 1); /* - 4 - l8 */
+ if (dif > 0)
+ return split_eat8(string, input, hint);
+ }
+
+ ret = qrinput_append(input, QR_MODE_AN, run, (unsigned char *)string);
+ if (ret < 0)
+ return -1;
+
+ return run;
+}
+
+static int split_eat8(const char *string, struct qrinput *input,
+ enum qrencode_mode hint)
+{
+ const char *p, *q;
+ enum qrencode_mode mode;
+ int ret;
+ int run;
+ int dif;
+ int la, ln, l8;
+ int swcost;
+
+ la = qrspec_length_indicator(QR_MODE_AN, input->version);
+ ln = qrspec_length_indicator(QR_MODE_NUM, input->version);
+ l8 = qrspec_length_indicator(QR_MODE_8, input->version);
+
+ p = string + 1;
+ while (*p != '\0') {
+ mode = split_identify_mode(p, hint);
+ if (mode == QR_MODE_NUM) {
+ q = p;
+ while (isdigit(*q))
+ q++;
+
+ if (split_identify_mode(q, hint) == QR_MODE_8)
+ swcost = 4 + l8;
+ else
+ swcost = 0;
+ dif = qrinput_estimate_bits_mode8(p - string)
+ /* + 4 + l8 */
+ + qrinput_estimate_bits_mode_num(q - p) + 4 + ln
+ + swcost
+ - qrinput_estimate_bits_mode8(q - string);
+ /* - 4 - l8 */
+ if (dif >= 0)
+ p = q;
+ else
+ break;
+ } else if (mode == QR_MODE_AN) {
+ q = p;
+ while (isalnum(*q))
+ q++;
+ if (split_identify_mode(q, hint) == QR_MODE_8)
+ swcost = 4 + l8;
+ else
+ swcost = 0;
+ dif = qrinput_estimate_bits_mode8(p - string)
+ /* + 4 + l8 */
+ + qrinput_estimate_bits_mode_an(q - p) + 4 + la
+ + swcost
+ - qrinput_estimate_bits_mode8(q - string);
+ /* - 4 - l8 */
+ if (dif >= 0)
+ p = q;
+ else
+ break;
+
+ } else {
+ p++;
+ }
+ }
+
+ run = p - string;
+ ret = qrinput_append(input, QR_MODE_8, run, (unsigned char *)string);
+ if (ret < 0)
+ return -1;
+
+ return run;
+}
+
+static int split_split_string(const char *string, struct qrinput *input,
+ enum qrencode_mode hint)
+{
+ int length;
+ enum qrencode_mode mode;
+
+ if (*string == '\0')
+ return 0;
+
+ mode = split_identify_mode(string, hint);
+ if (mode == QR_MODE_NUM)
+ length = split_eat_num(string, input, hint);
+ else if (mode == QR_MODE_AN)
+ length = split_eat_an(string, input, hint);
+ else
+ length = split_eat8(string, input, hint);
+ if (length == 0)
+ return 0;
+ if (length < 0)
+ return -1;
+ return split_split_string(&string[length], input, hint);
+}
+
+static char *dup_and_to_upper(const char *str, enum qrencode_mode hint)
+{
+ char *newstr, *p;
+ enum qrencode_mode mode;
+
+ newstr = kstrdup(str, GFP_ATOMIC);
+ if (!newstr)
+ return NULL;
+
+ p = newstr;
+ while (*p != '\0') {
+ mode = split_identify_mode(p, hint);
+ if (*p >= 'a' && *p <= 'z')
+ *p = (char)((int)*p - 32);
+ p++;
+ }
+
+ return newstr;
+}
+
+int split_split_string_to_qrinput(const char *string, struct qrinput *input,
+ enum qrencode_mode hint, int casesensitive)
+{
+ char *newstr;
+ int ret;
+
+ if (!string || *string == '\0')
+ return -1;
+ if (!casesensitive) {
+ newstr = dup_and_to_upper(string, hint);
+ if (!newstr)
+ return -1;
+ ret = split_split_string(newstr, input, hint);
+ kfree(newstr);
+ } else {
+ ret = split_split_string(string, input, hint);
+ }
+
+ return ret;
+}
diff --git a/lib/qr/split.h b/lib/qr/split.h
new file mode 100644
index 0000000..3dfb0be
--- /dev/null
+++ b/lib/qr/split.h
@@ -0,0 +1,48 @@
+/*
+ * qrencode - QR Code encoder
+ *
+ * Input data splitter.
+ * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@xxxxxxxxxxx>
+ *
+ * The following data / specifications are taken from
+ * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
+ * or
+ * "Automatic identification and data capture techniques --
+ * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SPLIT_H__
+#define __SPLIT_H__
+
+#include <linux/qrencode.h>
+
+/**
+ * Split the input string (null terminated) into qrinput.
+ * @param string input string
+ * @param hint give QR_MODE_KANJI if the input string contains Kanji character
+ * encoded in Shift-JIS. If not, give QR_MODE_8.
+ * @param casesensitive 0 for case-insensitive encoding (all alphabet characters
+ * are replaced to UPPER-CASE CHARACTERS.
+ * @retval 0 success.
+ * @retval -1 an error occurred. errno is set to indicate the error. See
+ * Exceptions for the details.
+ * @throw EINVAL invalid input object.
+ * @throw ENOMEM unable to allocate memory for input objects.
+ */
+int split_split_string_to_qrinput(const char *string,
+ struct qrinput *input,
+ enum qrencode_mode hint,
+ int casesensitive);
+
+#endif /* __SPLIT_H__ */
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/