From 69f10430b51de7682aee4c2369b672671887f95b Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Tue, 21 Apr 2015 13:21:24 +0530 Subject: [PATCH 001/100] Initial commit --- LICENSE | 340 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + 2 files changed, 342 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..8cdb8451d9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program 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 program 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. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + diff --git a/README.md b/README.md new file mode 100644 index 0000000000..f499907fd4 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# NXPNFC_I2CDriver +NFC I2C Open Source driver From b0f60480826c1a78be10440a97ba35c4d9581382 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Tue, 21 Apr 2015 14:54:58 +0530 Subject: [PATCH 002/100] Initial I2C Driver Commit for opensource --- pn5xx_i2c.c | 767 ++++++++++++++++++++++++++++++++++++++++++++++++++++ pn5xx_i2c.h | 48 ++++ 2 files changed, 815 insertions(+) create mode 100644 pn5xx_i2c.c create mode 100644 pn5xx_i2c.h diff --git a/pn5xx_i2c.c b/pn5xx_i2c.c new file mode 100644 index 0000000000..d9da2ebb7f --- /dev/null +++ b/pn5xx_i2c.c @@ -0,0 +1,767 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * modifications copyright (C) 2015 NXP B.V. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pn71xx.h" +#include +#include +#include + +#define MAX_BUFFER_SIZE 512 + +#define MODE_OFF 0 +#define MODE_RUN 1 +#define MODE_FW 2 + +/* Only pn548, pn547 and pn544 are supported */ +#define CHIP "pn544" +#define DRIVER_CARD "PN54x NFC" +#define DRIVER_DESC "NFC driver for PN54x Family" + +#ifndef CONFIG_OF +#define CONFIG_OF +#endif + +struct pn54x_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn54x_device; + int ven_gpio; + int firm_gpio; + int irq_gpio; + int clkreq_gpio; + struct regulator *pvdd_reg; + struct regulator *vbat_reg; + struct regulator *pmuvcc_reg; + struct regulator *sevdd_reg; + bool irq_enabled; + spinlock_t irq_enabled_lock; +}; + +/********************************************************** + * Interrupt control and handler + **********************************************************/ +static void pn54x_disable_irq(struct pn54x_dev *pn54x_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&pn54x_dev->irq_enabled_lock, flags); + if (pn54x_dev->irq_enabled) { + disable_irq_nosync(pn54x_dev->client->irq); + pn54x_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn54x_dev->irq_enabled_lock, flags); +} + +static irqreturn_t pn54x_dev_irq_handler(int irq, void *dev_id) +{ + struct pn54x_dev *pn54x_dev = dev_id; + + pn54x_disable_irq(pn54x_dev); + + /* Wake up waiting readers */ + wake_up(&pn54x_dev->read_wq); + + return IRQ_HANDLED; +} + +/********************************************************** + * private functions + **********************************************************/ +static int pn544_enable(struct pn54x_dev *dev, int mode) +{ + int r; + + /* turn on the regulators */ + /* -- if the regulators were specified, they're required */ + if(dev->pvdd_reg != NULL) + { + r = regulator_enable(dev->pvdd_reg); + if (r < 0){ + pr_err("%s: not able to enable pvdd\n", __func__); + return r; + } + } + if(dev->vbat_reg != NULL) + { + r = regulator_enable(dev->vbat_reg); + if (r < 0){ + pr_err("%s: not able to enable vbat\n", __func__); + goto enable_exit0; + } + } + if(dev->pmuvcc_reg != NULL) + { + r = regulator_enable(dev->pmuvcc_reg); + if (r < 0){ + pr_err("%s: not able to enable pmuvcc\n", __func__); + goto enable_exit1; + } + } + if(dev->sevdd_reg != NULL) + { + r = regulator_enable(dev->sevdd_reg); + if (r < 0){ + pr_err("%s: not able to enable sevdd\n", __func__); + goto enable_exit2; + } + } + + if (MODE_RUN == mode) { + pr_info("%s power on\n", __func__); + if (gpio_is_valid(dev->firm_gpio)) + gpio_set_value(dev->firm_gpio, 0); + gpio_set_value(dev->ven_gpio, 1); + msleep(100); + } + else if (MODE_FW == mode) { + /* power on with firmware download (requires hw reset) + */ + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(dev->ven_gpio, 1); + msleep(20); + if (gpio_is_valid(dev->firm_gpio)) + gpio_set_value(dev->firm_gpio, 1); + msleep(20); + gpio_set_value(dev->ven_gpio, 0); + msleep(100); + gpio_set_value(dev->ven_gpio, 1); + msleep(20); + } + else { + pr_err("%s bad arg %d\n", __func__, mode); + return -EINVAL; + } + + return 0; + +enable_exit2: + if(dev->pmuvcc_reg) regulator_disable(dev->pmuvcc_reg); +enable_exit1: + if(dev->vbat_reg) regulator_disable(dev->vbat_reg); +enable_exit0: + if(dev->pvdd_reg) regulator_disable(dev->pvdd_reg); + + return r; +} + +static void pn544_disable(struct pn54x_dev *dev) +{ + /* power off */ + pr_info("%s power off\n", __func__); + if (gpio_is_valid(dev->firm_gpio)) + gpio_set_value(dev->firm_gpio, 0); + gpio_set_value(dev->ven_gpio, 0); + msleep(100); + + if(dev->sevdd_reg) regulator_disable(dev->sevdd_reg); + if(dev->pmuvcc_reg) regulator_disable(dev->pmuvcc_reg); + if(dev->vbat_reg) regulator_disable(dev->vbat_reg); + if(dev->pvdd_reg) regulator_disable(dev->pvdd_reg); + +} + +/********************************************************** + * driver functions + **********************************************************/ +static ssize_t pn54x_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn54x_dev *pn54x_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + + mutex_lock(&pn54x_dev->read_mutex); + + if (!gpio_get_value(pn54x_dev->irq_gpio)) { + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } + + while (1) { + pn54x_dev->irq_enabled = true; + enable_irq(pn54x_dev->client->irq); + ret = wait_event_interruptible( + pn54x_dev->read_wq, + !pn54x_dev->irq_enabled); + + pn54x_disable_irq(pn54x_dev); + + if (ret) + goto fail; + + if (gpio_get_value(pn54x_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + + /* Read data */ + ret = i2c_master_recv(pn54x_dev->client, tmp, count); + + mutex_unlock(&pn54x_dev->read_mutex); + + /* pn54x seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ + udelay(1000); + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return ret; + +fail: + mutex_unlock(&pn54x_dev->read_mutex); + return ret; +} + +static ssize_t pn54x_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct pn54x_dev *pn54x_dev; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + pn54x_dev = filp->private_data; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + + pr_debug("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn54x_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + + /* pn54x seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); + + return ret; +} + +static int pn54x_dev_open(struct inode *inode, struct file *filp) +{ + struct pn54x_dev *pn54x_dev = container_of(filp->private_data, + struct pn54x_dev, + pn54x_device); + + filp->private_data = pn54x_dev; + + pr_info("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + + // pn544_enable(pn54x_dev, MODE_RUN); + + return 0; +} + +static int pn54x_dev_release(struct inode *inode, struct file *filp) +{ + // struct pn54x_dev *pn54x_dev = container_of(filp->private_data, + // struct pn54x_dev, + // pn54x_device); + + pr_info("%s : closing %d,%d\n", __func__, imajor(inode), iminor(inode)); + + // pn544_disable(pn54x_dev); + + return 0; +} + +static long pn54x_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct pn54x_dev *pn54x_dev = filp->private_data; + + pr_info("%s, cmd=%d, arg=%lu\n", __func__, cmd, arg); + switch (cmd) { + case PN544_SET_PWR: + if (arg == 2) { + /* power on w/FW */ + pn544_enable(pn54x_dev, arg); + } else if (arg == 1) { + /* power on */ + pn544_enable(pn54x_dev, arg); + } else if (arg == 0) { + /* power off */ + pn544_disable(pn54x_dev); + } else { + pr_err("%s bad SET_PWR arg %lu\n", __func__, arg); + return -EINVAL; + } + break; + case PN54X_CLK_REQ: + if(1 == arg){ + if(gpio_is_valid(pn54x_dev->clkreq_gpio)){ + gpio_set_value(pn54x_dev->clkreq_gpio, 1); + } + } + else if(0 == arg) { + if(gpio_is_valid(pn54x_dev->clkreq_gpio)){ + gpio_set_value(pn54x_dev->clkreq_gpio, 0); + } + } else { + pr_err("%s bad CLK_REQ arg %lu\n", __func__, arg); + return -EINVAL; + } + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + return -EINVAL; + } + + return 0; +} + +static const struct file_operations pn54x_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn54x_dev_read, + .write = pn54x_dev_write, + .open = pn54x_dev_open, + .release = pn54x_dev_release, + .unlocked_ioctl = pn54x_dev_ioctl, +}; + + +/* + * Handlers for alternative sources of platform_data + */ +#ifdef CONFIG_OF +/* + * Translate OpenFirmware node properties into platform_data + */ +static int pn54x_get_pdata(struct device *dev, + struct pn544_i2c_platform_data *pdata) +{ + struct device_node *node; + u32 flags; + int val; + + /* make sure there is actually a device tree node */ + node = dev->of_node; + if (!node) + return -ENODEV; + + memset(pdata, 0, sizeof(*pdata)); + + /* read the dev tree data */ + + /* ven pin - enable's power to the chip - REQUIRED */ + val = of_get_named_gpio_flags(node, "nxp,pn54x-ven", 0, &flags); + if (val >= 0) { + pdata->ven_gpio = val; + } + else{ + dev_err(dev, "VEN GPIO error getting from OF node\n"); + return val; + } + + /* firm pin - controls firmware download - OPTIONAL */ + val = of_get_named_gpio_flags(node, "nxp,pn54x-firm", 0, &flags); + if (val >= 0) { + pdata->firm_gpio = val; + } + else { + pdata->firm_gpio = -EINVAL; + dev_warn(dev, "FIRM GPIO error getting from OF node\n"); + } + + /* irq pin - data available irq - REQUIRED */ + val = of_get_named_gpio_flags(node, "nxp,pn54x-irq", 0, &flags); + if (val >= 0) { + pdata->irq_gpio = val; + } + else { + dev_err(dev, "IRQ GPIO error getting from OF node\n"); + return val; + } + + /* clkreq pin - controls the clock to the PN547 - OPTIONAL */ + val = of_get_named_gpio_flags(node, "nxp,pn54x-clkreq", 0, &flags); + if (val >= 0) { + pdata->clkreq_gpio = val; + } + else { + pdata->clkreq_gpio = -EINVAL; + dev_warn(dev, "CLKREQ GPIO error getting from OF node\n"); + } + + /* handle the regulator lines - these are optional + * PVdd - pad Vdd (544, 547) + * Vbat - Battery (544, 547) + * PMUVcc - UICC Power (544, 547) + * SEVdd - SE Power (544) + * + * Will attempt to load a matching Regulator Resource for each + * If no resource is provided, then the input will not be controlled + * Example: if only PVdd is provided, it is the only one that will be + * turned on/off. + */ + pdata->pvdd_reg = regulator_get(dev, "nxp,pn54x-pvdd"); + if(IS_ERR(pdata->pvdd_reg)) { + pr_err("%s: could not get nxp,pn54x-pvdd, rc=%ld\n", __func__, PTR_ERR(pdata->pvdd_reg)); + pdata->pvdd_reg = NULL; + } + + pdata->vbat_reg = regulator_get(dev, "nxp,pn54x-vbat"); + if (IS_ERR(pdata->vbat_reg)) { + pr_err("%s: could not get nxp,pn54x-vbat, rc=%ld\n", __func__, PTR_ERR(pdata->vbat_reg)); + pdata->vbat_reg = NULL; + } + + pdata->pmuvcc_reg = regulator_get(dev, "nxp,pn54x-pmuvcc"); + if (IS_ERR(pdata->pmuvcc_reg)) { + pr_err("%s: could not get nxp,pn54x-pmuvcc, rc=%ld\n", __func__, PTR_ERR(pdata->pmuvcc_reg)); + pdata->pmuvcc_reg = NULL; + } + + pdata->sevdd_reg = regulator_get(dev, "nxp,pn54x-sevdd"); + if (IS_ERR(pdata->sevdd_reg)) { + pr_err("%s: could not get nxp,pn54x-sevdd, rc=%ld\n", __func__, PTR_ERR(pdata->sevdd_reg)); + pdata->sevdd_reg = NULL; + } + + return 0; +} +#else +static int pn54x_get_pdata(struct device *dev, + struct pn544_i2c_platform_data *pdata) +{ + pdata = dev->platform_data; + return 0; +} +#endif + + +/* + * pn54x_probe + */ +#ifdef KERNEL_3_4_AND_OLDER + static int __devinit pn54x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +#else +static int pn54x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +#endif +{ + int ret; + struct pn544_i2c_platform_data *pdata; // gpio values, from board file or DT + struct pn544_i2c_platform_data tmp_pdata; + struct pn54x_dev *pn54x_dev; // internal device specific data + + pr_info("%s\n", __func__); + + /* ---- retrieve the platform data ---- */ + /* If the dev.platform_data is NULL, then */ + /* attempt to read from the device tree */ + if(!client->dev.platform_data) + { + ret = pn54x_get_pdata(&(client->dev), &tmp_pdata); + if(ret){ + return ret; + } + + pdata = &tmp_pdata; + } + else + { + pdata = client->dev.platform_data; + } + + if (pdata == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + + /* validate the the adapter has basic I2C functionality */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } + + /* reserve the GPIO pins */ + pr_info("%s: request irq_gpio %d\n", __func__, pdata->irq_gpio); + ret = gpio_request(pdata->irq_gpio, "nfc_int"); + if (ret){ + pr_err("%s :not able to get GPIO irq_gpio\n", __func__); + return -ENODEV; + } + ret = gpio_to_irq(pdata->irq_gpio); + if (ret < 0){ + pr_err("%s :not able to map GPIO irq_gpio to an IRQ\n", __func__); + goto err_ven; + } + else{ + client->irq = ret; + } + + pr_info("%s: request ven_gpio %d\n", __func__, pdata->ven_gpio); + ret = gpio_request(pdata->ven_gpio, "nfc_ven"); + if (ret){ + pr_err("%s :not able to get GPIO ven_gpio\n", __func__); + goto err_ven; + } + + if (gpio_is_valid(pdata->firm_gpio)) { + pr_info("%s: request firm_gpio %d\n", __func__, pdata->firm_gpio); + ret = gpio_request(pdata->firm_gpio, "nfc_firm"); + if (ret){ + pr_err("%s :not able to get GPIO firm_gpio\n", __func__); + goto err_firm; + } + } + + if (gpio_is_valid(pdata->clkreq_gpio)) { + pr_info("%s: request clkreq_gpio %d\n", __func__, pdata->clkreq_gpio); + ret = gpio_request(pdata->clkreq_gpio, "nfc_clkreq"); + if (ret){ + pr_err("%s :not able to get GPIO clkreq_gpio\n", __func__); + goto err_clkreq; + } + } + + /* allocate the pn54x driver information structure */ + pn54x_dev = kzalloc(sizeof(*pn54x_dev), GFP_KERNEL); + if (pn54x_dev == NULL) { + dev_err(&client->dev, "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + /* store the platform data in the driver info struct */ + pn54x_dev->irq_gpio = pdata->irq_gpio; + pn54x_dev->ven_gpio = pdata->ven_gpio; + pn54x_dev->firm_gpio = pdata->firm_gpio; + pn54x_dev->clkreq_gpio = pdata->clkreq_gpio; + pn54x_dev->pvdd_reg = pdata->pvdd_reg; + pn54x_dev->vbat_reg = pdata->vbat_reg; + pn54x_dev->pmuvcc_reg = pdata->vbat_reg; + pn54x_dev->sevdd_reg = pdata->sevdd_reg; + + pn54x_dev->client = client; + + /* finish configuring the I/O */ + ret = gpio_direction_input(pn54x_dev->irq_gpio); + if (ret < 0) { + pr_err("%s :not able to set irq_gpio as input\n", __func__); + goto err_exit; + } + + ret = gpio_direction_output(pn54x_dev->ven_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_exit; + } + + if (gpio_is_valid(pn54x_dev->firm_gpio)) { + ret = gpio_direction_output(pn54x_dev->firm_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set firm_gpio as output\n", + __func__); + goto err_exit; + } + } + + if (gpio_is_valid(pn54x_dev->clkreq_gpio)) { + ret = gpio_direction_output(pn54x_dev->clkreq_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set clkreq_gpio as output\n", + __func__); + goto err_exit; + } + } + + /* init mutex and queues */ + init_waitqueue_head(&pn54x_dev->read_wq); + mutex_init(&pn54x_dev->read_mutex); + spin_lock_init(&pn54x_dev->irq_enabled_lock); + + /* register as a misc device - character based with one entry point */ + pn54x_dev->pn54x_device.minor = MISC_DYNAMIC_MINOR; + pn54x_dev->pn54x_device.name = CHIP; + pn54x_dev->pn54x_device.fops = &pn54x_dev_fops; + ret = misc_register(&pn54x_dev->pn54x_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } + + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pn54x_dev->irq_enabled = true; + ret = request_irq(client->irq, pn54x_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, pn54x_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + pn54x_disable_irq(pn54x_dev); + + + i2c_set_clientdata(client, pn54x_dev); + + return 0; + +err_request_irq_failed: + misc_deregister(&pn54x_dev->pn54x_device); +err_misc_register: +err_exit: + if (gpio_is_valid(pdata->clkreq_gpio)) + gpio_free(pdata->clkreq_gpio); +err_clkreq: + if (gpio_is_valid(pdata->firm_gpio)) + gpio_free(pdata->firm_gpio); +err_firm: + gpio_free(pdata->ven_gpio); +err_ven: + gpio_free(pdata->irq_gpio); + return ret; +} + +#ifdef KERNEL_3_4_AND_OLDER +static int __devexit pn54x_remove(struct i2c_client *client) +#else +static int pn54x_remove(struct i2c_client *client) +#endif +{ + struct pn54x_dev *pn54x_dev; + + pr_info("%s\n", __func__); + + pn54x_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn54x_dev); + misc_deregister(&pn54x_dev->pn54x_device); + mutex_destroy(&pn54x_dev->read_mutex); + gpio_free(pn54x_dev->irq_gpio); + gpio_free(pn54x_dev->ven_gpio); + if (gpio_is_valid(pn54x_dev->firm_gpio)) + gpio_free(pn54x_dev->firm_gpio); + if (gpio_is_valid(pn54x_dev->clkreq_gpio)) + gpio_free(pn54x_dev->clkreq_gpio); + regulator_put(pn54x_dev->pvdd_reg); + regulator_put(pn54x_dev->vbat_reg); + regulator_put(pn54x_dev->pmuvcc_reg); + regulator_put(pn54x_dev->sevdd_reg); + + kfree(pn54x_dev); + + return 0; +} + +/* + * + */ +#ifdef CONFIG_OF +static struct of_device_id pn54x_dt_match[] = { + { .compatible = "nxp,pn547", }, + { .compatible = "nxp,pn544", }, + {}, +}; +MODULE_DEVICE_TABLE(of, pn54x_dt_match); +#endif + +static const struct i2c_device_id pn54x_id[] = { + { "pn547", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, pn54x_id); + +static struct i2c_driver pn54x_driver = { + .id_table = pn54x_id, + .probe = pn54x_probe, +#ifdef KERNEL_3_4_AND_OLDER + .remove = __devexit_p(pn54x_remove), +#else + .remove = pn54x_remove, +#endif + .driver = { + .owner = THIS_MODULE, + .name = "pn544", + .of_match_table = pn54x_dt_match, + }, +}; + +/* + * module load/unload record keeping + */ + +static int __init pn54x_dev_init(void) +{ + pr_info("%s\n", __func__); + return i2c_add_driver(&pn54x_driver); +} + +static void __exit pn54x_dev_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&pn54x_driver); +} + +module_init(pn54x_dev_init); +module_exit(pn54x_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + diff --git a/pn5xx_i2c.h b/pn5xx_i2c.h new file mode 100644 index 0000000000..c6fbcde887 --- /dev/null +++ b/pn5xx_i2c.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * modifications copyright (C) 2015 NXP B.V. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define PN544_MAGIC 0xE9 + +/* + * PN544 power control via ioctl + * PN544_SET_PWR(0): power off + * PN544_SET_PWR(1): power on + * PN544_SET_PWR(2): reset and power on with firmware download enabled + */ + +#define PWR_OFF 0 +#define PWR_ON 1 +#define PWR_FW 2 + +#define CLK_OFF 0 +#define CLK_ON 1 + +#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, unsigned int) +#define PN54X_CLK_REQ _IOW(PN544_MAGIC, 0x02, unsigned int) + +struct pn544_i2c_platform_data { + unsigned int irq_gpio; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int clkreq_gpio; + struct regulator *pvdd_reg; + struct regulator *vbat_reg; + struct regulator *pmuvcc_reg; + struct regulator *sevdd_reg; +}; From 2f5a46733e566f9c43bb35536cab2cdb62aa0ca6 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Wed, 22 Apr 2015 19:35:45 +0530 Subject: [PATCH 003/100] Updated name of included header --- pn5xx_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pn5xx_i2c.c b/pn5xx_i2c.c index d9da2ebb7f..39d9efa94a 100644 --- a/pn5xx_i2c.c +++ b/pn5xx_i2c.c @@ -35,7 +35,7 @@ #include #include #include -#include "pn71xx.h" +#include "pn5xx_i2c.h" #include #include #include From 915fb00cfcf5db53a392d1d354434a21dfaf58d3 Mon Sep 17 00:00:00 2001 From: Sunil Jogi Date: Wed, 22 Apr 2015 14:02:32 -0700 Subject: [PATCH 004/100] Adding Makefile and Kconfig. --- Kconfig | 12 ++++++++++++ Makefile | 10 ++++++++++ 2 files changed, 22 insertions(+) create mode 100644 Kconfig create mode 100644 Makefile diff --git a/Kconfig b/Kconfig new file mode 100644 index 0000000000..4e770199c8 --- /dev/null +++ b/Kconfig @@ -0,0 +1,12 @@ +config NFC_NXP_PN5XX + tristate "NXP PN5XX based driver" + depends on I2C + select CRC_CCITT + default n + ---help--- + NXP PN5XX driver based on I2C. + This is a driver to provides I2C access to PN5xx NFC Controller devices + + To compile this driver as a module, choose m here. The module will + be called pn5xx_i2c. + Say N if unsure. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..f4efe8ee70 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for NXP-NCI NFC driver +# + +nxp-pn5xx-objs = pn5xx_i2c.o + +obj-$(CONFIG_NFC_NXP_PN5XX) += pn5xx_i2c.o + +ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG +ccflags := -DDEBUG From f3fca28a9ae3325226b5c0f1d72a0611cabb9a5d Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Mon, 22 Jun 2015 17:11:10 +0530 Subject: [PATCH 005/100] Updated I2C Driver with Power Management Changes --- pn5xx_i2c.c | 1105 ++++++++++++++++++++++++++++++++++----------------- pn5xx_i2c.h | 60 ++- 2 files changed, 783 insertions(+), 382 deletions(-) diff --git a/pn5xx_i2c.c b/pn5xx_i2c.c index 39d9efa94a..c4c6d9a5e0 100644 --- a/pn5xx_i2c.c +++ b/pn5xx_i2c.c @@ -16,6 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + * */ #include @@ -39,73 +40,160 @@ #include #include #include +#include +#include +#include +#include -#define MAX_BUFFER_SIZE 512 +#define SIG_NFC 44 +#define MAX_BUFFER_SIZE 512 #define MODE_OFF 0 -#define MODE_RUN 1 +#define MODE_RUN 1 #define MODE_FW 2 /* Only pn548, pn547 and pn544 are supported */ #define CHIP "pn544" -#define DRIVER_CARD "PN54x NFC" -#define DRIVER_DESC "NFC driver for PN54x Family" +#define DRIVER_CARD "PN5xx NFC" +#define DRIVER_DESC "NFC driver for PN5xx Family" #ifndef CONFIG_OF #define CONFIG_OF #endif -struct pn54x_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct i2c_client *client; - struct miscdevice pn54x_device; - int ven_gpio; - int firm_gpio; - int irq_gpio; +struct pn5xx_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn5xx_device; + int ven_gpio; + int firm_gpio; + int irq_gpio; int clkreq_gpio; struct regulator *pvdd_reg; struct regulator *vbat_reg; struct regulator *pmuvcc_reg; struct regulator *sevdd_reg; - bool irq_enabled; - spinlock_t irq_enabled_lock; + unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ + struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ + p61_access_state_t p61_current_state; /* stores the current P61 state */ + bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ + bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + long nfc_service_pid; /*used to signal the nfc the nfc service */ }; +static void p61_get_access_state(struct pn5xx_dev*, p61_access_state_t*); + /********************************************************** * Interrupt control and handler **********************************************************/ -static void pn54x_disable_irq(struct pn54x_dev *pn54x_dev) +static void pn5xx_disable_irq(struct pn5xx_dev *pn5xx_dev) { - unsigned long flags; + unsigned long flags; - spin_lock_irqsave(&pn54x_dev->irq_enabled_lock, flags); - if (pn54x_dev->irq_enabled) { - disable_irq_nosync(pn54x_dev->client->irq); - pn54x_dev->irq_enabled = false; - } - spin_unlock_irqrestore(&pn54x_dev->irq_enabled_lock, flags); + spin_lock_irqsave(&pn5xx_dev->irq_enabled_lock, flags); + if (pn5xx_dev->irq_enabled) { + disable_irq_nosync(pn5xx_dev->client->irq); + pn5xx_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn5xx_dev->irq_enabled_lock, flags); } -static irqreturn_t pn54x_dev_irq_handler(int irq, void *dev_id) +static irqreturn_t pn5xx_dev_irq_handler(int irq, void *dev_id) { - struct pn54x_dev *pn54x_dev = dev_id; + struct pn5xx_dev *pn5xx_dev = dev_id; - pn54x_disable_irq(pn54x_dev); + pn5xx_disable_irq(pn5xx_dev); - /* Wake up waiting readers */ - wake_up(&pn54x_dev->read_wq); + /* Wake up waiting readers */ + wake_up(&pn5xx_dev->read_wq); - return IRQ_HANDLED; + return IRQ_HANDLED; } /********************************************************** * private functions **********************************************************/ -static int pn544_enable(struct pn54x_dev *dev, int mode) +static void p61_update_access_state(struct pn5xx_dev *pn5xx_dev, p61_access_state_t current_state, bool set) { - int r; - + pr_info("%s: Enter current_state = %x\n", __func__, pn5xx_dev->p61_current_state); + if (current_state) + { + if(set){ + if(pn5xx_dev->p61_current_state == P61_STATE_IDLE) + pn5xx_dev->p61_current_state = P61_STATE_INVALID; + pn5xx_dev->p61_current_state |= current_state; + } + else{ + pn5xx_dev->p61_current_state ^= current_state; + if(!pn5xx_dev->p61_current_state) + pn5xx_dev->p61_current_state = P61_STATE_IDLE; + } + } + pr_info("%s: Exit current_state = %x\n", __func__, pn5xx_dev->p61_current_state); +} + +static void p61_get_access_state(struct pn5xx_dev *pn5xx_dev, p61_access_state_t *current_state) +{ + + if (current_state == NULL) { + *current_state = P61_STATE_INVALID; + } else { + *current_state = pn5xx_dev->p61_current_state; + } +} + +static void p61_access_lock(struct pn5xx_dev *pn5xx_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_lock(&pn5xx_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} + +static void p61_access_unlock(struct pn5xx_dev *pn5xx_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_unlock(&pn5xx_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} + +static void signal_handler(p61_access_state_t state, long nfc_pid) +{ + struct siginfo sinfo; + pid_t pid; + struct task_struct *task; + int sigret = 0; + pr_info("%s: Enter\n", __func__); + + memset(&sinfo, 0, sizeof(struct siginfo)); + sinfo.si_signo = SIG_NFC; + sinfo.si_code = SI_QUEUE; + sinfo.si_int = state; + pid = nfc_pid; + + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if(task) + { + pr_info("%s.\n", task->comm); + sigret = send_sig_info(SIG_NFC, &sinfo, task); + if(sigret < 0){ + pr_info("send_sig_info failed..... sigret %d.\n", sigret); + //msleep(60); + } + } + else{ + pr_info("finding task from PID failed\r\n"); + } + pr_info("%s: Exit\n", __func__); +} + +static int pn5xx_enable(struct pn5xx_dev *dev, int mode) +{ + int r; + p61_access_state_t current_state; + /* turn on the regulators */ /* -- if the regulators were specified, they're required */ if(dev->pvdd_reg != NULL) @@ -140,34 +228,59 @@ static int pn544_enable(struct pn54x_dev *dev, int mode) goto enable_exit2; } } - - if (MODE_RUN == mode) { + + current_state = P61_STATE_INVALID; + p61_get_access_state(dev, ¤t_state); + if (MODE_RUN == mode) { pr_info("%s power on\n", __func__); - if (gpio_is_valid(dev->firm_gpio)) + if (gpio_is_valid(dev->firm_gpio)) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0) { + p61_update_access_state(dev, P61_STATE_IDLE, true); + } gpio_set_value(dev->firm_gpio, 0); - gpio_set_value(dev->ven_gpio, 1); - msleep(100); - } + } + + dev->nfc_ven_enabled = true; + if (dev->spi_ven_enabled == false) { + gpio_set_value(dev->ven_gpio, 1); + msleep(100); + } + } else if (MODE_FW == mode) { - /* power on with firmware download (requires hw reset) - */ - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(dev->ven_gpio, 1); - msleep(20); - if (gpio_is_valid(dev->firm_gpio)) - gpio_set_value(dev->firm_gpio, 1); - msleep(20); - gpio_set_value(dev->ven_gpio, 0); - msleep(100); - gpio_set_value(dev->ven_gpio, 1); - msleep(20); - } - else { + if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) + { + /* NFCC fw/download should not be allowed if p61 is used + * by SPI + */ + pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); + p61_access_unlock(dev); + return -EBUSY; /* Device or resource busy */ + } + dev->nfc_ven_enabled = true; + if (dev->spi_ven_enabled == false) + { + /* power on with firmware download (requires hw reset) + */ + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(dev->ven_gpio, 1); + msleep(20); + if (gpio_is_valid(dev->firm_gpio)) { + p61_update_access_state(dev, P61_STATE_DWNLD, true); + gpio_set_value(dev->firm_gpio, 1); + } + msleep(20); + gpio_set_value(dev->ven_gpio, 0); + msleep(100); + gpio_set_value(dev->ven_gpio, 1); + msleep(20); + } + } else { pr_err("%s bad arg %d\n", __func__, mode); + p61_access_unlock(dev); return -EINVAL; } - return 0; + return 0; enable_exit2: if(dev->pmuvcc_reg) regulator_disable(dev->pmuvcc_reg); @@ -179,14 +292,25 @@ enable_exit0: return r; } -static void pn544_disable(struct pn54x_dev *dev) +static void pn5xx_disable(struct pn5xx_dev *dev) { /* power off */ pr_info("%s power off\n", __func__); if (gpio_is_valid(dev->firm_gpio)) + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(dev, ¤t_state); + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0) { + p61_update_access_state(dev, P61_STATE_IDLE, true); + } gpio_set_value(dev->firm_gpio, 0); - gpio_set_value(dev->ven_gpio, 0); - msleep(100); + } + dev->nfc_ven_enabled = false; + /* Don't change Ven state if spi made it high */ + if (dev->spi_ven_enabled == false) { + gpio_set_value(dev->ven_gpio, 0); + msleep(100); + } if(dev->sevdd_reg) regulator_disable(dev->sevdd_reg); if(dev->pmuvcc_reg) regulator_disable(dev->pmuvcc_reg); @@ -198,190 +322,388 @@ static void pn544_disable(struct pn54x_dev *dev) /********************************************************** * driver functions **********************************************************/ -static ssize_t pn54x_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) +static ssize_t pn5xx_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) { - struct pn54x_dev *pn54x_dev = filp->private_data; - char tmp[MAX_BUFFER_SIZE]; - int ret; + struct pn5xx_dev *pn5xx_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; - pr_debug("%s : reading %zu bytes.\n", __func__, count); + pr_debug("%s : reading %zu bytes.\n", __func__, count); - mutex_lock(&pn54x_dev->read_mutex); + mutex_lock(&pn5xx_dev->read_mutex); - if (!gpio_get_value(pn54x_dev->irq_gpio)) { - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto fail; - } + if (!gpio_get_value(pn5xx_dev->irq_gpio)) { + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } - while (1) { - pn54x_dev->irq_enabled = true; - enable_irq(pn54x_dev->client->irq); - ret = wait_event_interruptible( - pn54x_dev->read_wq, - !pn54x_dev->irq_enabled); + while (1) { + pn5xx_dev->irq_enabled = true; + enable_irq(pn5xx_dev->client->irq); + ret = wait_event_interruptible( + pn5xx_dev->read_wq, + !pn5xx_dev->irq_enabled); - pn54x_disable_irq(pn54x_dev); + pn5xx_disable_irq(pn5xx_dev); - if (ret) - goto fail; + if (ret) + goto fail; - if (gpio_get_value(pn54x_dev->irq_gpio)) - break; + if (gpio_get_value(pn5xx_dev->irq_gpio)) + break; - pr_warning("%s: spurious interrupt detected\n", __func__); - } - } + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } - /* Read data */ - ret = i2c_master_recv(pn54x_dev->client, tmp, count); + /* Read data */ + ret = i2c_master_recv(pn5xx_dev->client, tmp, count); - mutex_unlock(&pn54x_dev->read_mutex); + mutex_unlock(&pn5xx_dev->read_mutex); - /* pn54x seems to be slow in handling I2C read requests - * so add 1ms delay after recv operation */ - udelay(1000); + /* pn5xx seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ + udelay(1000); - if (ret < 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - return ret; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - return -EIO; - } - if (copy_to_user(buf, tmp, ret)) { - pr_warning("%s : failed to copy to user space\n", __func__); - return -EFAULT; - } - return ret; + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return ret; fail: - mutex_unlock(&pn54x_dev->read_mutex); - return ret; + mutex_unlock(&pn5xx_dev->read_mutex); + return ret; } -static ssize_t pn54x_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) +static ssize_t pn5xx_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) { - struct pn54x_dev *pn54x_dev; - char tmp[MAX_BUFFER_SIZE]; - int ret; + struct pn5xx_dev *pn5xx_dev; + char tmp[MAX_BUFFER_SIZE]; + int ret; - pn54x_dev = filp->private_data; + pn5xx_dev = filp->private_data; - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - return -EFAULT; - } + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } - pr_debug("%s : writing %zu bytes.\n", __func__, count); - /* Write data */ - ret = i2c_master_send(pn54x_dev->client, tmp, count); - if (ret != count) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - ret = -EIO; - } + pr_debug("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn5xx_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } - /* pn54x seems to be slow in handling I2C write requests - * so add 1ms delay after I2C send oparation */ - udelay(1000); + /* pn5xx seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); - return ret; + return ret; } -static int pn54x_dev_open(struct inode *inode, struct file *filp) +static int pn5xx_dev_open(struct inode *inode, struct file *filp) { - struct pn54x_dev *pn54x_dev = container_of(filp->private_data, - struct pn54x_dev, - pn54x_device); + struct pn5xx_dev *pn5xx_dev = container_of(filp->private_data, + struct pn5xx_dev, + pn5xx_device); - filp->private_data = pn54x_dev; + filp->private_data = pn5xx_dev; - pr_info("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + pr_info("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); - // pn544_enable(pn54x_dev, MODE_RUN); + // pn5xx_enable(pn5xx_dev, MODE_RUN); - return 0; + return 0; } -static int pn54x_dev_release(struct inode *inode, struct file *filp) +static int pn5xx_dev_release(struct inode *inode, struct file *filp) { - // struct pn54x_dev *pn54x_dev = container_of(filp->private_data, - // struct pn54x_dev, - // pn54x_device); + // struct pn5xx_dev *pn5xx_dev = container_of(filp->private_data, + // struct pn5xx_dev, + // pn5xx_device); - pr_info("%s : closing %d,%d\n", __func__, imajor(inode), iminor(inode)); + pr_info("%s : closing %d,%d\n", __func__, imajor(inode), iminor(inode)); - // pn544_disable(pn54x_dev); + // pn5xx_disable(pn5xx_dev); - return 0; + return 0; } -static long pn54x_dev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) +static long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) { - struct pn54x_dev *pn54x_dev = filp->private_data; + struct pn5xx_dev *pn5xx_dev = filp->private_data; - pr_info("%s, cmd=%d, arg=%lu\n", __func__, cmd, arg); - switch (cmd) { - case PN544_SET_PWR: - if (arg == 2) { + pr_info("%s, cmd=%d, arg=%lu\n", __func__, cmd, arg); + p61_access_lock(pn5xx_dev); + switch (cmd) { + case PN5XX_SET_PWR: + if (arg == 2) { /* power on w/FW */ - pn544_enable(pn54x_dev, arg); - } else if (arg == 1) { - /* power on */ - pn544_enable(pn54x_dev, arg); - } else if (arg == 0) { - /* power off */ - pn544_disable(pn54x_dev); - } else { - pr_err("%s bad SET_PWR arg %lu\n", __func__, arg); - return -EINVAL; - } - break; - case PN54X_CLK_REQ: + pn5xx_enable(pn5xx_dev, arg); + } else if (arg == 1) { + /* power on */ + pn5xx_enable(pn5xx_dev, arg); + } else if (arg == 0) { + /* power off */ + pn5xx_disable(pn5xx_dev); + } else { + pr_err("%s bad SET_PWR arg %lu\n", __func__, arg); + return -EINVAL; + } + break; + case PN5XX_CLK_REQ: if(1 == arg){ - if(gpio_is_valid(pn54x_dev->clkreq_gpio)){ - gpio_set_value(pn54x_dev->clkreq_gpio, 1); + if(gpio_is_valid(pn5xx_dev->clkreq_gpio)){ + gpio_set_value(pn5xx_dev->clkreq_gpio, 1); } } else if(0 == arg) { - if(gpio_is_valid(pn54x_dev->clkreq_gpio)){ - gpio_set_value(pn54x_dev->clkreq_gpio, 0); + if(gpio_is_valid(pn5xx_dev->clkreq_gpio)){ + gpio_set_value(pn5xx_dev->clkreq_gpio, 0); } } else { - pr_err("%s bad CLK_REQ arg %lu\n", __func__, arg); - return -EINVAL; - } + pr_err("%s bad CLK_REQ arg %lu\n", __func__, arg); + return -EINVAL; + } break; - default: - pr_err("%s bad ioctl %u\n", __func__, cmd); - return -EINVAL; - } + case P61_SET_SPI_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn5xx_dev, ¤t_state); + if (arg == 1) { + pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { + p61_update_access_state(pn5xx_dev, P61_STATE_SPI, true); + pn5xx_dev->spi_ven_enabled = true; + if (pn5xx_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn5xx_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn5xx_dev->ese_pwr_gpio, 1); + } else { + pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); + p61_access_unlock(pn5xx_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); + if(current_state & P61_STATE_SPI_PRIO){ + p61_update_access_state(pn5xx_dev, P61_STATE_SPI_PRIO, false); + if (current_state & P61_STATE_WIRED) + { + if(pn5xx_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn5xx_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + } + } + if (!(current_state & P61_STATE_WIRED)) + gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); + pn5xx_dev->spi_ven_enabled = false; + if (pn5xx_dev->nfc_ven_enabled == false) { + gpio_set_value(pn5xx_dev->ven_gpio, 0); + msleep(10); + } + }else if(current_state & P61_STATE_SPI){ + p61_update_access_state(pn5xx_dev, P61_STATE_SPI, false); + if (!(current_state & P61_STATE_WIRED)) + gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); + pn5xx_dev->spi_ven_enabled = false; + if (pn5xx_dev->nfc_ven_enabled == false) { + gpio_set_value(pn5xx_dev->ven_gpio, 0); + msleep(10); + } + } else { + pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", + __func__, pn5xx_dev->p61_current_state); + p61_access_unlock(pn5xx_dev); + return -EPERM; /* Operation not permitted */ + } + }else if (arg == 2) { + pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); + if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + if (pn5xx_dev->spi_ven_enabled == false) + { + pn5xx_dev->spi_ven_enabled = true; + if (pn5xx_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn5xx_dev->ven_gpio, 1); + msleep(10); + } + } + gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); + msleep(10); + gpio_set_value(pn5xx_dev->ese_pwr_gpio, 1); + msleep(10); + } else { + pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); + p61_access_unlock(pn5xx_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 3) { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { + p61_update_access_state(pn5xx_dev, P61_STATE_SPI_PRIO, true); + if (current_state & P61_STATE_WIRED){ + if(pn5xx_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn5xx_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + } + } + pn5xx_dev->spi_ven_enabled = true; + if (pn5xx_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn5xx_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn5xx_dev->ese_pwr_gpio, 1); + }else { + pr_info("%s : Prio Session Start power on ese failed \n", __func__); + p61_access_unlock(pn5xx_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 4) { + if (current_state & P61_STATE_SPI_PRIO) + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); + p61_update_access_state(pn5xx_dev, P61_STATE_SPI_PRIO, false); + /*after SPI prio timeout, the state is changing from SPI prio to SPI */ + p61_update_access_state(pn5xx_dev, P61_STATE_SPI, true); + if (current_state & P61_STATE_WIRED) + { + if(pn5xx_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn5xx_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + } + } + } + else + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); + p61_access_unlock(pn5xx_dev); + return -EBADRQC; /* Device or resource busy */ + } + }else { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn5xx_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + case P61_GET_PWR_STATUS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn5xx_dev, ¤t_state); + pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); + put_user(current_state, (int __user *)arg); + } + break; + case P61_SET_WIRED_ACCESS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn5xx_dev, ¤t_state); + if (arg == 1) + { + if (current_state) + { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); + p61_update_access_state(pn5xx_dev, P61_STATE_WIRED, true); + if (current_state & P61_STATE_SPI_PRIO) + { + if(pn5xx_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn5xx_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + } + } + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + gpio_set_value(pn5xx_dev->ese_pwr_gpio, 1); + } else { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); + p61_access_unlock(pn5xx_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); + if (current_state & P61_STATE_WIRED){ + p61_update_access_state(pn5xx_dev, P61_STATE_WIRED, false); + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); + } else { + pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", + __func__, pn5xx_dev->p61_current_state); + p61_access_unlock(pn5xx_dev); + return -EPERM; /* Operation not permitted */ + } + } + else { + pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); + p61_access_unlock(pn5xx_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + case PN5XX_SET_NFC_SERVICE_PID: + { + pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); + pn5xx_dev->nfc_service_pid = arg; - return 0; + } + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + p61_access_unlock(pn5xx_dev); + return -EINVAL; + } + p61_access_unlock(pn5xx_dev); + return 0; } -static const struct file_operations pn54x_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = pn54x_dev_read, - .write = pn54x_dev_write, - .open = pn54x_dev_open, - .release = pn54x_dev_release, - .unlocked_ioctl = pn54x_dev_ioctl, +static const struct file_operations pn5xx_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn5xx_dev_read, + .write = pn5xx_dev_write, + .open = pn5xx_dev_open, + .release = pn5xx_dev_release, + .unlocked_ioctl = pn5xx_dev_ioctl, }; - /* * Handlers for alternative sources of platform_data */ @@ -389,61 +711,71 @@ static const struct file_operations pn54x_dev_fops = { /* * Translate OpenFirmware node properties into platform_data */ -static int pn54x_get_pdata(struct device *dev, - struct pn544_i2c_platform_data *pdata) +static int pn5xx_get_pdata(struct device *dev, + struct pn5xx_i2c_platform_data *pdata) { - struct device_node *node; + struct device_node *node; u32 flags; int val; /* make sure there is actually a device tree node */ node = dev->of_node; - if (!node) - return -ENODEV; + if (!node) + return -ENODEV; memset(pdata, 0, sizeof(*pdata)); /* read the dev tree data */ /* ven pin - enable's power to the chip - REQUIRED */ - val = of_get_named_gpio_flags(node, "nxp,pn54x-ven", 0, &flags); - if (val >= 0) { - pdata->ven_gpio = val; - } + val = of_get_named_gpio_flags(node, "nxp,pn544-ven", 0, &flags); + if (val >= 0) { + pdata->ven_gpio = val; + } else{ dev_err(dev, "VEN GPIO error getting from OF node\n"); return val; } /* firm pin - controls firmware download - OPTIONAL */ - val = of_get_named_gpio_flags(node, "nxp,pn54x-firm", 0, &flags); + val = of_get_named_gpio_flags(node, "nxp,pn544-fw-dwnld", 0, &flags); if (val >= 0) { - pdata->firm_gpio = val; + pdata->firm_gpio = val; } else { pdata->firm_gpio = -EINVAL; dev_warn(dev, "FIRM GPIO error getting from OF node\n"); - } + } /* irq pin - data available irq - REQUIRED */ - val = of_get_named_gpio_flags(node, "nxp,pn54x-irq", 0, &flags); - if (val >= 0) { - pdata->irq_gpio = val; - } + val = of_get_named_gpio_flags(node, "nxp,pn544-irq", 0, &flags); + if (val >= 0) { + pdata->irq_gpio = val; + } else { dev_err(dev, "IRQ GPIO error getting from OF node\n"); return val; } + /* ese-pwr pin - enable's power to the ese- REQUIRED */ + val = of_get_named_gpio_flags(node, "nxp,pn544-ese-pwr", 0, &flags); + if (val >= 0) { + pdata->ese_pwr_gpio = val; + } + else { + dev_err(dev, "ESE PWR GPIO error getting from OF node\n"); + return val; + } + /* clkreq pin - controls the clock to the PN547 - OPTIONAL */ - val = of_get_named_gpio_flags(node, "nxp,pn54x-clkreq", 0, &flags); - if (val >= 0) { - pdata->clkreq_gpio = val; + val = of_get_named_gpio_flags(node, "nxp,pn5xx-clkreq", 0, &flags); + if (val >= 0) { + pdata->clkreq_gpio = val; } else { pdata->clkreq_gpio = -EINVAL; dev_warn(dev, "CLKREQ GPIO error getting from OF node\n"); - } + } /* handle the regulator lines - these are optional * PVdd - pad Vdd (544, 547) @@ -456,94 +788,94 @@ static int pn54x_get_pdata(struct device *dev, * Example: if only PVdd is provided, it is the only one that will be * turned on/off. */ - pdata->pvdd_reg = regulator_get(dev, "nxp,pn54x-pvdd"); + pdata->pvdd_reg = regulator_get(dev, "nxp,pn5xx-pvdd"); if(IS_ERR(pdata->pvdd_reg)) { - pr_err("%s: could not get nxp,pn54x-pvdd, rc=%ld\n", __func__, PTR_ERR(pdata->pvdd_reg)); + pr_err("%s: could not get nxp,pn5xx-pvdd, rc=%ld\n", __func__, PTR_ERR(pdata->pvdd_reg)); pdata->pvdd_reg = NULL; } - pdata->vbat_reg = regulator_get(dev, "nxp,pn54x-vbat"); + pdata->vbat_reg = regulator_get(dev, "nxp,pn5xx-vbat"); if (IS_ERR(pdata->vbat_reg)) { - pr_err("%s: could not get nxp,pn54x-vbat, rc=%ld\n", __func__, PTR_ERR(pdata->vbat_reg)); + pr_err("%s: could not get nxp,pn5xx-vbat, rc=%ld\n", __func__, PTR_ERR(pdata->vbat_reg)); pdata->vbat_reg = NULL; } - pdata->pmuvcc_reg = regulator_get(dev, "nxp,pn54x-pmuvcc"); + pdata->pmuvcc_reg = regulator_get(dev, "nxp,pn5xx-pmuvcc"); if (IS_ERR(pdata->pmuvcc_reg)) { - pr_err("%s: could not get nxp,pn54x-pmuvcc, rc=%ld\n", __func__, PTR_ERR(pdata->pmuvcc_reg)); + pr_err("%s: could not get nxp,pn5xx-pmuvcc, rc=%ld\n", __func__, PTR_ERR(pdata->pmuvcc_reg)); pdata->pmuvcc_reg = NULL; } - pdata->sevdd_reg = regulator_get(dev, "nxp,pn54x-sevdd"); + pdata->sevdd_reg = regulator_get(dev, "nxp,pn5xx-sevdd"); if (IS_ERR(pdata->sevdd_reg)) { - pr_err("%s: could not get nxp,pn54x-sevdd, rc=%ld\n", __func__, PTR_ERR(pdata->sevdd_reg)); + pr_err("%s: could not get nxp,pn5xx-sevdd, rc=%ld\n", __func__, PTR_ERR(pdata->sevdd_reg)); pdata->sevdd_reg = NULL; } return 0; } #else -static int pn54x_get_pdata(struct device *dev, - struct pn544_i2c_platform_data *pdata) +static int pn5xx_get_pdata(struct device *dev, + struct pn5xx_i2c_platform_data *pdata) { pdata = dev->platform_data; - return 0; + return 0; } #endif /* - * pn54x_probe + * pn5xx_probe */ #ifdef KERNEL_3_4_AND_OLDER - static int __devinit pn54x_probe(struct i2c_client *client, - const struct i2c_device_id *id) + static int __devinit pn5xx_probe(struct i2c_client *client, + const struct i2c_device_id *id) #else -static int pn54x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pn5xx_probe(struct i2c_client *client, + const struct i2c_device_id *id) #endif { - int ret; - struct pn544_i2c_platform_data *pdata; // gpio values, from board file or DT - struct pn544_i2c_platform_data tmp_pdata; - struct pn54x_dev *pn54x_dev; // internal device specific data + int ret; + struct pn5xx_i2c_platform_data *pdata; // gpio values, from board file or DT + struct pn5xx_i2c_platform_data tmp_pdata; + struct pn5xx_dev *pn5xx_dev; // internal device specific data - pr_info("%s\n", __func__); + pr_info("%s\n", __func__); - /* ---- retrieve the platform data ---- */ + /* ---- retrieve the platform data ---- */ /* If the dev.platform_data is NULL, then */ /* attempt to read from the device tree */ if(!client->dev.platform_data) { - ret = pn54x_get_pdata(&(client->dev), &tmp_pdata); + ret = pn5xx_get_pdata(&(client->dev), &tmp_pdata); if(ret){ return ret; } pdata = &tmp_pdata; } - else + else { pdata = client->dev.platform_data; } - if (pdata == NULL) { - pr_err("%s : nfc probe fail\n", __func__); - return -ENODEV; - } + if (pdata == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } /* validate the the adapter has basic I2C functionality */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - return -ENODEV; - } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } /* reserve the GPIO pins */ - pr_info("%s: request irq_gpio %d\n", __func__, pdata->irq_gpio); - ret = gpio_request(pdata->irq_gpio, "nfc_int"); - if (ret){ + pr_info("%s: request irq_gpio %d\n", __func__, pdata->irq_gpio); + ret = gpio_request(pdata->irq_gpio, "nfc_int"); + if (ret){ pr_err("%s :not able to get GPIO irq_gpio\n", __func__); - return -ENODEV; + return -ENODEV; } ret = gpio_to_irq(pdata->irq_gpio); if (ret < 0){ @@ -554,7 +886,7 @@ static int pn54x_probe(struct i2c_client *client, client->irq = ret; } - pr_info("%s: request ven_gpio %d\n", __func__, pdata->ven_gpio); + pr_info("%s: request ven_gpio %d\n", __func__, pdata->ven_gpio); ret = gpio_request(pdata->ven_gpio, "nfc_ven"); if (ret){ pr_err("%s :not able to get GPIO ven_gpio\n", __func__); @@ -563,203 +895,234 @@ static int pn54x_probe(struct i2c_client *client, if (gpio_is_valid(pdata->firm_gpio)) { pr_info("%s: request firm_gpio %d\n", __func__, pdata->firm_gpio); - ret = gpio_request(pdata->firm_gpio, "nfc_firm"); - if (ret){ + ret = gpio_request(pdata->firm_gpio, "nfc_firm"); + if (ret){ pr_err("%s :not able to get GPIO firm_gpio\n", __func__); - goto err_firm; - } - } - - if (gpio_is_valid(pdata->clkreq_gpio)) { - pr_info("%s: request clkreq_gpio %d\n", __func__, pdata->clkreq_gpio); - ret = gpio_request(pdata->clkreq_gpio, "nfc_clkreq"); - if (ret){ - pr_err("%s :not able to get GPIO clkreq_gpio\n", __func__); - goto err_clkreq; + goto err_firm; } } - /* allocate the pn54x driver information structure */ - pn54x_dev = kzalloc(sizeof(*pn54x_dev), GFP_KERNEL); - if (pn54x_dev == NULL) { - dev_err(&client->dev, "failed to allocate memory for module data\n"); - ret = -ENOMEM; - goto err_exit; - } + if (gpio_is_valid(pdata->ese_pwr_gpio)) { + pr_info("%s: request ese_pwr_gpio %d\n", __func__, pdata->ese_pwr_gpio); + ret = gpio_request(pdata->ese_pwr_gpio, "nfc_ese_pwr"); + if (ret){ + pr_err("%s :not able to get GPIO ese_pwr_gpio\n", __func__); + goto err_ese_pwr; + } + } + + if (gpio_is_valid(pdata->clkreq_gpio)) { + pr_info("%s: request clkreq_gpio %d\n", __func__, pdata->clkreq_gpio); + ret = gpio_request(pdata->clkreq_gpio, "nfc_clkreq"); + if (ret){ + pr_err("%s :not able to get GPIO clkreq_gpio\n", __func__); + goto err_clkreq; + } + } + + /* allocate the pn5xx driver information structure */ + pn5xx_dev = kzalloc(sizeof(*pn5xx_dev), GFP_KERNEL); + if (pn5xx_dev == NULL) { + dev_err(&client->dev, "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } /* store the platform data in the driver info struct */ - pn54x_dev->irq_gpio = pdata->irq_gpio; - pn54x_dev->ven_gpio = pdata->ven_gpio; - pn54x_dev->firm_gpio = pdata->firm_gpio; - pn54x_dev->clkreq_gpio = pdata->clkreq_gpio; - pn54x_dev->pvdd_reg = pdata->pvdd_reg; - pn54x_dev->vbat_reg = pdata->vbat_reg; - pn54x_dev->pmuvcc_reg = pdata->vbat_reg; - pn54x_dev->sevdd_reg = pdata->sevdd_reg; + pn5xx_dev->irq_gpio = pdata->irq_gpio; + pn5xx_dev->ven_gpio = pdata->ven_gpio; + pn5xx_dev->firm_gpio = pdata->firm_gpio; + pn5xx_dev->ese_pwr_gpio = pdata->ese_pwr_gpio; + pn5xx_dev->p61_current_state = P61_STATE_IDLE; + pn5xx_dev->nfc_ven_enabled = false; + pn5xx_dev->spi_ven_enabled = false; + pn5xx_dev->clkreq_gpio = pdata->clkreq_gpio; + pn5xx_dev->pvdd_reg = pdata->pvdd_reg; + pn5xx_dev->vbat_reg = pdata->vbat_reg; + pn5xx_dev->pmuvcc_reg = pdata->vbat_reg; + pn5xx_dev->sevdd_reg = pdata->sevdd_reg; - pn54x_dev->client = client; + pn5xx_dev->client = client; /* finish configuring the I/O */ - ret = gpio_direction_input(pn54x_dev->irq_gpio); - if (ret < 0) { - pr_err("%s :not able to set irq_gpio as input\n", __func__); - goto err_exit; - } + ret = gpio_direction_input(pn5xx_dev->irq_gpio); + if (ret < 0) { + pr_err("%s :not able to set irq_gpio as input\n", __func__); + goto err_exit; + } - ret = gpio_direction_output(pn54x_dev->ven_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_exit; - } + ret = gpio_direction_output(pn5xx_dev->ven_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_exit; + } - if (gpio_is_valid(pn54x_dev->firm_gpio)) { - ret = gpio_direction_output(pn54x_dev->firm_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set firm_gpio as output\n", - __func__); - goto err_exit; - } - } + if (gpio_is_valid(pn5xx_dev->firm_gpio)) { + ret = gpio_direction_output(pn5xx_dev->firm_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set firm_gpio as output\n", + __func__); + goto err_exit; + } + } - if (gpio_is_valid(pn54x_dev->clkreq_gpio)) { - ret = gpio_direction_output(pn54x_dev->clkreq_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set clkreq_gpio as output\n", - __func__); - goto err_exit; - } - } + ret = gpio_direction_output(pn5xx_dev->ese_pwr_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); + goto err_ese_pwr; + } - /* init mutex and queues */ - init_waitqueue_head(&pn54x_dev->read_wq); - mutex_init(&pn54x_dev->read_mutex); - spin_lock_init(&pn54x_dev->irq_enabled_lock); + if (gpio_is_valid(pn5xx_dev->clkreq_gpio)) { + ret = gpio_direction_output(pn5xx_dev->clkreq_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set clkreq_gpio as output\n", + __func__); + goto err_exit; + } + } + + /* init mutex and queues */ + init_waitqueue_head(&pn5xx_dev->read_wq); + mutex_init(&pn5xx_dev->read_mutex); + mutex_init(&pn5xx_dev->p61_state_mutex); + spin_lock_init(&pn5xx_dev->irq_enabled_lock); /* register as a misc device - character based with one entry point */ - pn54x_dev->pn54x_device.minor = MISC_DYNAMIC_MINOR; - pn54x_dev->pn54x_device.name = CHIP; - pn54x_dev->pn54x_device.fops = &pn54x_dev_fops; - ret = misc_register(&pn54x_dev->pn54x_device); - if (ret) { - pr_err("%s : misc_register failed\n", __FILE__); - goto err_misc_register; - } + pn5xx_dev->pn5xx_device.minor = MISC_DYNAMIC_MINOR; + pn5xx_dev->pn5xx_device.name = CHIP; + pn5xx_dev->pn5xx_device.fops = &pn5xx_dev_fops; + ret = misc_register(&pn5xx_dev->pn5xx_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } - /* request irq. the irq is set whenever the chip has data available - * for reading. it is cleared when all data has been read. - */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - pn54x_dev->irq_enabled = true; - ret = request_irq(client->irq, pn54x_dev_irq_handler, - IRQF_TRIGGER_HIGH, client->name, pn54x_dev); - if (ret) { - dev_err(&client->dev, "request_irq failed\n"); - goto err_request_irq_failed; - } - pn54x_disable_irq(pn54x_dev); + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pn5xx_dev->irq_enabled = true; + ret = request_irq(client->irq, pn5xx_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, pn5xx_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + pn5xx_disable_irq(pn5xx_dev); - i2c_set_clientdata(client, pn54x_dev); + i2c_set_clientdata(client, pn5xx_dev); - return 0; + return 0; err_request_irq_failed: - misc_deregister(&pn54x_dev->pn54x_device); + misc_deregister(&pn5xx_dev->pn5xx_device); err_misc_register: + mutex_destroy(&pn5xx_dev->read_mutex); + mutex_destroy(&pn5xx_dev->p61_state_mutex); + kfree(pn5xx_dev); err_exit: - if (gpio_is_valid(pdata->clkreq_gpio)) - gpio_free(pdata->clkreq_gpio); + if (gpio_is_valid(pdata->clkreq_gpio)) + gpio_free(pdata->clkreq_gpio); +err_ese_pwr: + gpio_free(pdata->ese_pwr_gpio); err_clkreq: if (gpio_is_valid(pdata->firm_gpio)) gpio_free(pdata->firm_gpio); err_firm: - gpio_free(pdata->ven_gpio); + gpio_free(pdata->ven_gpio); err_ven: - gpio_free(pdata->irq_gpio); - return ret; + gpio_free(pdata->irq_gpio); + return ret; } #ifdef KERNEL_3_4_AND_OLDER -static int __devexit pn54x_remove(struct i2c_client *client) +static int __devexit pn5xx_remove(struct i2c_client *client) #else -static int pn54x_remove(struct i2c_client *client) +static int pn5xx_remove(struct i2c_client *client) #endif { - struct pn54x_dev *pn54x_dev; + struct pn5xx_dev *pn5xx_dev; pr_info("%s\n", __func__); - pn54x_dev = i2c_get_clientdata(client); - free_irq(client->irq, pn54x_dev); - misc_deregister(&pn54x_dev->pn54x_device); - mutex_destroy(&pn54x_dev->read_mutex); - gpio_free(pn54x_dev->irq_gpio); - gpio_free(pn54x_dev->ven_gpio); - if (gpio_is_valid(pn54x_dev->firm_gpio)) - gpio_free(pn54x_dev->firm_gpio); - if (gpio_is_valid(pn54x_dev->clkreq_gpio)) - gpio_free(pn54x_dev->clkreq_gpio); - regulator_put(pn54x_dev->pvdd_reg); - regulator_put(pn54x_dev->vbat_reg); - regulator_put(pn54x_dev->pmuvcc_reg); - regulator_put(pn54x_dev->sevdd_reg); - - kfree(pn54x_dev); + pn5xx_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn5xx_dev); + misc_deregister(&pn5xx_dev->pn5xx_device); + mutex_destroy(&pn5xx_dev->read_mutex); + mutex_destroy(&pn5xx_dev->p61_state_mutex); + gpio_free(pn5xx_dev->irq_gpio); + gpio_free(pn5xx_dev->ven_gpio); + gpio_free(pn5xx_dev->ese_pwr_gpio); + pn5xx_dev->p61_current_state = P61_STATE_INVALID; + pn5xx_dev->nfc_ven_enabled = false; + pn5xx_dev->spi_ven_enabled = false; - return 0; + if (gpio_is_valid(pn5xx_dev->firm_gpio)) + gpio_free(pn5xx_dev->firm_gpio); + if (gpio_is_valid(pn5xx_dev->clkreq_gpio)) + gpio_free(pn5xx_dev->clkreq_gpio); + regulator_put(pn5xx_dev->pvdd_reg); + regulator_put(pn5xx_dev->vbat_reg); + regulator_put(pn5xx_dev->pmuvcc_reg); + regulator_put(pn5xx_dev->sevdd_reg); + + kfree(pn5xx_dev); + + return 0; } /* * */ #ifdef CONFIG_OF -static struct of_device_id pn54x_dt_match[] = { +static struct of_device_id pn5xx_dt_match[] = { { .compatible = "nxp,pn547", }, { .compatible = "nxp,pn544", }, {}, }; -MODULE_DEVICE_TABLE(of, pn54x_dt_match); +MODULE_DEVICE_TABLE(of, pn5xx_dt_match); #endif -static const struct i2c_device_id pn54x_id[] = { - { "pn547", 0 }, - { }, +static const struct i2c_device_id pn5xx_id[] = { + { "pn547", 0 }, + { }, }; -MODULE_DEVICE_TABLE(i2c, pn54x_id); +MODULE_DEVICE_TABLE(i2c, pn5xx_id); -static struct i2c_driver pn54x_driver = { - .id_table = pn54x_id, - .probe = pn54x_probe, +static struct i2c_driver pn5xx_driver = { + .id_table = pn5xx_id, + .probe = pn5xx_probe, #ifdef KERNEL_3_4_AND_OLDER - .remove = __devexit_p(pn54x_remove), + .remove = __devexit_p(pn5xx_remove), #else - .remove = pn54x_remove, + .remove = pn5xx_remove, #endif - .driver = { - .owner = THIS_MODULE, - .name = "pn544", - .of_match_table = pn54x_dt_match, - }, + .driver = { + .owner = THIS_MODULE, + .name = "pn544", + .of_match_table = pn5xx_dt_match, + }, }; /* * module load/unload record keeping */ -static int __init pn54x_dev_init(void) +static int __init pn5xx_dev_init(void) { - pr_info("%s\n", __func__); - return i2c_add_driver(&pn54x_driver); + pr_info("%s\n", __func__); + return i2c_add_driver(&pn5xx_driver); } -static void __exit pn54x_dev_exit(void) +static void __exit pn5xx_dev_exit(void) { - pr_info("%s\n", __func__); - i2c_del_driver(&pn54x_driver); + pr_info("%s\n", __func__); + i2c_del_driver(&pn5xx_driver); } -module_init(pn54x_dev_init); -module_exit(pn54x_dev_exit); +module_init(pn5xx_dev_init); +module_exit(pn5xx_dev_exit); MODULE_AUTHOR("Sylvain Fonteneau"); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/pn5xx_i2c.h b/pn5xx_i2c.h index c6fbcde887..12083f1f64 100644 --- a/pn5xx_i2c.h +++ b/pn5xx_i2c.h @@ -17,13 +17,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define PN544_MAGIC 0xE9 +#define PN5XX_MAGIC 0xE9 /* - * PN544 power control via ioctl - * PN544_SET_PWR(0): power off - * PN544_SET_PWR(1): power on - * PN544_SET_PWR(2): reset and power on with firmware download enabled + * PN5XX power control via ioctl + * PN5XX_SET_PWR(0): power off + * PN5XX_SET_PWR(1): power on + * PN5XX_SET_PWR(2): reset and power on with firmware download enabled */ #define PWR_OFF 0 @@ -33,13 +33,51 @@ #define CLK_OFF 0 #define CLK_ON 1 -#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, unsigned int) -#define PN54X_CLK_REQ _IOW(PN544_MAGIC, 0x02, unsigned int) +#define PN5XX_SET_PWR _IOW(PN5XX_MAGIC, 0x01, unsigned int) -struct pn544_i2c_platform_data { - unsigned int irq_gpio; - unsigned int ven_gpio; - unsigned int firm_gpio; +/* + * SPI Request NFCC to enable p61 power, only in param + * Only for SPI + * level 1 = Enable power + * level 0 = Disable power + */ +#define P61_SET_SPI_PWR _IOW(PN5XX_MAGIC, 0x02, unsigned int) + +/* SPI or DWP can call this ioctl to get the current + * power state of P61 + * +*/ +#define P61_GET_PWR_STATUS _IOR(PN5XX_MAGIC, 0x03, unsigned int) + +/* DWP side this ioctl will be called + * level 1 = Wired access is enabled/ongoing + * level 0 = Wired access is disalbed/stopped +*/ +#define P61_SET_WIRED_ACCESS _IOW(PN5XX_MAGIC, 0x04, unsigned int) + +/* + NFC Init will call the ioctl to register the PID with the i2c driver +*/ +#define PN5XX_SET_NFC_SERVICE_PID _IOW(PN5XX_MAGIC, 0x05, long) + +#define PN5XX_CLK_REQ _IOW(PN5XX_MAGIC, 0x06, unsigned int) + +typedef enum p61_access_state{ + P61_STATE_INVALID = 0x0000, + P61_STATE_IDLE = 0x0100, /* p61 is free to use */ + P61_STATE_WIRED = 0x0200, /* p61 is being accessed by DWP (NFCC)*/ + P61_STATE_SPI = 0x0400, /* P61 is being accessed by SPI */ + P61_STATE_DWNLD = 0x0800, /* NFCC fw download is in progress */ + P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ + P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ +}p61_access_state_t; + + +struct pn5xx_i2c_platform_data { + unsigned int irq_gpio; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ unsigned int clkreq_gpio; struct regulator *pvdd_reg; struct regulator *vbat_reg; From 7221b816e74d894fabdf843cb4c5fca503ff7610 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Thu, 14 Jan 2016 22:11:33 +0530 Subject: [PATCH 006/100] driver updates --- pn5xx_i2c.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pn5xx_i2c.c b/pn5xx_i2c.c index c4c6d9a5e0..74e3938328 100644 --- a/pn5xx_i2c.c +++ b/pn5xx_i2c.c @@ -343,12 +343,17 @@ static ssize_t pn5xx_dev_read(struct file *filp, char __user *buf, } while (1) { + ret = 0; pn5xx_dev->irq_enabled = true; enable_irq(pn5xx_dev->client->irq); + /*If IRQ line is already high, which means IRQ was high + just before enabling the interrupt, skip waiting for interrupt, + as interrupt would have been disabled by then in the interrupt handler*/ + if (!gpio_get_value(pn544_dev->irq_gpio)){ ret = wait_event_interruptible( pn5xx_dev->read_wq, !pn5xx_dev->irq_enabled); - + } pn5xx_disable_irq(pn5xx_dev); if (ret) From a377fe1ed02203104a9b9d8829910541ed5bcbfd Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Fri, 27 May 2016 20:38:55 +0530 Subject: [PATCH 007/100] SEAccessKit_AR3.3.0_OpnSrc --- pn5xx_i2c.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++------- pn5xx_i2c.h | 9 +++++- 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/pn5xx_i2c.c b/pn5xx_i2c.c index 74e3938328..08bd9b5beb 100644 --- a/pn5xx_i2c.c +++ b/pn5xx_i2c.c @@ -84,6 +84,10 @@ struct pn5xx_dev { long nfc_service_pid; /*used to signal the nfc the nfc service */ }; +static struct pn5xx_dev *pn5xx_dev; +static struct semaphore ese_access_sema; +static void release_ese_lock(p61_access_state_t p61_current_state); +int get_ese_lock(p61_access_state_t p61_current_state, int timeout); static void p61_get_access_state(struct pn5xx_dev*, p61_access_state_t*); /********************************************************** @@ -177,9 +181,9 @@ static void signal_handler(p61_access_state_t state, long nfc_pid) if(task) { pr_info("%s.\n", task->comm); - sigret = send_sig_info(SIG_NFC, &sinfo, task); + sigret = force_sig_info(SIG_NFC, &sinfo, task); if(sigret < 0){ - pr_info("send_sig_info failed..... sigret %d.\n", sigret); + pr_info("force_sig_info failed..... sigret %d.\n", sigret); //msleep(60); } } @@ -349,7 +353,7 @@ static ssize_t pn5xx_dev_read(struct file *filp, char __user *buf, /*If IRQ line is already high, which means IRQ was high just before enabling the interrupt, skip waiting for interrupt, as interrupt would have been disabled by then in the interrupt handler*/ - if (!gpio_get_value(pn544_dev->irq_gpio)){ + if (!gpio_get_value(pn5xx_dev->irq_gpio)){ ret = wait_event_interruptible( pn5xx_dev->read_wq, !pn5xx_dev->irq_enabled); @@ -455,12 +459,17 @@ static int pn5xx_dev_release(struct inode *inode, struct file *filp) return 0; } -static long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, +long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct pn5xx_dev *pn5xx_dev = filp->private_data; pr_info("%s, cmd=%d, arg=%lu\n", __func__, cmd, arg); + + if (cmd == PN5XX_GET_ESE_ACCESS) + { + return get_ese_lock(P61_STATE_WIRED, arg); + } p61_access_lock(pn5xx_dev); switch (cmd) { case PN5XX_SET_PWR: @@ -501,6 +510,17 @@ static long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { p61_update_access_state(pn5xx_dev, P61_STATE_SPI, true); + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if (current_state & P61_STATE_WIRED){ + if(pn5xx_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI, pn5xx_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + } + } pn5xx_dev->spi_ven_enabled = true; if (pn5xx_dev->nfc_ven_enabled == false) { /* provide power to NFCC if, NFC service not provided */ @@ -537,8 +557,20 @@ static long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, } }else if(current_state & P61_STATE_SPI){ p61_update_access_state(pn5xx_dev, P61_STATE_SPI, false); - if (!(current_state & P61_STATE_WIRED)) + if (!(current_state & P61_STATE_WIRED)){ gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); + } + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if (current_state & P61_STATE_WIRED){ + if(pn5xx_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI, pn5xx_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); + } + } pn5xx_dev->spi_ven_enabled = false; if (pn5xx_dev->nfc_ven_enabled == false) { gpio_set_value(pn5xx_dev->ven_gpio, 0); @@ -621,7 +653,10 @@ static long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, p61_access_unlock(pn5xx_dev); return -EBADRQC; /* Device or resource busy */ } - }else { + } else if(arg == 5){ + release_ese_lock(P61_STATE_SPI); + } + else { pr_info("%s bad ese pwr arg %lu\n", __func__, arg); p61_access_unlock(pn5xx_dev); return -EBADRQC; /* Invalid request code */ @@ -676,6 +711,20 @@ static long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, return -EPERM; /* Operation not permitted */ } } + else if(arg == 2) + { + pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); + gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); + } + else if(arg == 3) + { + pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); + gpio_set_value(pn5xx_dev->ese_pwr_gpio, 1); + } + else if(arg == 4) + { + release_ese_lock(P61_STATE_WIRED); + } else { pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); p61_access_unlock(pn5xx_dev); @@ -699,6 +748,25 @@ static long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, return 0; } +EXPORT_SYMBOL(pn5xx_dev_ioctl); +int get_ese_lock(p61_access_state_t p61_current_state, int timeout) +{ + unsigned long tempJ = msecs_to_jiffies(timeout); + if(down_timeout(&ese_access_sema, tempJ) != 0) + { + printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); + return -EBUSY; + } + return 0; +} + +EXPORT_SYMBOL(get_ese_lock); + +static void release_ese_lock(p61_access_state_t p61_current_state) +{ + up(&ese_access_sema); +} + static const struct file_operations pn5xx_dev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -733,7 +801,7 @@ static int pn5xx_get_pdata(struct device *dev, /* read the dev tree data */ /* ven pin - enable's power to the chip - REQUIRED */ - val = of_get_named_gpio_flags(node, "nxp,pn544-ven", 0, &flags); + val = of_get_named_gpio_flags(node, "nxp,pn5xx-ven", 0, &flags); if (val >= 0) { pdata->ven_gpio = val; } @@ -743,7 +811,7 @@ static int pn5xx_get_pdata(struct device *dev, } /* firm pin - controls firmware download - OPTIONAL */ - val = of_get_named_gpio_flags(node, "nxp,pn544-fw-dwnld", 0, &flags); + val = of_get_named_gpio_flags(node, "nxp,pn5xx-fw-dwnld", 0, &flags); if (val >= 0) { pdata->firm_gpio = val; } @@ -753,7 +821,7 @@ static int pn5xx_get_pdata(struct device *dev, } /* irq pin - data available irq - REQUIRED */ - val = of_get_named_gpio_flags(node, "nxp,pn544-irq", 0, &flags); + val = of_get_named_gpio_flags(node, "nxp,pn5xx-irq", 0, &flags); if (val >= 0) { pdata->irq_gpio = val; } @@ -763,7 +831,7 @@ static int pn5xx_get_pdata(struct device *dev, } /* ese-pwr pin - enable's power to the ese- REQUIRED */ - val = of_get_named_gpio_flags(node, "nxp,pn544-ese-pwr", 0, &flags); + val = of_get_named_gpio_flags(node, "nxp,pn5xx-ese-pwr", 0, &flags); if (val >= 0) { pdata->ese_pwr_gpio = val; } @@ -843,7 +911,7 @@ static int pn5xx_probe(struct i2c_client *client, int ret; struct pn5xx_i2c_platform_data *pdata; // gpio values, from board file or DT struct pn5xx_i2c_platform_data tmp_pdata; - struct pn5xx_dev *pn5xx_dev; // internal device specific data +// struct pn5xx_dev *pn5xx_dev; // internal device specific data pr_info("%s\n", __func__); @@ -989,6 +1057,7 @@ static int pn5xx_probe(struct i2c_client *client, /* init mutex and queues */ init_waitqueue_head(&pn5xx_dev->read_wq); mutex_init(&pn5xx_dev->read_mutex); + sema_init(&ese_access_sema, 1); mutex_init(&pn5xx_dev->p61_state_mutex); spin_lock_init(&pn5xx_dev->irq_enabled_lock); diff --git a/pn5xx_i2c.h b/pn5xx_i2c.h index 12083f1f64..e6e864f791 100644 --- a/pn5xx_i2c.h +++ b/pn5xx_i2c.h @@ -59,8 +59,14 @@ NFC Init will call the ioctl to register the PID with the i2c driver */ #define PN5XX_SET_NFC_SERVICE_PID _IOW(PN5XX_MAGIC, 0x05, long) +/* + NFC and SPI will call the ioctl to get the i2c/spi bus access +*/ +#define PN5XX_GET_ESE_ACCESS _IOW(PN5XX_MAGIC, 0x06, long) + +#define PN5XX_CLK_REQ _IOW(PN5XX_MAGIC, 0x07, unsigned int) + -#define PN5XX_CLK_REQ _IOW(PN5XX_MAGIC, 0x06, unsigned int) typedef enum p61_access_state{ P61_STATE_INVALID = 0x0000, @@ -70,6 +76,7 @@ typedef enum p61_access_state{ P61_STATE_DWNLD = 0x0800, /* NFCC fw download is in progress */ P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ + P61_STATE_SPI_END = 0x4000, }p61_access_state_t; From 0f7c5e5cc0248f55111e9172319bc4632925f669 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Mon, 1 Aug 2016 18:55:41 +0530 Subject: [PATCH 008/100] driver updates for SEAccessKit_AR3.5.0_OpnSrc --- pn5xx_i2c.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ pn5xx_i2c.h | 14 +++++++++--- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/pn5xx_i2c.c b/pn5xx_i2c.c index 08bd9b5beb..09c03a29c4 100644 --- a/pn5xx_i2c.c +++ b/pn5xx_i2c.c @@ -185,6 +185,7 @@ static void signal_handler(p61_access_state_t state, long nfc_pid) if(sigret < 0){ pr_info("force_sig_info failed..... sigret %d.\n", sigret); //msleep(60); + ret = -1; } } else{ @@ -482,6 +483,22 @@ long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, } else if (arg == 0) { /* power off */ pn5xx_disable(pn5xx_dev); + } else if (arg == 3) { + /*NFC Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn5xx_dev, ¤t_state); + if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + p61_access_unlock(pn5xx_dev); + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_WIRED) { + p61_update_access_state(pn5xx_dev, P61_STATE_WIRED, false); + } + gpio_set_value(pn5xx_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn5xx_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from DWP DONE\n", __func__); } else { pr_err("%s bad SET_PWR arg %lu\n", __func__, arg); return -EINVAL; @@ -548,6 +565,12 @@ long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); } } + + pn5xx_dev->spi_ven_enabled = false; + + if(pn5xx_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + if (!(current_state & P61_STATE_WIRED)) gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); pn5xx_dev->spi_ven_enabled = false; @@ -655,6 +678,24 @@ long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, } } else if(arg == 5){ release_ese_lock(P61_STATE_SPI); + } else if (arg == 6) { + /*SPI Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn5xx_dev, ¤t_state); + if(current_state & P61_STATE_WIRED) { + p61_access_unlock(pn5xx_dev); + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_SPI) { + p61_update_access_state(pn5xx_dev, P61_STATE_SPI, false); + }else if(current_state & P61_STATE_SPI_PRIO) { + p61_update_access_state(pn5xx_dev, P61_STATE_SPI_PRIO, false); + } + gpio_set_value(pn5xx_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn5xx_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from SPI DONE\n", __func__); } else { pr_info("%s bad ese pwr arg %lu\n", __func__, arg); @@ -739,6 +780,29 @@ long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, } break; + case P5XX_SET_POWER_SCHEME: + { + if(arg == PN67T_PWR_SCHEME) + { + pn5xx_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); + } + else if(arg == PN80T_LEGACY_PWR_SCHEME) + { + pn5xx_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; + pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); + } + else if(arg == PN80T_EXT_PMU_SCHEME) + { + pn5xx_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; + pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); + } + else + { + pr_info("%s : The power scheme is invalid,\n", __func__); + } + } + break; default: pr_err("%s bad ioctl %u\n", __func__, cmd); p61_access_unlock(pn5xx_dev); diff --git a/pn5xx_i2c.h b/pn5xx_i2c.h index e6e864f791..7ecfaaa302 100644 --- a/pn5xx_i2c.h +++ b/pn5xx_i2c.h @@ -64,9 +64,11 @@ */ #define PN5XX_GET_ESE_ACCESS _IOW(PN5XX_MAGIC, 0x06, long) -#define PN5XX_CLK_REQ _IOW(PN5XX_MAGIC, 0x07, unsigned int) - - +/* + NFC and SPI will call the ioctl to update the power scheme +*/ +#define PN5XX_SET_POWER_SCHEME _IOW(PN5XX_MAGIC, 0x07, long) +#define PN5XX_CLK_REQ _IOW(PN5XX_MAGIC, 0x09, unsigned int) typedef enum p61_access_state{ P61_STATE_INVALID = 0x0000, @@ -79,6 +81,11 @@ typedef enum p61_access_state{ P61_STATE_SPI_END = 0x4000, }p61_access_state_t; +typedef enum chip_type_pwr_scheme{ + PN67T_PWR_SCHEME = 0x01, + PN80T_LEGACY_PWR_SCHEME, + PN80T_EXT_PMU_SCHEME, +}chip_pwr_scheme_t; struct pn5xx_i2c_platform_data { unsigned int irq_gpio; @@ -90,4 +97,5 @@ struct pn5xx_i2c_platform_data { struct regulator *vbat_reg; struct regulator *pmuvcc_reg; struct regulator *sevdd_reg; + unsigned int iso_rst_gpio; /* gpio used for ISO hard reset P73*/ }; From 9cfd4a3a279dd9e89a545a21ad55b26a1db92407 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Thu, 22 Dec 2016 18:49:38 +0530 Subject: [PATCH 009/100] NFC_NCIHALx_ARC0.7.2.0_N --- Kconfig | 12 - Makefile | 10 - pn5xx_i2c.c | 1268 --------------------------------------------------- pn5xx_i2c.h | 101 ---- 4 files changed, 1391 deletions(-) delete mode 100644 Kconfig delete mode 100644 Makefile delete mode 100644 pn5xx_i2c.c delete mode 100644 pn5xx_i2c.h diff --git a/Kconfig b/Kconfig deleted file mode 100644 index 4e770199c8..0000000000 --- a/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config NFC_NXP_PN5XX - tristate "NXP PN5XX based driver" - depends on I2C - select CRC_CCITT - default n - ---help--- - NXP PN5XX driver based on I2C. - This is a driver to provides I2C access to PN5xx NFC Controller devices - - To compile this driver as a module, choose m here. The module will - be called pn5xx_i2c. - Say N if unsure. diff --git a/Makefile b/Makefile deleted file mode 100644 index f4efe8ee70..0000000000 --- a/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for NXP-NCI NFC driver -# - -nxp-pn5xx-objs = pn5xx_i2c.o - -obj-$(CONFIG_NFC_NXP_PN5XX) += pn5xx_i2c.o - -ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG -ccflags := -DDEBUG diff --git a/pn5xx_i2c.c b/pn5xx_i2c.c deleted file mode 100644 index 09c03a29c4..0000000000 --- a/pn5xx_i2c.c +++ /dev/null @@ -1,1268 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * modifications copyright (C) 2015 NXP B.V. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pn5xx_i2c.h" -#include -#include -#include -#include -#include -#include -#include - -#define SIG_NFC 44 -#define MAX_BUFFER_SIZE 512 - -#define MODE_OFF 0 -#define MODE_RUN 1 -#define MODE_FW 2 - -/* Only pn548, pn547 and pn544 are supported */ -#define CHIP "pn544" -#define DRIVER_CARD "PN5xx NFC" -#define DRIVER_DESC "NFC driver for PN5xx Family" - -#ifndef CONFIG_OF -#define CONFIG_OF -#endif - -struct pn5xx_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct i2c_client *client; - struct miscdevice pn5xx_device; - int ven_gpio; - int firm_gpio; - int irq_gpio; - int clkreq_gpio; - struct regulator *pvdd_reg; - struct regulator *vbat_reg; - struct regulator *pmuvcc_reg; - struct regulator *sevdd_reg; - unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ - struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ - p61_access_state_t p61_current_state; /* stores the current P61 state */ - bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ - bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ - bool irq_enabled; - spinlock_t irq_enabled_lock; - long nfc_service_pid; /*used to signal the nfc the nfc service */ -}; - -static struct pn5xx_dev *pn5xx_dev; -static struct semaphore ese_access_sema; -static void release_ese_lock(p61_access_state_t p61_current_state); -int get_ese_lock(p61_access_state_t p61_current_state, int timeout); -static void p61_get_access_state(struct pn5xx_dev*, p61_access_state_t*); - -/********************************************************** - * Interrupt control and handler - **********************************************************/ -static void pn5xx_disable_irq(struct pn5xx_dev *pn5xx_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pn5xx_dev->irq_enabled_lock, flags); - if (pn5xx_dev->irq_enabled) { - disable_irq_nosync(pn5xx_dev->client->irq); - pn5xx_dev->irq_enabled = false; - } - spin_unlock_irqrestore(&pn5xx_dev->irq_enabled_lock, flags); -} - -static irqreturn_t pn5xx_dev_irq_handler(int irq, void *dev_id) -{ - struct pn5xx_dev *pn5xx_dev = dev_id; - - pn5xx_disable_irq(pn5xx_dev); - - /* Wake up waiting readers */ - wake_up(&pn5xx_dev->read_wq); - - return IRQ_HANDLED; -} - -/********************************************************** - * private functions - **********************************************************/ -static void p61_update_access_state(struct pn5xx_dev *pn5xx_dev, p61_access_state_t current_state, bool set) -{ - pr_info("%s: Enter current_state = %x\n", __func__, pn5xx_dev->p61_current_state); - if (current_state) - { - if(set){ - if(pn5xx_dev->p61_current_state == P61_STATE_IDLE) - pn5xx_dev->p61_current_state = P61_STATE_INVALID; - pn5xx_dev->p61_current_state |= current_state; - } - else{ - pn5xx_dev->p61_current_state ^= current_state; - if(!pn5xx_dev->p61_current_state) - pn5xx_dev->p61_current_state = P61_STATE_IDLE; - } - } - pr_info("%s: Exit current_state = %x\n", __func__, pn5xx_dev->p61_current_state); -} - -static void p61_get_access_state(struct pn5xx_dev *pn5xx_dev, p61_access_state_t *current_state) -{ - - if (current_state == NULL) { - *current_state = P61_STATE_INVALID; - } else { - *current_state = pn5xx_dev->p61_current_state; - } -} - -static void p61_access_lock(struct pn5xx_dev *pn5xx_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_lock(&pn5xx_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} - -static void p61_access_unlock(struct pn5xx_dev *pn5xx_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_unlock(&pn5xx_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} - -static void signal_handler(p61_access_state_t state, long nfc_pid) -{ - struct siginfo sinfo; - pid_t pid; - struct task_struct *task; - int sigret = 0; - pr_info("%s: Enter\n", __func__); - - memset(&sinfo, 0, sizeof(struct siginfo)); - sinfo.si_signo = SIG_NFC; - sinfo.si_code = SI_QUEUE; - sinfo.si_int = state; - pid = nfc_pid; - - task = pid_task(find_vpid(pid), PIDTYPE_PID); - if(task) - { - pr_info("%s.\n", task->comm); - sigret = force_sig_info(SIG_NFC, &sinfo, task); - if(sigret < 0){ - pr_info("force_sig_info failed..... sigret %d.\n", sigret); - //msleep(60); - ret = -1; - } - } - else{ - pr_info("finding task from PID failed\r\n"); - } - pr_info("%s: Exit\n", __func__); -} - -static int pn5xx_enable(struct pn5xx_dev *dev, int mode) -{ - int r; - p61_access_state_t current_state; - - /* turn on the regulators */ - /* -- if the regulators were specified, they're required */ - if(dev->pvdd_reg != NULL) - { - r = regulator_enable(dev->pvdd_reg); - if (r < 0){ - pr_err("%s: not able to enable pvdd\n", __func__); - return r; - } - } - if(dev->vbat_reg != NULL) - { - r = regulator_enable(dev->vbat_reg); - if (r < 0){ - pr_err("%s: not able to enable vbat\n", __func__); - goto enable_exit0; - } - } - if(dev->pmuvcc_reg != NULL) - { - r = regulator_enable(dev->pmuvcc_reg); - if (r < 0){ - pr_err("%s: not able to enable pmuvcc\n", __func__); - goto enable_exit1; - } - } - if(dev->sevdd_reg != NULL) - { - r = regulator_enable(dev->sevdd_reg); - if (r < 0){ - pr_err("%s: not able to enable sevdd\n", __func__); - goto enable_exit2; - } - } - - current_state = P61_STATE_INVALID; - p61_get_access_state(dev, ¤t_state); - if (MODE_RUN == mode) { - pr_info("%s power on\n", __func__); - if (gpio_is_valid(dev->firm_gpio)) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0) { - p61_update_access_state(dev, P61_STATE_IDLE, true); - } - gpio_set_value(dev->firm_gpio, 0); - } - - dev->nfc_ven_enabled = true; - if (dev->spi_ven_enabled == false) { - gpio_set_value(dev->ven_gpio, 1); - msleep(100); - } - } - else if (MODE_FW == mode) { - if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) - { - /* NFCC fw/download should not be allowed if p61 is used - * by SPI - */ - pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); - p61_access_unlock(dev); - return -EBUSY; /* Device or resource busy */ - } - dev->nfc_ven_enabled = true; - if (dev->spi_ven_enabled == false) - { - /* power on with firmware download (requires hw reset) - */ - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(dev->ven_gpio, 1); - msleep(20); - if (gpio_is_valid(dev->firm_gpio)) { - p61_update_access_state(dev, P61_STATE_DWNLD, true); - gpio_set_value(dev->firm_gpio, 1); - } - msleep(20); - gpio_set_value(dev->ven_gpio, 0); - msleep(100); - gpio_set_value(dev->ven_gpio, 1); - msleep(20); - } - } else { - pr_err("%s bad arg %d\n", __func__, mode); - p61_access_unlock(dev); - return -EINVAL; - } - - return 0; - -enable_exit2: - if(dev->pmuvcc_reg) regulator_disable(dev->pmuvcc_reg); -enable_exit1: - if(dev->vbat_reg) regulator_disable(dev->vbat_reg); -enable_exit0: - if(dev->pvdd_reg) regulator_disable(dev->pvdd_reg); - - return r; -} - -static void pn5xx_disable(struct pn5xx_dev *dev) -{ - /* power off */ - pr_info("%s power off\n", __func__); - if (gpio_is_valid(dev->firm_gpio)) - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(dev, ¤t_state); - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0) { - p61_update_access_state(dev, P61_STATE_IDLE, true); - } - gpio_set_value(dev->firm_gpio, 0); - } - dev->nfc_ven_enabled = false; - /* Don't change Ven state if spi made it high */ - if (dev->spi_ven_enabled == false) { - gpio_set_value(dev->ven_gpio, 0); - msleep(100); - } - - if(dev->sevdd_reg) regulator_disable(dev->sevdd_reg); - if(dev->pmuvcc_reg) regulator_disable(dev->pmuvcc_reg); - if(dev->vbat_reg) regulator_disable(dev->vbat_reg); - if(dev->pvdd_reg) regulator_disable(dev->pvdd_reg); - -} - -/********************************************************** - * driver functions - **********************************************************/ -static ssize_t pn5xx_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - struct pn5xx_dev *pn5xx_dev = filp->private_data; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - pr_debug("%s : reading %zu bytes.\n", __func__, count); - - mutex_lock(&pn5xx_dev->read_mutex); - - if (!gpio_get_value(pn5xx_dev->irq_gpio)) { - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto fail; - } - - while (1) { - ret = 0; - pn5xx_dev->irq_enabled = true; - enable_irq(pn5xx_dev->client->irq); - /*If IRQ line is already high, which means IRQ was high - just before enabling the interrupt, skip waiting for interrupt, - as interrupt would have been disabled by then in the interrupt handler*/ - if (!gpio_get_value(pn5xx_dev->irq_gpio)){ - ret = wait_event_interruptible( - pn5xx_dev->read_wq, - !pn5xx_dev->irq_enabled); - } - pn5xx_disable_irq(pn5xx_dev); - - if (ret) - goto fail; - - if (gpio_get_value(pn5xx_dev->irq_gpio)) - break; - - pr_warning("%s: spurious interrupt detected\n", __func__); - } - } - - /* Read data */ - ret = i2c_master_recv(pn5xx_dev->client, tmp, count); - - mutex_unlock(&pn5xx_dev->read_mutex); - - /* pn5xx seems to be slow in handling I2C read requests - * so add 1ms delay after recv operation */ - udelay(1000); - - if (ret < 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - return ret; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - return -EIO; - } - if (copy_to_user(buf, tmp, ret)) { - pr_warning("%s : failed to copy to user space\n", __func__); - return -EFAULT; - } - return ret; - -fail: - mutex_unlock(&pn5xx_dev->read_mutex); - return ret; -} - -static ssize_t pn5xx_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - struct pn5xx_dev *pn5xx_dev; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - pn5xx_dev = filp->private_data; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - return -EFAULT; - } - - pr_debug("%s : writing %zu bytes.\n", __func__, count); - /* Write data */ - ret = i2c_master_send(pn5xx_dev->client, tmp, count); - if (ret != count) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - ret = -EIO; - } - - /* pn5xx seems to be slow in handling I2C write requests - * so add 1ms delay after I2C send oparation */ - udelay(1000); - - return ret; -} - -static int pn5xx_dev_open(struct inode *inode, struct file *filp) -{ - struct pn5xx_dev *pn5xx_dev = container_of(filp->private_data, - struct pn5xx_dev, - pn5xx_device); - - filp->private_data = pn5xx_dev; - - pr_info("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); - - // pn5xx_enable(pn5xx_dev, MODE_RUN); - - return 0; -} - -static int pn5xx_dev_release(struct inode *inode, struct file *filp) -{ - // struct pn5xx_dev *pn5xx_dev = container_of(filp->private_data, - // struct pn5xx_dev, - // pn5xx_device); - - pr_info("%s : closing %d,%d\n", __func__, imajor(inode), iminor(inode)); - - // pn5xx_disable(pn5xx_dev); - - return 0; -} - -long pn5xx_dev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct pn5xx_dev *pn5xx_dev = filp->private_data; - - pr_info("%s, cmd=%d, arg=%lu\n", __func__, cmd, arg); - - if (cmd == PN5XX_GET_ESE_ACCESS) - { - return get_ese_lock(P61_STATE_WIRED, arg); - } - p61_access_lock(pn5xx_dev); - switch (cmd) { - case PN5XX_SET_PWR: - if (arg == 2) { - /* power on w/FW */ - pn5xx_enable(pn5xx_dev, arg); - } else if (arg == 1) { - /* power on */ - pn5xx_enable(pn5xx_dev, arg); - } else if (arg == 0) { - /* power off */ - pn5xx_disable(pn5xx_dev); - } else if (arg == 3) { - /*NFC Service called ISO-RST*/ - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn5xx_dev, ¤t_state); - if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - p61_access_unlock(pn5xx_dev); - return -EPERM; /* Operation not permitted */ - } - if(current_state & P61_STATE_WIRED) { - p61_update_access_state(pn5xx_dev, P61_STATE_WIRED, false); - } - gpio_set_value(pn5xx_dev->iso_rst_gpio, 0); - msleep(50); - gpio_set_value(pn5xx_dev->iso_rst_gpio, 1); - msleep(50); - pr_info("%s ISO RESET from DWP DONE\n", __func__); - } else { - pr_err("%s bad SET_PWR arg %lu\n", __func__, arg); - return -EINVAL; - } - break; - case PN5XX_CLK_REQ: - if(1 == arg){ - if(gpio_is_valid(pn5xx_dev->clkreq_gpio)){ - gpio_set_value(pn5xx_dev->clkreq_gpio, 1); - } - } - else if(0 == arg) { - if(gpio_is_valid(pn5xx_dev->clkreq_gpio)){ - gpio_set_value(pn5xx_dev->clkreq_gpio, 0); - } - } else { - pr_err("%s bad CLK_REQ arg %lu\n", __func__, arg); - return -EINVAL; - } - break; - case P61_SET_SPI_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn5xx_dev, ¤t_state); - if (arg == 1) { - pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { - p61_update_access_state(pn5xx_dev, P61_STATE_SPI, true); - /*To handle triple mode protection signal - NFC service when SPI session started*/ - if (current_state & P61_STATE_WIRED){ - if(pn5xx_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI, pn5xx_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - } - } - pn5xx_dev->spi_ven_enabled = true; - if (pn5xx_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn5xx_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn5xx_dev->ese_pwr_gpio, 1); - } else { - pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); - p61_access_unlock(pn5xx_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); - if(current_state & P61_STATE_SPI_PRIO){ - p61_update_access_state(pn5xx_dev, P61_STATE_SPI_PRIO, false); - if (current_state & P61_STATE_WIRED) - { - if(pn5xx_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn5xx_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - } - } - - pn5xx_dev->spi_ven_enabled = false; - - if(pn5xx_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) - break; - - if (!(current_state & P61_STATE_WIRED)) - gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); - pn5xx_dev->spi_ven_enabled = false; - if (pn5xx_dev->nfc_ven_enabled == false) { - gpio_set_value(pn5xx_dev->ven_gpio, 0); - msleep(10); - } - }else if(current_state & P61_STATE_SPI){ - p61_update_access_state(pn5xx_dev, P61_STATE_SPI, false); - if (!(current_state & P61_STATE_WIRED)){ - gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); - } - /*To handle triple mode protection signal - NFC service when SPI session started*/ - if (current_state & P61_STATE_WIRED){ - if(pn5xx_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI, pn5xx_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - } - } - pn5xx_dev->spi_ven_enabled = false; - if (pn5xx_dev->nfc_ven_enabled == false) { - gpio_set_value(pn5xx_dev->ven_gpio, 0); - msleep(10); - } - } else { - pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", - __func__, pn5xx_dev->p61_current_state); - p61_access_unlock(pn5xx_dev); - return -EPERM; /* Operation not permitted */ - } - }else if (arg == 2) { - pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); - if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - if (pn5xx_dev->spi_ven_enabled == false) - { - pn5xx_dev->spi_ven_enabled = true; - if (pn5xx_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn5xx_dev->ven_gpio, 1); - msleep(10); - } - } - gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); - msleep(10); - gpio_set_value(pn5xx_dev->ese_pwr_gpio, 1); - msleep(10); - } else { - pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); - p61_access_unlock(pn5xx_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 3) { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { - p61_update_access_state(pn5xx_dev, P61_STATE_SPI_PRIO, true); - if (current_state & P61_STATE_WIRED){ - if(pn5xx_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn5xx_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - } - } - pn5xx_dev->spi_ven_enabled = true; - if (pn5xx_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn5xx_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn5xx_dev->ese_pwr_gpio, 1); - }else { - pr_info("%s : Prio Session Start power on ese failed \n", __func__); - p61_access_unlock(pn5xx_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 4) { - if (current_state & P61_STATE_SPI_PRIO) - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); - p61_update_access_state(pn5xx_dev, P61_STATE_SPI_PRIO, false); - /*after SPI prio timeout, the state is changing from SPI prio to SPI */ - p61_update_access_state(pn5xx_dev, P61_STATE_SPI, true); - if (current_state & P61_STATE_WIRED) - { - if(pn5xx_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn5xx_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - } - } - } - else - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); - p61_access_unlock(pn5xx_dev); - return -EBADRQC; /* Device or resource busy */ - } - } else if(arg == 5){ - release_ese_lock(P61_STATE_SPI); - } else if (arg == 6) { - /*SPI Service called ISO-RST*/ - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn5xx_dev, ¤t_state); - if(current_state & P61_STATE_WIRED) { - p61_access_unlock(pn5xx_dev); - return -EPERM; /* Operation not permitted */ - } - if(current_state & P61_STATE_SPI) { - p61_update_access_state(pn5xx_dev, P61_STATE_SPI, false); - }else if(current_state & P61_STATE_SPI_PRIO) { - p61_update_access_state(pn5xx_dev, P61_STATE_SPI_PRIO, false); - } - gpio_set_value(pn5xx_dev->iso_rst_gpio, 0); - msleep(50); - gpio_set_value(pn5xx_dev->iso_rst_gpio, 1); - msleep(50); - pr_info("%s ISO RESET from SPI DONE\n", __func__); - } - else { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn5xx_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - case P61_GET_PWR_STATUS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn5xx_dev, ¤t_state); - pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); - put_user(current_state, (int __user *)arg); - } - break; - case P61_SET_WIRED_ACCESS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn5xx_dev, ¤t_state); - if (arg == 1) - { - if (current_state) - { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); - p61_update_access_state(pn5xx_dev, P61_STATE_WIRED, true); - if (current_state & P61_STATE_SPI_PRIO) - { - if(pn5xx_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn5xx_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn5xx_dev->nfc_service_pid); - } - } - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - gpio_set_value(pn5xx_dev->ese_pwr_gpio, 1); - } else { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); - p61_access_unlock(pn5xx_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); - if (current_state & P61_STATE_WIRED){ - p61_update_access_state(pn5xx_dev, P61_STATE_WIRED, false); - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); - } else { - pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", - __func__, pn5xx_dev->p61_current_state); - p61_access_unlock(pn5xx_dev); - return -EPERM; /* Operation not permitted */ - } - } - else if(arg == 2) - { - pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); - gpio_set_value(pn5xx_dev->ese_pwr_gpio, 0); - } - else if(arg == 3) - { - pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); - gpio_set_value(pn5xx_dev->ese_pwr_gpio, 1); - } - else if(arg == 4) - { - release_ese_lock(P61_STATE_WIRED); - } - else { - pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); - p61_access_unlock(pn5xx_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - case PN5XX_SET_NFC_SERVICE_PID: - { - pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); - pn5xx_dev->nfc_service_pid = arg; - - } - break; - case P5XX_SET_POWER_SCHEME: - { - if(arg == PN67T_PWR_SCHEME) - { - pn5xx_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; - pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); - } - else if(arg == PN80T_LEGACY_PWR_SCHEME) - { - pn5xx_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; - pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); - } - else if(arg == PN80T_EXT_PMU_SCHEME) - { - pn5xx_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; - pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); - } - else - { - pr_info("%s : The power scheme is invalid,\n", __func__); - } - } - break; - default: - pr_err("%s bad ioctl %u\n", __func__, cmd); - p61_access_unlock(pn5xx_dev); - return -EINVAL; - } - p61_access_unlock(pn5xx_dev); - return 0; -} - -EXPORT_SYMBOL(pn5xx_dev_ioctl); -int get_ese_lock(p61_access_state_t p61_current_state, int timeout) -{ - unsigned long tempJ = msecs_to_jiffies(timeout); - if(down_timeout(&ese_access_sema, tempJ) != 0) - { - printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); - return -EBUSY; - } - return 0; -} - -EXPORT_SYMBOL(get_ese_lock); - -static void release_ese_lock(p61_access_state_t p61_current_state) -{ - up(&ese_access_sema); -} - -static const struct file_operations pn5xx_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = pn5xx_dev_read, - .write = pn5xx_dev_write, - .open = pn5xx_dev_open, - .release = pn5xx_dev_release, - .unlocked_ioctl = pn5xx_dev_ioctl, -}; - -/* - * Handlers for alternative sources of platform_data - */ -#ifdef CONFIG_OF -/* - * Translate OpenFirmware node properties into platform_data - */ -static int pn5xx_get_pdata(struct device *dev, - struct pn5xx_i2c_platform_data *pdata) -{ - struct device_node *node; - u32 flags; - int val; - - /* make sure there is actually a device tree node */ - node = dev->of_node; - if (!node) - return -ENODEV; - - memset(pdata, 0, sizeof(*pdata)); - - /* read the dev tree data */ - - /* ven pin - enable's power to the chip - REQUIRED */ - val = of_get_named_gpio_flags(node, "nxp,pn5xx-ven", 0, &flags); - if (val >= 0) { - pdata->ven_gpio = val; - } - else{ - dev_err(dev, "VEN GPIO error getting from OF node\n"); - return val; - } - - /* firm pin - controls firmware download - OPTIONAL */ - val = of_get_named_gpio_flags(node, "nxp,pn5xx-fw-dwnld", 0, &flags); - if (val >= 0) { - pdata->firm_gpio = val; - } - else { - pdata->firm_gpio = -EINVAL; - dev_warn(dev, "FIRM GPIO error getting from OF node\n"); - } - - /* irq pin - data available irq - REQUIRED */ - val = of_get_named_gpio_flags(node, "nxp,pn5xx-irq", 0, &flags); - if (val >= 0) { - pdata->irq_gpio = val; - } - else { - dev_err(dev, "IRQ GPIO error getting from OF node\n"); - return val; - } - - /* ese-pwr pin - enable's power to the ese- REQUIRED */ - val = of_get_named_gpio_flags(node, "nxp,pn5xx-ese-pwr", 0, &flags); - if (val >= 0) { - pdata->ese_pwr_gpio = val; - } - else { - dev_err(dev, "ESE PWR GPIO error getting from OF node\n"); - return val; - } - - /* clkreq pin - controls the clock to the PN547 - OPTIONAL */ - val = of_get_named_gpio_flags(node, "nxp,pn5xx-clkreq", 0, &flags); - if (val >= 0) { - pdata->clkreq_gpio = val; - } - else { - pdata->clkreq_gpio = -EINVAL; - dev_warn(dev, "CLKREQ GPIO error getting from OF node\n"); - } - - /* handle the regulator lines - these are optional - * PVdd - pad Vdd (544, 547) - * Vbat - Battery (544, 547) - * PMUVcc - UICC Power (544, 547) - * SEVdd - SE Power (544) - * - * Will attempt to load a matching Regulator Resource for each - * If no resource is provided, then the input will not be controlled - * Example: if only PVdd is provided, it is the only one that will be - * turned on/off. - */ - pdata->pvdd_reg = regulator_get(dev, "nxp,pn5xx-pvdd"); - if(IS_ERR(pdata->pvdd_reg)) { - pr_err("%s: could not get nxp,pn5xx-pvdd, rc=%ld\n", __func__, PTR_ERR(pdata->pvdd_reg)); - pdata->pvdd_reg = NULL; - } - - pdata->vbat_reg = regulator_get(dev, "nxp,pn5xx-vbat"); - if (IS_ERR(pdata->vbat_reg)) { - pr_err("%s: could not get nxp,pn5xx-vbat, rc=%ld\n", __func__, PTR_ERR(pdata->vbat_reg)); - pdata->vbat_reg = NULL; - } - - pdata->pmuvcc_reg = regulator_get(dev, "nxp,pn5xx-pmuvcc"); - if (IS_ERR(pdata->pmuvcc_reg)) { - pr_err("%s: could not get nxp,pn5xx-pmuvcc, rc=%ld\n", __func__, PTR_ERR(pdata->pmuvcc_reg)); - pdata->pmuvcc_reg = NULL; - } - - pdata->sevdd_reg = regulator_get(dev, "nxp,pn5xx-sevdd"); - if (IS_ERR(pdata->sevdd_reg)) { - pr_err("%s: could not get nxp,pn5xx-sevdd, rc=%ld\n", __func__, PTR_ERR(pdata->sevdd_reg)); - pdata->sevdd_reg = NULL; - } - - return 0; -} -#else -static int pn5xx_get_pdata(struct device *dev, - struct pn5xx_i2c_platform_data *pdata) -{ - pdata = dev->platform_data; - return 0; -} -#endif - - -/* - * pn5xx_probe - */ -#ifdef KERNEL_3_4_AND_OLDER - static int __devinit pn5xx_probe(struct i2c_client *client, - const struct i2c_device_id *id) -#else -static int pn5xx_probe(struct i2c_client *client, - const struct i2c_device_id *id) -#endif -{ - int ret; - struct pn5xx_i2c_platform_data *pdata; // gpio values, from board file or DT - struct pn5xx_i2c_platform_data tmp_pdata; -// struct pn5xx_dev *pn5xx_dev; // internal device specific data - - pr_info("%s\n", __func__); - - /* ---- retrieve the platform data ---- */ - /* If the dev.platform_data is NULL, then */ - /* attempt to read from the device tree */ - if(!client->dev.platform_data) - { - ret = pn5xx_get_pdata(&(client->dev), &tmp_pdata); - if(ret){ - return ret; - } - - pdata = &tmp_pdata; - } - else - { - pdata = client->dev.platform_data; - } - - if (pdata == NULL) { - pr_err("%s : nfc probe fail\n", __func__); - return -ENODEV; - } - - /* validate the the adapter has basic I2C functionality */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - return -ENODEV; - } - - /* reserve the GPIO pins */ - pr_info("%s: request irq_gpio %d\n", __func__, pdata->irq_gpio); - ret = gpio_request(pdata->irq_gpio, "nfc_int"); - if (ret){ - pr_err("%s :not able to get GPIO irq_gpio\n", __func__); - return -ENODEV; - } - ret = gpio_to_irq(pdata->irq_gpio); - if (ret < 0){ - pr_err("%s :not able to map GPIO irq_gpio to an IRQ\n", __func__); - goto err_ven; - } - else{ - client->irq = ret; - } - - pr_info("%s: request ven_gpio %d\n", __func__, pdata->ven_gpio); - ret = gpio_request(pdata->ven_gpio, "nfc_ven"); - if (ret){ - pr_err("%s :not able to get GPIO ven_gpio\n", __func__); - goto err_ven; - } - - if (gpio_is_valid(pdata->firm_gpio)) { - pr_info("%s: request firm_gpio %d\n", __func__, pdata->firm_gpio); - ret = gpio_request(pdata->firm_gpio, "nfc_firm"); - if (ret){ - pr_err("%s :not able to get GPIO firm_gpio\n", __func__); - goto err_firm; - } - } - - if (gpio_is_valid(pdata->ese_pwr_gpio)) { - pr_info("%s: request ese_pwr_gpio %d\n", __func__, pdata->ese_pwr_gpio); - ret = gpio_request(pdata->ese_pwr_gpio, "nfc_ese_pwr"); - if (ret){ - pr_err("%s :not able to get GPIO ese_pwr_gpio\n", __func__); - goto err_ese_pwr; - } - } - - if (gpio_is_valid(pdata->clkreq_gpio)) { - pr_info("%s: request clkreq_gpio %d\n", __func__, pdata->clkreq_gpio); - ret = gpio_request(pdata->clkreq_gpio, "nfc_clkreq"); - if (ret){ - pr_err("%s :not able to get GPIO clkreq_gpio\n", __func__); - goto err_clkreq; - } - } - - /* allocate the pn5xx driver information structure */ - pn5xx_dev = kzalloc(sizeof(*pn5xx_dev), GFP_KERNEL); - if (pn5xx_dev == NULL) { - dev_err(&client->dev, "failed to allocate memory for module data\n"); - ret = -ENOMEM; - goto err_exit; - } - - /* store the platform data in the driver info struct */ - pn5xx_dev->irq_gpio = pdata->irq_gpio; - pn5xx_dev->ven_gpio = pdata->ven_gpio; - pn5xx_dev->firm_gpio = pdata->firm_gpio; - pn5xx_dev->ese_pwr_gpio = pdata->ese_pwr_gpio; - pn5xx_dev->p61_current_state = P61_STATE_IDLE; - pn5xx_dev->nfc_ven_enabled = false; - pn5xx_dev->spi_ven_enabled = false; - pn5xx_dev->clkreq_gpio = pdata->clkreq_gpio; - pn5xx_dev->pvdd_reg = pdata->pvdd_reg; - pn5xx_dev->vbat_reg = pdata->vbat_reg; - pn5xx_dev->pmuvcc_reg = pdata->vbat_reg; - pn5xx_dev->sevdd_reg = pdata->sevdd_reg; - - pn5xx_dev->client = client; - - /* finish configuring the I/O */ - ret = gpio_direction_input(pn5xx_dev->irq_gpio); - if (ret < 0) { - pr_err("%s :not able to set irq_gpio as input\n", __func__); - goto err_exit; - } - - ret = gpio_direction_output(pn5xx_dev->ven_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_exit; - } - - if (gpio_is_valid(pn5xx_dev->firm_gpio)) { - ret = gpio_direction_output(pn5xx_dev->firm_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set firm_gpio as output\n", - __func__); - goto err_exit; - } - } - - ret = gpio_direction_output(pn5xx_dev->ese_pwr_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); - goto err_ese_pwr; - } - - if (gpio_is_valid(pn5xx_dev->clkreq_gpio)) { - ret = gpio_direction_output(pn5xx_dev->clkreq_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set clkreq_gpio as output\n", - __func__); - goto err_exit; - } - } - - /* init mutex and queues */ - init_waitqueue_head(&pn5xx_dev->read_wq); - mutex_init(&pn5xx_dev->read_mutex); - sema_init(&ese_access_sema, 1); - mutex_init(&pn5xx_dev->p61_state_mutex); - spin_lock_init(&pn5xx_dev->irq_enabled_lock); - - /* register as a misc device - character based with one entry point */ - pn5xx_dev->pn5xx_device.minor = MISC_DYNAMIC_MINOR; - pn5xx_dev->pn5xx_device.name = CHIP; - pn5xx_dev->pn5xx_device.fops = &pn5xx_dev_fops; - ret = misc_register(&pn5xx_dev->pn5xx_device); - if (ret) { - pr_err("%s : misc_register failed\n", __FILE__); - goto err_misc_register; - } - - /* request irq. the irq is set whenever the chip has data available - * for reading. it is cleared when all data has been read. - */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - pn5xx_dev->irq_enabled = true; - ret = request_irq(client->irq, pn5xx_dev_irq_handler, - IRQF_TRIGGER_HIGH, client->name, pn5xx_dev); - if (ret) { - dev_err(&client->dev, "request_irq failed\n"); - goto err_request_irq_failed; - } - pn5xx_disable_irq(pn5xx_dev); - - - i2c_set_clientdata(client, pn5xx_dev); - - return 0; - -err_request_irq_failed: - misc_deregister(&pn5xx_dev->pn5xx_device); -err_misc_register: - mutex_destroy(&pn5xx_dev->read_mutex); - mutex_destroy(&pn5xx_dev->p61_state_mutex); - kfree(pn5xx_dev); -err_exit: - if (gpio_is_valid(pdata->clkreq_gpio)) - gpio_free(pdata->clkreq_gpio); -err_ese_pwr: - gpio_free(pdata->ese_pwr_gpio); -err_clkreq: - if (gpio_is_valid(pdata->firm_gpio)) - gpio_free(pdata->firm_gpio); -err_firm: - gpio_free(pdata->ven_gpio); -err_ven: - gpio_free(pdata->irq_gpio); - return ret; -} - -#ifdef KERNEL_3_4_AND_OLDER -static int __devexit pn5xx_remove(struct i2c_client *client) -#else -static int pn5xx_remove(struct i2c_client *client) -#endif -{ - struct pn5xx_dev *pn5xx_dev; - - pr_info("%s\n", __func__); - - pn5xx_dev = i2c_get_clientdata(client); - free_irq(client->irq, pn5xx_dev); - misc_deregister(&pn5xx_dev->pn5xx_device); - mutex_destroy(&pn5xx_dev->read_mutex); - mutex_destroy(&pn5xx_dev->p61_state_mutex); - gpio_free(pn5xx_dev->irq_gpio); - gpio_free(pn5xx_dev->ven_gpio); - gpio_free(pn5xx_dev->ese_pwr_gpio); - pn5xx_dev->p61_current_state = P61_STATE_INVALID; - pn5xx_dev->nfc_ven_enabled = false; - pn5xx_dev->spi_ven_enabled = false; - - if (gpio_is_valid(pn5xx_dev->firm_gpio)) - gpio_free(pn5xx_dev->firm_gpio); - if (gpio_is_valid(pn5xx_dev->clkreq_gpio)) - gpio_free(pn5xx_dev->clkreq_gpio); - regulator_put(pn5xx_dev->pvdd_reg); - regulator_put(pn5xx_dev->vbat_reg); - regulator_put(pn5xx_dev->pmuvcc_reg); - regulator_put(pn5xx_dev->sevdd_reg); - - kfree(pn5xx_dev); - - return 0; -} - -/* - * - */ -#ifdef CONFIG_OF -static struct of_device_id pn5xx_dt_match[] = { - { .compatible = "nxp,pn547", }, - { .compatible = "nxp,pn544", }, - {}, -}; -MODULE_DEVICE_TABLE(of, pn5xx_dt_match); -#endif - -static const struct i2c_device_id pn5xx_id[] = { - { "pn547", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, pn5xx_id); - -static struct i2c_driver pn5xx_driver = { - .id_table = pn5xx_id, - .probe = pn5xx_probe, -#ifdef KERNEL_3_4_AND_OLDER - .remove = __devexit_p(pn5xx_remove), -#else - .remove = pn5xx_remove, -#endif - .driver = { - .owner = THIS_MODULE, - .name = "pn544", - .of_match_table = pn5xx_dt_match, - }, -}; - -/* - * module load/unload record keeping - */ - -static int __init pn5xx_dev_init(void) -{ - pr_info("%s\n", __func__); - return i2c_add_driver(&pn5xx_driver); -} - -static void __exit pn5xx_dev_exit(void) -{ - pr_info("%s\n", __func__); - i2c_del_driver(&pn5xx_driver); -} - -module_init(pn5xx_dev_init); -module_exit(pn5xx_dev_exit); - -MODULE_AUTHOR("Sylvain Fonteneau"); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - diff --git a/pn5xx_i2c.h b/pn5xx_i2c.h deleted file mode 100644 index 7ecfaaa302..0000000000 --- a/pn5xx_i2c.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * modifications copyright (C) 2015 NXP B.V. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define PN5XX_MAGIC 0xE9 - -/* - * PN5XX power control via ioctl - * PN5XX_SET_PWR(0): power off - * PN5XX_SET_PWR(1): power on - * PN5XX_SET_PWR(2): reset and power on with firmware download enabled - */ - -#define PWR_OFF 0 -#define PWR_ON 1 -#define PWR_FW 2 - -#define CLK_OFF 0 -#define CLK_ON 1 - -#define PN5XX_SET_PWR _IOW(PN5XX_MAGIC, 0x01, unsigned int) - -/* - * SPI Request NFCC to enable p61 power, only in param - * Only for SPI - * level 1 = Enable power - * level 0 = Disable power - */ -#define P61_SET_SPI_PWR _IOW(PN5XX_MAGIC, 0x02, unsigned int) - -/* SPI or DWP can call this ioctl to get the current - * power state of P61 - * -*/ -#define P61_GET_PWR_STATUS _IOR(PN5XX_MAGIC, 0x03, unsigned int) - -/* DWP side this ioctl will be called - * level 1 = Wired access is enabled/ongoing - * level 0 = Wired access is disalbed/stopped -*/ -#define P61_SET_WIRED_ACCESS _IOW(PN5XX_MAGIC, 0x04, unsigned int) - -/* - NFC Init will call the ioctl to register the PID with the i2c driver -*/ -#define PN5XX_SET_NFC_SERVICE_PID _IOW(PN5XX_MAGIC, 0x05, long) -/* - NFC and SPI will call the ioctl to get the i2c/spi bus access -*/ -#define PN5XX_GET_ESE_ACCESS _IOW(PN5XX_MAGIC, 0x06, long) - -/* - NFC and SPI will call the ioctl to update the power scheme -*/ -#define PN5XX_SET_POWER_SCHEME _IOW(PN5XX_MAGIC, 0x07, long) -#define PN5XX_CLK_REQ _IOW(PN5XX_MAGIC, 0x09, unsigned int) - -typedef enum p61_access_state{ - P61_STATE_INVALID = 0x0000, - P61_STATE_IDLE = 0x0100, /* p61 is free to use */ - P61_STATE_WIRED = 0x0200, /* p61 is being accessed by DWP (NFCC)*/ - P61_STATE_SPI = 0x0400, /* P61 is being accessed by SPI */ - P61_STATE_DWNLD = 0x0800, /* NFCC fw download is in progress */ - P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ - P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ - P61_STATE_SPI_END = 0x4000, -}p61_access_state_t; - -typedef enum chip_type_pwr_scheme{ - PN67T_PWR_SCHEME = 0x01, - PN80T_LEGACY_PWR_SCHEME, - PN80T_EXT_PMU_SCHEME, -}chip_pwr_scheme_t; - -struct pn5xx_i2c_platform_data { - unsigned int irq_gpio; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ - unsigned int clkreq_gpio; - struct regulator *pvdd_reg; - struct regulator *vbat_reg; - struct regulator *pmuvcc_reg; - struct regulator *sevdd_reg; - unsigned int iso_rst_gpio; /* gpio used for ISO hard reset P73*/ -}; From 089d289a6ec0196105f90908fda07d5df0a7c341 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Thu, 22 Dec 2016 19:33:43 +0530 Subject: [PATCH 010/100] NFC_NCIHALx_ARC0.7.2.0_N_OpnSrc --- pn6xT/pn54x-i2c/Kconfig | 13 + pn6xT/pn54x-i2c/Makefile | 8 + pn6xT/pn54x-i2c/pn54x.c | 1016 +++++++++++++++++++++++++++++++ pn6xT/pn54x-i2c/pn54x.h | 113 ++++ pn8xT/pn553-i2c/Kconfig | 13 + pn8xT/pn553-i2c/Makefile | 8 + pn8xT/pn553-i2c/pn553.c | 1223 ++++++++++++++++++++++++++++++++++++++ pn8xT/pn553-i2c/pn553.h | 124 ++++ 8 files changed, 2518 insertions(+) create mode 100644 pn6xT/pn54x-i2c/Kconfig create mode 100644 pn6xT/pn54x-i2c/Makefile create mode 100644 pn6xT/pn54x-i2c/pn54x.c create mode 100644 pn6xT/pn54x-i2c/pn54x.h create mode 100644 pn8xT/pn553-i2c/Kconfig create mode 100644 pn8xT/pn553-i2c/Makefile create mode 100644 pn8xT/pn553-i2c/pn553.c create mode 100644 pn8xT/pn553-i2c/pn553.h diff --git a/pn6xT/pn54x-i2c/Kconfig b/pn6xT/pn54x-i2c/Kconfig new file mode 100644 index 0000000000..e42ba0d9dc --- /dev/null +++ b/pn6xT/pn54x-i2c/Kconfig @@ -0,0 +1,13 @@ +# +# Nxp Nci protocol (I2C) devices +# + +menuconfig NFC_PN54X_DEVICES + bool "Nxp pn54x NCI protocol driver (I2C) devices" + default y + ---help--- + You'll have to say Y if your computer contains an I2C device that + you want to use under Linux. + + You can say N here if you don't have any SPI connected to your computer. + diff --git a/pn6xT/pn54x-i2c/Makefile b/pn6xT/pn54x-i2c/Makefile new file mode 100644 index 0000000000..6c257880c6 --- /dev/null +++ b/pn6xT/pn54x-i2c/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for nfc devices +# + +obj-$(CONFIG_NFC_PN54X_DEVICES) += pn54x.o + +ccflags-$(CONFIG_NFC_PN54X_DEVICES_DEBUG) := -DDEBUG + diff --git a/pn6xT/pn54x-i2c/pn54x.c b/pn6xT/pn54x-i2c/pn54x.c new file mode 100644 index 0000000000..805eb86b54 --- /dev/null +++ b/pn6xT/pn54x-i2c/pn54x.c @@ -0,0 +1,1016 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pn54x.h" + +#define NEXUS5x 0 +#define DRAGON_NFC 1 +#define SIG_NFC 44 +#define MAX_BUFFER_SIZE 512 + +struct pn544_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn544_device; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int irq_gpio; + unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ + struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ + p61_access_state_t p61_current_state; /* stores the current P61 state */ + bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ + bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + long nfc_service_pid; /*used to signal the nfc the nfc service */ +}; +static struct pn544_dev *pn544_dev; +static struct semaphore ese_access_sema; +static struct semaphore svdd_sync_onoff_sema; +static void release_ese_lock(p61_access_state_t p61_current_state); +int get_ese_lock(p61_access_state_t p61_current_state, int timeout); +static void pn544_disable_irq(struct pn544_dev *pn544_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + if (pn544_dev->irq_enabled) { + disable_irq_nosync(pn544_dev->client->irq); + pn544_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); +} + +static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) +{ + struct pn544_dev *pn544_dev = dev_id; + + pn544_disable_irq(pn544_dev); + + /* Wake up waiting readers */ + wake_up(&pn544_dev->read_wq); + + return IRQ_HANDLED; +} + +static ssize_t pn544_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + + mutex_lock(&pn544_dev->read_mutex); + + if (!gpio_get_value(pn544_dev->irq_gpio)) { + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } + + while (1) { + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + pn544_disable_irq(pn544_dev); + + if (ret) + goto fail; + + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + + /* Read data */ + ret = i2c_master_recv(pn544_dev->client, tmp, count); + + mutex_unlock(&pn544_dev->read_mutex); + + /* pn544 seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ +#if !NEXUS5x + udelay(1000); +#endif + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return ret; + + fail: + mutex_unlock(&pn544_dev->read_mutex); + return ret; +} + +static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + pn544_dev = filp->private_data; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + + pr_debug("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn544_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + + /* pn544 seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); + + return ret; +} + +static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) +{ + pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); + if (current_state) + { + if(set){ + if(pn544_dev->p61_current_state == P61_STATE_IDLE) + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->p61_current_state |= current_state; + } + else{ + pn544_dev->p61_current_state ^= current_state; + if(!pn544_dev->p61_current_state) + pn544_dev->p61_current_state = P61_STATE_IDLE; + } + } + pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); +} + +static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) +{ + + if (current_state == NULL) { + //*current_state = P61_STATE_INVALID; + pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); + } else { + *current_state = pn544_dev->p61_current_state; + } +} +static void p61_access_lock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_lock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} +static void p61_access_unlock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_unlock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} + +static int signal_handler(p61_access_state_t state, long nfc_pid) +{ + struct siginfo sinfo; + pid_t pid; + struct task_struct *task; + int sigret = 0; + int ret = 0; + pr_info("%s: Enter\n", __func__); + + memset(&sinfo, 0, sizeof(struct siginfo)); + sinfo.si_signo = SIG_NFC; + sinfo.si_code = SI_QUEUE; + sinfo.si_int = state; + pid = nfc_pid; + + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if(task) + { + pr_info("%s.\n", task->comm); + sigret = force_sig_info(SIG_NFC, &sinfo, task); + if(sigret < 0){ + pr_info("send_sig_info failed..... sigret %d.\n", sigret); + ret = -1; + } + } + else + { + pr_info("finding task from PID failed\r\n"); + ret = -1; + } + pr_info("%s: Exit ret = %d\n", __func__, ret); + return ret; +} +static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 100; //100 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); + if(nfc_service_pid) + { + if (0 == signal_handler(origin, nfc_service_pid)) + { + sema_init(&svdd_sync_onoff_sema, 0); + pr_info("Waiting for svdd protection response"); + if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) + { + pr_info("svdd wait protection: Timeout"); + } + pr_info("svdd wait protection : released"); + } + } + pr_info("%s: Exit\n", __func__); +} +static int release_svdd_wait(void) +{ + pr_info("%s: Enter \n", __func__); + up(&svdd_sync_onoff_sema); + pr_info("%s: Exit\n", __func__); + return 0; +} +static int pn544_dev_open(struct inode *inode, struct file *filp) +{ + struct pn544_dev *pn544_dev = container_of(filp->private_data, + struct pn544_dev, + pn544_device); + + filp->private_data = pn544_dev; + + pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + + return 0; +} + +long pn544_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); + + if (cmd == P544_GET_ESE_ACCESS) + { + return get_ese_lock(P61_STATE_WIRED, arg); + } + else if(cmd == P544_REL_SVDD_WAIT) + { + return release_svdd_wait(); + } + p61_access_lock(pn544_dev); + switch (cmd) { + case PN544_SET_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 2) { + if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) + { + /* NFCC fw/download should not be allowed if p61 is used + * by SPI + */ + pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + pn544_dev->nfc_ven_enabled = true; + if (pn544_dev->spi_ven_enabled == false) + { + /* power on with firmware download (requires hw reset) + */ + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } else if (arg == 1) { + /* power on */ + pr_info("%s power on\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = true; + if (pn544_dev->spi_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 1); + } + } else if (arg == 0) { + /* power off */ + pr_info("%s power off\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = false; + /* Don't change Ven state if spi made it high */ + if (pn544_dev->spi_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 0); + } + } else { + pr_err("%s bad arg %lu\n", __func__, arg); + /* changed the p61 state to idle*/ + p61_access_unlock(pn544_dev); + return -EINVAL; + } + } + break; + case P61_SET_SPI_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) { + pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if ((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) + { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } else { + pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); + if(current_state & P61_STATE_SPI_PRIO){ + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + if (!(current_state & P61_STATE_WIRED)) + { + if((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | + P61_STATE_SPI_PRIO_END); + } + else + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + else if ((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else + { + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if(current_state & P61_STATE_JCOP_DWNLD) + p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); + pn544_dev->spi_ven_enabled = false; + if (pn544_dev->nfc_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + }else if(current_state & P61_STATE_SPI){ + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + if (!(current_state & P61_STATE_WIRED)) + { + if((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + } + else + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + /*If JCOP3.2 or 3.3 for handling triple mode + protection signal NFC service */ + else + { + if ((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + if(current_state & P61_STATE_JCOP_DWNLD) + p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); + pn544_dev->spi_ven_enabled = false; + if (pn544_dev->nfc_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + } else { + pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + }else if (arg == 2) { + pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); + if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + msleep(10); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } else { + pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 3) { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); + //if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + }else { + pr_info("%s : Prio Session Start power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 4) { + if (current_state & P61_STATE_SPI_PRIO) + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + /*after SPI prio timeout, the state is changing from SPI prio to SPI */ + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + //if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + else + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Device or resource busy */ + } + } else if(arg == 5){ + release_ese_lock(P61_STATE_SPI); + } + else { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + + case P61_SET_PWR_STATUS: + { + pr_info("%s: P61_SET_PWR_STATUS = %lx",__func__, arg); + p61_update_access_state(pn544_dev, arg, true); + } + break; + case P61_GET_PWR_STATUS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); + put_user(current_state, (int __user *)arg); + } + break; + case P61_SET_WIRED_ACCESS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) + { + if (current_state) + { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); + if (current_state & P61_STATE_SPI_PRIO) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + } else { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); + if (current_state & P61_STATE_WIRED){ + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); + } + } else { + pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + } + else if(arg == 2) + { + pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); + } + else if(arg == 3) + { + pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + else if(arg == 4) + { + release_ese_lock(P61_STATE_WIRED); + } + else { + pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + case P544_SET_NFC_SERVICE_PID: + { + pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); + pn544_dev->nfc_service_pid = arg; + + } + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + p61_access_unlock(pn544_dev); + return -EINVAL; + } + p61_access_unlock(pn544_dev); + pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); + return 0; +} +EXPORT_SYMBOL(pn544_dev_ioctl); + +int get_ese_lock(p61_access_state_t p61_current_state, int timeout) +{ + unsigned long tempJ = msecs_to_jiffies(timeout); + if(down_timeout(&ese_access_sema, tempJ) != 0) + { + printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); + return -EBUSY; + } + return 0; +} +EXPORT_SYMBOL(get_ese_lock); + +static void release_ese_lock(p61_access_state_t p61_current_state) +{ + up(&ese_access_sema); +} + + +static const struct file_operations pn544_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_dev_read, + .write = pn544_dev_write, + .open = pn544_dev_open, + .unlocked_ioctl = pn544_dev_ioctl, +}; +#if DRAGON_NFC +static int pn544_parse_dt(struct device *dev, + struct pn544_i2c_platform_data *data) +{ + struct device_node *np = dev->of_node; + int errorno = 0; + +#if !NEXUS5x + data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); + if ((!gpio_is_valid(data->irq_gpio))) + return -EINVAL; + + data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); + if ((!gpio_is_valid(data->ven_gpio))) + return -EINVAL; + + data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); + if ((!gpio_is_valid(data->firm_gpio))) + return -EINVAL; + + data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); + if ((!gpio_is_valid(data->ese_pwr_gpio))) + return -EINVAL; +#else + data->ven_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_ven", 0, NULL); + data->firm_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_mode", 0, NULL); + data->irq_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_irq", 0, NULL); +#endif + pr_info("%s: %d, %d, %d, %d %d\n", __func__, + data->irq_gpio, data->ven_gpio, data->firm_gpio, data->ese_pwr_gpio, errorno); + + return errorno; +} +#endif + +static int pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct pn544_i2c_platform_data *platform_data; + //struct pn544_dev *pn544_dev; + +#if !DRAGON_NFC + platform_data = client->dev.platform_data; +#else + struct device_node *node = client->dev.of_node; + + if (node) { + platform_data = devm_kzalloc(&client->dev, + sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); + if (!platform_data) { + dev_err(&client->dev, + "nfc-nci probe: Failed to allocate memory\n"); + return -ENOMEM; + } + ret = pn544_parse_dt(&client->dev, platform_data); + if (ret) + { + pr_info("%s pn544_parse_dt failed", __func__); + } + client->irq = gpio_to_irq(platform_data->irq_gpio); + if (client->irq < 0) + { + pr_info("%s gpio to irq failed", __func__); + } + } else { + platform_data = client->dev.platform_data; + } +#endif + if (platform_data == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } +#if !DRAGON_NFC + ret = gpio_request(platform_data->irq_gpio, "nfc_int"); + if (ret) + return -ENODEV; + ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); + if (ret) + goto err_ven; + ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); + if (ret) + goto err_ese_pwr; + if (platform_data->firm_gpio) { + ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); + if (ret) + goto err_firm; + } +#endif + pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); + if (pn544_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + pn544_dev->irq_gpio = platform_data->irq_gpio; + pn544_dev->ven_gpio = platform_data->ven_gpio; + pn544_dev->firm_gpio = platform_data->firm_gpio; + pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; + pn544_dev->p61_current_state = P61_STATE_IDLE; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + pn544_dev->client = client; + + ret = gpio_direction_input(pn544_dev->irq_gpio); + if (ret < 0) { + pr_err("%s :not able to set irq_gpio as input\n", __func__); + goto err_ven; + } + ret = gpio_direction_output(pn544_dev->ven_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_firm; + } + ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); + goto err_ese_pwr; + } + if (platform_data->firm_gpio) { + ret = gpio_direction_output(pn544_dev->firm_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set firm_gpio as output\n", + __func__); + goto err_exit; + } + } + + /* init mutex and queues */ + init_waitqueue_head(&pn544_dev->read_wq); + mutex_init(&pn544_dev->read_mutex); + sema_init(&ese_access_sema, 1); + mutex_init(&pn544_dev->p61_state_mutex); + spin_lock_init(&pn544_dev->irq_enabled_lock); + + pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; + pn544_dev->pn544_device.name = "pn54x"; + pn544_dev->pn544_device.fops = &pn544_dev_fops; + + ret = misc_register(&pn544_dev->pn544_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } + + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pn544_dev->irq_enabled = true; + ret = request_irq(client->irq, pn544_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, pn544_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + pn544_disable_irq(pn544_dev); + i2c_set_clientdata(client, pn544_dev); + + return 0; + + err_request_irq_failed: + misc_deregister(&pn544_dev->pn544_device); + err_misc_register: + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + kfree(pn544_dev); + err_exit: + if (pn544_dev->firm_gpio) + gpio_free(platform_data->firm_gpio); + err_firm: + gpio_free(platform_data->ese_pwr_gpio); + err_ese_pwr: + gpio_free(platform_data->ven_gpio); + err_ven: + gpio_free(platform_data->irq_gpio); + return ret; +} + +static int pn544_remove(struct i2c_client *client) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn544_dev); + misc_deregister(&pn544_dev->pn544_device); + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + gpio_free(pn544_dev->irq_gpio); + gpio_free(pn544_dev->ven_gpio); + gpio_free(pn544_dev->ese_pwr_gpio); + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + + if (pn544_dev->firm_gpio) + gpio_free(pn544_dev->firm_gpio); + kfree(pn544_dev); + + return 0; +} + +static const struct i2c_device_id pn544_id[] = { +#if NEXUS5x + { "pn548", 0 }, +#else + { "pn544", 0 }, +#endif + { } +}; +#if DRAGON_NFC +static struct of_device_id pn544_i2c_dt_match[] = { + { +#if NEXUS5x + .compatible = "nxp,pn548", +#else + .compatible = "nxp,pn544", +#endif + }, + {} +}; +#endif +static struct i2c_driver pn544_driver = { + .id_table = pn544_id, + .probe = pn544_probe, + .remove = pn544_remove, + .driver = { + .owner = THIS_MODULE, +#if NEXUS5x + .name = "pn548", +#else + .name = "pn544", +#endif +#if DRAGON_NFC + .of_match_table = pn544_i2c_dt_match, +#endif + }, +}; + +/* + * module load/unload record keeping + */ + +static int __init pn544_dev_init(void) +{ + pr_info("Loading pn544 driver\n"); + return i2c_add_driver(&pn544_driver); +} +module_init(pn544_dev_init); + +static void __exit pn544_dev_exit(void) +{ + pr_info("Unloading pn544 driver\n"); + i2c_del_driver(&pn544_driver); +} +module_exit(pn544_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION("NFC PN544 driver"); +MODULE_LICENSE("GPL"); diff --git a/pn6xT/pn54x-i2c/pn54x.h b/pn6xT/pn54x-i2c/pn54x.h new file mode 100644 index 0000000000..29cba731f4 --- /dev/null +++ b/pn6xT/pn54x-i2c/pn54x.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#define PN544_MAGIC 0xE9 + +/* + * PN544 power control via ioctl + * PN544_SET_PWR(0): power off + * PN544_SET_PWR(1): power on + * PN544_SET_PWR(2): reset and power on with firmware download enabled + */ +#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, long) + +/* + * SPI Request NFCC to enable p61 power, only in param + * Only for SPI + * level 1 = Enable power + * level 0 = Disable power + */ +#define P61_SET_SPI_PWR _IOW(PN544_MAGIC, 0x02, long) + +/* SPI or DWP can call this ioctl to get the current + * power state of P61 + * +*/ +#define P61_GET_PWR_STATUS _IOR(PN544_MAGIC, 0x03, long) + +/* DWP side this ioctl will be called + * level 1 = Wired access is enabled/ongoing + * level 0 = Wired access is disalbed/stopped +*/ +#define P61_SET_WIRED_ACCESS _IOW(PN544_MAGIC, 0x04, long) + +/* + NFC Init will call the ioctl to register the PID with the i2c driver +*/ +#define P544_SET_NFC_SERVICE_PID _IOW(PN544_MAGIC, 0x05, long) + +/* + NFC and SPI will call the ioctl to get the i2c/spi bus access +*/ +#define P544_GET_ESE_ACCESS _IOW(PN544_MAGIC, 0x06, long) + +/* + NFC will call the ioctl to release the svdd protection +*/ +#define P544_REL_SVDD_WAIT _IOW(PN544_MAGIC, 0x08, long) + +/* SPI or DWP can call this ioctl to set the current + * power state of P61 + * +*/ +#define P61_SET_PWR_STATUS _IOR(PN544_MAGIC, 0x09, long) + +typedef enum p61_access_state{ + P61_STATE_INVALID = 0x0000, + P61_STATE_IDLE = 0x0100, /* p61 is free to use */ + P61_STATE_WIRED = 0x0200, /* p61 is being accessed by DWP (NFCC)*/ + P61_STATE_SPI = 0x0400, /* P61 is being accessed by SPI */ + P61_STATE_DWNLD = 0x0800, /* NFCC fw download is in progress */ + P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ + P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ + P61_STATE_SPI_END = 0x4000, + P61_STATE_JCOP_DWNLD = 0x8000, /* Jcop download is in progress */ + P61_STATE_SPI_SVDD_SYNC_START = 0x0001, /*ESE_VDD Low req by SPI*/ + P61_STATE_SPI_SVDD_SYNC_END = 0x0002, /*ESE_VDD is Low by SPI*/ + P61_STATE_DWP_SVDD_SYNC_START = 0x0004, /*ESE_VDD Low req by Nfc*/ + P61_STATE_DWP_SVDD_SYNC_END = 0x0008, /*ESE_VDD is Low by Nfc*/ +}p61_access_state_t; + + +struct pn544_i2c_platform_data { + unsigned int irq_gpio; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ +}; diff --git a/pn8xT/pn553-i2c/Kconfig b/pn8xT/pn553-i2c/Kconfig new file mode 100644 index 0000000000..878e4a8169 --- /dev/null +++ b/pn8xT/pn553-i2c/Kconfig @@ -0,0 +1,13 @@ +# +# Nxp Nci protocol (I2C) devices +# + +config NFC_PN553_DEVICES + bool "Nxp pn553 NCI protocol driver (I2C) devices" + default y + ---help--- + You'll have to say Y if your computer contains an I2C device that + you want to use under Linux. + + You can say N here if you don't have any SPI connected to your computer. + diff --git a/pn8xT/pn553-i2c/Makefile b/pn8xT/pn553-i2c/Makefile new file mode 100644 index 0000000000..0534eed532 --- /dev/null +++ b/pn8xT/pn553-i2c/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for nfc devices +# + +obj-$(CONFIG_NFC_PN553_DEVICES) += pn553.o + +ccflags-$(CONFIG_NFC_PN553_DEVICES) := -DDEBUG + diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c new file mode 100644 index 0000000000..6882713ed5 --- /dev/null +++ b/pn8xT/pn553-i2c/pn553.c @@ -0,0 +1,1223 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pn553.h" + +#define NEXUS5x 0 +#if NEXUS5x +#undef ISO_RST +#else +#define ISO_RST +#endif +#define DRAGON_NFC 1 +#define SIG_NFC 44 +#define MAX_BUFFER_SIZE 512 +#define MAX_SECURE_SESSIONS 1 + +struct pn544_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn544_device; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int irq_gpio; + unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ +#ifdef ISO_RST + unsigned int iso_rst_gpio; /* ISO-RST pin gpio*/ +#endif + struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ + p61_access_state_t p61_current_state; /* stores the current P61 state */ + bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ + bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + long nfc_service_pid; /*used to signal the nfc the nfc service */ + chip_pwr_scheme_t chip_pwr_scheme; + unsigned int secure_timer_cnt; +}; +struct wake_lock nfc_wake_lock; +static bool sIsWakeLocked = false; +static struct pn544_dev *pn544_dev; +static struct semaphore ese_access_sema; +static void release_ese_lock(p61_access_state_t p61_current_state); +int get_ese_lock(p61_access_state_t p61_current_state, int timeout); +static long set_jcop_download_state(unsigned long arg); +static void pn544_disable_irq(struct pn544_dev *pn544_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + if (pn544_dev->irq_enabled) { + disable_irq_nosync(pn544_dev->client->irq); + disable_irq_wake(pn544_dev->client->irq); + pn544_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); +} + +static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) +{ + struct pn544_dev *pn544_dev = dev_id; + + pn544_disable_irq(pn544_dev); + if (sIsWakeLocked == false) + { + wake_lock(&nfc_wake_lock); + sIsWakeLocked = true; + } else { + pr_debug("%s already wake locked!\n", __func__); + } + /* Wake up waiting readers */ + wake_up(&pn544_dev->read_wq); + + + return IRQ_HANDLED; +} + +static ssize_t pn544_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + + mutex_lock(&pn544_dev->read_mutex); + + if (!gpio_get_value(pn544_dev->irq_gpio)) { + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } + + while (1) { + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + enable_irq_wake(pn544_dev->client->irq); + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + pn544_disable_irq(pn544_dev); + + if (ret) + goto fail; + + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + + /* Read data */ + ret = i2c_master_recv(pn544_dev->client, tmp, count); + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } + mutex_unlock(&pn544_dev->read_mutex); + + /* pn544 seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ +#if !NEXUS5x + udelay(1000); +#endif + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return ret; + + fail: + mutex_unlock(&pn544_dev->read_mutex); + return ret; +} + +static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + pn544_dev = filp->private_data; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + + pr_debug("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn544_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + + /* pn544 seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); + + return ret; +} + +static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) +{ + pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); + if (current_state) + { + if(set){ + if(pn544_dev->p61_current_state == P61_STATE_IDLE) + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->p61_current_state |= current_state; + } + else{ + pn544_dev->p61_current_state ^= current_state; + if(!pn544_dev->p61_current_state) + pn544_dev->p61_current_state = P61_STATE_IDLE; + } + } + pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); +} + +static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) +{ + + if (current_state == NULL) { + //*current_state = P61_STATE_INVALID; + pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); + } else { + *current_state = pn544_dev->p61_current_state; + } +} +static void p61_access_lock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_lock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} +static void p61_access_unlock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_unlock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} + +static void signal_handler(p61_access_state_t state, long nfc_pid) +{ + struct siginfo sinfo; + pid_t pid; + struct task_struct *task; + int sigret = 0; + pr_info("%s: Enter\n", __func__); + + if(nfc_pid == 0) + { + pr_info("nfc_pid is clear don't call signal_handler.\n"); + } + else + { + memset(&sinfo, 0, sizeof(struct siginfo)); + sinfo.si_signo = SIG_NFC; + sinfo.si_code = SI_QUEUE; + sinfo.si_int = state; + pid = nfc_pid; + + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if(task) + { + pr_info("%s.\n", task->comm); + sigret = force_sig_info(SIG_NFC, &sinfo, task); + if(sigret < 0){ + pr_info("send_sig_info failed..... sigret %d.\n", sigret); + //msleep(60); + } + } + else{ + pr_info("finding task from PID failed\r\n"); + } + } + pr_info("%s: Exit\n", __func__); +} +static int pn544_dev_open(struct inode *inode, struct file *filp) +{ + struct pn544_dev *pn544_dev = container_of(filp->private_data, + struct pn544_dev, + pn544_device); + + filp->private_data = pn544_dev; + + pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + + return 0; +} + +long pn544_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); + + if (cmd == P544_GET_ESE_ACCESS) + { + return get_ese_lock(P61_STATE_WIRED, arg); + } + p61_access_lock(pn544_dev); + switch (cmd) { + case PN544_SET_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 2) { + if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) + { + /* NFCC fw/download should not be allowed if p61 is used + * by SPI + */ + pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + pn544_dev->nfc_ven_enabled = true; + if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) + || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) + { + /* power on with firmware download (requires hw reset) + */ + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } else if (arg == 1) { + /* power on */ + pr_info("%s power on\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + if(current_state & P61_STATE_DWNLD){ + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, false); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = true; + if (pn544_dev->spi_ven_enabled == false || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { + gpio_set_value(pn544_dev->ven_gpio, 1); + } + } else if (arg == 0) { + /* power off */ + pr_info("%s power off\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = false; + /* Don't change Ven state if spi made it high */ + if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) + || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + } + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } + } else if (arg == 3) { + /*NFC Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_WIRED) { + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + } +#ifdef ISO_RST + gpio_set_value(pn544_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn544_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from DWP DONE\n", __func__); +#endif + } + else { + pr_err("%s bad arg %lu\n", __func__, arg); + /* changed the p61 state to idle*/ + p61_access_unlock(pn544_dev); + return -EINVAL; + } + } + break; + case P61_SET_SPI_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) { + pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if (!(current_state & P61_STATE_JCP_DWNLD)){ + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + + if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + + if (pn544_dev->nfc_ven_enabled == false) + { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } else { + pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); + if(current_state & P61_STATE_SPI_PRIO){ + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + if (!(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = false; + + if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + + if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + + if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + }else if(current_state & P61_STATE_SPI){ + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + if (!(current_state & P61_STATE_WIRED) && + (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) && + !(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + } + /*If JCOP3.2 or 3.3 for handling triple mode + protection signal NFC service */ + else + { + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME && !(pn544_dev->secure_timer_cnt)) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); + } + if (!(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + pn544_dev->spi_ven_enabled = false; + if (pn544_dev->nfc_ven_enabled == false && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) + && !(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + } else { + pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + }else if (arg == 2) { + pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); + if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + if ((pn544_dev->nfc_ven_enabled == false) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } + if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + } else { + pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 3) { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); + if (current_state & P61_STATE_WIRED){ + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) + { + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + }else { + pr_info("%s : Prio Session Start power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 4) { + if (current_state & P61_STATE_SPI_PRIO) + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + /*after SPI prio timeout, the state is changing from SPI prio to SPI */ + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + else + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Device or resource busy */ + } + } else if(arg == 5){ + release_ese_lock(P61_STATE_SPI); + } else if (arg == 6) { + /*SPI Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if(current_state & P61_STATE_WIRED) { + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_SPI) { + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + }else if(current_state & P61_STATE_SPI_PRIO) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + } +#ifdef ISO_RST + gpio_set_value(pn544_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn544_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from SPI DONE\n", __func__); +#endif + } + else { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + + case P61_GET_PWR_STATUS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); + put_user(current_state, (int __user *)arg); + } + break; + + case PN544_SET_DWNLD_STATUS: + { + long ret; + ret = set_jcop_download_state(arg); + if(ret < 0) + { + p61_access_unlock(pn544_dev); + return ret; + } + } + break; + + case P61_SET_WIRED_ACCESS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) + { + if (current_state) + { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); + if (current_state & P61_STATE_SPI_PRIO) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } else { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); + if (current_state & P61_STATE_WIRED){ + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + } else { + pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + } + else if(arg == 2) + { + pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); + if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + } + else if(arg == 3) + { + pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); + if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + else if(arg == 4) + { + release_ese_lock(P61_STATE_WIRED); + } + else { + pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + case P544_SET_NFC_SERVICE_PID: + { + pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); + pn544_dev->nfc_service_pid = arg; + + } + break; + case P544_SET_POWER_SCHEME: + { + if(arg == PN67T_PWR_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); + } + else if(arg == PN80T_LEGACY_PWR_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; + pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); + } + else if(arg == PN80T_EXT_PMU_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; + pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); + } + else + { + pr_info("%s : The power scheme is invalid,\n", __func__); + } + } + break; + case P544_SECURE_TIMER_SESSION: + { + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + if(arg == 1) + { + if(pn544_dev->secure_timer_cnt < MAX_SECURE_SESSIONS) + { + pn544_dev->secure_timer_cnt++; + pr_info("%s : eSE secure timer session start : count = %d,\n", + __func__, pn544_dev->secure_timer_cnt); + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + } else if(arg == 0){ + if(pn544_dev->secure_timer_cnt > 0) + { + pn544_dev->secure_timer_cnt--; + pr_info("%s : eSE secure timer session stop : count = %d,\n", + __func__, pn544_dev->secure_timer_cnt); + if((pn544_dev->secure_timer_cnt == 0) && (pn544_dev->spi_ven_enabled == false)) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + if(pn544_dev->nfc_ven_enabled == false) + { + /* Turn off GPIO as none of the interfaces are active */ + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + } + } + } + } + else + { + pr_info("%s :Secure timer session not applicable \n", __func__); + } + } + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + p61_access_unlock(pn544_dev); + return -EINVAL; + } + p61_access_unlock(pn544_dev); + pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); + return 0; +} +EXPORT_SYMBOL(pn544_dev_ioctl); + +static long set_jcop_download_state(unsigned long arg) +{ + p61_access_state_t current_state = P61_STATE_INVALID; + long ret = 0; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s:Enter PN544_SET_DWNLD_STATUS:JCOP Dwnld state arg = %ld",__func__, arg); + if(arg == JCP_DWNLD_INIT) + { + if(pn544_dev->nfc_service_pid) + { + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(JCP_DWNLD_INIT, pn544_dev->nfc_service_pid); + } + else + { + if (current_state & P61_STATE_JCP_DWNLD) + { + ret = -EINVAL; + } + else + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); + } + } + } + else if (arg == JCP_DWNLD_START) + { + if (current_state & P61_STATE_JCP_DWNLD) + { + ret = -EINVAL; + } + else + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); + } + } + else if (arg == JCP_SPI_DWNLD_COMPLETE) + { + if(pn544_dev->nfc_service_pid) + { + signal_handler(JCP_DWP_DWNLD_COMPLETE, pn544_dev->nfc_service_pid); + } + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); + } + else if (arg == JCP_DWP_DWNLD_COMPLETE) + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); + } + else + { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + pr_info("%s: PN544_SET_DWNLD_STATUS = %x",__func__, current_state); + + return ret; +} + +int get_ese_lock(p61_access_state_t p61_current_state, int timeout) +{ + unsigned long tempJ = msecs_to_jiffies(timeout); + if(down_timeout(&ese_access_sema, tempJ) != 0) + { + printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); + return -EBUSY; + } + return 0; +} +EXPORT_SYMBOL(get_ese_lock); + +static void release_ese_lock(p61_access_state_t p61_current_state) +{ + up(&ese_access_sema); +} + + +static const struct file_operations pn544_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_dev_read, + .write = pn544_dev_write, + .open = pn544_dev_open, + .unlocked_ioctl = pn544_dev_ioctl, +}; +#if DRAGON_NFC +static int pn544_parse_dt(struct device *dev, + struct pn544_i2c_platform_data *data) +{ + struct device_node *np = dev->of_node; + int errorno = 0; + +#if !NEXUS5x + data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); + if ((!gpio_is_valid(data->irq_gpio))) + return -EINVAL; + + data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); + if ((!gpio_is_valid(data->ven_gpio))) + return -EINVAL; + + data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); + if ((!gpio_is_valid(data->firm_gpio))) + return -EINVAL; + + data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); + if ((!gpio_is_valid(data->ese_pwr_gpio))) + return -EINVAL; + data->iso_rst_gpio = of_get_named_gpio(np, "nxp,pn544-iso-pwr-rst", 0); + if ((!gpio_is_valid(data->iso_rst_gpio))) + return -EINVAL; +#else + data->ven_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_ven", 0, NULL); + data->firm_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_mode", 0, NULL); + data->irq_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_irq", 0, NULL); +#endif + pr_info("%s: %d, %d, %d, %d, %d error:%d\n", __func__, + data->irq_gpio, data->ven_gpio, data->firm_gpio, data->iso_rst_gpio, + data->ese_pwr_gpio, errorno); + + return errorno; +} +#endif + +static int pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct pn544_i2c_platform_data *platform_data; + //struct pn544_dev *pn544_dev; + +#if !DRAGON_NFC + platform_data = client->dev.platform_data; +#else + struct device_node *node = client->dev.of_node; + + if (node) { + platform_data = devm_kzalloc(&client->dev, + sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); + if (!platform_data) { + dev_err(&client->dev, + "nfc-nci probe: Failed to allocate memory\n"); + return -ENOMEM; + } + ret = pn544_parse_dt(&client->dev, platform_data); + if (ret) + { + pr_info("%s pn544_parse_dt failed", __func__); + } + client->irq = gpio_to_irq(platform_data->irq_gpio); + if (client->irq < 0) + { + pr_info("%s gpio to irq failed", __func__); + } + } else { + platform_data = client->dev.platform_data; + } +#endif + if (platform_data == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } +#if !DRAGON_NFC + ret = gpio_request(platform_data->irq_gpio, "nfc_int"); + if (ret) + return -ENODEV; + ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); + if (ret) + goto err_ven; + ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); + if (ret) + goto err_ese_pwr; + if (platform_data->firm_gpio) { + ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); + if (ret) + goto err_firm; + } +#ifdef ISO_RST + if(platform_data->iso_rst_gpio) { + ret = gpio_request(platform_data->iso_rst_gpio, "nfc_iso_rst"); + if (ret) + goto err_iso_rst; + } +#endif +#endif + pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); + if (pn544_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + pn544_dev->irq_gpio = platform_data->irq_gpio; + pn544_dev->ven_gpio = platform_data->ven_gpio; + pn544_dev->firm_gpio = platform_data->firm_gpio; + pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; +#ifdef ISO_RST + pn544_dev->iso_rst_gpio = platform_data->iso_rst_gpio; +#endif + pn544_dev->p61_current_state = P61_STATE_IDLE; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + pn544_dev->client = client; + pn544_dev->secure_timer_cnt = 0; + + ret = gpio_direction_input(pn544_dev->irq_gpio); + if (ret < 0) { + pr_err("%s :not able to set irq_gpio as input\n", __func__); + goto err_ven; + } + ret = gpio_direction_output(pn544_dev->ven_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_firm; + } + ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); + goto err_ese_pwr; + } + if (platform_data->firm_gpio) { + ret = gpio_direction_output(pn544_dev->firm_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set firm_gpio as output\n", + __func__); + goto err_exit; + } + } +#ifdef ISO_RST + ret = gpio_direction_output(pn544_dev->iso_rst_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set iso rst gpio as output\n", __func__); + goto err_iso_rst; + } +#endif + /* init mutex and queues */ + init_waitqueue_head(&pn544_dev->read_wq); + mutex_init(&pn544_dev->read_mutex); + sema_init(&ese_access_sema, 1); + mutex_init(&pn544_dev->p61_state_mutex); + spin_lock_init(&pn544_dev->irq_enabled_lock); + + pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; + pn544_dev->pn544_device.name = "pn553"; + pn544_dev->pn544_device.fops = &pn544_dev_fops; + + ret = misc_register(&pn544_dev->pn544_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } + wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); +#ifdef ISO_RST + /* Setting ISO RESET pin high to power ESE during init */ + gpio_set_value(pn544_dev->iso_rst_gpio, 1); +#endif + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pn544_dev->irq_enabled = true; + ret = request_irq(client->irq, pn544_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, pn544_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + enable_irq_wake(pn544_dev->client->irq); + pn544_disable_irq(pn544_dev); + i2c_set_clientdata(client, pn544_dev); + + return 0; + + err_request_irq_failed: + misc_deregister(&pn544_dev->pn544_device); + err_misc_register: + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + kfree(pn544_dev); + err_exit: + if (pn544_dev->firm_gpio) + gpio_free(platform_data->firm_gpio); + err_firm: + gpio_free(platform_data->ese_pwr_gpio); + err_ese_pwr: + gpio_free(platform_data->ven_gpio); + err_ven: + gpio_free(platform_data->irq_gpio); +#ifdef ISO_RST + err_iso_rst: + gpio_free(platform_data->iso_rst_gpio); +#endif + return ret; +} + +static int pn544_remove(struct i2c_client *client) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn544_dev); + misc_deregister(&pn544_dev->pn544_device); + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + gpio_free(pn544_dev->irq_gpio); + gpio_free(pn544_dev->ven_gpio); + gpio_free(pn544_dev->ese_pwr_gpio); +#ifdef ISO_RST + gpio_free(pn544_dev->iso_rst_gpio); +#endif + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + + if (pn544_dev->firm_gpio) + gpio_free(pn544_dev->firm_gpio); + kfree(pn544_dev); + + return 0; +} + +static const struct i2c_device_id pn544_id[] = { +#if NEXUS5x + { "pn548", 0 }, +#else + { "pn544", 0 }, +#endif + { } +}; +#if DRAGON_NFC +static struct of_device_id pn544_i2c_dt_match[] = { + { +#if NEXUS5x + .compatible = "nxp,pn548", +#else + .compatible = "nxp,pn544", +#endif + }, + {} +}; +#endif +static struct i2c_driver pn544_driver = { + .id_table = pn544_id, + .probe = pn544_probe, + .remove = pn544_remove, + .driver = { + .owner = THIS_MODULE, +#if NEXUS5x + .name = "pn548", +#else + .name = "pn544", +#endif +#if DRAGON_NFC + .of_match_table = pn544_i2c_dt_match, +#endif + }, +}; + +/* + * module load/unload record keeping + */ + +static int __init pn544_dev_init(void) +{ + pr_info("Loading pn544 driver\n"); + return i2c_add_driver(&pn544_driver); +} +module_init(pn544_dev_init); + +static void __exit pn544_dev_exit(void) +{ + pr_info("Unloading pn544 driver\n"); + i2c_del_driver(&pn544_driver); +} +module_exit(pn544_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION("NFC PN544 driver"); +MODULE_LICENSE("GPL"); diff --git a/pn8xT/pn553-i2c/pn553.h b/pn8xT/pn553-i2c/pn553.h new file mode 100644 index 0000000000..592f5326f2 --- /dev/null +++ b/pn8xT/pn553-i2c/pn553.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#define PN544_MAGIC 0xE9 + +/* + * PN544 power control via ioctl + * PN544_SET_PWR(0): power off + * PN544_SET_PWR(1): power on + * PN544_SET_PWR(2): reset and power on with firmware download enabled + */ +#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, long) + +/* + * SPI Request NFCC to enable p61 power, only in param + * Only for SPI + * level 1 = Enable power + * level 0 = Disable power + */ +#define P61_SET_SPI_PWR _IOW(PN544_MAGIC, 0x02, long) + +/* SPI or DWP can call this ioctl to get the current + * power state of P61 + * +*/ +#define P61_GET_PWR_STATUS _IOR(PN544_MAGIC, 0x03, long) + +/* DWP side this ioctl will be called + * level 1 = Wired access is enabled/ongoing + * level 0 = Wired access is disalbed/stopped +*/ +#define P61_SET_WIRED_ACCESS _IOW(PN544_MAGIC, 0x04, long) + +/* + NFC Init will call the ioctl to register the PID with the i2c driver +*/ +#define P544_SET_NFC_SERVICE_PID _IOW(PN544_MAGIC, 0x05, long) + +/* + NFC and SPI will call the ioctl to get the i2c/spi bus access +*/ +#define P544_GET_ESE_ACCESS _IOW(PN544_MAGIC, 0x06, long) +/* + NFC and SPI will call the ioctl to update the power scheme +*/ +#define P544_SET_POWER_SCHEME _IOW(PN544_MAGIC, 0x07, long) + +/* SPI or DWP can call this ioctl to get the current + * power state of P61 + * +*/ +#define PN544_SET_DWNLD_STATUS _IOW(PN544_MAGIC, 0x09, long) + +#define P544_SECURE_TIMER_SESSION _IOW(PN544_MAGIC, 0x0A, long) + +typedef enum p61_access_state{ + P61_STATE_INVALID = 0x0000, + P61_STATE_IDLE = 0x0100, /* p61 is free to use */ + P61_STATE_WIRED = 0x0200, /* p61 is being accessed by DWP (NFCC)*/ + P61_STATE_SPI = 0x0400, /* P61 is being accessed by SPI */ + P61_STATE_DWNLD = 0x0800, /* NFCC fw download is in progress */ + P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ + P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ + P61_STATE_SPI_END = 0x4000, + P61_STATE_JCP_DWNLD = 0x8000/* JCOP downlad in progress */ +}p61_access_state_t; + +typedef enum chip_type_pwr_scheme{ + PN67T_PWR_SCHEME = 0x01, + PN80T_LEGACY_PWR_SCHEME, + PN80T_EXT_PMU_SCHEME, +}chip_pwr_scheme_t; + +typedef enum jcop_dwnld_state{ + JCP_DWNLD_IDLE, /* jcop dwnld is not ongoing*/ + JCP_DWNLD_INIT, /* jcop dwonload init state*/ + JCP_DWNLD_START, /* download started */ + JCP_SPI_DWNLD_COMPLETE, /* jcop download complete in spi interface*/ + JCP_DWP_DWNLD_COMPLETE, /* jcop download complete */ +} jcop_dwnld_state_t; + +struct pn544_i2c_platform_data { + unsigned int irq_gpio; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ + unsigned int iso_rst_gpio; /* gpio used for ISO hard reset P73*/ +}; From c1b82121911e9dbc6684d57745a0b373413bf1c6 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Fri, 24 Feb 2017 16:43:08 +0530 Subject: [PATCH 011/100] NFC_NCIHALx_AR3C.7.3.6_N --- pn6xT/pn54x-i2c/pn54x.c | 25 ++++++++++- pn8xT/pn553-i2c/pn553.c | 98 ++++++++++++++++++++++++++++++++++------- pn8xT/pn553-i2c/pn553.h | 11 ++++- 3 files changed, 115 insertions(+), 19 deletions(-) diff --git a/pn6xT/pn54x-i2c/pn54x.c b/pn6xT/pn54x-i2c/pn54x.c index 805eb86b54..b5ea40f78c 100644 --- a/pn6xT/pn54x-i2c/pn54x.c +++ b/pn6xT/pn54x-i2c/pn54x.c @@ -60,6 +60,7 @@ #include #include #include +#include #include "pn54x.h" #define NEXUS5x 0 @@ -84,6 +85,8 @@ struct pn544_dev { spinlock_t irq_enabled_lock; long nfc_service_pid; /*used to signal the nfc the nfc service */ }; +struct wake_lock nfc_wake_lock; +static bool sIsWakeLocked = false; static struct pn544_dev *pn544_dev; static struct semaphore ese_access_sema; static struct semaphore svdd_sync_onoff_sema; @@ -96,6 +99,7 @@ static void pn544_disable_irq(struct pn544_dev *pn544_dev) spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); if (pn544_dev->irq_enabled) { disable_irq_nosync(pn544_dev->client->irq); + disable_irq_wake(pn544_dev->client->irq); pn544_dev->irq_enabled = false; } spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); @@ -106,7 +110,13 @@ static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) struct pn544_dev *pn544_dev = dev_id; pn544_disable_irq(pn544_dev); - + if (sIsWakeLocked == false) + { + wake_lock(&nfc_wake_lock); + sIsWakeLocked = true; + } else { + pr_debug("%s already wake locked!\n", __func__); + } /* Wake up waiting readers */ wake_up(&pn544_dev->read_wq); @@ -136,6 +146,7 @@ static ssize_t pn544_dev_read(struct file *filp, char __user *buf, while (1) { pn544_dev->irq_enabled = true; enable_irq(pn544_dev->client->irq); + enable_irq_wake(pn544_dev->client->irq); ret = wait_event_interruptible( pn544_dev->read_wq, !pn544_dev->irq_enabled); @@ -154,7 +165,10 @@ static ssize_t pn544_dev_read(struct file *filp, char __user *buf, /* Read data */ ret = i2c_master_recv(pn544_dev->client, tmp, count); - + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } mutex_unlock(&pn544_dev->read_mutex); /* pn544 seems to be slow in handling I2C read requests @@ -406,6 +420,10 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, if (pn544_dev->spi_ven_enabled == false) { gpio_set_value(pn544_dev->ven_gpio, 0); } + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } } else { pr_err("%s bad arg %lu\n", __func__, arg); /* changed the p61 state to idle*/ @@ -898,6 +916,7 @@ static int pn544_probe(struct i2c_client *client, pr_err("%s : misc_register failed\n", __FILE__); goto err_misc_register; } + wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); /* request irq. the irq is set whenever the chip has data available * for reading. it is cleared when all data has been read. @@ -910,6 +929,8 @@ static int pn544_probe(struct i2c_client *client, dev_err(&client->dev, "request_irq failed\n"); goto err_request_irq_failed; } + pr_info("%s : Enabling IRQ Wake\n", __func__); + enable_irq_wake(pn544_dev->client->irq); pn544_disable_irq(pn544_dev); i2c_set_clientdata(client, pn544_dev); diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c index 6882713ed5..dcdf140ba4 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn8xT/pn553-i2c/pn553.c @@ -100,6 +100,7 @@ struct wake_lock nfc_wake_lock; static bool sIsWakeLocked = false; static struct pn544_dev *pn544_dev; static struct semaphore ese_access_sema; +static struct semaphore svdd_sync_onoff_sema; static void release_ese_lock(p61_access_state_t p61_current_state); int get_ese_lock(p61_access_state_t p61_current_state, int timeout); static long set_jcop_download_state(unsigned long arg); @@ -283,12 +284,12 @@ static void p61_access_unlock(struct pn544_dev *pn544_dev) pr_info("%s: Exit\n", __func__); } -static void signal_handler(p61_access_state_t state, long nfc_pid) +static int signal_handler(p61_access_state_t state, long nfc_pid) { struct siginfo sinfo; pid_t pid; struct task_struct *task; - int sigret = 0; + int sigret = 0, ret = 0; pr_info("%s: Enter\n", __func__); if(nfc_pid == 0) @@ -310,15 +311,45 @@ static void signal_handler(p61_access_state_t state, long nfc_pid) sigret = force_sig_info(SIG_NFC, &sinfo, task); if(sigret < 0){ pr_info("send_sig_info failed..... sigret %d.\n", sigret); + ret = -1; //msleep(60); } } else{ pr_info("finding task from PID failed\r\n"); + ret = -1; + } + } + pr_info("%s: Exit ret = %d\n", __func__, ret); + return ret; +} +static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 100; //100 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); + if(nfc_service_pid) + { + if (0 == signal_handler(origin, nfc_service_pid)) + { + sema_init(&svdd_sync_onoff_sema, 0); + pr_info("Waiting for svdd protection response"); + if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) + { + pr_info("svdd wait protection: Timeout"); + } + pr_info("svdd wait protection : released"); } } pr_info("%s: Exit\n", __func__); } +static int release_svdd_wait(void) +{ + pr_info("%s: Enter \n", __func__); + up(&svdd_sync_onoff_sema); + pr_info("%s: Exit\n", __func__); + return 0; +} static int pn544_dev_open(struct inode *inode, struct file *filp) { struct pn544_dev *pn544_dev = container_of(filp->private_data, @@ -341,6 +372,10 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, { return get_ese_lock(P61_STATE_WIRED, arg); } + else if(cmd == P544_REL_SVDD_WAIT) + { + return release_svdd_wait(); + } p61_access_lock(pn544_dev); switch (cmd) { case PN544_SET_PWR: @@ -486,11 +521,19 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, { if(pn544_dev->nfc_service_pid){ pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } + if(!(current_state & P61_STATE_WIRED)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | + P61_STATE_SPI_PRIO_END); + }else { + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } else if (!(current_state & P61_STATE_WIRED)) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); } pn544_dev->spi_ven_enabled = false; @@ -498,7 +541,10 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, break; if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) + { gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { gpio_set_value(pn544_dev->ven_gpio, 0); @@ -512,32 +558,42 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, { if(pn544_dev->nfc_service_pid){ pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); } else{ pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); } - if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) + if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } } /*If JCOP3.2 or 3.3 for handling triple mode protection signal NFC service */ else { - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME && !(pn544_dev->secure_timer_cnt)) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); - } if (!(current_state & P61_STATE_JCP_DWNLD)) { if(pn544_dev->nfc_service_pid){ pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + } else { + signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + } } else{ pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); } + } else if (pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); } } pn544_dev->spi_ven_enabled = false; @@ -566,7 +622,9 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); msleep(10); gpio_set_value(pn544_dev->ese_pwr_gpio, 1); msleep(10); @@ -713,7 +771,11 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, if (current_state & P61_STATE_WIRED){ p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } } else { pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", __func__, pn544_dev->p61_current_state); @@ -725,7 +787,11 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, { pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } } else if(arg == 3) { diff --git a/pn8xT/pn553-i2c/pn553.h b/pn8xT/pn553-i2c/pn553.h index 592f5326f2..582895b309 100644 --- a/pn8xT/pn553-i2c/pn553.h +++ b/pn8xT/pn553-i2c/pn553.h @@ -81,6 +81,11 @@ */ #define P544_SET_POWER_SCHEME _IOW(PN544_MAGIC, 0x07, long) +/* + NFC will call the ioctl to release the svdd protection +*/ +#define P544_REL_SVDD_WAIT _IOW(PN544_MAGIC, 0x08, long) + /* SPI or DWP can call this ioctl to get the current * power state of P61 * @@ -98,7 +103,11 @@ typedef enum p61_access_state{ P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ P61_STATE_SPI_END = 0x4000, - P61_STATE_JCP_DWNLD = 0x8000/* JCOP downlad in progress */ + P61_STATE_JCP_DWNLD = 0x8000,/* JCOP downlad in progress */ + P61_STATE_SPI_SVDD_SYNC_START = 0x0001, /*ESE_VDD Low req by SPI*/ + P61_STATE_SPI_SVDD_SYNC_END = 0x0002, /*ESE_VDD is Low by SPI*/ + P61_STATE_DWP_SVDD_SYNC_START = 0x0004, /*ESE_VDD Low req by Nfc*/ + P61_STATE_DWP_SVDD_SYNC_END = 0x0008 /*ESE_VDD is Low by Nfc*/ }p61_access_state_t; typedef enum chip_type_pwr_scheme{ From 0299bae0b0dc7bb3489504bbfa40297146438c40 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Tue, 11 Apr 2017 11:38:57 +0530 Subject: [PATCH 012/100] NFC_NCIHALx_ARC0.7.4.8_N --- pn6xT/pn54x-i2c/built-in.o | Bin 0 -> 188560 bytes pn6xT/pn54x-i2c/modules.order | 0 pn6xT/pn54x-i2c/pn54x.c~ | 1016 ++++++++++++++++++++++++++ pn6xT/pn54x-i2c/pn54x.o | Bin 0 -> 188568 bytes pn8xT/pn553-i2c/built-in.o | Bin 0 -> 199640 bytes pn8xT/pn553-i2c/modules.order | 0 pn8xT/pn553-i2c/pn553.c | 2 +- pn8xT/pn553-i2c/pn553.c~ | 1289 +++++++++++++++++++++++++++++++++ pn8xT/pn553-i2c/pn553.h | 2 +- pn8xT/pn553-i2c/pn553.o | Bin 0 -> 199648 bytes 10 files changed, 2307 insertions(+), 2 deletions(-) create mode 100644 pn6xT/pn54x-i2c/built-in.o create mode 100644 pn6xT/pn54x-i2c/modules.order create mode 100644 pn6xT/pn54x-i2c/pn54x.c~ create mode 100644 pn6xT/pn54x-i2c/pn54x.o create mode 100644 pn8xT/pn553-i2c/built-in.o create mode 100644 pn8xT/pn553-i2c/modules.order create mode 100644 pn8xT/pn553-i2c/pn553.c~ create mode 100644 pn8xT/pn553-i2c/pn553.o diff --git a/pn6xT/pn54x-i2c/built-in.o b/pn6xT/pn54x-i2c/built-in.o new file mode 100644 index 0000000000000000000000000000000000000000..fb26d66f7d0f277a3377243a0cbc4123a44e1555 GIT binary patch literal 188560 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

xGG2q{YWsLaXyfvZyql3MnmG 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 Nzdq-)EdN{n{{#O|!QKD> literal 0 HcmV?d00001 diff --git a/pn6xT/pn54x-i2c/modules.order b/pn6xT/pn54x-i2c/modules.order new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pn6xT/pn54x-i2c/pn54x.c~ b/pn6xT/pn54x-i2c/pn54x.c~ new file mode 100644 index 0000000000..805eb86b54 --- /dev/null +++ b/pn6xT/pn54x-i2c/pn54x.c~ @@ -0,0 +1,1016 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pn54x.h" + +#define NEXUS5x 0 +#define DRAGON_NFC 1 +#define SIG_NFC 44 +#define MAX_BUFFER_SIZE 512 + +struct pn544_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn544_device; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int irq_gpio; + unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ + struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ + p61_access_state_t p61_current_state; /* stores the current P61 state */ + bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ + bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + long nfc_service_pid; /*used to signal the nfc the nfc service */ +}; +static struct pn544_dev *pn544_dev; +static struct semaphore ese_access_sema; +static struct semaphore svdd_sync_onoff_sema; +static void release_ese_lock(p61_access_state_t p61_current_state); +int get_ese_lock(p61_access_state_t p61_current_state, int timeout); +static void pn544_disable_irq(struct pn544_dev *pn544_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + if (pn544_dev->irq_enabled) { + disable_irq_nosync(pn544_dev->client->irq); + pn544_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); +} + +static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) +{ + struct pn544_dev *pn544_dev = dev_id; + + pn544_disable_irq(pn544_dev); + + /* Wake up waiting readers */ + wake_up(&pn544_dev->read_wq); + + return IRQ_HANDLED; +} + +static ssize_t pn544_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + + mutex_lock(&pn544_dev->read_mutex); + + if (!gpio_get_value(pn544_dev->irq_gpio)) { + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } + + while (1) { + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + pn544_disable_irq(pn544_dev); + + if (ret) + goto fail; + + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + + /* Read data */ + ret = i2c_master_recv(pn544_dev->client, tmp, count); + + mutex_unlock(&pn544_dev->read_mutex); + + /* pn544 seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ +#if !NEXUS5x + udelay(1000); +#endif + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return ret; + + fail: + mutex_unlock(&pn544_dev->read_mutex); + return ret; +} + +static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + pn544_dev = filp->private_data; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + + pr_debug("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn544_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + + /* pn544 seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); + + return ret; +} + +static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) +{ + pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); + if (current_state) + { + if(set){ + if(pn544_dev->p61_current_state == P61_STATE_IDLE) + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->p61_current_state |= current_state; + } + else{ + pn544_dev->p61_current_state ^= current_state; + if(!pn544_dev->p61_current_state) + pn544_dev->p61_current_state = P61_STATE_IDLE; + } + } + pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); +} + +static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) +{ + + if (current_state == NULL) { + //*current_state = P61_STATE_INVALID; + pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); + } else { + *current_state = pn544_dev->p61_current_state; + } +} +static void p61_access_lock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_lock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} +static void p61_access_unlock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_unlock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} + +static int signal_handler(p61_access_state_t state, long nfc_pid) +{ + struct siginfo sinfo; + pid_t pid; + struct task_struct *task; + int sigret = 0; + int ret = 0; + pr_info("%s: Enter\n", __func__); + + memset(&sinfo, 0, sizeof(struct siginfo)); + sinfo.si_signo = SIG_NFC; + sinfo.si_code = SI_QUEUE; + sinfo.si_int = state; + pid = nfc_pid; + + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if(task) + { + pr_info("%s.\n", task->comm); + sigret = force_sig_info(SIG_NFC, &sinfo, task); + if(sigret < 0){ + pr_info("send_sig_info failed..... sigret %d.\n", sigret); + ret = -1; + } + } + else + { + pr_info("finding task from PID failed\r\n"); + ret = -1; + } + pr_info("%s: Exit ret = %d\n", __func__, ret); + return ret; +} +static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 100; //100 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); + if(nfc_service_pid) + { + if (0 == signal_handler(origin, nfc_service_pid)) + { + sema_init(&svdd_sync_onoff_sema, 0); + pr_info("Waiting for svdd protection response"); + if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) + { + pr_info("svdd wait protection: Timeout"); + } + pr_info("svdd wait protection : released"); + } + } + pr_info("%s: Exit\n", __func__); +} +static int release_svdd_wait(void) +{ + pr_info("%s: Enter \n", __func__); + up(&svdd_sync_onoff_sema); + pr_info("%s: Exit\n", __func__); + return 0; +} +static int pn544_dev_open(struct inode *inode, struct file *filp) +{ + struct pn544_dev *pn544_dev = container_of(filp->private_data, + struct pn544_dev, + pn544_device); + + filp->private_data = pn544_dev; + + pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + + return 0; +} + +long pn544_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); + + if (cmd == P544_GET_ESE_ACCESS) + { + return get_ese_lock(P61_STATE_WIRED, arg); + } + else if(cmd == P544_REL_SVDD_WAIT) + { + return release_svdd_wait(); + } + p61_access_lock(pn544_dev); + switch (cmd) { + case PN544_SET_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 2) { + if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) + { + /* NFCC fw/download should not be allowed if p61 is used + * by SPI + */ + pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + pn544_dev->nfc_ven_enabled = true; + if (pn544_dev->spi_ven_enabled == false) + { + /* power on with firmware download (requires hw reset) + */ + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } else if (arg == 1) { + /* power on */ + pr_info("%s power on\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = true; + if (pn544_dev->spi_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 1); + } + } else if (arg == 0) { + /* power off */ + pr_info("%s power off\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = false; + /* Don't change Ven state if spi made it high */ + if (pn544_dev->spi_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 0); + } + } else { + pr_err("%s bad arg %lu\n", __func__, arg); + /* changed the p61 state to idle*/ + p61_access_unlock(pn544_dev); + return -EINVAL; + } + } + break; + case P61_SET_SPI_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) { + pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if ((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) + { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } else { + pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); + if(current_state & P61_STATE_SPI_PRIO){ + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + if (!(current_state & P61_STATE_WIRED)) + { + if((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | + P61_STATE_SPI_PRIO_END); + } + else + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + else if ((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else + { + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if(current_state & P61_STATE_JCOP_DWNLD) + p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); + pn544_dev->spi_ven_enabled = false; + if (pn544_dev->nfc_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + }else if(current_state & P61_STATE_SPI){ + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + if (!(current_state & P61_STATE_WIRED)) + { + if((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + } + else + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + /*If JCOP3.2 or 3.3 for handling triple mode + protection signal NFC service */ + else + { + if ((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + if(current_state & P61_STATE_JCOP_DWNLD) + p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); + pn544_dev->spi_ven_enabled = false; + if (pn544_dev->nfc_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + } else { + pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + }else if (arg == 2) { + pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); + if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + msleep(10); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } else { + pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 3) { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); + //if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + }else { + pr_info("%s : Prio Session Start power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 4) { + if (current_state & P61_STATE_SPI_PRIO) + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + /*after SPI prio timeout, the state is changing from SPI prio to SPI */ + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + //if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + else + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Device or resource busy */ + } + } else if(arg == 5){ + release_ese_lock(P61_STATE_SPI); + } + else { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + + case P61_SET_PWR_STATUS: + { + pr_info("%s: P61_SET_PWR_STATUS = %lx",__func__, arg); + p61_update_access_state(pn544_dev, arg, true); + } + break; + case P61_GET_PWR_STATUS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); + put_user(current_state, (int __user *)arg); + } + break; + case P61_SET_WIRED_ACCESS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) + { + if (current_state) + { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); + if (current_state & P61_STATE_SPI_PRIO) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + } else { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); + if (current_state & P61_STATE_WIRED){ + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); + } + } else { + pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + } + else if(arg == 2) + { + pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); + } + else if(arg == 3) + { + pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + else if(arg == 4) + { + release_ese_lock(P61_STATE_WIRED); + } + else { + pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + case P544_SET_NFC_SERVICE_PID: + { + pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); + pn544_dev->nfc_service_pid = arg; + + } + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + p61_access_unlock(pn544_dev); + return -EINVAL; + } + p61_access_unlock(pn544_dev); + pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); + return 0; +} +EXPORT_SYMBOL(pn544_dev_ioctl); + +int get_ese_lock(p61_access_state_t p61_current_state, int timeout) +{ + unsigned long tempJ = msecs_to_jiffies(timeout); + if(down_timeout(&ese_access_sema, tempJ) != 0) + { + printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); + return -EBUSY; + } + return 0; +} +EXPORT_SYMBOL(get_ese_lock); + +static void release_ese_lock(p61_access_state_t p61_current_state) +{ + up(&ese_access_sema); +} + + +static const struct file_operations pn544_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_dev_read, + .write = pn544_dev_write, + .open = pn544_dev_open, + .unlocked_ioctl = pn544_dev_ioctl, +}; +#if DRAGON_NFC +static int pn544_parse_dt(struct device *dev, + struct pn544_i2c_platform_data *data) +{ + struct device_node *np = dev->of_node; + int errorno = 0; + +#if !NEXUS5x + data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); + if ((!gpio_is_valid(data->irq_gpio))) + return -EINVAL; + + data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); + if ((!gpio_is_valid(data->ven_gpio))) + return -EINVAL; + + data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); + if ((!gpio_is_valid(data->firm_gpio))) + return -EINVAL; + + data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); + if ((!gpio_is_valid(data->ese_pwr_gpio))) + return -EINVAL; +#else + data->ven_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_ven", 0, NULL); + data->firm_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_mode", 0, NULL); + data->irq_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_irq", 0, NULL); +#endif + pr_info("%s: %d, %d, %d, %d %d\n", __func__, + data->irq_gpio, data->ven_gpio, data->firm_gpio, data->ese_pwr_gpio, errorno); + + return errorno; +} +#endif + +static int pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct pn544_i2c_platform_data *platform_data; + //struct pn544_dev *pn544_dev; + +#if !DRAGON_NFC + platform_data = client->dev.platform_data; +#else + struct device_node *node = client->dev.of_node; + + if (node) { + platform_data = devm_kzalloc(&client->dev, + sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); + if (!platform_data) { + dev_err(&client->dev, + "nfc-nci probe: Failed to allocate memory\n"); + return -ENOMEM; + } + ret = pn544_parse_dt(&client->dev, platform_data); + if (ret) + { + pr_info("%s pn544_parse_dt failed", __func__); + } + client->irq = gpio_to_irq(platform_data->irq_gpio); + if (client->irq < 0) + { + pr_info("%s gpio to irq failed", __func__); + } + } else { + platform_data = client->dev.platform_data; + } +#endif + if (platform_data == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } +#if !DRAGON_NFC + ret = gpio_request(platform_data->irq_gpio, "nfc_int"); + if (ret) + return -ENODEV; + ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); + if (ret) + goto err_ven; + ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); + if (ret) + goto err_ese_pwr; + if (platform_data->firm_gpio) { + ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); + if (ret) + goto err_firm; + } +#endif + pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); + if (pn544_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + pn544_dev->irq_gpio = platform_data->irq_gpio; + pn544_dev->ven_gpio = platform_data->ven_gpio; + pn544_dev->firm_gpio = platform_data->firm_gpio; + pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; + pn544_dev->p61_current_state = P61_STATE_IDLE; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + pn544_dev->client = client; + + ret = gpio_direction_input(pn544_dev->irq_gpio); + if (ret < 0) { + pr_err("%s :not able to set irq_gpio as input\n", __func__); + goto err_ven; + } + ret = gpio_direction_output(pn544_dev->ven_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_firm; + } + ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); + goto err_ese_pwr; + } + if (platform_data->firm_gpio) { + ret = gpio_direction_output(pn544_dev->firm_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set firm_gpio as output\n", + __func__); + goto err_exit; + } + } + + /* init mutex and queues */ + init_waitqueue_head(&pn544_dev->read_wq); + mutex_init(&pn544_dev->read_mutex); + sema_init(&ese_access_sema, 1); + mutex_init(&pn544_dev->p61_state_mutex); + spin_lock_init(&pn544_dev->irq_enabled_lock); + + pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; + pn544_dev->pn544_device.name = "pn54x"; + pn544_dev->pn544_device.fops = &pn544_dev_fops; + + ret = misc_register(&pn544_dev->pn544_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } + + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pn544_dev->irq_enabled = true; + ret = request_irq(client->irq, pn544_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, pn544_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + pn544_disable_irq(pn544_dev); + i2c_set_clientdata(client, pn544_dev); + + return 0; + + err_request_irq_failed: + misc_deregister(&pn544_dev->pn544_device); + err_misc_register: + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + kfree(pn544_dev); + err_exit: + if (pn544_dev->firm_gpio) + gpio_free(platform_data->firm_gpio); + err_firm: + gpio_free(platform_data->ese_pwr_gpio); + err_ese_pwr: + gpio_free(platform_data->ven_gpio); + err_ven: + gpio_free(platform_data->irq_gpio); + return ret; +} + +static int pn544_remove(struct i2c_client *client) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn544_dev); + misc_deregister(&pn544_dev->pn544_device); + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + gpio_free(pn544_dev->irq_gpio); + gpio_free(pn544_dev->ven_gpio); + gpio_free(pn544_dev->ese_pwr_gpio); + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + + if (pn544_dev->firm_gpio) + gpio_free(pn544_dev->firm_gpio); + kfree(pn544_dev); + + return 0; +} + +static const struct i2c_device_id pn544_id[] = { +#if NEXUS5x + { "pn548", 0 }, +#else + { "pn544", 0 }, +#endif + { } +}; +#if DRAGON_NFC +static struct of_device_id pn544_i2c_dt_match[] = { + { +#if NEXUS5x + .compatible = "nxp,pn548", +#else + .compatible = "nxp,pn544", +#endif + }, + {} +}; +#endif +static struct i2c_driver pn544_driver = { + .id_table = pn544_id, + .probe = pn544_probe, + .remove = pn544_remove, + .driver = { + .owner = THIS_MODULE, +#if NEXUS5x + .name = "pn548", +#else + .name = "pn544", +#endif +#if DRAGON_NFC + .of_match_table = pn544_i2c_dt_match, +#endif + }, +}; + +/* + * module load/unload record keeping + */ + +static int __init pn544_dev_init(void) +{ + pr_info("Loading pn544 driver\n"); + return i2c_add_driver(&pn544_driver); +} +module_init(pn544_dev_init); + +static void __exit pn544_dev_exit(void) +{ + pr_info("Unloading pn544 driver\n"); + i2c_del_driver(&pn544_driver); +} +module_exit(pn544_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION("NFC PN544 driver"); +MODULE_LICENSE("GPL"); diff --git a/pn6xT/pn54x-i2c/pn54x.o b/pn6xT/pn54x-i2c/pn54x.o new file mode 100644 index 0000000000000000000000000000000000000000..6df2414bfcb070c59614939b5b4f316c4ee58da1 GIT binary patch literal 188568 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 literal 0 HcmV?d00001 diff --git a/pn8xT/pn553-i2c/built-in.o b/pn8xT/pn553-i2c/built-in.o new file mode 100644 index 0000000000000000000000000000000000000000..0fe3c0b1383e13ab7a9427201607d33c14807c05 GIT binary patch literal 199640 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

TO1=O z@Kgi0XD2eyN$q!_z)q>*sfIQDi%)o8p3@`vR6{CR(w)Fc+<_In#yxUK&(%6=3+P;X zN+Q%KlW;UiUTODQD17|<@^k2z=yuOEPzl`qV<(A1Q6=ik+yhY6>bY;KxTfl+KBv_P439q59QC--XXNva zqn@wBQ9o|z|AYT`hvwGFmZaatcYmX`tR?;Fs&}eKIH6U2B2>|;Y9dzMR3WGmA63O_ zNSd^u>Yb_^Va2&Aa%K8XQ2dxElB`8>`tf6Z$IYTtE*-(Ps8>(YhpMig3HG1+Nma4> z(zU8s)lC%@t8Q3KqiCa?mZ=dYKvgD~0<$#lLf|MfmqOrJHLzE3elyMU4=Y9IF-`ns zUofLLW$vCQ8qWf#QmX0SLBV<4i}bp%=yw`_r>dw{^IRj7t1Ac;`frVYoUVn=oA;Mh zQ2BY1yMc5jI>0s;R=f{45~BJ;fgU7u`k~aH;I8RDd`YqW=c8kGdEpv&Sv)`@N`cZ2 zCN|3D@~=~-%4PX#2DRk!+@%Th+`grM1mw5hjEaftBHW2vV1s-|k+k95Up8!Fu~vKu zVCH*b)C#r(%Mxq{mM52QJj$PAmjbVAUv`e6zs;ear;iT4{6;{eR7Wr073}N#Q~a$K zy&kMwcRY|j&<0H3#XI~bP2|3WSy#H_*2b?pgqNI_AYAyT^LZ$x)H5q-J#u;3QvMp7 zUcO-;FiVZ?#d)N)e=S80ElB9T_g6fse%_y*4xics){f&9(bTj3fXEB`-oaxm18a@jLzXCK7PG+Kl{&|8c8NM;4Wq~F`cHFPn&u4WptRu7ye}v5o~eg zo8?OKpK!SOtE1>TmXe~SR|+T4t<%htdlhxVxqP32n&yS?!I$LIT+f%*-Om(`W=XFV z1nHkjHVtzvnz_HSnOi^<_u}a^d-W(E@e3pUb^MV783fsa_s~72heNZZRzBXz%KwE= z_=UHaMJO*E{xrR2dMcCvrfy=YK{J!H^yPW~z=2>GLJ7$y%>?P=lUEY=ReUU8Isn*d zf|)IpPIs^Xvk01*N+~0xG?)6WTgZr^B9!hgxI((mu)OwzOs0*!{#=IVo0(DQwcz>| zwuZ5Kd7?!ZJiv&#*RSRbR}E*VBwtRtjl_&BF{8Y6}kWt$8o7;dCN}loiUX`w-)Y z$`}Gz@FhkHwKakuy`Hr*WT&KM0A3p;?MVMaijfkZf7VH+A_E$_qmMEAX30+!gkzHa zw}y{7Ju73?Oc?lvJ1wN-;Xh^73>kRsIsRty90LQ*lmvoUx0_1)UvtUZ`A8^EHfiQ9 zkTSraJw8A;yYyJAmICsqd4NuLA)Y)klJ2G}-6QD&kpy&r>zFd9vRS@JYDFsZLRf9_ ze(~av}?~D~BJZO5wfxX5pzD+O&=+bzD7Qhh`u69H@|Mt>jkzDH%;zl zQDbV+BHr-*#pj^d(&Hg4Pf4BqNhvQP+tlrP9q694|j5I{THZ z^CVtii&v%eqD99qTD*wwoC2UVfw!+X2^c$2_|#LqdX`k)#P7`J;S@57e!}!g>lMS!1AmYV%y4+r|+Z7-Y zn<7QeLO+t5SF`C@Yc7yK=diCrF5r00sa3T5orILqp>w6rD0ZF=AG(56l>`B((N<{_ z1elGIyu8XtDL1Pt-Q#JvN@RI*exqxF+^!`DVOviEmF`@Kb~ROo_#!NV(Z#}RXxwWn zxGMwvIyAD0Bl>!4pftUs4V95b9KjYry>4E@OvoF?O~RR%R0?a+4F;H3dArkI5bPTb zmE3Gv>*3wJ2otOekOcXq65F%YvzUQHtEP&0ZJS_BO+Q_A6U3 z3OyBU-6x%xdijD4OFpns=Fg5wn;I~Udn9yBF<|!5o|yvHazW07J&ZTDjZJQhd*q+GFTsP^u8_wZ?

F^?m!Iv*U++GR* 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 literal 0 HcmV?d00001 diff --git a/pn8xT/pn553-i2c/modules.order b/pn8xT/pn553-i2c/modules.order new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c index dcdf140ba4..309b6e1e51 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn8xT/pn553-i2c/pn553.c @@ -563,7 +563,7 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, else{ pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); } - if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { + if (!(pn544_dev->secure_timer_cnt)) { gpio_set_value(pn544_dev->ese_pwr_gpio, 0); svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); } diff --git a/pn8xT/pn553-i2c/pn553.c~ b/pn8xT/pn553-i2c/pn553.c~ new file mode 100644 index 0000000000..309b6e1e51 --- /dev/null +++ b/pn8xT/pn553-i2c/pn553.c~ @@ -0,0 +1,1289 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pn553.h" + +#define NEXUS5x 0 +#if NEXUS5x +#undef ISO_RST +#else +#define ISO_RST +#endif +#define DRAGON_NFC 1 +#define SIG_NFC 44 +#define MAX_BUFFER_SIZE 512 +#define MAX_SECURE_SESSIONS 1 + +struct pn544_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn544_device; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int irq_gpio; + unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ +#ifdef ISO_RST + unsigned int iso_rst_gpio; /* ISO-RST pin gpio*/ +#endif + struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ + p61_access_state_t p61_current_state; /* stores the current P61 state */ + bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ + bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + long nfc_service_pid; /*used to signal the nfc the nfc service */ + chip_pwr_scheme_t chip_pwr_scheme; + unsigned int secure_timer_cnt; +}; +struct wake_lock nfc_wake_lock; +static bool sIsWakeLocked = false; +static struct pn544_dev *pn544_dev; +static struct semaphore ese_access_sema; +static struct semaphore svdd_sync_onoff_sema; +static void release_ese_lock(p61_access_state_t p61_current_state); +int get_ese_lock(p61_access_state_t p61_current_state, int timeout); +static long set_jcop_download_state(unsigned long arg); +static void pn544_disable_irq(struct pn544_dev *pn544_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + if (pn544_dev->irq_enabled) { + disable_irq_nosync(pn544_dev->client->irq); + disable_irq_wake(pn544_dev->client->irq); + pn544_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); +} + +static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) +{ + struct pn544_dev *pn544_dev = dev_id; + + pn544_disable_irq(pn544_dev); + if (sIsWakeLocked == false) + { + wake_lock(&nfc_wake_lock); + sIsWakeLocked = true; + } else { + pr_debug("%s already wake locked!\n", __func__); + } + /* Wake up waiting readers */ + wake_up(&pn544_dev->read_wq); + + + return IRQ_HANDLED; +} + +static ssize_t pn544_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + + mutex_lock(&pn544_dev->read_mutex); + + if (!gpio_get_value(pn544_dev->irq_gpio)) { + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } + + while (1) { + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + enable_irq_wake(pn544_dev->client->irq); + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + pn544_disable_irq(pn544_dev); + + if (ret) + goto fail; + + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + + /* Read data */ + ret = i2c_master_recv(pn544_dev->client, tmp, count); + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } + mutex_unlock(&pn544_dev->read_mutex); + + /* pn544 seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ +#if !NEXUS5x + udelay(1000); +#endif + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return ret; + + fail: + mutex_unlock(&pn544_dev->read_mutex); + return ret; +} + +static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + pn544_dev = filp->private_data; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + + pr_debug("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn544_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + + /* pn544 seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); + + return ret; +} + +static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) +{ + pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); + if (current_state) + { + if(set){ + if(pn544_dev->p61_current_state == P61_STATE_IDLE) + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->p61_current_state |= current_state; + } + else{ + pn544_dev->p61_current_state ^= current_state; + if(!pn544_dev->p61_current_state) + pn544_dev->p61_current_state = P61_STATE_IDLE; + } + } + pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); +} + +static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) +{ + + if (current_state == NULL) { + //*current_state = P61_STATE_INVALID; + pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); + } else { + *current_state = pn544_dev->p61_current_state; + } +} +static void p61_access_lock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_lock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} +static void p61_access_unlock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_unlock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} + +static int signal_handler(p61_access_state_t state, long nfc_pid) +{ + struct siginfo sinfo; + pid_t pid; + struct task_struct *task; + int sigret = 0, ret = 0; + pr_info("%s: Enter\n", __func__); + + if(nfc_pid == 0) + { + pr_info("nfc_pid is clear don't call signal_handler.\n"); + } + else + { + memset(&sinfo, 0, sizeof(struct siginfo)); + sinfo.si_signo = SIG_NFC; + sinfo.si_code = SI_QUEUE; + sinfo.si_int = state; + pid = nfc_pid; + + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if(task) + { + pr_info("%s.\n", task->comm); + sigret = force_sig_info(SIG_NFC, &sinfo, task); + if(sigret < 0){ + pr_info("send_sig_info failed..... sigret %d.\n", sigret); + ret = -1; + //msleep(60); + } + } + else{ + pr_info("finding task from PID failed\r\n"); + ret = -1; + } + } + pr_info("%s: Exit ret = %d\n", __func__, ret); + return ret; +} +static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 100; //100 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); + if(nfc_service_pid) + { + if (0 == signal_handler(origin, nfc_service_pid)) + { + sema_init(&svdd_sync_onoff_sema, 0); + pr_info("Waiting for svdd protection response"); + if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) + { + pr_info("svdd wait protection: Timeout"); + } + pr_info("svdd wait protection : released"); + } + } + pr_info("%s: Exit\n", __func__); +} +static int release_svdd_wait(void) +{ + pr_info("%s: Enter \n", __func__); + up(&svdd_sync_onoff_sema); + pr_info("%s: Exit\n", __func__); + return 0; +} +static int pn544_dev_open(struct inode *inode, struct file *filp) +{ + struct pn544_dev *pn544_dev = container_of(filp->private_data, + struct pn544_dev, + pn544_device); + + filp->private_data = pn544_dev; + + pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + + return 0; +} + +long pn544_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); + + if (cmd == P544_GET_ESE_ACCESS) + { + return get_ese_lock(P61_STATE_WIRED, arg); + } + else if(cmd == P544_REL_SVDD_WAIT) + { + return release_svdd_wait(); + } + p61_access_lock(pn544_dev); + switch (cmd) { + case PN544_SET_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 2) { + if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) + { + /* NFCC fw/download should not be allowed if p61 is used + * by SPI + */ + pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + pn544_dev->nfc_ven_enabled = true; + if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) + || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) + { + /* power on with firmware download (requires hw reset) + */ + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } else if (arg == 1) { + /* power on */ + pr_info("%s power on\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + if(current_state & P61_STATE_DWNLD){ + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, false); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = true; + if (pn544_dev->spi_ven_enabled == false || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { + gpio_set_value(pn544_dev->ven_gpio, 1); + } + } else if (arg == 0) { + /* power off */ + pr_info("%s power off\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = false; + /* Don't change Ven state if spi made it high */ + if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) + || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + } + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } + } else if (arg == 3) { + /*NFC Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_WIRED) { + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + } +#ifdef ISO_RST + gpio_set_value(pn544_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn544_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from DWP DONE\n", __func__); +#endif + } + else { + pr_err("%s bad arg %lu\n", __func__, arg); + /* changed the p61 state to idle*/ + p61_access_unlock(pn544_dev); + return -EINVAL; + } + } + break; + case P61_SET_SPI_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) { + pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if (!(current_state & P61_STATE_JCP_DWNLD)){ + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + + if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + + if (pn544_dev->nfc_ven_enabled == false) + { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } else { + pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); + if(current_state & P61_STATE_SPI_PRIO){ + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + if (!(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + if(!(current_state & P61_STATE_WIRED)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | + P61_STATE_SPI_PRIO_END); + }else { + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } else if (!(current_state & P61_STATE_WIRED)) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + pn544_dev->spi_ven_enabled = false; + + if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + + if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + + if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + }else if(current_state & P61_STATE_SPI){ + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + if (!(current_state & P61_STATE_WIRED) && + (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) && + !(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + if (!(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } + /*If JCOP3.2 or 3.3 for handling triple mode + protection signal NFC service */ + else + { + if (!(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + } else { + signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } else if (pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); + } + } + pn544_dev->spi_ven_enabled = false; + if (pn544_dev->nfc_ven_enabled == false && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) + && !(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + } else { + pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + }else if (arg == 2) { + pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); + if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + if ((pn544_dev->nfc_ven_enabled == false) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } + if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + msleep(10); + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + } else { + pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 3) { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); + if (current_state & P61_STATE_WIRED){ + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) + { + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + }else { + pr_info("%s : Prio Session Start power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 4) { + if (current_state & P61_STATE_SPI_PRIO) + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + /*after SPI prio timeout, the state is changing from SPI prio to SPI */ + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + else + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Device or resource busy */ + } + } else if(arg == 5){ + release_ese_lock(P61_STATE_SPI); + } else if (arg == 6) { + /*SPI Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if(current_state & P61_STATE_WIRED) { + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_SPI) { + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + }else if(current_state & P61_STATE_SPI_PRIO) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + } +#ifdef ISO_RST + gpio_set_value(pn544_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn544_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from SPI DONE\n", __func__); +#endif + } + else { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + + case P61_GET_PWR_STATUS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); + put_user(current_state, (int __user *)arg); + } + break; + + case PN544_SET_DWNLD_STATUS: + { + long ret; + ret = set_jcop_download_state(arg); + if(ret < 0) + { + p61_access_unlock(pn544_dev); + return ret; + } + } + break; + + case P61_SET_WIRED_ACCESS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) + { + if (current_state) + { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); + if (current_state & P61_STATE_SPI_PRIO) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } else { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); + if (current_state & P61_STATE_WIRED){ + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } else { + pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + } + else if(arg == 2) + { + pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); + if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } + else if(arg == 3) + { + pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); + if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + else if(arg == 4) + { + release_ese_lock(P61_STATE_WIRED); + } + else { + pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + case P544_SET_NFC_SERVICE_PID: + { + pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); + pn544_dev->nfc_service_pid = arg; + + } + break; + case P544_SET_POWER_SCHEME: + { + if(arg == PN67T_PWR_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); + } + else if(arg == PN80T_LEGACY_PWR_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; + pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); + } + else if(arg == PN80T_EXT_PMU_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; + pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); + } + else + { + pr_info("%s : The power scheme is invalid,\n", __func__); + } + } + break; + case P544_SECURE_TIMER_SESSION: + { + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + if(arg == 1) + { + if(pn544_dev->secure_timer_cnt < MAX_SECURE_SESSIONS) + { + pn544_dev->secure_timer_cnt++; + pr_info("%s : eSE secure timer session start : count = %d,\n", + __func__, pn544_dev->secure_timer_cnt); + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + } else if(arg == 0){ + if(pn544_dev->secure_timer_cnt > 0) + { + pn544_dev->secure_timer_cnt--; + pr_info("%s : eSE secure timer session stop : count = %d,\n", + __func__, pn544_dev->secure_timer_cnt); + if((pn544_dev->secure_timer_cnt == 0) && (pn544_dev->spi_ven_enabled == false)) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + if(pn544_dev->nfc_ven_enabled == false) + { + /* Turn off GPIO as none of the interfaces are active */ + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + } + } + } + } + else + { + pr_info("%s :Secure timer session not applicable \n", __func__); + } + } + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + p61_access_unlock(pn544_dev); + return -EINVAL; + } + p61_access_unlock(pn544_dev); + pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); + return 0; +} +EXPORT_SYMBOL(pn544_dev_ioctl); + +static long set_jcop_download_state(unsigned long arg) +{ + p61_access_state_t current_state = P61_STATE_INVALID; + long ret = 0; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s:Enter PN544_SET_DWNLD_STATUS:JCOP Dwnld state arg = %ld",__func__, arg); + if(arg == JCP_DWNLD_INIT) + { + if(pn544_dev->nfc_service_pid) + { + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(JCP_DWNLD_INIT, pn544_dev->nfc_service_pid); + } + else + { + if (current_state & P61_STATE_JCP_DWNLD) + { + ret = -EINVAL; + } + else + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); + } + } + } + else if (arg == JCP_DWNLD_START) + { + if (current_state & P61_STATE_JCP_DWNLD) + { + ret = -EINVAL; + } + else + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); + } + } + else if (arg == JCP_SPI_DWNLD_COMPLETE) + { + if(pn544_dev->nfc_service_pid) + { + signal_handler(JCP_DWP_DWNLD_COMPLETE, pn544_dev->nfc_service_pid); + } + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); + } + else if (arg == JCP_DWP_DWNLD_COMPLETE) + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); + } + else + { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + pr_info("%s: PN544_SET_DWNLD_STATUS = %x",__func__, current_state); + + return ret; +} + +int get_ese_lock(p61_access_state_t p61_current_state, int timeout) +{ + unsigned long tempJ = msecs_to_jiffies(timeout); + if(down_timeout(&ese_access_sema, tempJ) != 0) + { + printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); + return -EBUSY; + } + return 0; +} +EXPORT_SYMBOL(get_ese_lock); + +static void release_ese_lock(p61_access_state_t p61_current_state) +{ + up(&ese_access_sema); +} + + +static const struct file_operations pn544_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_dev_read, + .write = pn544_dev_write, + .open = pn544_dev_open, + .unlocked_ioctl = pn544_dev_ioctl, +}; +#if DRAGON_NFC +static int pn544_parse_dt(struct device *dev, + struct pn544_i2c_platform_data *data) +{ + struct device_node *np = dev->of_node; + int errorno = 0; + +#if !NEXUS5x + data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); + if ((!gpio_is_valid(data->irq_gpio))) + return -EINVAL; + + data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); + if ((!gpio_is_valid(data->ven_gpio))) + return -EINVAL; + + data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); + if ((!gpio_is_valid(data->firm_gpio))) + return -EINVAL; + + data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); + if ((!gpio_is_valid(data->ese_pwr_gpio))) + return -EINVAL; + data->iso_rst_gpio = of_get_named_gpio(np, "nxp,pn544-iso-pwr-rst", 0); + if ((!gpio_is_valid(data->iso_rst_gpio))) + return -EINVAL; +#else + data->ven_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_ven", 0, NULL); + data->firm_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_mode", 0, NULL); + data->irq_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_irq", 0, NULL); +#endif + pr_info("%s: %d, %d, %d, %d, %d error:%d\n", __func__, + data->irq_gpio, data->ven_gpio, data->firm_gpio, data->iso_rst_gpio, + data->ese_pwr_gpio, errorno); + + return errorno; +} +#endif + +static int pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct pn544_i2c_platform_data *platform_data; + //struct pn544_dev *pn544_dev; + +#if !DRAGON_NFC + platform_data = client->dev.platform_data; +#else + struct device_node *node = client->dev.of_node; + + if (node) { + platform_data = devm_kzalloc(&client->dev, + sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); + if (!platform_data) { + dev_err(&client->dev, + "nfc-nci probe: Failed to allocate memory\n"); + return -ENOMEM; + } + ret = pn544_parse_dt(&client->dev, platform_data); + if (ret) + { + pr_info("%s pn544_parse_dt failed", __func__); + } + client->irq = gpio_to_irq(platform_data->irq_gpio); + if (client->irq < 0) + { + pr_info("%s gpio to irq failed", __func__); + } + } else { + platform_data = client->dev.platform_data; + } +#endif + if (platform_data == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } +#if !DRAGON_NFC + ret = gpio_request(platform_data->irq_gpio, "nfc_int"); + if (ret) + return -ENODEV; + ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); + if (ret) + goto err_ven; + ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); + if (ret) + goto err_ese_pwr; + if (platform_data->firm_gpio) { + ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); + if (ret) + goto err_firm; + } +#ifdef ISO_RST + if(platform_data->iso_rst_gpio) { + ret = gpio_request(platform_data->iso_rst_gpio, "nfc_iso_rst"); + if (ret) + goto err_iso_rst; + } +#endif +#endif + pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); + if (pn544_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + pn544_dev->irq_gpio = platform_data->irq_gpio; + pn544_dev->ven_gpio = platform_data->ven_gpio; + pn544_dev->firm_gpio = platform_data->firm_gpio; + pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; +#ifdef ISO_RST + pn544_dev->iso_rst_gpio = platform_data->iso_rst_gpio; +#endif + pn544_dev->p61_current_state = P61_STATE_IDLE; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + pn544_dev->client = client; + pn544_dev->secure_timer_cnt = 0; + + ret = gpio_direction_input(pn544_dev->irq_gpio); + if (ret < 0) { + pr_err("%s :not able to set irq_gpio as input\n", __func__); + goto err_ven; + } + ret = gpio_direction_output(pn544_dev->ven_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_firm; + } + ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); + goto err_ese_pwr; + } + if (platform_data->firm_gpio) { + ret = gpio_direction_output(pn544_dev->firm_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set firm_gpio as output\n", + __func__); + goto err_exit; + } + } +#ifdef ISO_RST + ret = gpio_direction_output(pn544_dev->iso_rst_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set iso rst gpio as output\n", __func__); + goto err_iso_rst; + } +#endif + /* init mutex and queues */ + init_waitqueue_head(&pn544_dev->read_wq); + mutex_init(&pn544_dev->read_mutex); + sema_init(&ese_access_sema, 1); + mutex_init(&pn544_dev->p61_state_mutex); + spin_lock_init(&pn544_dev->irq_enabled_lock); + + pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; + pn544_dev->pn544_device.name = "pn553"; + pn544_dev->pn544_device.fops = &pn544_dev_fops; + + ret = misc_register(&pn544_dev->pn544_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } + wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); +#ifdef ISO_RST + /* Setting ISO RESET pin high to power ESE during init */ + gpio_set_value(pn544_dev->iso_rst_gpio, 1); +#endif + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pn544_dev->irq_enabled = true; + ret = request_irq(client->irq, pn544_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, pn544_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + enable_irq_wake(pn544_dev->client->irq); + pn544_disable_irq(pn544_dev); + i2c_set_clientdata(client, pn544_dev); + + return 0; + + err_request_irq_failed: + misc_deregister(&pn544_dev->pn544_device); + err_misc_register: + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + kfree(pn544_dev); + err_exit: + if (pn544_dev->firm_gpio) + gpio_free(platform_data->firm_gpio); + err_firm: + gpio_free(platform_data->ese_pwr_gpio); + err_ese_pwr: + gpio_free(platform_data->ven_gpio); + err_ven: + gpio_free(platform_data->irq_gpio); +#ifdef ISO_RST + err_iso_rst: + gpio_free(platform_data->iso_rst_gpio); +#endif + return ret; +} + +static int pn544_remove(struct i2c_client *client) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn544_dev); + misc_deregister(&pn544_dev->pn544_device); + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + gpio_free(pn544_dev->irq_gpio); + gpio_free(pn544_dev->ven_gpio); + gpio_free(pn544_dev->ese_pwr_gpio); +#ifdef ISO_RST + gpio_free(pn544_dev->iso_rst_gpio); +#endif + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + + if (pn544_dev->firm_gpio) + gpio_free(pn544_dev->firm_gpio); + kfree(pn544_dev); + + return 0; +} + +static const struct i2c_device_id pn544_id[] = { +#if NEXUS5x + { "pn548", 0 }, +#else + { "pn544", 0 }, +#endif + { } +}; +#if DRAGON_NFC +static struct of_device_id pn544_i2c_dt_match[] = { + { +#if NEXUS5x + .compatible = "nxp,pn548", +#else + .compatible = "nxp,pn544", +#endif + }, + {} +}; +#endif +static struct i2c_driver pn544_driver = { + .id_table = pn544_id, + .probe = pn544_probe, + .remove = pn544_remove, + .driver = { + .owner = THIS_MODULE, +#if NEXUS5x + .name = "pn548", +#else + .name = "pn544", +#endif +#if DRAGON_NFC + .of_match_table = pn544_i2c_dt_match, +#endif + }, +}; + +/* + * module load/unload record keeping + */ + +static int __init pn544_dev_init(void) +{ + pr_info("Loading pn544 driver\n"); + return i2c_add_driver(&pn544_driver); +} +module_init(pn544_dev_init); + +static void __exit pn544_dev_exit(void) +{ + pr_info("Unloading pn544 driver\n"); + i2c_del_driver(&pn544_driver); +} +module_exit(pn544_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION("NFC PN544 driver"); +MODULE_LICENSE("GPL"); diff --git a/pn8xT/pn553-i2c/pn553.h b/pn8xT/pn553-i2c/pn553.h index 582895b309..1fb3c5b041 100644 --- a/pn8xT/pn553-i2c/pn553.h +++ b/pn8xT/pn553-i2c/pn553.h @@ -117,7 +117,7 @@ typedef enum chip_type_pwr_scheme{ }chip_pwr_scheme_t; typedef enum jcop_dwnld_state{ - JCP_DWNLD_IDLE, /* jcop dwnld is not ongoing*/ + JCP_DWNLD_IDLE = P61_STATE_JCP_DWNLD, /* jcop dwnld is ongoing*/ JCP_DWNLD_INIT, /* jcop dwonload init state*/ JCP_DWNLD_START, /* download started */ JCP_SPI_DWNLD_COMPLETE, /* jcop download complete in spi interface*/ diff --git a/pn8xT/pn553-i2c/pn553.o b/pn8xT/pn553-i2c/pn553.o new file mode 100644 index 0000000000000000000000000000000000000000..0bd031f8aeca0f4ee8119aebd470545c115d2be0 GIT binary patch literal 199648 zcmeFad3;sX^)`Oax%cK?LJ~sA3?wHZ7s4Fo5QAKXNI=k#M46N%B!Pq}F#!zKYEWyj z);1_AwGIK>igd!N6|B{Wt);DPt!hhV2!m-UiRp{CwJ=Tk-vZrzWbR>4SAC%^dFyYB9H!3t8_n;X`g`Titi$!UL=Im$**Ejb>Asl} z%bH5Leq)Pebyvrid+O@Yuj{PP8z(ROVYEK!uyaVH`jvE`T$cej0*(V%7(`?jp$TyvmxgWgz`MYlG_hlTo+Oi%vZpsW;R=SOH zJxp6%+j;>0?x9Z#EcI7Gzt*|e?!M7Q9`f+F%bp+EZriET9bo2}i!|n$3;CB#8GVJ3 z6VN~AC6tXkyN~;D)>-!7BbHT5K7IGjs<~*lC-%d4yR_}%d>8TUVw?5*(hs~d#5%z| z?*P}A&6|ljPpyZYR^ME0JJ9rthp#O2&162W4(|+!oY1y(l$4E&cArQ>SjN zUlWf_ z!~P#Ye&*Hou5S2y2{OtLhX$6ppVzg7Q&zj19J_P;zu`8^5>k}ge`|L4jb2{zNN+|P zz7?{jb(=c%nYMh%m&3Zsxc?P&JlN=%x>!BOeOc1yP3)0=Z~DPhaz z^XHs+9Q2vS=X;Iw?me+#KKfe)#_E&%Px%IXY^-veBFOZx-?HBC`0Ozk4zp@@pwF&x zB%bana5Z-Sj$;>TnfT4O{Flr@Jh;-a4mTienw2qTD`>{KUdLJ#VY|5)cSxfi>Z5+6 zOMDt1M>K{!CS#}&F?OzN|GKc<u2sDCoC$6=GbhK@9XSjvPk+>0un0i*};S)t9H& z6o8)F?d-Z{v6Y6hb~DbOyzFrkHy(+OPmV#3MaCp++?*3`(0bs3eb%lWPWLnHgHCRb z^ka!(mh~X@GoAXWx86p~w5{|9Cd`T2=b$XgcyXdW!8#nDkNhYv@ytB7!*2DH_F?#r zK5I;X|Bg7jni3<2gV58QrtPveMd!PEZKvJ6N1Vg;=)=sj!|~Bpu{Qy2a{rphiJMRt z@|Zq=?UaI86T;ZXpKHy2Hruk&5T7|tMTYjX&IOj}+8uGa(~ck?`C0gT7q;5)l`~x9 znC0pi>qAW7{M~PS*9+fL&ldU({`(qq)WhcP+t7Ddw;S<`y6w0Hzo^rWJK-O1P_R#@3rrMqiqlTYA(_|687G;`7}8-{slP zy1@26jEQJ@yZ^hqYmirb2w(oz_~|HNjXl=JJ7LH9&f06f6KH{@$bG%63q^#}Ny!om2_WX2vyQGB}FD>zL zzpkBR%|Ra0rB9W>cJ^23l0LFq;!(QHM;r&tPu{*Ga}R@#??;mV$FS#W%mbA9n&Z2k zx-mwcIaKPK`5=7Jdz<7F8_*}GQjTjX%2BuY2X!HxY}yTRc8v7FKFv#+Kb$;u>*M%k zUdl2i42FEa13jq`spos3`ypeY-RgDTqRqSOz43)UD%gxO)NhOzyBK3nUiPEt+C


&N(bYhdI=Y(4z2#AI)+Lw{42v1<=( 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 RJ8i%9WPAM>ER4DR{|_+FV+Q~L literal 0 HcmV?d00001 From 1ce9cd3b2c8677f6ceabe9553d0baead957f6e78 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Tue, 11 Apr 2017 11:44:40 +0530 Subject: [PATCH 013/100] Removing intermediate files --- pn6xT/pn54x-i2c/pn54x.c~ | 1016 ------------------------------ pn8xT/pn553-i2c/pn553.c~ | 1289 -------------------------------------- 2 files changed, 2305 deletions(-) delete mode 100644 pn6xT/pn54x-i2c/pn54x.c~ delete mode 100644 pn8xT/pn553-i2c/pn553.c~ diff --git a/pn6xT/pn54x-i2c/pn54x.c~ b/pn6xT/pn54x-i2c/pn54x.c~ deleted file mode 100644 index 805eb86b54..0000000000 --- a/pn6xT/pn54x-i2c/pn54x.c~ +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -/****************************************************************************** - * - * The original Work has been changed by NXP Semiconductors. - * - * Copyright (C) 2013-2014 NXP Semiconductors - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pn54x.h" - -#define NEXUS5x 0 -#define DRAGON_NFC 1 -#define SIG_NFC 44 -#define MAX_BUFFER_SIZE 512 - -struct pn544_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct i2c_client *client; - struct miscdevice pn544_device; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int irq_gpio; - unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ - struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ - p61_access_state_t p61_current_state; /* stores the current P61 state */ - bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ - bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ - bool irq_enabled; - spinlock_t irq_enabled_lock; - long nfc_service_pid; /*used to signal the nfc the nfc service */ -}; -static struct pn544_dev *pn544_dev; -static struct semaphore ese_access_sema; -static struct semaphore svdd_sync_onoff_sema; -static void release_ese_lock(p61_access_state_t p61_current_state); -int get_ese_lock(p61_access_state_t p61_current_state, int timeout); -static void pn544_disable_irq(struct pn544_dev *pn544_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); - if (pn544_dev->irq_enabled) { - disable_irq_nosync(pn544_dev->client->irq); - pn544_dev->irq_enabled = false; - } - spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); -} - -static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) -{ - struct pn544_dev *pn544_dev = dev_id; - - pn544_disable_irq(pn544_dev); - - /* Wake up waiting readers */ - wake_up(&pn544_dev->read_wq); - - return IRQ_HANDLED; -} - -static ssize_t pn544_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev = filp->private_data; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - pr_debug("%s : reading %zu bytes.\n", __func__, count); - - mutex_lock(&pn544_dev->read_mutex); - - if (!gpio_get_value(pn544_dev->irq_gpio)) { - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto fail; - } - - while (1) { - pn544_dev->irq_enabled = true; - enable_irq(pn544_dev->client->irq); - ret = wait_event_interruptible( - pn544_dev->read_wq, - !pn544_dev->irq_enabled); - - pn544_disable_irq(pn544_dev); - - if (ret) - goto fail; - - if (gpio_get_value(pn544_dev->irq_gpio)) - break; - - pr_warning("%s: spurious interrupt detected\n", __func__); - } - } - - /* Read data */ - ret = i2c_master_recv(pn544_dev->client, tmp, count); - - mutex_unlock(&pn544_dev->read_mutex); - - /* pn544 seems to be slow in handling I2C read requests - * so add 1ms delay after recv operation */ -#if !NEXUS5x - udelay(1000); -#endif - - if (ret < 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - return ret; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - return -EIO; - } - if (copy_to_user(buf, tmp, ret)) { - pr_warning("%s : failed to copy to user space\n", __func__); - return -EFAULT; - } - return ret; - - fail: - mutex_unlock(&pn544_dev->read_mutex); - return ret; -} - -static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - pn544_dev = filp->private_data; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - return -EFAULT; - } - - pr_debug("%s : writing %zu bytes.\n", __func__, count); - /* Write data */ - ret = i2c_master_send(pn544_dev->client, tmp, count); - if (ret != count) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - ret = -EIO; - } - - /* pn544 seems to be slow in handling I2C write requests - * so add 1ms delay after I2C send oparation */ - udelay(1000); - - return ret; -} - -static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) -{ - pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); - if (current_state) - { - if(set){ - if(pn544_dev->p61_current_state == P61_STATE_IDLE) - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->p61_current_state |= current_state; - } - else{ - pn544_dev->p61_current_state ^= current_state; - if(!pn544_dev->p61_current_state) - pn544_dev->p61_current_state = P61_STATE_IDLE; - } - } - pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); -} - -static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) -{ - - if (current_state == NULL) { - //*current_state = P61_STATE_INVALID; - pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); - } else { - *current_state = pn544_dev->p61_current_state; - } -} -static void p61_access_lock(struct pn544_dev *pn544_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_lock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} -static void p61_access_unlock(struct pn544_dev *pn544_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_unlock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} - -static int signal_handler(p61_access_state_t state, long nfc_pid) -{ - struct siginfo sinfo; - pid_t pid; - struct task_struct *task; - int sigret = 0; - int ret = 0; - pr_info("%s: Enter\n", __func__); - - memset(&sinfo, 0, sizeof(struct siginfo)); - sinfo.si_signo = SIG_NFC; - sinfo.si_code = SI_QUEUE; - sinfo.si_int = state; - pid = nfc_pid; - - task = pid_task(find_vpid(pid), PIDTYPE_PID); - if(task) - { - pr_info("%s.\n", task->comm); - sigret = force_sig_info(SIG_NFC, &sinfo, task); - if(sigret < 0){ - pr_info("send_sig_info failed..... sigret %d.\n", sigret); - ret = -1; - } - } - else - { - pr_info("finding task from PID failed\r\n"); - ret = -1; - } - pr_info("%s: Exit ret = %d\n", __func__, ret); - return ret; -} -static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) -{ - int timeout = 100; //100 ms timeout - unsigned long tempJ = msecs_to_jiffies(timeout); - pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); - if(nfc_service_pid) - { - if (0 == signal_handler(origin, nfc_service_pid)) - { - sema_init(&svdd_sync_onoff_sema, 0); - pr_info("Waiting for svdd protection response"); - if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) - { - pr_info("svdd wait protection: Timeout"); - } - pr_info("svdd wait protection : released"); - } - } - pr_info("%s: Exit\n", __func__); -} -static int release_svdd_wait(void) -{ - pr_info("%s: Enter \n", __func__); - up(&svdd_sync_onoff_sema); - pr_info("%s: Exit\n", __func__); - return 0; -} -static int pn544_dev_open(struct inode *inode, struct file *filp) -{ - struct pn544_dev *pn544_dev = container_of(filp->private_data, - struct pn544_dev, - pn544_device); - - filp->private_data = pn544_dev; - - pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); - - return 0; -} - -long pn544_dev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); - - if (cmd == P544_GET_ESE_ACCESS) - { - return get_ese_lock(P61_STATE_WIRED, arg); - } - else if(cmd == P544_REL_SVDD_WAIT) - { - return release_svdd_wait(); - } - p61_access_lock(pn544_dev); - switch (cmd) { - case PN544_SET_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 2) { - if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) - { - /* NFCC fw/download should not be allowed if p61 is used - * by SPI - */ - pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - pn544_dev->nfc_ven_enabled = true; - if (pn544_dev->spi_ven_enabled == false) - { - /* power on with firmware download (requires hw reset) - */ - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - } - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } else if (arg == 1) { - /* power on */ - pr_info("%s power on\n", __func__); - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = true; - if (pn544_dev->spi_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 1); - } - } else if (arg == 0) { - /* power off */ - pr_info("%s power off\n", __func__); - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = false; - /* Don't change Ven state if spi made it high */ - if (pn544_dev->spi_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 0); - } - } else { - pr_err("%s bad arg %lu\n", __func__, arg); - /* changed the p61 state to idle*/ - p61_access_unlock(pn544_dev); - return -EINVAL; - } - } - break; - case P61_SET_SPI_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) { - pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - /*To handle triple mode protection signal - NFC service when SPI session started*/ - if ((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) - { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } else { - pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); - if(current_state & P61_STATE_SPI_PRIO){ - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - if (!(current_state & P61_STATE_WIRED)) - { - if((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | - P61_STATE_SPI_PRIO_END); - } - else - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - else if ((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else - { - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - if(current_state & P61_STATE_JCOP_DWNLD) - p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); - pn544_dev->spi_ven_enabled = false; - if (pn544_dev->nfc_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - }else if(current_state & P61_STATE_SPI){ - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - if (!(current_state & P61_STATE_WIRED)) - { - if((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } - else - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - /*If JCOP3.2 or 3.3 for handling triple mode - protection signal NFC service */ - else - { - if ((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - } - if(current_state & P61_STATE_JCOP_DWNLD) - p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); - pn544_dev->spi_ven_enabled = false; - if (pn544_dev->nfc_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - } else { - pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - }else if (arg == 2) { - pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); - if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - if (pn544_dev->spi_ven_enabled == false) - { - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - msleep(10); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } else { - pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 3) { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); - //if (current_state & P61_STATE_WIRED) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - }else { - pr_info("%s : Prio Session Start power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 4) { - if (current_state & P61_STATE_SPI_PRIO) - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - /*after SPI prio timeout, the state is changing from SPI prio to SPI */ - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - //if (current_state & P61_STATE_WIRED) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - } - else - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Device or resource busy */ - } - } else if(arg == 5){ - release_ese_lock(P61_STATE_SPI); - } - else { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - - case P61_SET_PWR_STATUS: - { - pr_info("%s: P61_SET_PWR_STATUS = %lx",__func__, arg); - p61_update_access_state(pn544_dev, arg, true); - } - break; - case P61_GET_PWR_STATUS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); - put_user(current_state, (int __user *)arg); - } - break; - case P61_SET_WIRED_ACCESS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) - { - if (current_state) - { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); - if (current_state & P61_STATE_SPI_PRIO) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } - } else { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); - if (current_state & P61_STATE_WIRED){ - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); - } - } else { - pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - } - else if(arg == 2) - { - pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); - } - else if(arg == 3) - { - pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } - else if(arg == 4) - { - release_ese_lock(P61_STATE_WIRED); - } - else { - pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - case P544_SET_NFC_SERVICE_PID: - { - pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); - pn544_dev->nfc_service_pid = arg; - - } - break; - default: - pr_err("%s bad ioctl %u\n", __func__, cmd); - p61_access_unlock(pn544_dev); - return -EINVAL; - } - p61_access_unlock(pn544_dev); - pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); - return 0; -} -EXPORT_SYMBOL(pn544_dev_ioctl); - -int get_ese_lock(p61_access_state_t p61_current_state, int timeout) -{ - unsigned long tempJ = msecs_to_jiffies(timeout); - if(down_timeout(&ese_access_sema, tempJ) != 0) - { - printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); - return -EBUSY; - } - return 0; -} -EXPORT_SYMBOL(get_ese_lock); - -static void release_ese_lock(p61_access_state_t p61_current_state) -{ - up(&ese_access_sema); -} - - -static const struct file_operations pn544_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = pn544_dev_read, - .write = pn544_dev_write, - .open = pn544_dev_open, - .unlocked_ioctl = pn544_dev_ioctl, -}; -#if DRAGON_NFC -static int pn544_parse_dt(struct device *dev, - struct pn544_i2c_platform_data *data) -{ - struct device_node *np = dev->of_node; - int errorno = 0; - -#if !NEXUS5x - data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); - if ((!gpio_is_valid(data->irq_gpio))) - return -EINVAL; - - data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); - if ((!gpio_is_valid(data->ven_gpio))) - return -EINVAL; - - data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); - if ((!gpio_is_valid(data->firm_gpio))) - return -EINVAL; - - data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); - if ((!gpio_is_valid(data->ese_pwr_gpio))) - return -EINVAL; -#else - data->ven_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_ven", 0, NULL); - data->firm_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_mode", 0, NULL); - data->irq_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_irq", 0, NULL); -#endif - pr_info("%s: %d, %d, %d, %d %d\n", __func__, - data->irq_gpio, data->ven_gpio, data->firm_gpio, data->ese_pwr_gpio, errorno); - - return errorno; -} -#endif - -static int pn544_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - struct pn544_i2c_platform_data *platform_data; - //struct pn544_dev *pn544_dev; - -#if !DRAGON_NFC - platform_data = client->dev.platform_data; -#else - struct device_node *node = client->dev.of_node; - - if (node) { - platform_data = devm_kzalloc(&client->dev, - sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); - if (!platform_data) { - dev_err(&client->dev, - "nfc-nci probe: Failed to allocate memory\n"); - return -ENOMEM; - } - ret = pn544_parse_dt(&client->dev, platform_data); - if (ret) - { - pr_info("%s pn544_parse_dt failed", __func__); - } - client->irq = gpio_to_irq(platform_data->irq_gpio); - if (client->irq < 0) - { - pr_info("%s gpio to irq failed", __func__); - } - } else { - platform_data = client->dev.platform_data; - } -#endif - if (platform_data == NULL) { - pr_err("%s : nfc probe fail\n", __func__); - return -ENODEV; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - return -ENODEV; - } -#if !DRAGON_NFC - ret = gpio_request(platform_data->irq_gpio, "nfc_int"); - if (ret) - return -ENODEV; - ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); - if (ret) - goto err_ven; - ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); - if (ret) - goto err_ese_pwr; - if (platform_data->firm_gpio) { - ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); - if (ret) - goto err_firm; - } -#endif - pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); - if (pn544_dev == NULL) { - dev_err(&client->dev, - "failed to allocate memory for module data\n"); - ret = -ENOMEM; - goto err_exit; - } - - pn544_dev->irq_gpio = platform_data->irq_gpio; - pn544_dev->ven_gpio = platform_data->ven_gpio; - pn544_dev->firm_gpio = platform_data->firm_gpio; - pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; - pn544_dev->p61_current_state = P61_STATE_IDLE; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - pn544_dev->client = client; - - ret = gpio_direction_input(pn544_dev->irq_gpio); - if (ret < 0) { - pr_err("%s :not able to set irq_gpio as input\n", __func__); - goto err_ven; - } - ret = gpio_direction_output(pn544_dev->ven_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_firm; - } - ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); - goto err_ese_pwr; - } - if (platform_data->firm_gpio) { - ret = gpio_direction_output(pn544_dev->firm_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set firm_gpio as output\n", - __func__); - goto err_exit; - } - } - - /* init mutex and queues */ - init_waitqueue_head(&pn544_dev->read_wq); - mutex_init(&pn544_dev->read_mutex); - sema_init(&ese_access_sema, 1); - mutex_init(&pn544_dev->p61_state_mutex); - spin_lock_init(&pn544_dev->irq_enabled_lock); - - pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; - pn544_dev->pn544_device.name = "pn54x"; - pn544_dev->pn544_device.fops = &pn544_dev_fops; - - ret = misc_register(&pn544_dev->pn544_device); - if (ret) { - pr_err("%s : misc_register failed\n", __FILE__); - goto err_misc_register; - } - - /* request irq. the irq is set whenever the chip has data available - * for reading. it is cleared when all data has been read. - */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - pn544_dev->irq_enabled = true; - ret = request_irq(client->irq, pn544_dev_irq_handler, - IRQF_TRIGGER_HIGH, client->name, pn544_dev); - if (ret) { - dev_err(&client->dev, "request_irq failed\n"); - goto err_request_irq_failed; - } - pn544_disable_irq(pn544_dev); - i2c_set_clientdata(client, pn544_dev); - - return 0; - - err_request_irq_failed: - misc_deregister(&pn544_dev->pn544_device); - err_misc_register: - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - kfree(pn544_dev); - err_exit: - if (pn544_dev->firm_gpio) - gpio_free(platform_data->firm_gpio); - err_firm: - gpio_free(platform_data->ese_pwr_gpio); - err_ese_pwr: - gpio_free(platform_data->ven_gpio); - err_ven: - gpio_free(platform_data->irq_gpio); - return ret; -} - -static int pn544_remove(struct i2c_client *client) -{ - struct pn544_dev *pn544_dev; - - pn544_dev = i2c_get_clientdata(client); - free_irq(client->irq, pn544_dev); - misc_deregister(&pn544_dev->pn544_device); - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - gpio_free(pn544_dev->irq_gpio); - gpio_free(pn544_dev->ven_gpio); - gpio_free(pn544_dev->ese_pwr_gpio); - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - - if (pn544_dev->firm_gpio) - gpio_free(pn544_dev->firm_gpio); - kfree(pn544_dev); - - return 0; -} - -static const struct i2c_device_id pn544_id[] = { -#if NEXUS5x - { "pn548", 0 }, -#else - { "pn544", 0 }, -#endif - { } -}; -#if DRAGON_NFC -static struct of_device_id pn544_i2c_dt_match[] = { - { -#if NEXUS5x - .compatible = "nxp,pn548", -#else - .compatible = "nxp,pn544", -#endif - }, - {} -}; -#endif -static struct i2c_driver pn544_driver = { - .id_table = pn544_id, - .probe = pn544_probe, - .remove = pn544_remove, - .driver = { - .owner = THIS_MODULE, -#if NEXUS5x - .name = "pn548", -#else - .name = "pn544", -#endif -#if DRAGON_NFC - .of_match_table = pn544_i2c_dt_match, -#endif - }, -}; - -/* - * module load/unload record keeping - */ - -static int __init pn544_dev_init(void) -{ - pr_info("Loading pn544 driver\n"); - return i2c_add_driver(&pn544_driver); -} -module_init(pn544_dev_init); - -static void __exit pn544_dev_exit(void) -{ - pr_info("Unloading pn544 driver\n"); - i2c_del_driver(&pn544_driver); -} -module_exit(pn544_dev_exit); - -MODULE_AUTHOR("Sylvain Fonteneau"); -MODULE_DESCRIPTION("NFC PN544 driver"); -MODULE_LICENSE("GPL"); diff --git a/pn8xT/pn553-i2c/pn553.c~ b/pn8xT/pn553-i2c/pn553.c~ deleted file mode 100644 index 309b6e1e51..0000000000 --- a/pn8xT/pn553-i2c/pn553.c~ +++ /dev/null @@ -1,1289 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -/****************************************************************************** - * - * The original Work has been changed by NXP Semiconductors. - * - * Copyright (C) 2013-2014 NXP Semiconductors - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pn553.h" - -#define NEXUS5x 0 -#if NEXUS5x -#undef ISO_RST -#else -#define ISO_RST -#endif -#define DRAGON_NFC 1 -#define SIG_NFC 44 -#define MAX_BUFFER_SIZE 512 -#define MAX_SECURE_SESSIONS 1 - -struct pn544_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct i2c_client *client; - struct miscdevice pn544_device; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int irq_gpio; - unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ -#ifdef ISO_RST - unsigned int iso_rst_gpio; /* ISO-RST pin gpio*/ -#endif - struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ - p61_access_state_t p61_current_state; /* stores the current P61 state */ - bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ - bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ - bool irq_enabled; - spinlock_t irq_enabled_lock; - long nfc_service_pid; /*used to signal the nfc the nfc service */ - chip_pwr_scheme_t chip_pwr_scheme; - unsigned int secure_timer_cnt; -}; -struct wake_lock nfc_wake_lock; -static bool sIsWakeLocked = false; -static struct pn544_dev *pn544_dev; -static struct semaphore ese_access_sema; -static struct semaphore svdd_sync_onoff_sema; -static void release_ese_lock(p61_access_state_t p61_current_state); -int get_ese_lock(p61_access_state_t p61_current_state, int timeout); -static long set_jcop_download_state(unsigned long arg); -static void pn544_disable_irq(struct pn544_dev *pn544_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); - if (pn544_dev->irq_enabled) { - disable_irq_nosync(pn544_dev->client->irq); - disable_irq_wake(pn544_dev->client->irq); - pn544_dev->irq_enabled = false; - } - spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); -} - -static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) -{ - struct pn544_dev *pn544_dev = dev_id; - - pn544_disable_irq(pn544_dev); - if (sIsWakeLocked == false) - { - wake_lock(&nfc_wake_lock); - sIsWakeLocked = true; - } else { - pr_debug("%s already wake locked!\n", __func__); - } - /* Wake up waiting readers */ - wake_up(&pn544_dev->read_wq); - - - return IRQ_HANDLED; -} - -static ssize_t pn544_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev = filp->private_data; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - pr_debug("%s : reading %zu bytes.\n", __func__, count); - - mutex_lock(&pn544_dev->read_mutex); - - if (!gpio_get_value(pn544_dev->irq_gpio)) { - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto fail; - } - - while (1) { - pn544_dev->irq_enabled = true; - enable_irq(pn544_dev->client->irq); - enable_irq_wake(pn544_dev->client->irq); - ret = wait_event_interruptible( - pn544_dev->read_wq, - !pn544_dev->irq_enabled); - - pn544_disable_irq(pn544_dev); - - if (ret) - goto fail; - - if (gpio_get_value(pn544_dev->irq_gpio)) - break; - - pr_warning("%s: spurious interrupt detected\n", __func__); - } - } - - /* Read data */ - ret = i2c_master_recv(pn544_dev->client, tmp, count); - if (sIsWakeLocked == true) { - wake_unlock(&nfc_wake_lock); - sIsWakeLocked = false; - } - mutex_unlock(&pn544_dev->read_mutex); - - /* pn544 seems to be slow in handling I2C read requests - * so add 1ms delay after recv operation */ -#if !NEXUS5x - udelay(1000); -#endif - - if (ret < 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - return ret; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - return -EIO; - } - if (copy_to_user(buf, tmp, ret)) { - pr_warning("%s : failed to copy to user space\n", __func__); - return -EFAULT; - } - return ret; - - fail: - mutex_unlock(&pn544_dev->read_mutex); - return ret; -} - -static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - pn544_dev = filp->private_data; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - return -EFAULT; - } - - pr_debug("%s : writing %zu bytes.\n", __func__, count); - /* Write data */ - ret = i2c_master_send(pn544_dev->client, tmp, count); - if (ret != count) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - ret = -EIO; - } - - /* pn544 seems to be slow in handling I2C write requests - * so add 1ms delay after I2C send oparation */ - udelay(1000); - - return ret; -} - -static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) -{ - pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); - if (current_state) - { - if(set){ - if(pn544_dev->p61_current_state == P61_STATE_IDLE) - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->p61_current_state |= current_state; - } - else{ - pn544_dev->p61_current_state ^= current_state; - if(!pn544_dev->p61_current_state) - pn544_dev->p61_current_state = P61_STATE_IDLE; - } - } - pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); -} - -static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) -{ - - if (current_state == NULL) { - //*current_state = P61_STATE_INVALID; - pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); - } else { - *current_state = pn544_dev->p61_current_state; - } -} -static void p61_access_lock(struct pn544_dev *pn544_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_lock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} -static void p61_access_unlock(struct pn544_dev *pn544_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_unlock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} - -static int signal_handler(p61_access_state_t state, long nfc_pid) -{ - struct siginfo sinfo; - pid_t pid; - struct task_struct *task; - int sigret = 0, ret = 0; - pr_info("%s: Enter\n", __func__); - - if(nfc_pid == 0) - { - pr_info("nfc_pid is clear don't call signal_handler.\n"); - } - else - { - memset(&sinfo, 0, sizeof(struct siginfo)); - sinfo.si_signo = SIG_NFC; - sinfo.si_code = SI_QUEUE; - sinfo.si_int = state; - pid = nfc_pid; - - task = pid_task(find_vpid(pid), PIDTYPE_PID); - if(task) - { - pr_info("%s.\n", task->comm); - sigret = force_sig_info(SIG_NFC, &sinfo, task); - if(sigret < 0){ - pr_info("send_sig_info failed..... sigret %d.\n", sigret); - ret = -1; - //msleep(60); - } - } - else{ - pr_info("finding task from PID failed\r\n"); - ret = -1; - } - } - pr_info("%s: Exit ret = %d\n", __func__, ret); - return ret; -} -static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) -{ - int timeout = 100; //100 ms timeout - unsigned long tempJ = msecs_to_jiffies(timeout); - pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); - if(nfc_service_pid) - { - if (0 == signal_handler(origin, nfc_service_pid)) - { - sema_init(&svdd_sync_onoff_sema, 0); - pr_info("Waiting for svdd protection response"); - if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) - { - pr_info("svdd wait protection: Timeout"); - } - pr_info("svdd wait protection : released"); - } - } - pr_info("%s: Exit\n", __func__); -} -static int release_svdd_wait(void) -{ - pr_info("%s: Enter \n", __func__); - up(&svdd_sync_onoff_sema); - pr_info("%s: Exit\n", __func__); - return 0; -} -static int pn544_dev_open(struct inode *inode, struct file *filp) -{ - struct pn544_dev *pn544_dev = container_of(filp->private_data, - struct pn544_dev, - pn544_device); - - filp->private_data = pn544_dev; - - pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); - - return 0; -} - -long pn544_dev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); - - if (cmd == P544_GET_ESE_ACCESS) - { - return get_ese_lock(P61_STATE_WIRED, arg); - } - else if(cmd == P544_REL_SVDD_WAIT) - { - return release_svdd_wait(); - } - p61_access_lock(pn544_dev); - switch (cmd) { - case PN544_SET_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 2) { - if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) - { - /* NFCC fw/download should not be allowed if p61 is used - * by SPI - */ - pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - pn544_dev->nfc_ven_enabled = true; - if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) - || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) - { - /* power on with firmware download (requires hw reset) - */ - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - } - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } else if (arg == 1) { - /* power on */ - pr_info("%s power on\n", __func__); - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - if(current_state & P61_STATE_DWNLD){ - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, false); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = true; - if (pn544_dev->spi_ven_enabled == false || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { - gpio_set_value(pn544_dev->ven_gpio, 1); - } - } else if (arg == 0) { - /* power off */ - pr_info("%s power off\n", __func__); - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = false; - /* Don't change Ven state if spi made it high */ - if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) - || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - } - if (sIsWakeLocked == true) { - wake_unlock(&nfc_wake_lock); - sIsWakeLocked = false; - } - } else if (arg == 3) { - /*NFC Service called ISO-RST*/ - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - if(current_state & P61_STATE_WIRED) { - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - } -#ifdef ISO_RST - gpio_set_value(pn544_dev->iso_rst_gpio, 0); - msleep(50); - gpio_set_value(pn544_dev->iso_rst_gpio, 1); - msleep(50); - pr_info("%s ISO RESET from DWP DONE\n", __func__); -#endif - } - else { - pr_err("%s bad arg %lu\n", __func__, arg); - /* changed the p61 state to idle*/ - p61_access_unlock(pn544_dev); - return -EINVAL; - } - } - break; - case P61_SET_SPI_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) { - pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - /*To handle triple mode protection signal - NFC service when SPI session started*/ - if (!(current_state & P61_STATE_JCP_DWNLD)){ - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - - if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) - break; - - if (pn544_dev->nfc_ven_enabled == false) - { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } else { - pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); - if(current_state & P61_STATE_SPI_PRIO){ - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - if (!(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - if(!(current_state & P61_STATE_WIRED)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | - P61_STATE_SPI_PRIO_END); - }else { - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } else if (!(current_state & P61_STATE_WIRED)) { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - pn544_dev->spi_ven_enabled = false; - - if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) - break; - - if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - - if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - }else if(current_state & P61_STATE_SPI){ - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - if (!(current_state & P61_STATE_WIRED) && - (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) && - !(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - if (!(pn544_dev->secure_timer_cnt)) { - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } - /*If JCOP3.2 or 3.3 for handling triple mode - protection signal NFC service */ - else - { - if (!(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } else { - signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); - } - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } else if (pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); - } - } - pn544_dev->spi_ven_enabled = false; - if (pn544_dev->nfc_ven_enabled == false && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) - && !(pn544_dev->secure_timer_cnt)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - } else { - pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - }else if (arg == 2) { - pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); - if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - if (pn544_dev->spi_ven_enabled == false) - { - pn544_dev->spi_ven_enabled = true; - if ((pn544_dev->nfc_ven_enabled == false) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } - if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - msleep(10); - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } - } else { - pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 3) { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); - if (current_state & P61_STATE_WIRED){ - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) - { - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } - }else { - pr_info("%s : Prio Session Start power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 4) { - if (current_state & P61_STATE_SPI_PRIO) - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - /*after SPI prio timeout, the state is changing from SPI prio to SPI */ - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - if (current_state & P61_STATE_WIRED) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - } - else - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Device or resource busy */ - } - } else if(arg == 5){ - release_ese_lock(P61_STATE_SPI); - } else if (arg == 6) { - /*SPI Service called ISO-RST*/ - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if(current_state & P61_STATE_WIRED) { - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - if(current_state & P61_STATE_SPI) { - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - }else if(current_state & P61_STATE_SPI_PRIO) { - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - } -#ifdef ISO_RST - gpio_set_value(pn544_dev->iso_rst_gpio, 0); - msleep(50); - gpio_set_value(pn544_dev->iso_rst_gpio, 1); - msleep(50); - pr_info("%s ISO RESET from SPI DONE\n", __func__); -#endif - } - else { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - - case P61_GET_PWR_STATUS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); - put_user(current_state, (int __user *)arg); - } - break; - - case PN544_SET_DWNLD_STATUS: - { - long ret; - ret = set_jcop_download_state(arg); - if(ret < 0) - { - p61_access_unlock(pn544_dev); - return ret; - } - } - break; - - case P61_SET_WIRED_ACCESS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) - { - if (current_state) - { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); - if (current_state & P61_STATE_SPI_PRIO) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } else { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); - if (current_state & P61_STATE_WIRED){ - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } else { - pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - } - else if(arg == 2) - { - pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); - if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } - else if(arg == 3) - { - pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); - if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } - else if(arg == 4) - { - release_ese_lock(P61_STATE_WIRED); - } - else { - pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - case P544_SET_NFC_SERVICE_PID: - { - pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); - pn544_dev->nfc_service_pid = arg; - - } - break; - case P544_SET_POWER_SCHEME: - { - if(arg == PN67T_PWR_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; - pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); - } - else if(arg == PN80T_LEGACY_PWR_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; - pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); - } - else if(arg == PN80T_EXT_PMU_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; - pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); - } - else - { - pr_info("%s : The power scheme is invalid,\n", __func__); - } - } - break; - case P544_SECURE_TIMER_SESSION: - { - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - if(arg == 1) - { - if(pn544_dev->secure_timer_cnt < MAX_SECURE_SESSIONS) - { - pn544_dev->secure_timer_cnt++; - pr_info("%s : eSE secure timer session start : count = %d,\n", - __func__, pn544_dev->secure_timer_cnt); - if (pn544_dev->spi_ven_enabled == false) - { - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } - } else if(arg == 0){ - if(pn544_dev->secure_timer_cnt > 0) - { - pn544_dev->secure_timer_cnt--; - pr_info("%s : eSE secure timer session stop : count = %d,\n", - __func__, pn544_dev->secure_timer_cnt); - if((pn544_dev->secure_timer_cnt == 0) && (pn544_dev->spi_ven_enabled == false)) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - if(pn544_dev->nfc_ven_enabled == false) - { - /* Turn off GPIO as none of the interfaces are active */ - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - } - } - } - } - else - { - pr_info("%s :Secure timer session not applicable \n", __func__); - } - } - break; - default: - pr_err("%s bad ioctl %u\n", __func__, cmd); - p61_access_unlock(pn544_dev); - return -EINVAL; - } - p61_access_unlock(pn544_dev); - pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); - return 0; -} -EXPORT_SYMBOL(pn544_dev_ioctl); - -static long set_jcop_download_state(unsigned long arg) -{ - p61_access_state_t current_state = P61_STATE_INVALID; - long ret = 0; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s:Enter PN544_SET_DWNLD_STATUS:JCOP Dwnld state arg = %ld",__func__, arg); - if(arg == JCP_DWNLD_INIT) - { - if(pn544_dev->nfc_service_pid) - { - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(JCP_DWNLD_INIT, pn544_dev->nfc_service_pid); - } - else - { - if (current_state & P61_STATE_JCP_DWNLD) - { - ret = -EINVAL; - } - else - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); - } - } - } - else if (arg == JCP_DWNLD_START) - { - if (current_state & P61_STATE_JCP_DWNLD) - { - ret = -EINVAL; - } - else - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); - } - } - else if (arg == JCP_SPI_DWNLD_COMPLETE) - { - if(pn544_dev->nfc_service_pid) - { - signal_handler(JCP_DWP_DWNLD_COMPLETE, pn544_dev->nfc_service_pid); - } - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); - } - else if (arg == JCP_DWP_DWNLD_COMPLETE) - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); - } - else - { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - pr_info("%s: PN544_SET_DWNLD_STATUS = %x",__func__, current_state); - - return ret; -} - -int get_ese_lock(p61_access_state_t p61_current_state, int timeout) -{ - unsigned long tempJ = msecs_to_jiffies(timeout); - if(down_timeout(&ese_access_sema, tempJ) != 0) - { - printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); - return -EBUSY; - } - return 0; -} -EXPORT_SYMBOL(get_ese_lock); - -static void release_ese_lock(p61_access_state_t p61_current_state) -{ - up(&ese_access_sema); -} - - -static const struct file_operations pn544_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = pn544_dev_read, - .write = pn544_dev_write, - .open = pn544_dev_open, - .unlocked_ioctl = pn544_dev_ioctl, -}; -#if DRAGON_NFC -static int pn544_parse_dt(struct device *dev, - struct pn544_i2c_platform_data *data) -{ - struct device_node *np = dev->of_node; - int errorno = 0; - -#if !NEXUS5x - data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); - if ((!gpio_is_valid(data->irq_gpio))) - return -EINVAL; - - data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); - if ((!gpio_is_valid(data->ven_gpio))) - return -EINVAL; - - data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); - if ((!gpio_is_valid(data->firm_gpio))) - return -EINVAL; - - data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); - if ((!gpio_is_valid(data->ese_pwr_gpio))) - return -EINVAL; - data->iso_rst_gpio = of_get_named_gpio(np, "nxp,pn544-iso-pwr-rst", 0); - if ((!gpio_is_valid(data->iso_rst_gpio))) - return -EINVAL; -#else - data->ven_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_ven", 0, NULL); - data->firm_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_mode", 0, NULL); - data->irq_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_irq", 0, NULL); -#endif - pr_info("%s: %d, %d, %d, %d, %d error:%d\n", __func__, - data->irq_gpio, data->ven_gpio, data->firm_gpio, data->iso_rst_gpio, - data->ese_pwr_gpio, errorno); - - return errorno; -} -#endif - -static int pn544_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - struct pn544_i2c_platform_data *platform_data; - //struct pn544_dev *pn544_dev; - -#if !DRAGON_NFC - platform_data = client->dev.platform_data; -#else - struct device_node *node = client->dev.of_node; - - if (node) { - platform_data = devm_kzalloc(&client->dev, - sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); - if (!platform_data) { - dev_err(&client->dev, - "nfc-nci probe: Failed to allocate memory\n"); - return -ENOMEM; - } - ret = pn544_parse_dt(&client->dev, platform_data); - if (ret) - { - pr_info("%s pn544_parse_dt failed", __func__); - } - client->irq = gpio_to_irq(platform_data->irq_gpio); - if (client->irq < 0) - { - pr_info("%s gpio to irq failed", __func__); - } - } else { - platform_data = client->dev.platform_data; - } -#endif - if (platform_data == NULL) { - pr_err("%s : nfc probe fail\n", __func__); - return -ENODEV; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - return -ENODEV; - } -#if !DRAGON_NFC - ret = gpio_request(platform_data->irq_gpio, "nfc_int"); - if (ret) - return -ENODEV; - ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); - if (ret) - goto err_ven; - ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); - if (ret) - goto err_ese_pwr; - if (platform_data->firm_gpio) { - ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); - if (ret) - goto err_firm; - } -#ifdef ISO_RST - if(platform_data->iso_rst_gpio) { - ret = gpio_request(platform_data->iso_rst_gpio, "nfc_iso_rst"); - if (ret) - goto err_iso_rst; - } -#endif -#endif - pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); - if (pn544_dev == NULL) { - dev_err(&client->dev, - "failed to allocate memory for module data\n"); - ret = -ENOMEM; - goto err_exit; - } - - pn544_dev->irq_gpio = platform_data->irq_gpio; - pn544_dev->ven_gpio = platform_data->ven_gpio; - pn544_dev->firm_gpio = platform_data->firm_gpio; - pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; -#ifdef ISO_RST - pn544_dev->iso_rst_gpio = platform_data->iso_rst_gpio; -#endif - pn544_dev->p61_current_state = P61_STATE_IDLE; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; - pn544_dev->client = client; - pn544_dev->secure_timer_cnt = 0; - - ret = gpio_direction_input(pn544_dev->irq_gpio); - if (ret < 0) { - pr_err("%s :not able to set irq_gpio as input\n", __func__); - goto err_ven; - } - ret = gpio_direction_output(pn544_dev->ven_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_firm; - } - ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); - goto err_ese_pwr; - } - if (platform_data->firm_gpio) { - ret = gpio_direction_output(pn544_dev->firm_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set firm_gpio as output\n", - __func__); - goto err_exit; - } - } -#ifdef ISO_RST - ret = gpio_direction_output(pn544_dev->iso_rst_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set iso rst gpio as output\n", __func__); - goto err_iso_rst; - } -#endif - /* init mutex and queues */ - init_waitqueue_head(&pn544_dev->read_wq); - mutex_init(&pn544_dev->read_mutex); - sema_init(&ese_access_sema, 1); - mutex_init(&pn544_dev->p61_state_mutex); - spin_lock_init(&pn544_dev->irq_enabled_lock); - - pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; - pn544_dev->pn544_device.name = "pn553"; - pn544_dev->pn544_device.fops = &pn544_dev_fops; - - ret = misc_register(&pn544_dev->pn544_device); - if (ret) { - pr_err("%s : misc_register failed\n", __FILE__); - goto err_misc_register; - } - wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); -#ifdef ISO_RST - /* Setting ISO RESET pin high to power ESE during init */ - gpio_set_value(pn544_dev->iso_rst_gpio, 1); -#endif - /* request irq. the irq is set whenever the chip has data available - * for reading. it is cleared when all data has been read. - */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - pn544_dev->irq_enabled = true; - ret = request_irq(client->irq, pn544_dev_irq_handler, - IRQF_TRIGGER_HIGH, client->name, pn544_dev); - if (ret) { - dev_err(&client->dev, "request_irq failed\n"); - goto err_request_irq_failed; - } - enable_irq_wake(pn544_dev->client->irq); - pn544_disable_irq(pn544_dev); - i2c_set_clientdata(client, pn544_dev); - - return 0; - - err_request_irq_failed: - misc_deregister(&pn544_dev->pn544_device); - err_misc_register: - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - kfree(pn544_dev); - err_exit: - if (pn544_dev->firm_gpio) - gpio_free(platform_data->firm_gpio); - err_firm: - gpio_free(platform_data->ese_pwr_gpio); - err_ese_pwr: - gpio_free(platform_data->ven_gpio); - err_ven: - gpio_free(platform_data->irq_gpio); -#ifdef ISO_RST - err_iso_rst: - gpio_free(platform_data->iso_rst_gpio); -#endif - return ret; -} - -static int pn544_remove(struct i2c_client *client) -{ - struct pn544_dev *pn544_dev; - - pn544_dev = i2c_get_clientdata(client); - free_irq(client->irq, pn544_dev); - misc_deregister(&pn544_dev->pn544_device); - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - gpio_free(pn544_dev->irq_gpio); - gpio_free(pn544_dev->ven_gpio); - gpio_free(pn544_dev->ese_pwr_gpio); -#ifdef ISO_RST - gpio_free(pn544_dev->iso_rst_gpio); -#endif - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - - if (pn544_dev->firm_gpio) - gpio_free(pn544_dev->firm_gpio); - kfree(pn544_dev); - - return 0; -} - -static const struct i2c_device_id pn544_id[] = { -#if NEXUS5x - { "pn548", 0 }, -#else - { "pn544", 0 }, -#endif - { } -}; -#if DRAGON_NFC -static struct of_device_id pn544_i2c_dt_match[] = { - { -#if NEXUS5x - .compatible = "nxp,pn548", -#else - .compatible = "nxp,pn544", -#endif - }, - {} -}; -#endif -static struct i2c_driver pn544_driver = { - .id_table = pn544_id, - .probe = pn544_probe, - .remove = pn544_remove, - .driver = { - .owner = THIS_MODULE, -#if NEXUS5x - .name = "pn548", -#else - .name = "pn544", -#endif -#if DRAGON_NFC - .of_match_table = pn544_i2c_dt_match, -#endif - }, -}; - -/* - * module load/unload record keeping - */ - -static int __init pn544_dev_init(void) -{ - pr_info("Loading pn544 driver\n"); - return i2c_add_driver(&pn544_driver); -} -module_init(pn544_dev_init); - -static void __exit pn544_dev_exit(void) -{ - pr_info("Unloading pn544 driver\n"); - i2c_del_driver(&pn544_driver); -} -module_exit(pn544_dev_exit); - -MODULE_AUTHOR("Sylvain Fonteneau"); -MODULE_DESCRIPTION("NFC PN544 driver"); -MODULE_LICENSE("GPL"); From 04dfbf55405f5a1334dfaf3930d60b35a5eb298e Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Fri, 12 May 2017 16:24:12 +0530 Subject: [PATCH 014/100] SEAccessKit_AR7.4.0_OpnSrc --- pn6xT/pn54x-i2c/pn54x.c~ | 1016 ++++++++++++++++++++++++++++ pn8xT/pn553-i2c/built-in.o | Bin 199640 -> 199640 bytes pn8xT/pn553-i2c/pn553.c~ | 1289 ++++++++++++++++++++++++++++++++++++ pn8xT/pn553-i2c/pn553.h | 8 +- pn8xT/pn553-i2c/pn553.o | Bin 199648 -> 199648 bytes 5 files changed, 2309 insertions(+), 4 deletions(-) create mode 100644 pn6xT/pn54x-i2c/pn54x.c~ create mode 100644 pn8xT/pn553-i2c/pn553.c~ diff --git a/pn6xT/pn54x-i2c/pn54x.c~ b/pn6xT/pn54x-i2c/pn54x.c~ new file mode 100644 index 0000000000..805eb86b54 --- /dev/null +++ b/pn6xT/pn54x-i2c/pn54x.c~ @@ -0,0 +1,1016 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pn54x.h" + +#define NEXUS5x 0 +#define DRAGON_NFC 1 +#define SIG_NFC 44 +#define MAX_BUFFER_SIZE 512 + +struct pn544_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn544_device; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int irq_gpio; + unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ + struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ + p61_access_state_t p61_current_state; /* stores the current P61 state */ + bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ + bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + long nfc_service_pid; /*used to signal the nfc the nfc service */ +}; +static struct pn544_dev *pn544_dev; +static struct semaphore ese_access_sema; +static struct semaphore svdd_sync_onoff_sema; +static void release_ese_lock(p61_access_state_t p61_current_state); +int get_ese_lock(p61_access_state_t p61_current_state, int timeout); +static void pn544_disable_irq(struct pn544_dev *pn544_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + if (pn544_dev->irq_enabled) { + disable_irq_nosync(pn544_dev->client->irq); + pn544_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); +} + +static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) +{ + struct pn544_dev *pn544_dev = dev_id; + + pn544_disable_irq(pn544_dev); + + /* Wake up waiting readers */ + wake_up(&pn544_dev->read_wq); + + return IRQ_HANDLED; +} + +static ssize_t pn544_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + + mutex_lock(&pn544_dev->read_mutex); + + if (!gpio_get_value(pn544_dev->irq_gpio)) { + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } + + while (1) { + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + pn544_disable_irq(pn544_dev); + + if (ret) + goto fail; + + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + + /* Read data */ + ret = i2c_master_recv(pn544_dev->client, tmp, count); + + mutex_unlock(&pn544_dev->read_mutex); + + /* pn544 seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ +#if !NEXUS5x + udelay(1000); +#endif + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return ret; + + fail: + mutex_unlock(&pn544_dev->read_mutex); + return ret; +} + +static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + pn544_dev = filp->private_data; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + + pr_debug("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn544_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + + /* pn544 seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); + + return ret; +} + +static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) +{ + pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); + if (current_state) + { + if(set){ + if(pn544_dev->p61_current_state == P61_STATE_IDLE) + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->p61_current_state |= current_state; + } + else{ + pn544_dev->p61_current_state ^= current_state; + if(!pn544_dev->p61_current_state) + pn544_dev->p61_current_state = P61_STATE_IDLE; + } + } + pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); +} + +static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) +{ + + if (current_state == NULL) { + //*current_state = P61_STATE_INVALID; + pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); + } else { + *current_state = pn544_dev->p61_current_state; + } +} +static void p61_access_lock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_lock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} +static void p61_access_unlock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_unlock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} + +static int signal_handler(p61_access_state_t state, long nfc_pid) +{ + struct siginfo sinfo; + pid_t pid; + struct task_struct *task; + int sigret = 0; + int ret = 0; + pr_info("%s: Enter\n", __func__); + + memset(&sinfo, 0, sizeof(struct siginfo)); + sinfo.si_signo = SIG_NFC; + sinfo.si_code = SI_QUEUE; + sinfo.si_int = state; + pid = nfc_pid; + + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if(task) + { + pr_info("%s.\n", task->comm); + sigret = force_sig_info(SIG_NFC, &sinfo, task); + if(sigret < 0){ + pr_info("send_sig_info failed..... sigret %d.\n", sigret); + ret = -1; + } + } + else + { + pr_info("finding task from PID failed\r\n"); + ret = -1; + } + pr_info("%s: Exit ret = %d\n", __func__, ret); + return ret; +} +static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 100; //100 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); + if(nfc_service_pid) + { + if (0 == signal_handler(origin, nfc_service_pid)) + { + sema_init(&svdd_sync_onoff_sema, 0); + pr_info("Waiting for svdd protection response"); + if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) + { + pr_info("svdd wait protection: Timeout"); + } + pr_info("svdd wait protection : released"); + } + } + pr_info("%s: Exit\n", __func__); +} +static int release_svdd_wait(void) +{ + pr_info("%s: Enter \n", __func__); + up(&svdd_sync_onoff_sema); + pr_info("%s: Exit\n", __func__); + return 0; +} +static int pn544_dev_open(struct inode *inode, struct file *filp) +{ + struct pn544_dev *pn544_dev = container_of(filp->private_data, + struct pn544_dev, + pn544_device); + + filp->private_data = pn544_dev; + + pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + + return 0; +} + +long pn544_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); + + if (cmd == P544_GET_ESE_ACCESS) + { + return get_ese_lock(P61_STATE_WIRED, arg); + } + else if(cmd == P544_REL_SVDD_WAIT) + { + return release_svdd_wait(); + } + p61_access_lock(pn544_dev); + switch (cmd) { + case PN544_SET_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 2) { + if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) + { + /* NFCC fw/download should not be allowed if p61 is used + * by SPI + */ + pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + pn544_dev->nfc_ven_enabled = true; + if (pn544_dev->spi_ven_enabled == false) + { + /* power on with firmware download (requires hw reset) + */ + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } else if (arg == 1) { + /* power on */ + pr_info("%s power on\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = true; + if (pn544_dev->spi_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 1); + } + } else if (arg == 0) { + /* power off */ + pr_info("%s power off\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = false; + /* Don't change Ven state if spi made it high */ + if (pn544_dev->spi_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 0); + } + } else { + pr_err("%s bad arg %lu\n", __func__, arg); + /* changed the p61 state to idle*/ + p61_access_unlock(pn544_dev); + return -EINVAL; + } + } + break; + case P61_SET_SPI_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) { + pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if ((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) + { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } else { + pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); + if(current_state & P61_STATE_SPI_PRIO){ + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + if (!(current_state & P61_STATE_WIRED)) + { + if((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | + P61_STATE_SPI_PRIO_END); + } + else + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + else if ((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else + { + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if(current_state & P61_STATE_JCOP_DWNLD) + p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); + pn544_dev->spi_ven_enabled = false; + if (pn544_dev->nfc_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + }else if(current_state & P61_STATE_SPI){ + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + if (!(current_state & P61_STATE_WIRED)) + { + if((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + } + else + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + /*If JCOP3.2 or 3.3 for handling triple mode + protection signal NFC service */ + else + { + if ((current_state & P61_STATE_JCOP_DWNLD) == 0) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + if(current_state & P61_STATE_JCOP_DWNLD) + p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); + pn544_dev->spi_ven_enabled = false; + if (pn544_dev->nfc_ven_enabled == false) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + } else { + pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + }else if (arg == 2) { + pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); + if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + msleep(10); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } else { + pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 3) { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); + //if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + }else { + pr_info("%s : Prio Session Start power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 4) { + if (current_state & P61_STATE_SPI_PRIO) + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + /*after SPI prio timeout, the state is changing from SPI prio to SPI */ + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + //if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + else + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Device or resource busy */ + } + } else if(arg == 5){ + release_ese_lock(P61_STATE_SPI); + } + else { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + + case P61_SET_PWR_STATUS: + { + pr_info("%s: P61_SET_PWR_STATUS = %lx",__func__, arg); + p61_update_access_state(pn544_dev, arg, true); + } + break; + case P61_GET_PWR_STATUS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); + put_user(current_state, (int __user *)arg); + } + break; + case P61_SET_WIRED_ACCESS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) + { + if (current_state) + { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); + if (current_state & P61_STATE_SPI_PRIO) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + } else { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); + if (current_state & P61_STATE_WIRED){ + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); + } + } else { + pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + } + else if(arg == 2) + { + pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); + } + else if(arg == 3) + { + pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + else if(arg == 4) + { + release_ese_lock(P61_STATE_WIRED); + } + else { + pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + case P544_SET_NFC_SERVICE_PID: + { + pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); + pn544_dev->nfc_service_pid = arg; + + } + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + p61_access_unlock(pn544_dev); + return -EINVAL; + } + p61_access_unlock(pn544_dev); + pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); + return 0; +} +EXPORT_SYMBOL(pn544_dev_ioctl); + +int get_ese_lock(p61_access_state_t p61_current_state, int timeout) +{ + unsigned long tempJ = msecs_to_jiffies(timeout); + if(down_timeout(&ese_access_sema, tempJ) != 0) + { + printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); + return -EBUSY; + } + return 0; +} +EXPORT_SYMBOL(get_ese_lock); + +static void release_ese_lock(p61_access_state_t p61_current_state) +{ + up(&ese_access_sema); +} + + +static const struct file_operations pn544_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_dev_read, + .write = pn544_dev_write, + .open = pn544_dev_open, + .unlocked_ioctl = pn544_dev_ioctl, +}; +#if DRAGON_NFC +static int pn544_parse_dt(struct device *dev, + struct pn544_i2c_platform_data *data) +{ + struct device_node *np = dev->of_node; + int errorno = 0; + +#if !NEXUS5x + data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); + if ((!gpio_is_valid(data->irq_gpio))) + return -EINVAL; + + data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); + if ((!gpio_is_valid(data->ven_gpio))) + return -EINVAL; + + data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); + if ((!gpio_is_valid(data->firm_gpio))) + return -EINVAL; + + data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); + if ((!gpio_is_valid(data->ese_pwr_gpio))) + return -EINVAL; +#else + data->ven_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_ven", 0, NULL); + data->firm_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_mode", 0, NULL); + data->irq_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_irq", 0, NULL); +#endif + pr_info("%s: %d, %d, %d, %d %d\n", __func__, + data->irq_gpio, data->ven_gpio, data->firm_gpio, data->ese_pwr_gpio, errorno); + + return errorno; +} +#endif + +static int pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct pn544_i2c_platform_data *platform_data; + //struct pn544_dev *pn544_dev; + +#if !DRAGON_NFC + platform_data = client->dev.platform_data; +#else + struct device_node *node = client->dev.of_node; + + if (node) { + platform_data = devm_kzalloc(&client->dev, + sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); + if (!platform_data) { + dev_err(&client->dev, + "nfc-nci probe: Failed to allocate memory\n"); + return -ENOMEM; + } + ret = pn544_parse_dt(&client->dev, platform_data); + if (ret) + { + pr_info("%s pn544_parse_dt failed", __func__); + } + client->irq = gpio_to_irq(platform_data->irq_gpio); + if (client->irq < 0) + { + pr_info("%s gpio to irq failed", __func__); + } + } else { + platform_data = client->dev.platform_data; + } +#endif + if (platform_data == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } +#if !DRAGON_NFC + ret = gpio_request(platform_data->irq_gpio, "nfc_int"); + if (ret) + return -ENODEV; + ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); + if (ret) + goto err_ven; + ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); + if (ret) + goto err_ese_pwr; + if (platform_data->firm_gpio) { + ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); + if (ret) + goto err_firm; + } +#endif + pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); + if (pn544_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + pn544_dev->irq_gpio = platform_data->irq_gpio; + pn544_dev->ven_gpio = platform_data->ven_gpio; + pn544_dev->firm_gpio = platform_data->firm_gpio; + pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; + pn544_dev->p61_current_state = P61_STATE_IDLE; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + pn544_dev->client = client; + + ret = gpio_direction_input(pn544_dev->irq_gpio); + if (ret < 0) { + pr_err("%s :not able to set irq_gpio as input\n", __func__); + goto err_ven; + } + ret = gpio_direction_output(pn544_dev->ven_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_firm; + } + ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); + goto err_ese_pwr; + } + if (platform_data->firm_gpio) { + ret = gpio_direction_output(pn544_dev->firm_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set firm_gpio as output\n", + __func__); + goto err_exit; + } + } + + /* init mutex and queues */ + init_waitqueue_head(&pn544_dev->read_wq); + mutex_init(&pn544_dev->read_mutex); + sema_init(&ese_access_sema, 1); + mutex_init(&pn544_dev->p61_state_mutex); + spin_lock_init(&pn544_dev->irq_enabled_lock); + + pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; + pn544_dev->pn544_device.name = "pn54x"; + pn544_dev->pn544_device.fops = &pn544_dev_fops; + + ret = misc_register(&pn544_dev->pn544_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } + + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pn544_dev->irq_enabled = true; + ret = request_irq(client->irq, pn544_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, pn544_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + pn544_disable_irq(pn544_dev); + i2c_set_clientdata(client, pn544_dev); + + return 0; + + err_request_irq_failed: + misc_deregister(&pn544_dev->pn544_device); + err_misc_register: + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + kfree(pn544_dev); + err_exit: + if (pn544_dev->firm_gpio) + gpio_free(platform_data->firm_gpio); + err_firm: + gpio_free(platform_data->ese_pwr_gpio); + err_ese_pwr: + gpio_free(platform_data->ven_gpio); + err_ven: + gpio_free(platform_data->irq_gpio); + return ret; +} + +static int pn544_remove(struct i2c_client *client) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn544_dev); + misc_deregister(&pn544_dev->pn544_device); + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + gpio_free(pn544_dev->irq_gpio); + gpio_free(pn544_dev->ven_gpio); + gpio_free(pn544_dev->ese_pwr_gpio); + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + + if (pn544_dev->firm_gpio) + gpio_free(pn544_dev->firm_gpio); + kfree(pn544_dev); + + return 0; +} + +static const struct i2c_device_id pn544_id[] = { +#if NEXUS5x + { "pn548", 0 }, +#else + { "pn544", 0 }, +#endif + { } +}; +#if DRAGON_NFC +static struct of_device_id pn544_i2c_dt_match[] = { + { +#if NEXUS5x + .compatible = "nxp,pn548", +#else + .compatible = "nxp,pn544", +#endif + }, + {} +}; +#endif +static struct i2c_driver pn544_driver = { + .id_table = pn544_id, + .probe = pn544_probe, + .remove = pn544_remove, + .driver = { + .owner = THIS_MODULE, +#if NEXUS5x + .name = "pn548", +#else + .name = "pn544", +#endif +#if DRAGON_NFC + .of_match_table = pn544_i2c_dt_match, +#endif + }, +}; + +/* + * module load/unload record keeping + */ + +static int __init pn544_dev_init(void) +{ + pr_info("Loading pn544 driver\n"); + return i2c_add_driver(&pn544_driver); +} +module_init(pn544_dev_init); + +static void __exit pn544_dev_exit(void) +{ + pr_info("Unloading pn544 driver\n"); + i2c_del_driver(&pn544_driver); +} +module_exit(pn544_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION("NFC PN544 driver"); +MODULE_LICENSE("GPL"); diff --git a/pn8xT/pn553-i2c/built-in.o b/pn8xT/pn553-i2c/built-in.o index 0fe3c0b1383e13ab7a9427201607d33c14807c05..cf9a6eb192d4014104abba2cd30ce38344fa8aa1 100644 GIT binary patch delta 102 zcmcaHo#)1Mo((2qObkqu&BWZ87+5CPiK$63a7?&#pNZl1K}Lp<1wsx#8FL(dCNeN= wVGx+SPfU%8L16PUv7*IN6B?L!7=T~_ls*8Z8ycI7cC{DnV%%P|izzJ-04_xypa1{> delta 102 zcmcaHo#)1Mo((2qObQH>&BWZ892h3oiK$5?Fif~~pNZl1K}Lp<1wsx#8FL(dCNeN= wX<(SVPfU%efnoDAv7*INjSWmZ3_#EXrJJF2OG9(fuJ)o`jN6NLF{K3p0Eq7&%K!iX diff --git a/pn8xT/pn553-i2c/pn553.c~ b/pn8xT/pn553-i2c/pn553.c~ new file mode 100644 index 0000000000..309b6e1e51 --- /dev/null +++ b/pn8xT/pn553-i2c/pn553.c~ @@ -0,0 +1,1289 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pn553.h" + +#define NEXUS5x 0 +#if NEXUS5x +#undef ISO_RST +#else +#define ISO_RST +#endif +#define DRAGON_NFC 1 +#define SIG_NFC 44 +#define MAX_BUFFER_SIZE 512 +#define MAX_SECURE_SESSIONS 1 + +struct pn544_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn544_device; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int irq_gpio; + unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ +#ifdef ISO_RST + unsigned int iso_rst_gpio; /* ISO-RST pin gpio*/ +#endif + struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ + p61_access_state_t p61_current_state; /* stores the current P61 state */ + bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ + bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + long nfc_service_pid; /*used to signal the nfc the nfc service */ + chip_pwr_scheme_t chip_pwr_scheme; + unsigned int secure_timer_cnt; +}; +struct wake_lock nfc_wake_lock; +static bool sIsWakeLocked = false; +static struct pn544_dev *pn544_dev; +static struct semaphore ese_access_sema; +static struct semaphore svdd_sync_onoff_sema; +static void release_ese_lock(p61_access_state_t p61_current_state); +int get_ese_lock(p61_access_state_t p61_current_state, int timeout); +static long set_jcop_download_state(unsigned long arg); +static void pn544_disable_irq(struct pn544_dev *pn544_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + if (pn544_dev->irq_enabled) { + disable_irq_nosync(pn544_dev->client->irq); + disable_irq_wake(pn544_dev->client->irq); + pn544_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); +} + +static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) +{ + struct pn544_dev *pn544_dev = dev_id; + + pn544_disable_irq(pn544_dev); + if (sIsWakeLocked == false) + { + wake_lock(&nfc_wake_lock); + sIsWakeLocked = true; + } else { + pr_debug("%s already wake locked!\n", __func__); + } + /* Wake up waiting readers */ + wake_up(&pn544_dev->read_wq); + + + return IRQ_HANDLED; +} + +static ssize_t pn544_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + + mutex_lock(&pn544_dev->read_mutex); + + if (!gpio_get_value(pn544_dev->irq_gpio)) { + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } + + while (1) { + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + enable_irq_wake(pn544_dev->client->irq); + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + pn544_disable_irq(pn544_dev); + + if (ret) + goto fail; + + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + + /* Read data */ + ret = i2c_master_recv(pn544_dev->client, tmp, count); + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } + mutex_unlock(&pn544_dev->read_mutex); + + /* pn544 seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ +#if !NEXUS5x + udelay(1000); +#endif + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return ret; + + fail: + mutex_unlock(&pn544_dev->read_mutex); + return ret; +} + +static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + pn544_dev = filp->private_data; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + + pr_debug("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn544_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + + /* pn544 seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); + + return ret; +} + +static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) +{ + pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); + if (current_state) + { + if(set){ + if(pn544_dev->p61_current_state == P61_STATE_IDLE) + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->p61_current_state |= current_state; + } + else{ + pn544_dev->p61_current_state ^= current_state; + if(!pn544_dev->p61_current_state) + pn544_dev->p61_current_state = P61_STATE_IDLE; + } + } + pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); +} + +static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) +{ + + if (current_state == NULL) { + //*current_state = P61_STATE_INVALID; + pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); + } else { + *current_state = pn544_dev->p61_current_state; + } +} +static void p61_access_lock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_lock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} +static void p61_access_unlock(struct pn544_dev *pn544_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_unlock(&pn544_dev->p61_state_mutex); + pr_info("%s: Exit\n", __func__); +} + +static int signal_handler(p61_access_state_t state, long nfc_pid) +{ + struct siginfo sinfo; + pid_t pid; + struct task_struct *task; + int sigret = 0, ret = 0; + pr_info("%s: Enter\n", __func__); + + if(nfc_pid == 0) + { + pr_info("nfc_pid is clear don't call signal_handler.\n"); + } + else + { + memset(&sinfo, 0, sizeof(struct siginfo)); + sinfo.si_signo = SIG_NFC; + sinfo.si_code = SI_QUEUE; + sinfo.si_int = state; + pid = nfc_pid; + + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if(task) + { + pr_info("%s.\n", task->comm); + sigret = force_sig_info(SIG_NFC, &sinfo, task); + if(sigret < 0){ + pr_info("send_sig_info failed..... sigret %d.\n", sigret); + ret = -1; + //msleep(60); + } + } + else{ + pr_info("finding task from PID failed\r\n"); + ret = -1; + } + } + pr_info("%s: Exit ret = %d\n", __func__, ret); + return ret; +} +static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 100; //100 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); + if(nfc_service_pid) + { + if (0 == signal_handler(origin, nfc_service_pid)) + { + sema_init(&svdd_sync_onoff_sema, 0); + pr_info("Waiting for svdd protection response"); + if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) + { + pr_info("svdd wait protection: Timeout"); + } + pr_info("svdd wait protection : released"); + } + } + pr_info("%s: Exit\n", __func__); +} +static int release_svdd_wait(void) +{ + pr_info("%s: Enter \n", __func__); + up(&svdd_sync_onoff_sema); + pr_info("%s: Exit\n", __func__); + return 0; +} +static int pn544_dev_open(struct inode *inode, struct file *filp) +{ + struct pn544_dev *pn544_dev = container_of(filp->private_data, + struct pn544_dev, + pn544_device); + + filp->private_data = pn544_dev; + + pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + + return 0; +} + +long pn544_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); + + if (cmd == P544_GET_ESE_ACCESS) + { + return get_ese_lock(P61_STATE_WIRED, arg); + } + else if(cmd == P544_REL_SVDD_WAIT) + { + return release_svdd_wait(); + } + p61_access_lock(pn544_dev); + switch (cmd) { + case PN544_SET_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 2) { + if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) + { + /* NFCC fw/download should not be allowed if p61 is used + * by SPI + */ + pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + pn544_dev->nfc_ven_enabled = true; + if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) + || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) + { + /* power on with firmware download (requires hw reset) + */ + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } else if (arg == 1) { + /* power on */ + pr_info("%s power on\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + if(current_state & P61_STATE_DWNLD){ + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, false); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = true; + if (pn544_dev->spi_ven_enabled == false || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { + gpio_set_value(pn544_dev->ven_gpio, 1); + } + } else if (arg == 0) { + /* power off */ + pr_info("%s power off\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = false; + /* Don't change Ven state if spi made it high */ + if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) + || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + } + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } + } else if (arg == 3) { + /*NFC Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_WIRED) { + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + } +#ifdef ISO_RST + gpio_set_value(pn544_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn544_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from DWP DONE\n", __func__); +#endif + } + else { + pr_err("%s bad arg %lu\n", __func__, arg); + /* changed the p61 state to idle*/ + p61_access_unlock(pn544_dev); + return -EINVAL; + } + } + break; + case P61_SET_SPI_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) { + pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if (!(current_state & P61_STATE_JCP_DWNLD)){ + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + + if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + + if (pn544_dev->nfc_ven_enabled == false) + { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } else { + pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); + if(current_state & P61_STATE_SPI_PRIO){ + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + if (!(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + if(!(current_state & P61_STATE_WIRED)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | + P61_STATE_SPI_PRIO_END); + }else { + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } else if (!(current_state & P61_STATE_WIRED)) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + pn544_dev->spi_ven_enabled = false; + + if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + + if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + + if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + }else if(current_state & P61_STATE_SPI){ + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + if (!(current_state & P61_STATE_WIRED) && + (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) && + !(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + if (!(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } + /*If JCOP3.2 or 3.3 for handling triple mode + protection signal NFC service */ + else + { + if (!(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + } else { + signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } else if (pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); + } + } + pn544_dev->spi_ven_enabled = false; + if (pn544_dev->nfc_ven_enabled == false && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) + && !(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + } else { + pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + }else if (arg == 2) { + pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); + if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + if ((pn544_dev->nfc_ven_enabled == false) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } + if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + msleep(10); + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + } else { + pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 3) { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); + if (current_state & P61_STATE_WIRED){ + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) + { + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + }else { + pr_info("%s : Prio Session Start power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 4) { + if (current_state & P61_STATE_SPI_PRIO) + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + /*after SPI prio timeout, the state is changing from SPI prio to SPI */ + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + else + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Device or resource busy */ + } + } else if(arg == 5){ + release_ese_lock(P61_STATE_SPI); + } else if (arg == 6) { + /*SPI Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if(current_state & P61_STATE_WIRED) { + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_SPI) { + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + }else if(current_state & P61_STATE_SPI_PRIO) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + } +#ifdef ISO_RST + gpio_set_value(pn544_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn544_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from SPI DONE\n", __func__); +#endif + } + else { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + + case P61_GET_PWR_STATUS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); + put_user(current_state, (int __user *)arg); + } + break; + + case PN544_SET_DWNLD_STATUS: + { + long ret; + ret = set_jcop_download_state(arg); + if(ret < 0) + { + p61_access_unlock(pn544_dev); + return ret; + } + } + break; + + case P61_SET_WIRED_ACCESS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) + { + if (current_state) + { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); + if (current_state & P61_STATE_SPI_PRIO) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } else { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); + if (current_state & P61_STATE_WIRED){ + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } else { + pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + } + else if(arg == 2) + { + pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); + if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } + else if(arg == 3) + { + pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); + if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + else if(arg == 4) + { + release_ese_lock(P61_STATE_WIRED); + } + else { + pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + case P544_SET_NFC_SERVICE_PID: + { + pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); + pn544_dev->nfc_service_pid = arg; + + } + break; + case P544_SET_POWER_SCHEME: + { + if(arg == PN67T_PWR_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); + } + else if(arg == PN80T_LEGACY_PWR_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; + pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); + } + else if(arg == PN80T_EXT_PMU_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; + pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); + } + else + { + pr_info("%s : The power scheme is invalid,\n", __func__); + } + } + break; + case P544_SECURE_TIMER_SESSION: + { + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + if(arg == 1) + { + if(pn544_dev->secure_timer_cnt < MAX_SECURE_SESSIONS) + { + pn544_dev->secure_timer_cnt++; + pr_info("%s : eSE secure timer session start : count = %d,\n", + __func__, pn544_dev->secure_timer_cnt); + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + } else if(arg == 0){ + if(pn544_dev->secure_timer_cnt > 0) + { + pn544_dev->secure_timer_cnt--; + pr_info("%s : eSE secure timer session stop : count = %d,\n", + __func__, pn544_dev->secure_timer_cnt); + if((pn544_dev->secure_timer_cnt == 0) && (pn544_dev->spi_ven_enabled == false)) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + if(pn544_dev->nfc_ven_enabled == false) + { + /* Turn off GPIO as none of the interfaces are active */ + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + } + } + } + } + else + { + pr_info("%s :Secure timer session not applicable \n", __func__); + } + } + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + p61_access_unlock(pn544_dev); + return -EINVAL; + } + p61_access_unlock(pn544_dev); + pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); + return 0; +} +EXPORT_SYMBOL(pn544_dev_ioctl); + +static long set_jcop_download_state(unsigned long arg) +{ + p61_access_state_t current_state = P61_STATE_INVALID; + long ret = 0; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s:Enter PN544_SET_DWNLD_STATUS:JCOP Dwnld state arg = %ld",__func__, arg); + if(arg == JCP_DWNLD_INIT) + { + if(pn544_dev->nfc_service_pid) + { + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(JCP_DWNLD_INIT, pn544_dev->nfc_service_pid); + } + else + { + if (current_state & P61_STATE_JCP_DWNLD) + { + ret = -EINVAL; + } + else + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); + } + } + } + else if (arg == JCP_DWNLD_START) + { + if (current_state & P61_STATE_JCP_DWNLD) + { + ret = -EINVAL; + } + else + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); + } + } + else if (arg == JCP_SPI_DWNLD_COMPLETE) + { + if(pn544_dev->nfc_service_pid) + { + signal_handler(JCP_DWP_DWNLD_COMPLETE, pn544_dev->nfc_service_pid); + } + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); + } + else if (arg == JCP_DWP_DWNLD_COMPLETE) + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); + } + else + { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + pr_info("%s: PN544_SET_DWNLD_STATUS = %x",__func__, current_state); + + return ret; +} + +int get_ese_lock(p61_access_state_t p61_current_state, int timeout) +{ + unsigned long tempJ = msecs_to_jiffies(timeout); + if(down_timeout(&ese_access_sema, tempJ) != 0) + { + printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); + return -EBUSY; + } + return 0; +} +EXPORT_SYMBOL(get_ese_lock); + +static void release_ese_lock(p61_access_state_t p61_current_state) +{ + up(&ese_access_sema); +} + + +static const struct file_operations pn544_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_dev_read, + .write = pn544_dev_write, + .open = pn544_dev_open, + .unlocked_ioctl = pn544_dev_ioctl, +}; +#if DRAGON_NFC +static int pn544_parse_dt(struct device *dev, + struct pn544_i2c_platform_data *data) +{ + struct device_node *np = dev->of_node; + int errorno = 0; + +#if !NEXUS5x + data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); + if ((!gpio_is_valid(data->irq_gpio))) + return -EINVAL; + + data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); + if ((!gpio_is_valid(data->ven_gpio))) + return -EINVAL; + + data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); + if ((!gpio_is_valid(data->firm_gpio))) + return -EINVAL; + + data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); + if ((!gpio_is_valid(data->ese_pwr_gpio))) + return -EINVAL; + data->iso_rst_gpio = of_get_named_gpio(np, "nxp,pn544-iso-pwr-rst", 0); + if ((!gpio_is_valid(data->iso_rst_gpio))) + return -EINVAL; +#else + data->ven_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_ven", 0, NULL); + data->firm_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_mode", 0, NULL); + data->irq_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_irq", 0, NULL); +#endif + pr_info("%s: %d, %d, %d, %d, %d error:%d\n", __func__, + data->irq_gpio, data->ven_gpio, data->firm_gpio, data->iso_rst_gpio, + data->ese_pwr_gpio, errorno); + + return errorno; +} +#endif + +static int pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct pn544_i2c_platform_data *platform_data; + //struct pn544_dev *pn544_dev; + +#if !DRAGON_NFC + platform_data = client->dev.platform_data; +#else + struct device_node *node = client->dev.of_node; + + if (node) { + platform_data = devm_kzalloc(&client->dev, + sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); + if (!platform_data) { + dev_err(&client->dev, + "nfc-nci probe: Failed to allocate memory\n"); + return -ENOMEM; + } + ret = pn544_parse_dt(&client->dev, platform_data); + if (ret) + { + pr_info("%s pn544_parse_dt failed", __func__); + } + client->irq = gpio_to_irq(platform_data->irq_gpio); + if (client->irq < 0) + { + pr_info("%s gpio to irq failed", __func__); + } + } else { + platform_data = client->dev.platform_data; + } +#endif + if (platform_data == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } +#if !DRAGON_NFC + ret = gpio_request(platform_data->irq_gpio, "nfc_int"); + if (ret) + return -ENODEV; + ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); + if (ret) + goto err_ven; + ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); + if (ret) + goto err_ese_pwr; + if (platform_data->firm_gpio) { + ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); + if (ret) + goto err_firm; + } +#ifdef ISO_RST + if(platform_data->iso_rst_gpio) { + ret = gpio_request(platform_data->iso_rst_gpio, "nfc_iso_rst"); + if (ret) + goto err_iso_rst; + } +#endif +#endif + pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); + if (pn544_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + pn544_dev->irq_gpio = platform_data->irq_gpio; + pn544_dev->ven_gpio = platform_data->ven_gpio; + pn544_dev->firm_gpio = platform_data->firm_gpio; + pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; +#ifdef ISO_RST + pn544_dev->iso_rst_gpio = platform_data->iso_rst_gpio; +#endif + pn544_dev->p61_current_state = P61_STATE_IDLE; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + pn544_dev->client = client; + pn544_dev->secure_timer_cnt = 0; + + ret = gpio_direction_input(pn544_dev->irq_gpio); + if (ret < 0) { + pr_err("%s :not able to set irq_gpio as input\n", __func__); + goto err_ven; + } + ret = gpio_direction_output(pn544_dev->ven_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_firm; + } + ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); + goto err_ese_pwr; + } + if (platform_data->firm_gpio) { + ret = gpio_direction_output(pn544_dev->firm_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set firm_gpio as output\n", + __func__); + goto err_exit; + } + } +#ifdef ISO_RST + ret = gpio_direction_output(pn544_dev->iso_rst_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set iso rst gpio as output\n", __func__); + goto err_iso_rst; + } +#endif + /* init mutex and queues */ + init_waitqueue_head(&pn544_dev->read_wq); + mutex_init(&pn544_dev->read_mutex); + sema_init(&ese_access_sema, 1); + mutex_init(&pn544_dev->p61_state_mutex); + spin_lock_init(&pn544_dev->irq_enabled_lock); + + pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; + pn544_dev->pn544_device.name = "pn553"; + pn544_dev->pn544_device.fops = &pn544_dev_fops; + + ret = misc_register(&pn544_dev->pn544_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } + wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); +#ifdef ISO_RST + /* Setting ISO RESET pin high to power ESE during init */ + gpio_set_value(pn544_dev->iso_rst_gpio, 1); +#endif + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pn544_dev->irq_enabled = true; + ret = request_irq(client->irq, pn544_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, pn544_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + enable_irq_wake(pn544_dev->client->irq); + pn544_disable_irq(pn544_dev); + i2c_set_clientdata(client, pn544_dev); + + return 0; + + err_request_irq_failed: + misc_deregister(&pn544_dev->pn544_device); + err_misc_register: + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + kfree(pn544_dev); + err_exit: + if (pn544_dev->firm_gpio) + gpio_free(platform_data->firm_gpio); + err_firm: + gpio_free(platform_data->ese_pwr_gpio); + err_ese_pwr: + gpio_free(platform_data->ven_gpio); + err_ven: + gpio_free(platform_data->irq_gpio); +#ifdef ISO_RST + err_iso_rst: + gpio_free(platform_data->iso_rst_gpio); +#endif + return ret; +} + +static int pn544_remove(struct i2c_client *client) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn544_dev); + misc_deregister(&pn544_dev->pn544_device); + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + gpio_free(pn544_dev->irq_gpio); + gpio_free(pn544_dev->ven_gpio); + gpio_free(pn544_dev->ese_pwr_gpio); +#ifdef ISO_RST + gpio_free(pn544_dev->iso_rst_gpio); +#endif + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + + if (pn544_dev->firm_gpio) + gpio_free(pn544_dev->firm_gpio); + kfree(pn544_dev); + + return 0; +} + +static const struct i2c_device_id pn544_id[] = { +#if NEXUS5x + { "pn548", 0 }, +#else + { "pn544", 0 }, +#endif + { } +}; +#if DRAGON_NFC +static struct of_device_id pn544_i2c_dt_match[] = { + { +#if NEXUS5x + .compatible = "nxp,pn548", +#else + .compatible = "nxp,pn544", +#endif + }, + {} +}; +#endif +static struct i2c_driver pn544_driver = { + .id_table = pn544_id, + .probe = pn544_probe, + .remove = pn544_remove, + .driver = { + .owner = THIS_MODULE, +#if NEXUS5x + .name = "pn548", +#else + .name = "pn544", +#endif +#if DRAGON_NFC + .of_match_table = pn544_i2c_dt_match, +#endif + }, +}; + +/* + * module load/unload record keeping + */ + +static int __init pn544_dev_init(void) +{ + pr_info("Loading pn544 driver\n"); + return i2c_add_driver(&pn544_driver); +} +module_init(pn544_dev_init); + +static void __exit pn544_dev_exit(void) +{ + pr_info("Unloading pn544 driver\n"); + i2c_del_driver(&pn544_driver); +} +module_exit(pn544_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION("NFC PN544 driver"); +MODULE_LICENSE("GPL"); diff --git a/pn8xT/pn553-i2c/pn553.h b/pn8xT/pn553-i2c/pn553.h index 1fb3c5b041..96275e366f 100644 --- a/pn8xT/pn553-i2c/pn553.h +++ b/pn8xT/pn553-i2c/pn553.h @@ -118,10 +118,10 @@ typedef enum chip_type_pwr_scheme{ typedef enum jcop_dwnld_state{ JCP_DWNLD_IDLE = P61_STATE_JCP_DWNLD, /* jcop dwnld is ongoing*/ - JCP_DWNLD_INIT, /* jcop dwonload init state*/ - JCP_DWNLD_START, /* download started */ - JCP_SPI_DWNLD_COMPLETE, /* jcop download complete in spi interface*/ - JCP_DWP_DWNLD_COMPLETE, /* jcop download complete */ + JCP_DWNLD_INIT=0x8010, /* jcop dwonload init state*/ + JCP_DWNLD_START=0x8020, /* download started */ + JCP_SPI_DWNLD_COMPLETE=0x8040, /* jcop download complete in spi interface*/ + JCP_DWP_DWNLD_COMPLETE=0x8080, /* jcop download complete */ } jcop_dwnld_state_t; struct pn544_i2c_platform_data { diff --git a/pn8xT/pn553-i2c/pn553.o b/pn8xT/pn553-i2c/pn553.o index 0bd031f8aeca0f4ee8119aebd470545c115d2be0..b83943d093983fdd140f1709c9efbc400beb9038 100644 GIT binary patch delta 102 zcmaDbo#(-Ho((2qObkqu&BWZ87+5CPiK$63a7?&#pNZl1K}Lp<1wsx#8FL(dCNeN= wVGx+SPfU%8L16PUu``RLCNwbdFaW^&BWZ892h3oiK$5?Fif~~pNZl1K}Lp<1wsx#8FL(dCNeN= wX<(SVPfU%efnoDAu``RL8XK5+7=WM&N;gC4mWJjtJKN9fWZZscCzD7J0H!=3?f?J) From ed9c28bc44c78a3a52d3f4e1f2f5eacb238871af Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Wed, 12 Jul 2017 18:24:54 +0530 Subject: [PATCH 015/100] NFC_NCIHALx_AR1800.8.0.6_OpnSrc --- pn6xT/pn54x-i2c/pn54x.c~ | 1016 ------------------------------ pn8xT/pn553-i2c/pn553.c | 160 +++-- pn8xT/pn553-i2c/pn553.c~ | 1289 -------------------------------------- pn8xT/pn553-i2c/pn553.h | 5 +- 4 files changed, 119 insertions(+), 2351 deletions(-) delete mode 100644 pn6xT/pn54x-i2c/pn54x.c~ delete mode 100644 pn8xT/pn553-i2c/pn553.c~ diff --git a/pn6xT/pn54x-i2c/pn54x.c~ b/pn6xT/pn54x-i2c/pn54x.c~ deleted file mode 100644 index 805eb86b54..0000000000 --- a/pn6xT/pn54x-i2c/pn54x.c~ +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -/****************************************************************************** - * - * The original Work has been changed by NXP Semiconductors. - * - * Copyright (C) 2013-2014 NXP Semiconductors - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pn54x.h" - -#define NEXUS5x 0 -#define DRAGON_NFC 1 -#define SIG_NFC 44 -#define MAX_BUFFER_SIZE 512 - -struct pn544_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct i2c_client *client; - struct miscdevice pn544_device; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int irq_gpio; - unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ - struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ - p61_access_state_t p61_current_state; /* stores the current P61 state */ - bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ - bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ - bool irq_enabled; - spinlock_t irq_enabled_lock; - long nfc_service_pid; /*used to signal the nfc the nfc service */ -}; -static struct pn544_dev *pn544_dev; -static struct semaphore ese_access_sema; -static struct semaphore svdd_sync_onoff_sema; -static void release_ese_lock(p61_access_state_t p61_current_state); -int get_ese_lock(p61_access_state_t p61_current_state, int timeout); -static void pn544_disable_irq(struct pn544_dev *pn544_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); - if (pn544_dev->irq_enabled) { - disable_irq_nosync(pn544_dev->client->irq); - pn544_dev->irq_enabled = false; - } - spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); -} - -static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) -{ - struct pn544_dev *pn544_dev = dev_id; - - pn544_disable_irq(pn544_dev); - - /* Wake up waiting readers */ - wake_up(&pn544_dev->read_wq); - - return IRQ_HANDLED; -} - -static ssize_t pn544_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev = filp->private_data; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - pr_debug("%s : reading %zu bytes.\n", __func__, count); - - mutex_lock(&pn544_dev->read_mutex); - - if (!gpio_get_value(pn544_dev->irq_gpio)) { - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto fail; - } - - while (1) { - pn544_dev->irq_enabled = true; - enable_irq(pn544_dev->client->irq); - ret = wait_event_interruptible( - pn544_dev->read_wq, - !pn544_dev->irq_enabled); - - pn544_disable_irq(pn544_dev); - - if (ret) - goto fail; - - if (gpio_get_value(pn544_dev->irq_gpio)) - break; - - pr_warning("%s: spurious interrupt detected\n", __func__); - } - } - - /* Read data */ - ret = i2c_master_recv(pn544_dev->client, tmp, count); - - mutex_unlock(&pn544_dev->read_mutex); - - /* pn544 seems to be slow in handling I2C read requests - * so add 1ms delay after recv operation */ -#if !NEXUS5x - udelay(1000); -#endif - - if (ret < 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - return ret; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - return -EIO; - } - if (copy_to_user(buf, tmp, ret)) { - pr_warning("%s : failed to copy to user space\n", __func__); - return -EFAULT; - } - return ret; - - fail: - mutex_unlock(&pn544_dev->read_mutex); - return ret; -} - -static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - pn544_dev = filp->private_data; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - return -EFAULT; - } - - pr_debug("%s : writing %zu bytes.\n", __func__, count); - /* Write data */ - ret = i2c_master_send(pn544_dev->client, tmp, count); - if (ret != count) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - ret = -EIO; - } - - /* pn544 seems to be slow in handling I2C write requests - * so add 1ms delay after I2C send oparation */ - udelay(1000); - - return ret; -} - -static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) -{ - pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); - if (current_state) - { - if(set){ - if(pn544_dev->p61_current_state == P61_STATE_IDLE) - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->p61_current_state |= current_state; - } - else{ - pn544_dev->p61_current_state ^= current_state; - if(!pn544_dev->p61_current_state) - pn544_dev->p61_current_state = P61_STATE_IDLE; - } - } - pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); -} - -static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) -{ - - if (current_state == NULL) { - //*current_state = P61_STATE_INVALID; - pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); - } else { - *current_state = pn544_dev->p61_current_state; - } -} -static void p61_access_lock(struct pn544_dev *pn544_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_lock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} -static void p61_access_unlock(struct pn544_dev *pn544_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_unlock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} - -static int signal_handler(p61_access_state_t state, long nfc_pid) -{ - struct siginfo sinfo; - pid_t pid; - struct task_struct *task; - int sigret = 0; - int ret = 0; - pr_info("%s: Enter\n", __func__); - - memset(&sinfo, 0, sizeof(struct siginfo)); - sinfo.si_signo = SIG_NFC; - sinfo.si_code = SI_QUEUE; - sinfo.si_int = state; - pid = nfc_pid; - - task = pid_task(find_vpid(pid), PIDTYPE_PID); - if(task) - { - pr_info("%s.\n", task->comm); - sigret = force_sig_info(SIG_NFC, &sinfo, task); - if(sigret < 0){ - pr_info("send_sig_info failed..... sigret %d.\n", sigret); - ret = -1; - } - } - else - { - pr_info("finding task from PID failed\r\n"); - ret = -1; - } - pr_info("%s: Exit ret = %d\n", __func__, ret); - return ret; -} -static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) -{ - int timeout = 100; //100 ms timeout - unsigned long tempJ = msecs_to_jiffies(timeout); - pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); - if(nfc_service_pid) - { - if (0 == signal_handler(origin, nfc_service_pid)) - { - sema_init(&svdd_sync_onoff_sema, 0); - pr_info("Waiting for svdd protection response"); - if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) - { - pr_info("svdd wait protection: Timeout"); - } - pr_info("svdd wait protection : released"); - } - } - pr_info("%s: Exit\n", __func__); -} -static int release_svdd_wait(void) -{ - pr_info("%s: Enter \n", __func__); - up(&svdd_sync_onoff_sema); - pr_info("%s: Exit\n", __func__); - return 0; -} -static int pn544_dev_open(struct inode *inode, struct file *filp) -{ - struct pn544_dev *pn544_dev = container_of(filp->private_data, - struct pn544_dev, - pn544_device); - - filp->private_data = pn544_dev; - - pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); - - return 0; -} - -long pn544_dev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); - - if (cmd == P544_GET_ESE_ACCESS) - { - return get_ese_lock(P61_STATE_WIRED, arg); - } - else if(cmd == P544_REL_SVDD_WAIT) - { - return release_svdd_wait(); - } - p61_access_lock(pn544_dev); - switch (cmd) { - case PN544_SET_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 2) { - if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) - { - /* NFCC fw/download should not be allowed if p61 is used - * by SPI - */ - pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - pn544_dev->nfc_ven_enabled = true; - if (pn544_dev->spi_ven_enabled == false) - { - /* power on with firmware download (requires hw reset) - */ - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - } - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } else if (arg == 1) { - /* power on */ - pr_info("%s power on\n", __func__); - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = true; - if (pn544_dev->spi_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 1); - } - } else if (arg == 0) { - /* power off */ - pr_info("%s power off\n", __func__); - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = false; - /* Don't change Ven state if spi made it high */ - if (pn544_dev->spi_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 0); - } - } else { - pr_err("%s bad arg %lu\n", __func__, arg); - /* changed the p61 state to idle*/ - p61_access_unlock(pn544_dev); - return -EINVAL; - } - } - break; - case P61_SET_SPI_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) { - pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - /*To handle triple mode protection signal - NFC service when SPI session started*/ - if ((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) - { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } else { - pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); - if(current_state & P61_STATE_SPI_PRIO){ - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - if (!(current_state & P61_STATE_WIRED)) - { - if((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | - P61_STATE_SPI_PRIO_END); - } - else - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - else if ((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else - { - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - if(current_state & P61_STATE_JCOP_DWNLD) - p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); - pn544_dev->spi_ven_enabled = false; - if (pn544_dev->nfc_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - }else if(current_state & P61_STATE_SPI){ - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - if (!(current_state & P61_STATE_WIRED)) - { - if((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } - else - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - /*If JCOP3.2 or 3.3 for handling triple mode - protection signal NFC service */ - else - { - if ((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - } - if(current_state & P61_STATE_JCOP_DWNLD) - p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); - pn544_dev->spi_ven_enabled = false; - if (pn544_dev->nfc_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - } else { - pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - }else if (arg == 2) { - pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); - if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - if (pn544_dev->spi_ven_enabled == false) - { - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - msleep(10); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } else { - pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 3) { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); - //if (current_state & P61_STATE_WIRED) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - }else { - pr_info("%s : Prio Session Start power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 4) { - if (current_state & P61_STATE_SPI_PRIO) - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - /*after SPI prio timeout, the state is changing from SPI prio to SPI */ - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - //if (current_state & P61_STATE_WIRED) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - } - else - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Device or resource busy */ - } - } else if(arg == 5){ - release_ese_lock(P61_STATE_SPI); - } - else { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - - case P61_SET_PWR_STATUS: - { - pr_info("%s: P61_SET_PWR_STATUS = %lx",__func__, arg); - p61_update_access_state(pn544_dev, arg, true); - } - break; - case P61_GET_PWR_STATUS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); - put_user(current_state, (int __user *)arg); - } - break; - case P61_SET_WIRED_ACCESS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) - { - if (current_state) - { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); - if (current_state & P61_STATE_SPI_PRIO) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } - } else { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); - if (current_state & P61_STATE_WIRED){ - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); - } - } else { - pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - } - else if(arg == 2) - { - pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); - } - else if(arg == 3) - { - pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } - else if(arg == 4) - { - release_ese_lock(P61_STATE_WIRED); - } - else { - pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - case P544_SET_NFC_SERVICE_PID: - { - pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); - pn544_dev->nfc_service_pid = arg; - - } - break; - default: - pr_err("%s bad ioctl %u\n", __func__, cmd); - p61_access_unlock(pn544_dev); - return -EINVAL; - } - p61_access_unlock(pn544_dev); - pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); - return 0; -} -EXPORT_SYMBOL(pn544_dev_ioctl); - -int get_ese_lock(p61_access_state_t p61_current_state, int timeout) -{ - unsigned long tempJ = msecs_to_jiffies(timeout); - if(down_timeout(&ese_access_sema, tempJ) != 0) - { - printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); - return -EBUSY; - } - return 0; -} -EXPORT_SYMBOL(get_ese_lock); - -static void release_ese_lock(p61_access_state_t p61_current_state) -{ - up(&ese_access_sema); -} - - -static const struct file_operations pn544_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = pn544_dev_read, - .write = pn544_dev_write, - .open = pn544_dev_open, - .unlocked_ioctl = pn544_dev_ioctl, -}; -#if DRAGON_NFC -static int pn544_parse_dt(struct device *dev, - struct pn544_i2c_platform_data *data) -{ - struct device_node *np = dev->of_node; - int errorno = 0; - -#if !NEXUS5x - data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); - if ((!gpio_is_valid(data->irq_gpio))) - return -EINVAL; - - data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); - if ((!gpio_is_valid(data->ven_gpio))) - return -EINVAL; - - data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); - if ((!gpio_is_valid(data->firm_gpio))) - return -EINVAL; - - data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); - if ((!gpio_is_valid(data->ese_pwr_gpio))) - return -EINVAL; -#else - data->ven_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_ven", 0, NULL); - data->firm_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_mode", 0, NULL); - data->irq_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_irq", 0, NULL); -#endif - pr_info("%s: %d, %d, %d, %d %d\n", __func__, - data->irq_gpio, data->ven_gpio, data->firm_gpio, data->ese_pwr_gpio, errorno); - - return errorno; -} -#endif - -static int pn544_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - struct pn544_i2c_platform_data *platform_data; - //struct pn544_dev *pn544_dev; - -#if !DRAGON_NFC - platform_data = client->dev.platform_data; -#else - struct device_node *node = client->dev.of_node; - - if (node) { - platform_data = devm_kzalloc(&client->dev, - sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); - if (!platform_data) { - dev_err(&client->dev, - "nfc-nci probe: Failed to allocate memory\n"); - return -ENOMEM; - } - ret = pn544_parse_dt(&client->dev, platform_data); - if (ret) - { - pr_info("%s pn544_parse_dt failed", __func__); - } - client->irq = gpio_to_irq(platform_data->irq_gpio); - if (client->irq < 0) - { - pr_info("%s gpio to irq failed", __func__); - } - } else { - platform_data = client->dev.platform_data; - } -#endif - if (platform_data == NULL) { - pr_err("%s : nfc probe fail\n", __func__); - return -ENODEV; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - return -ENODEV; - } -#if !DRAGON_NFC - ret = gpio_request(platform_data->irq_gpio, "nfc_int"); - if (ret) - return -ENODEV; - ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); - if (ret) - goto err_ven; - ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); - if (ret) - goto err_ese_pwr; - if (platform_data->firm_gpio) { - ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); - if (ret) - goto err_firm; - } -#endif - pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); - if (pn544_dev == NULL) { - dev_err(&client->dev, - "failed to allocate memory for module data\n"); - ret = -ENOMEM; - goto err_exit; - } - - pn544_dev->irq_gpio = platform_data->irq_gpio; - pn544_dev->ven_gpio = platform_data->ven_gpio; - pn544_dev->firm_gpio = platform_data->firm_gpio; - pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; - pn544_dev->p61_current_state = P61_STATE_IDLE; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - pn544_dev->client = client; - - ret = gpio_direction_input(pn544_dev->irq_gpio); - if (ret < 0) { - pr_err("%s :not able to set irq_gpio as input\n", __func__); - goto err_ven; - } - ret = gpio_direction_output(pn544_dev->ven_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_firm; - } - ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); - goto err_ese_pwr; - } - if (platform_data->firm_gpio) { - ret = gpio_direction_output(pn544_dev->firm_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set firm_gpio as output\n", - __func__); - goto err_exit; - } - } - - /* init mutex and queues */ - init_waitqueue_head(&pn544_dev->read_wq); - mutex_init(&pn544_dev->read_mutex); - sema_init(&ese_access_sema, 1); - mutex_init(&pn544_dev->p61_state_mutex); - spin_lock_init(&pn544_dev->irq_enabled_lock); - - pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; - pn544_dev->pn544_device.name = "pn54x"; - pn544_dev->pn544_device.fops = &pn544_dev_fops; - - ret = misc_register(&pn544_dev->pn544_device); - if (ret) { - pr_err("%s : misc_register failed\n", __FILE__); - goto err_misc_register; - } - - /* request irq. the irq is set whenever the chip has data available - * for reading. it is cleared when all data has been read. - */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - pn544_dev->irq_enabled = true; - ret = request_irq(client->irq, pn544_dev_irq_handler, - IRQF_TRIGGER_HIGH, client->name, pn544_dev); - if (ret) { - dev_err(&client->dev, "request_irq failed\n"); - goto err_request_irq_failed; - } - pn544_disable_irq(pn544_dev); - i2c_set_clientdata(client, pn544_dev); - - return 0; - - err_request_irq_failed: - misc_deregister(&pn544_dev->pn544_device); - err_misc_register: - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - kfree(pn544_dev); - err_exit: - if (pn544_dev->firm_gpio) - gpio_free(platform_data->firm_gpio); - err_firm: - gpio_free(platform_data->ese_pwr_gpio); - err_ese_pwr: - gpio_free(platform_data->ven_gpio); - err_ven: - gpio_free(platform_data->irq_gpio); - return ret; -} - -static int pn544_remove(struct i2c_client *client) -{ - struct pn544_dev *pn544_dev; - - pn544_dev = i2c_get_clientdata(client); - free_irq(client->irq, pn544_dev); - misc_deregister(&pn544_dev->pn544_device); - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - gpio_free(pn544_dev->irq_gpio); - gpio_free(pn544_dev->ven_gpio); - gpio_free(pn544_dev->ese_pwr_gpio); - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - - if (pn544_dev->firm_gpio) - gpio_free(pn544_dev->firm_gpio); - kfree(pn544_dev); - - return 0; -} - -static const struct i2c_device_id pn544_id[] = { -#if NEXUS5x - { "pn548", 0 }, -#else - { "pn544", 0 }, -#endif - { } -}; -#if DRAGON_NFC -static struct of_device_id pn544_i2c_dt_match[] = { - { -#if NEXUS5x - .compatible = "nxp,pn548", -#else - .compatible = "nxp,pn544", -#endif - }, - {} -}; -#endif -static struct i2c_driver pn544_driver = { - .id_table = pn544_id, - .probe = pn544_probe, - .remove = pn544_remove, - .driver = { - .owner = THIS_MODULE, -#if NEXUS5x - .name = "pn548", -#else - .name = "pn544", -#endif -#if DRAGON_NFC - .of_match_table = pn544_i2c_dt_match, -#endif - }, -}; - -/* - * module load/unload record keeping - */ - -static int __init pn544_dev_init(void) -{ - pr_info("Loading pn544 driver\n"); - return i2c_add_driver(&pn544_driver); -} -module_init(pn544_dev_init); - -static void __exit pn544_dev_exit(void) -{ - pr_info("Unloading pn544 driver\n"); - i2c_del_driver(&pn544_driver); -} -module_exit(pn544_dev_exit); - -MODULE_AUTHOR("Sylvain Fonteneau"); -MODULE_DESCRIPTION("NFC PN544 driver"); -MODULE_LICENSE("GPL"); diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c index 309b6e1e51..380f44ee57 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn8xT/pn553-i2c/pn553.c @@ -60,7 +60,13 @@ #include #include #include +/* HiKey Compilation fix */ +#define HiKey_620_COMPILATION_FIX 1 +#ifndef HiKey_620_COMPILATION_FIX #include +#endif + +#include #include "pn553.h" #define NEXUS5x 0 @@ -73,6 +79,8 @@ #define SIG_NFC 44 #define MAX_BUFFER_SIZE 512 #define MAX_SECURE_SESSIONS 1 +/* Macro added to disable SVDD power toggling */ +/* #define JCOP_4X_VALIDATION */ struct pn544_dev { wait_queue_head_t read_wq; @@ -96,14 +104,21 @@ struct pn544_dev { chip_pwr_scheme_t chip_pwr_scheme; unsigned int secure_timer_cnt; }; +/* HiKey Compilation fix */ +#ifndef HiKey_620_COMPILATION_FIX struct wake_lock nfc_wake_lock; static bool sIsWakeLocked = false; +#endif static struct pn544_dev *pn544_dev; static struct semaphore ese_access_sema; static struct semaphore svdd_sync_onoff_sema; +static struct timer_list secure_timer; static void release_ese_lock(p61_access_state_t p61_current_state); int get_ese_lock(p61_access_state_t p61_current_state, int timeout); static long set_jcop_download_state(unsigned long arg); +static long start_seccure_timer(unsigned long timer_value); +static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg); + static void pn544_disable_irq(struct pn544_dev *pn544_dev) { unsigned long flags; @@ -122,6 +137,8 @@ static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) struct pn544_dev *pn544_dev = dev_id; pn544_disable_irq(pn544_dev); + /* HiKey Compilation fix */ + #ifndef HiKey_620_COMPILATION_FIX if (sIsWakeLocked == false) { wake_lock(&nfc_wake_lock); @@ -129,6 +146,7 @@ static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) } else { pr_debug("%s already wake locked!\n", __func__); } + #endif /* Wake up waiting readers */ wake_up(&pn544_dev->read_wq); @@ -178,10 +196,13 @@ static ssize_t pn544_dev_read(struct file *filp, char __user *buf, /* Read data */ ret = i2c_master_recv(pn544_dev->client, tmp, count); + #ifndef HiKey_620_COMPILATION_FIX + /* HiKey Compilation fix */ if (sIsWakeLocked == true) { wake_unlock(&nfc_wake_lock); sIsWakeLocked = false; } + #endif mutex_unlock(&pn544_dev->read_mutex); /* pn544 seems to be slow in handling I2C read requests @@ -444,10 +465,13 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { gpio_set_value(pn544_dev->ven_gpio, 0); } + /* HiKey Compilation fix */ + #ifndef HiKey_620_COMPILATION_FIX if (sIsWakeLocked == true) { wake_unlock(&nfc_wake_lock); sIsWakeLocked = false; } + #endif } else if (arg == 3) { /*NFC Service called ISO-RST*/ p61_access_state_t current_state = P61_STATE_INVALID; @@ -542,14 +566,17 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) { +#ifndef JCOP_4X_VALIDATION gpio_set_value(pn544_dev->ese_pwr_gpio, 0); +#endif svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); } - +#ifndef JCOP_4X_VALIDATION if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { gpio_set_value(pn544_dev->ven_gpio, 0); msleep(10); } +#endif }else if(current_state & P61_STATE_SPI){ p61_update_access_state(pn544_dev, P61_STATE_SPI, false); if (!(current_state & P61_STATE_WIRED) && @@ -564,7 +591,9 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); } if (!(pn544_dev->secure_timer_cnt)) { +#ifndef JCOP_4X_VALIDATION gpio_set_value(pn544_dev->ese_pwr_gpio, 0); +#endif svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); } } @@ -591,7 +620,9 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) { +#ifndef JCOP_4X_VALIDATION gpio_set_value(pn544_dev->ese_pwr_gpio, 0); +#endif svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); } @@ -623,10 +654,13 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) { svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); +#ifndef JCOP_4X_VALIDATION gpio_set_value(pn544_dev->ese_pwr_gpio, 0); +#endif svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); msleep(10); - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + if(!gpio_get_value(pn544_dev->ese_pwr_gpio)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); msleep(10); } } else { @@ -842,49 +876,7 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, break; case P544_SECURE_TIMER_SESSION: { - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - if(arg == 1) - { - if(pn544_dev->secure_timer_cnt < MAX_SECURE_SESSIONS) - { - pn544_dev->secure_timer_cnt++; - pr_info("%s : eSE secure timer session start : count = %d,\n", - __func__, pn544_dev->secure_timer_cnt); - if (pn544_dev->spi_ven_enabled == false) - { - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } - } else if(arg == 0){ - if(pn544_dev->secure_timer_cnt > 0) - { - pn544_dev->secure_timer_cnt--; - pr_info("%s : eSE secure timer session stop : count = %d,\n", - __func__, pn544_dev->secure_timer_cnt); - if((pn544_dev->secure_timer_cnt == 0) && (pn544_dev->spi_ven_enabled == false)) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - if(pn544_dev->nfc_ven_enabled == false) - { - /* Turn off GPIO as none of the interfaces are active */ - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - } - } - } - } - else - { - pr_info("%s :Secure timer session not applicable \n", __func__); - } + secure_timer_operation(pn544_dev, arg); } break; default: @@ -898,6 +890,80 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } EXPORT_SYMBOL(pn544_dev_ioctl); +static void secure_timer_callback( unsigned long data ) +{ + p61_access_state_t current_state = P61_STATE_INVALID; + printk( KERN_INFO "secure_timer_callback: called (%lu).\n", jiffies); + + p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); + p61_get_access_state(pn544_dev, ¤t_state); + + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + printk( KERN_INFO "secure_timer_callback: make se_pwer_gpio low, state = %d", current_state); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + if(pn544_dev->nfc_service_pid == 0x00) + { + gpio_set_value(pn544_dev->ven_gpio, 0); + printk( KERN_INFO "secure_timer_callback :make ven_gpio low, state = %d", current_state); + } + } + pn544_dev->secure_timer_cnt = 0; +} + +static long start_seccure_timer(unsigned long timer_value) +{ + long ret = -EINVAL; + pr_info("start_seccure_timer: enter\n"); + /* Delete the timer if timer pending */ + if(timer_pending(&secure_timer) == 1) + { + pr_info("start_seccure_timer: delete pending timer \n"); + /* delete timer if already pending */ + del_timer(&secure_timer); + } + /* Start the timer if timer value is non-zero */ + if(timer_value) + { + init_timer(&secure_timer); + setup_timer( &secure_timer, secure_timer_callback, 0 ); + + pr_info("start_seccure_timer: timeout %lums (%lu)\n",timer_value, jiffies ); + ret = mod_timer( &secure_timer, jiffies + msecs_to_jiffies(timer_value)); + if (ret) + pr_info("start_seccure_timer: Error in mod_timer\n"); + } + return ret; +} + +static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg) +{ + long ret = -EINVAL; + unsigned long timer_value = arg; + + printk( KERN_INFO "secure_timer_operation, %d\n",pn544_dev->chip_pwr_scheme); + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + ret = start_seccure_timer(timer_value); + if(!ret) + { + pn544_dev->secure_timer_cnt = 1; + p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, true); + } + else + { + pn544_dev->secure_timer_cnt = 0; + p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); + pr_info("%s :Secure timer reset \n", __func__); + } + } + else + { + pr_info("%s :Secure timer session not applicable \n", __func__); + } + return ret; +} + static long set_jcop_download_state(unsigned long arg) { p61_access_state_t current_state = P61_STATE_INVALID; @@ -1159,7 +1225,10 @@ static int pn544_probe(struct i2c_client *client, pr_err("%s : misc_register failed\n", __FILE__); goto err_misc_register; } + /* HiKey Compilation fix */ + #ifndef HiKey_620_COMPILATION_FIX wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); + #endif #ifdef ISO_RST /* Setting ISO RESET pin high to power ESE during init */ gpio_set_value(pn544_dev->iso_rst_gpio, 1); @@ -1179,6 +1248,7 @@ static int pn544_probe(struct i2c_client *client, pn544_disable_irq(pn544_dev); i2c_set_clientdata(client, pn544_dev); + return 0; err_request_irq_failed: diff --git a/pn8xT/pn553-i2c/pn553.c~ b/pn8xT/pn553-i2c/pn553.c~ deleted file mode 100644 index 309b6e1e51..0000000000 --- a/pn8xT/pn553-i2c/pn553.c~ +++ /dev/null @@ -1,1289 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -/****************************************************************************** - * - * The original Work has been changed by NXP Semiconductors. - * - * Copyright (C) 2013-2014 NXP Semiconductors - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pn553.h" - -#define NEXUS5x 0 -#if NEXUS5x -#undef ISO_RST -#else -#define ISO_RST -#endif -#define DRAGON_NFC 1 -#define SIG_NFC 44 -#define MAX_BUFFER_SIZE 512 -#define MAX_SECURE_SESSIONS 1 - -struct pn544_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct i2c_client *client; - struct miscdevice pn544_device; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int irq_gpio; - unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ -#ifdef ISO_RST - unsigned int iso_rst_gpio; /* ISO-RST pin gpio*/ -#endif - struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ - p61_access_state_t p61_current_state; /* stores the current P61 state */ - bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ - bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ - bool irq_enabled; - spinlock_t irq_enabled_lock; - long nfc_service_pid; /*used to signal the nfc the nfc service */ - chip_pwr_scheme_t chip_pwr_scheme; - unsigned int secure_timer_cnt; -}; -struct wake_lock nfc_wake_lock; -static bool sIsWakeLocked = false; -static struct pn544_dev *pn544_dev; -static struct semaphore ese_access_sema; -static struct semaphore svdd_sync_onoff_sema; -static void release_ese_lock(p61_access_state_t p61_current_state); -int get_ese_lock(p61_access_state_t p61_current_state, int timeout); -static long set_jcop_download_state(unsigned long arg); -static void pn544_disable_irq(struct pn544_dev *pn544_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); - if (pn544_dev->irq_enabled) { - disable_irq_nosync(pn544_dev->client->irq); - disable_irq_wake(pn544_dev->client->irq); - pn544_dev->irq_enabled = false; - } - spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); -} - -static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) -{ - struct pn544_dev *pn544_dev = dev_id; - - pn544_disable_irq(pn544_dev); - if (sIsWakeLocked == false) - { - wake_lock(&nfc_wake_lock); - sIsWakeLocked = true; - } else { - pr_debug("%s already wake locked!\n", __func__); - } - /* Wake up waiting readers */ - wake_up(&pn544_dev->read_wq); - - - return IRQ_HANDLED; -} - -static ssize_t pn544_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev = filp->private_data; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - pr_debug("%s : reading %zu bytes.\n", __func__, count); - - mutex_lock(&pn544_dev->read_mutex); - - if (!gpio_get_value(pn544_dev->irq_gpio)) { - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto fail; - } - - while (1) { - pn544_dev->irq_enabled = true; - enable_irq(pn544_dev->client->irq); - enable_irq_wake(pn544_dev->client->irq); - ret = wait_event_interruptible( - pn544_dev->read_wq, - !pn544_dev->irq_enabled); - - pn544_disable_irq(pn544_dev); - - if (ret) - goto fail; - - if (gpio_get_value(pn544_dev->irq_gpio)) - break; - - pr_warning("%s: spurious interrupt detected\n", __func__); - } - } - - /* Read data */ - ret = i2c_master_recv(pn544_dev->client, tmp, count); - if (sIsWakeLocked == true) { - wake_unlock(&nfc_wake_lock); - sIsWakeLocked = false; - } - mutex_unlock(&pn544_dev->read_mutex); - - /* pn544 seems to be slow in handling I2C read requests - * so add 1ms delay after recv operation */ -#if !NEXUS5x - udelay(1000); -#endif - - if (ret < 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - return ret; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - return -EIO; - } - if (copy_to_user(buf, tmp, ret)) { - pr_warning("%s : failed to copy to user space\n", __func__); - return -EFAULT; - } - return ret; - - fail: - mutex_unlock(&pn544_dev->read_mutex); - return ret; -} - -static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - pn544_dev = filp->private_data; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - return -EFAULT; - } - - pr_debug("%s : writing %zu bytes.\n", __func__, count); - /* Write data */ - ret = i2c_master_send(pn544_dev->client, tmp, count); - if (ret != count) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - ret = -EIO; - } - - /* pn544 seems to be slow in handling I2C write requests - * so add 1ms delay after I2C send oparation */ - udelay(1000); - - return ret; -} - -static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) -{ - pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); - if (current_state) - { - if(set){ - if(pn544_dev->p61_current_state == P61_STATE_IDLE) - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->p61_current_state |= current_state; - } - else{ - pn544_dev->p61_current_state ^= current_state; - if(!pn544_dev->p61_current_state) - pn544_dev->p61_current_state = P61_STATE_IDLE; - } - } - pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); -} - -static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) -{ - - if (current_state == NULL) { - //*current_state = P61_STATE_INVALID; - pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); - } else { - *current_state = pn544_dev->p61_current_state; - } -} -static void p61_access_lock(struct pn544_dev *pn544_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_lock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} -static void p61_access_unlock(struct pn544_dev *pn544_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_unlock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} - -static int signal_handler(p61_access_state_t state, long nfc_pid) -{ - struct siginfo sinfo; - pid_t pid; - struct task_struct *task; - int sigret = 0, ret = 0; - pr_info("%s: Enter\n", __func__); - - if(nfc_pid == 0) - { - pr_info("nfc_pid is clear don't call signal_handler.\n"); - } - else - { - memset(&sinfo, 0, sizeof(struct siginfo)); - sinfo.si_signo = SIG_NFC; - sinfo.si_code = SI_QUEUE; - sinfo.si_int = state; - pid = nfc_pid; - - task = pid_task(find_vpid(pid), PIDTYPE_PID); - if(task) - { - pr_info("%s.\n", task->comm); - sigret = force_sig_info(SIG_NFC, &sinfo, task); - if(sigret < 0){ - pr_info("send_sig_info failed..... sigret %d.\n", sigret); - ret = -1; - //msleep(60); - } - } - else{ - pr_info("finding task from PID failed\r\n"); - ret = -1; - } - } - pr_info("%s: Exit ret = %d\n", __func__, ret); - return ret; -} -static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) -{ - int timeout = 100; //100 ms timeout - unsigned long tempJ = msecs_to_jiffies(timeout); - pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); - if(nfc_service_pid) - { - if (0 == signal_handler(origin, nfc_service_pid)) - { - sema_init(&svdd_sync_onoff_sema, 0); - pr_info("Waiting for svdd protection response"); - if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) - { - pr_info("svdd wait protection: Timeout"); - } - pr_info("svdd wait protection : released"); - } - } - pr_info("%s: Exit\n", __func__); -} -static int release_svdd_wait(void) -{ - pr_info("%s: Enter \n", __func__); - up(&svdd_sync_onoff_sema); - pr_info("%s: Exit\n", __func__); - return 0; -} -static int pn544_dev_open(struct inode *inode, struct file *filp) -{ - struct pn544_dev *pn544_dev = container_of(filp->private_data, - struct pn544_dev, - pn544_device); - - filp->private_data = pn544_dev; - - pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); - - return 0; -} - -long pn544_dev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); - - if (cmd == P544_GET_ESE_ACCESS) - { - return get_ese_lock(P61_STATE_WIRED, arg); - } - else if(cmd == P544_REL_SVDD_WAIT) - { - return release_svdd_wait(); - } - p61_access_lock(pn544_dev); - switch (cmd) { - case PN544_SET_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 2) { - if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) - { - /* NFCC fw/download should not be allowed if p61 is used - * by SPI - */ - pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - pn544_dev->nfc_ven_enabled = true; - if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) - || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) - { - /* power on with firmware download (requires hw reset) - */ - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - } - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } else if (arg == 1) { - /* power on */ - pr_info("%s power on\n", __func__); - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - if(current_state & P61_STATE_DWNLD){ - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, false); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = true; - if (pn544_dev->spi_ven_enabled == false || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { - gpio_set_value(pn544_dev->ven_gpio, 1); - } - } else if (arg == 0) { - /* power off */ - pr_info("%s power off\n", __func__); - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = false; - /* Don't change Ven state if spi made it high */ - if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) - || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - } - if (sIsWakeLocked == true) { - wake_unlock(&nfc_wake_lock); - sIsWakeLocked = false; - } - } else if (arg == 3) { - /*NFC Service called ISO-RST*/ - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - if(current_state & P61_STATE_WIRED) { - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - } -#ifdef ISO_RST - gpio_set_value(pn544_dev->iso_rst_gpio, 0); - msleep(50); - gpio_set_value(pn544_dev->iso_rst_gpio, 1); - msleep(50); - pr_info("%s ISO RESET from DWP DONE\n", __func__); -#endif - } - else { - pr_err("%s bad arg %lu\n", __func__, arg); - /* changed the p61 state to idle*/ - p61_access_unlock(pn544_dev); - return -EINVAL; - } - } - break; - case P61_SET_SPI_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) { - pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - /*To handle triple mode protection signal - NFC service when SPI session started*/ - if (!(current_state & P61_STATE_JCP_DWNLD)){ - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - - if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) - break; - - if (pn544_dev->nfc_ven_enabled == false) - { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } else { - pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); - if(current_state & P61_STATE_SPI_PRIO){ - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - if (!(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - if(!(current_state & P61_STATE_WIRED)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | - P61_STATE_SPI_PRIO_END); - }else { - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } else if (!(current_state & P61_STATE_WIRED)) { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - pn544_dev->spi_ven_enabled = false; - - if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) - break; - - if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - - if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - }else if(current_state & P61_STATE_SPI){ - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - if (!(current_state & P61_STATE_WIRED) && - (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) && - !(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - if (!(pn544_dev->secure_timer_cnt)) { - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } - /*If JCOP3.2 or 3.3 for handling triple mode - protection signal NFC service */ - else - { - if (!(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } else { - signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); - } - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } else if (pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); - } - } - pn544_dev->spi_ven_enabled = false; - if (pn544_dev->nfc_ven_enabled == false && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) - && !(pn544_dev->secure_timer_cnt)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - } else { - pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - }else if (arg == 2) { - pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); - if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - if (pn544_dev->spi_ven_enabled == false) - { - pn544_dev->spi_ven_enabled = true; - if ((pn544_dev->nfc_ven_enabled == false) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } - if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - msleep(10); - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } - } else { - pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 3) { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); - if (current_state & P61_STATE_WIRED){ - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) - { - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } - }else { - pr_info("%s : Prio Session Start power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 4) { - if (current_state & P61_STATE_SPI_PRIO) - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - /*after SPI prio timeout, the state is changing from SPI prio to SPI */ - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - if (current_state & P61_STATE_WIRED) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - } - else - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Device or resource busy */ - } - } else if(arg == 5){ - release_ese_lock(P61_STATE_SPI); - } else if (arg == 6) { - /*SPI Service called ISO-RST*/ - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if(current_state & P61_STATE_WIRED) { - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - if(current_state & P61_STATE_SPI) { - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - }else if(current_state & P61_STATE_SPI_PRIO) { - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - } -#ifdef ISO_RST - gpio_set_value(pn544_dev->iso_rst_gpio, 0); - msleep(50); - gpio_set_value(pn544_dev->iso_rst_gpio, 1); - msleep(50); - pr_info("%s ISO RESET from SPI DONE\n", __func__); -#endif - } - else { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - - case P61_GET_PWR_STATUS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); - put_user(current_state, (int __user *)arg); - } - break; - - case PN544_SET_DWNLD_STATUS: - { - long ret; - ret = set_jcop_download_state(arg); - if(ret < 0) - { - p61_access_unlock(pn544_dev); - return ret; - } - } - break; - - case P61_SET_WIRED_ACCESS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) - { - if (current_state) - { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); - if (current_state & P61_STATE_SPI_PRIO) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } else { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); - if (current_state & P61_STATE_WIRED){ - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } else { - pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - } - else if(arg == 2) - { - pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); - if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } - else if(arg == 3) - { - pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); - if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } - else if(arg == 4) - { - release_ese_lock(P61_STATE_WIRED); - } - else { - pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - case P544_SET_NFC_SERVICE_PID: - { - pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); - pn544_dev->nfc_service_pid = arg; - - } - break; - case P544_SET_POWER_SCHEME: - { - if(arg == PN67T_PWR_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; - pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); - } - else if(arg == PN80T_LEGACY_PWR_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; - pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); - } - else if(arg == PN80T_EXT_PMU_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; - pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); - } - else - { - pr_info("%s : The power scheme is invalid,\n", __func__); - } - } - break; - case P544_SECURE_TIMER_SESSION: - { - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - if(arg == 1) - { - if(pn544_dev->secure_timer_cnt < MAX_SECURE_SESSIONS) - { - pn544_dev->secure_timer_cnt++; - pr_info("%s : eSE secure timer session start : count = %d,\n", - __func__, pn544_dev->secure_timer_cnt); - if (pn544_dev->spi_ven_enabled == false) - { - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } - } else if(arg == 0){ - if(pn544_dev->secure_timer_cnt > 0) - { - pn544_dev->secure_timer_cnt--; - pr_info("%s : eSE secure timer session stop : count = %d,\n", - __func__, pn544_dev->secure_timer_cnt); - if((pn544_dev->secure_timer_cnt == 0) && (pn544_dev->spi_ven_enabled == false)) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - if(pn544_dev->nfc_ven_enabled == false) - { - /* Turn off GPIO as none of the interfaces are active */ - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - } - } - } - } - else - { - pr_info("%s :Secure timer session not applicable \n", __func__); - } - } - break; - default: - pr_err("%s bad ioctl %u\n", __func__, cmd); - p61_access_unlock(pn544_dev); - return -EINVAL; - } - p61_access_unlock(pn544_dev); - pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); - return 0; -} -EXPORT_SYMBOL(pn544_dev_ioctl); - -static long set_jcop_download_state(unsigned long arg) -{ - p61_access_state_t current_state = P61_STATE_INVALID; - long ret = 0; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s:Enter PN544_SET_DWNLD_STATUS:JCOP Dwnld state arg = %ld",__func__, arg); - if(arg == JCP_DWNLD_INIT) - { - if(pn544_dev->nfc_service_pid) - { - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(JCP_DWNLD_INIT, pn544_dev->nfc_service_pid); - } - else - { - if (current_state & P61_STATE_JCP_DWNLD) - { - ret = -EINVAL; - } - else - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); - } - } - } - else if (arg == JCP_DWNLD_START) - { - if (current_state & P61_STATE_JCP_DWNLD) - { - ret = -EINVAL; - } - else - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); - } - } - else if (arg == JCP_SPI_DWNLD_COMPLETE) - { - if(pn544_dev->nfc_service_pid) - { - signal_handler(JCP_DWP_DWNLD_COMPLETE, pn544_dev->nfc_service_pid); - } - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); - } - else if (arg == JCP_DWP_DWNLD_COMPLETE) - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); - } - else - { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - pr_info("%s: PN544_SET_DWNLD_STATUS = %x",__func__, current_state); - - return ret; -} - -int get_ese_lock(p61_access_state_t p61_current_state, int timeout) -{ - unsigned long tempJ = msecs_to_jiffies(timeout); - if(down_timeout(&ese_access_sema, tempJ) != 0) - { - printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); - return -EBUSY; - } - return 0; -} -EXPORT_SYMBOL(get_ese_lock); - -static void release_ese_lock(p61_access_state_t p61_current_state) -{ - up(&ese_access_sema); -} - - -static const struct file_operations pn544_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = pn544_dev_read, - .write = pn544_dev_write, - .open = pn544_dev_open, - .unlocked_ioctl = pn544_dev_ioctl, -}; -#if DRAGON_NFC -static int pn544_parse_dt(struct device *dev, - struct pn544_i2c_platform_data *data) -{ - struct device_node *np = dev->of_node; - int errorno = 0; - -#if !NEXUS5x - data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); - if ((!gpio_is_valid(data->irq_gpio))) - return -EINVAL; - - data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); - if ((!gpio_is_valid(data->ven_gpio))) - return -EINVAL; - - data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); - if ((!gpio_is_valid(data->firm_gpio))) - return -EINVAL; - - data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); - if ((!gpio_is_valid(data->ese_pwr_gpio))) - return -EINVAL; - data->iso_rst_gpio = of_get_named_gpio(np, "nxp,pn544-iso-pwr-rst", 0); - if ((!gpio_is_valid(data->iso_rst_gpio))) - return -EINVAL; -#else - data->ven_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_ven", 0, NULL); - data->firm_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_mode", 0, NULL); - data->irq_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_irq", 0, NULL); -#endif - pr_info("%s: %d, %d, %d, %d, %d error:%d\n", __func__, - data->irq_gpio, data->ven_gpio, data->firm_gpio, data->iso_rst_gpio, - data->ese_pwr_gpio, errorno); - - return errorno; -} -#endif - -static int pn544_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - struct pn544_i2c_platform_data *platform_data; - //struct pn544_dev *pn544_dev; - -#if !DRAGON_NFC - platform_data = client->dev.platform_data; -#else - struct device_node *node = client->dev.of_node; - - if (node) { - platform_data = devm_kzalloc(&client->dev, - sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); - if (!platform_data) { - dev_err(&client->dev, - "nfc-nci probe: Failed to allocate memory\n"); - return -ENOMEM; - } - ret = pn544_parse_dt(&client->dev, platform_data); - if (ret) - { - pr_info("%s pn544_parse_dt failed", __func__); - } - client->irq = gpio_to_irq(platform_data->irq_gpio); - if (client->irq < 0) - { - pr_info("%s gpio to irq failed", __func__); - } - } else { - platform_data = client->dev.platform_data; - } -#endif - if (platform_data == NULL) { - pr_err("%s : nfc probe fail\n", __func__); - return -ENODEV; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - return -ENODEV; - } -#if !DRAGON_NFC - ret = gpio_request(platform_data->irq_gpio, "nfc_int"); - if (ret) - return -ENODEV; - ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); - if (ret) - goto err_ven; - ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); - if (ret) - goto err_ese_pwr; - if (platform_data->firm_gpio) { - ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); - if (ret) - goto err_firm; - } -#ifdef ISO_RST - if(platform_data->iso_rst_gpio) { - ret = gpio_request(platform_data->iso_rst_gpio, "nfc_iso_rst"); - if (ret) - goto err_iso_rst; - } -#endif -#endif - pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); - if (pn544_dev == NULL) { - dev_err(&client->dev, - "failed to allocate memory for module data\n"); - ret = -ENOMEM; - goto err_exit; - } - - pn544_dev->irq_gpio = platform_data->irq_gpio; - pn544_dev->ven_gpio = platform_data->ven_gpio; - pn544_dev->firm_gpio = platform_data->firm_gpio; - pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; -#ifdef ISO_RST - pn544_dev->iso_rst_gpio = platform_data->iso_rst_gpio; -#endif - pn544_dev->p61_current_state = P61_STATE_IDLE; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; - pn544_dev->client = client; - pn544_dev->secure_timer_cnt = 0; - - ret = gpio_direction_input(pn544_dev->irq_gpio); - if (ret < 0) { - pr_err("%s :not able to set irq_gpio as input\n", __func__); - goto err_ven; - } - ret = gpio_direction_output(pn544_dev->ven_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_firm; - } - ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); - goto err_ese_pwr; - } - if (platform_data->firm_gpio) { - ret = gpio_direction_output(pn544_dev->firm_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set firm_gpio as output\n", - __func__); - goto err_exit; - } - } -#ifdef ISO_RST - ret = gpio_direction_output(pn544_dev->iso_rst_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set iso rst gpio as output\n", __func__); - goto err_iso_rst; - } -#endif - /* init mutex and queues */ - init_waitqueue_head(&pn544_dev->read_wq); - mutex_init(&pn544_dev->read_mutex); - sema_init(&ese_access_sema, 1); - mutex_init(&pn544_dev->p61_state_mutex); - spin_lock_init(&pn544_dev->irq_enabled_lock); - - pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; - pn544_dev->pn544_device.name = "pn553"; - pn544_dev->pn544_device.fops = &pn544_dev_fops; - - ret = misc_register(&pn544_dev->pn544_device); - if (ret) { - pr_err("%s : misc_register failed\n", __FILE__); - goto err_misc_register; - } - wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); -#ifdef ISO_RST - /* Setting ISO RESET pin high to power ESE during init */ - gpio_set_value(pn544_dev->iso_rst_gpio, 1); -#endif - /* request irq. the irq is set whenever the chip has data available - * for reading. it is cleared when all data has been read. - */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - pn544_dev->irq_enabled = true; - ret = request_irq(client->irq, pn544_dev_irq_handler, - IRQF_TRIGGER_HIGH, client->name, pn544_dev); - if (ret) { - dev_err(&client->dev, "request_irq failed\n"); - goto err_request_irq_failed; - } - enable_irq_wake(pn544_dev->client->irq); - pn544_disable_irq(pn544_dev); - i2c_set_clientdata(client, pn544_dev); - - return 0; - - err_request_irq_failed: - misc_deregister(&pn544_dev->pn544_device); - err_misc_register: - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - kfree(pn544_dev); - err_exit: - if (pn544_dev->firm_gpio) - gpio_free(platform_data->firm_gpio); - err_firm: - gpio_free(platform_data->ese_pwr_gpio); - err_ese_pwr: - gpio_free(platform_data->ven_gpio); - err_ven: - gpio_free(platform_data->irq_gpio); -#ifdef ISO_RST - err_iso_rst: - gpio_free(platform_data->iso_rst_gpio); -#endif - return ret; -} - -static int pn544_remove(struct i2c_client *client) -{ - struct pn544_dev *pn544_dev; - - pn544_dev = i2c_get_clientdata(client); - free_irq(client->irq, pn544_dev); - misc_deregister(&pn544_dev->pn544_device); - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - gpio_free(pn544_dev->irq_gpio); - gpio_free(pn544_dev->ven_gpio); - gpio_free(pn544_dev->ese_pwr_gpio); -#ifdef ISO_RST - gpio_free(pn544_dev->iso_rst_gpio); -#endif - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - - if (pn544_dev->firm_gpio) - gpio_free(pn544_dev->firm_gpio); - kfree(pn544_dev); - - return 0; -} - -static const struct i2c_device_id pn544_id[] = { -#if NEXUS5x - { "pn548", 0 }, -#else - { "pn544", 0 }, -#endif - { } -}; -#if DRAGON_NFC -static struct of_device_id pn544_i2c_dt_match[] = { - { -#if NEXUS5x - .compatible = "nxp,pn548", -#else - .compatible = "nxp,pn544", -#endif - }, - {} -}; -#endif -static struct i2c_driver pn544_driver = { - .id_table = pn544_id, - .probe = pn544_probe, - .remove = pn544_remove, - .driver = { - .owner = THIS_MODULE, -#if NEXUS5x - .name = "pn548", -#else - .name = "pn544", -#endif -#if DRAGON_NFC - .of_match_table = pn544_i2c_dt_match, -#endif - }, -}; - -/* - * module load/unload record keeping - */ - -static int __init pn544_dev_init(void) -{ - pr_info("Loading pn544 driver\n"); - return i2c_add_driver(&pn544_driver); -} -module_init(pn544_dev_init); - -static void __exit pn544_dev_exit(void) -{ - pr_info("Unloading pn544 driver\n"); - i2c_del_driver(&pn544_driver); -} -module_exit(pn544_dev_exit); - -MODULE_AUTHOR("Sylvain Fonteneau"); -MODULE_DESCRIPTION("NFC PN544 driver"); -MODULE_LICENSE("GPL"); diff --git a/pn8xT/pn553-i2c/pn553.h b/pn8xT/pn553-i2c/pn553.h index 96275e366f..34e3fe72ad 100644 --- a/pn8xT/pn553-i2c/pn553.h +++ b/pn8xT/pn553-i2c/pn553.h @@ -36,7 +36,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ - +#ifndef _PN553_H_ +#define _PN553_H_ #define PN544_MAGIC 0xE9 /* @@ -104,6 +105,7 @@ typedef enum p61_access_state{ P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ P61_STATE_SPI_END = 0x4000, P61_STATE_JCP_DWNLD = 0x8000,/* JCOP downlad in progress */ + P61_STATE_SECURE_MODE = 0x100000, /* secure mode state*/ P61_STATE_SPI_SVDD_SYNC_START = 0x0001, /*ESE_VDD Low req by SPI*/ P61_STATE_SPI_SVDD_SYNC_END = 0x0002, /*ESE_VDD is Low by SPI*/ P61_STATE_DWP_SVDD_SYNC_START = 0x0004, /*ESE_VDD Low req by Nfc*/ @@ -131,3 +133,4 @@ struct pn544_i2c_platform_data { unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ unsigned int iso_rst_gpio; /* gpio used for ISO hard reset P73*/ }; +#endif From 30fe2b6eee3e4813a6188b46e9e2a9d38ec8f644 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Mon, 31 Jul 2017 17:37:26 +0530 Subject: [PATCH 016/100] SEAccessKit_AR8.0.C_OpnSrc --- pn8xT/pn553-i2c/pn553.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c index 380f44ee57..a702ee252c 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn8xT/pn553-i2c/pn553.c @@ -164,7 +164,7 @@ static ssize_t pn544_dev_read(struct file *filp, char __user *buf, if (count > MAX_BUFFER_SIZE) count = MAX_BUFFER_SIZE; - pr_debug("%s : reading %zu bytes.\n", __func__, count); + //pr_debug("%s : reading %zu bytes.\n", __func__, count); mutex_lock(&pn544_dev->read_mutex); @@ -248,7 +248,7 @@ static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, return -EFAULT; } - pr_debug("%s : writing %zu bytes.\n", __func__, count); + //pr_debug("%s : writing %zu bytes.\n", __func__, count); /* Write data */ ret = i2c_master_send(pn544_dev->client, tmp, count); if (ret != count) { From cf81601f2eb6facd7318ab0de392699dc4724b78 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Mon, 14 Aug 2017 12:56:28 +0530 Subject: [PATCH 017/100] Jcop boot time + SPI init delay management --- pn8xT/pn553-i2c/pn553.c | 28 +++++++++++++++++++++++++++- pn8xT/pn553-i2c/pn553.h | 1 + 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c index a702ee252c..6531a07fe5 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn8xT/pn553-i2c/pn553.c @@ -532,6 +532,10 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } /* pull the gpio to high once NFCC is power on*/ gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + + /* Delay (10ms) after SVDD_PWR_ON to allow JCOP to bootup (5ms jcop boot time + 5ms guard time) */ + usleep_range(10000, 12000); + } else { pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); p61_access_unlock(pn544_dev); @@ -564,10 +568,17 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) break; + /* if secure timer is running, Delay the SPI close by 25ms after sending End of Apdu to enable eSE go into DPD + gracefully (20ms after EOS + 5ms DPD settlement time) */ + if(pn544_dev->secure_timer_cnt) + usleep_range(25000, 30000); + if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) { #ifndef JCOP_4X_VALIDATION gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); #endif svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); } @@ -590,9 +601,16 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, else{ pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); } + /* if secure timer is running, Delay the SPI close by 25ms after sending End of Apdu to enable eSE go into DPD + gracefully (20ms after EOS + 5ms DPD settlement time) */ + if(pn544_dev->secure_timer_cnt) + usleep_range(25000, 30000); + if (!(pn544_dev->secure_timer_cnt)) { #ifndef JCOP_4X_VALIDATION gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); #endif svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); } @@ -691,6 +709,9 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } /* pull the gpio to high once NFCC is power on*/ gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + + /* Delay (10ms) after SVDD_PWR_ON to allow JCOP to bootup (5ms jcop boot time + 5ms guard time) */ + usleep_range(10000, 12000); } }else { pr_info("%s : Prio Session Start power on ese failed \n", __func__); @@ -894,7 +915,8 @@ static void secure_timer_callback( unsigned long data ) { p61_access_state_t current_state = P61_STATE_INVALID; printk( KERN_INFO "secure_timer_callback: called (%lu).\n", jiffies); - + /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: START */ + get_ese_lock(P61_STATE_WIRED, MAX_ESE_ACCESS_TIME_OUT_MS); p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); p61_get_access_state(pn544_dev, ¤t_state); @@ -902,6 +924,8 @@ static void secure_timer_callback( unsigned long data ) { printk( KERN_INFO "secure_timer_callback: make se_pwer_gpio low, state = %d", current_state); gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); if(pn544_dev->nfc_service_pid == 0x00) { gpio_set_value(pn544_dev->ven_gpio, 0); @@ -909,6 +933,8 @@ static void secure_timer_callback( unsigned long data ) } } pn544_dev->secure_timer_cnt = 0; + /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: END */ + release_ese_lock(P61_STATE_WIRED); } static long start_seccure_timer(unsigned long timer_value) diff --git a/pn8xT/pn553-i2c/pn553.h b/pn8xT/pn553-i2c/pn553.h index 34e3fe72ad..49c03db105 100644 --- a/pn8xT/pn553-i2c/pn553.h +++ b/pn8xT/pn553-i2c/pn553.h @@ -94,6 +94,7 @@ #define PN544_SET_DWNLD_STATUS _IOW(PN544_MAGIC, 0x09, long) #define P544_SECURE_TIMER_SESSION _IOW(PN544_MAGIC, 0x0A, long) +#define MAX_ESE_ACCESS_TIME_OUT_MS 200 /*100 milliseconds*/ typedef enum p61_access_state{ P61_STATE_INVALID = 0x0000, From 57220780e510b3df8c98efff67bef7f8f66629f2 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Tue, 22 Aug 2017 15:34:43 +0530 Subject: [PATCH 018/100] [HW_VERSION_CHECK] : HW version check added during probe. --- pn8xT/pn553-i2c/pn553.c | 128 +++++++++++++++++++++++++++++++++++++++- pn8xT/pn553-i2c/pn553.h | 18 ++++++ 2 files changed, 144 insertions(+), 2 deletions(-) diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c index 6531a07fe5..26ef41a757 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn8xT/pn553-i2c/pn553.c @@ -70,6 +70,7 @@ #include "pn553.h" #define NEXUS5x 0 +#define HWINFO 0 #if NEXUS5x #undef ISO_RST #else @@ -107,6 +108,9 @@ struct pn544_dev { /* HiKey Compilation fix */ #ifndef HiKey_620_COMPILATION_FIX struct wake_lock nfc_wake_lock; +#if HWINFO +struct hw_type_info hw_info; +#endif static bool sIsWakeLocked = false; #endif static struct pn544_dev *pn544_dev; @@ -118,7 +122,9 @@ int get_ese_lock(p61_access_state_t p61_current_state, int timeout); static long set_jcop_download_state(unsigned long arg); static long start_seccure_timer(unsigned long timer_value); static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg); - +#if HWINFO +static void check_hw_info(void); +#endif static void pn544_disable_irq(struct pn544_dev *pn544_dev) { unsigned long flags; @@ -1273,7 +1279,12 @@ static int pn544_probe(struct i2c_client *client, enable_irq_wake(pn544_dev->client->irq); pn544_disable_irq(pn544_dev); i2c_set_clientdata(client, pn544_dev); - +#if HWINFO + /* + * This function is used only if + * hardware info is required during probe*/ + check_hw_info(); +#endif return 0; @@ -1361,7 +1372,120 @@ static struct i2c_driver pn544_driver = { #endif }, }; +#if HWINFO +/****************************************************************************** + * Function check_hw_info + * + * Description This function is called during pn544_probe to retrieve + * HW info. + * Useful get HW information in case of previous FW download is + * interrupted and core reset is not allowed. + * This function checks if core reset is allowed, if not + * sets DWNLD_REQ(firm_gpio) , ven reset and sends firmware + * get version command. + * In response HW information will be received. + * + * Returns None + * + ******************************************************************************/ +static void check_hw_info() { + char read_data[20]; + int ret, get_version_len = 8, retry_count = 0; + static uint8_t cmd_reset_nci[] = {0x20, 0x00, 0x01, 0x00}; + char get_version_cmd[] = + {0x00, 0x04, 0xF1, 0x00, 0x00, 0x00, 0x6E, 0xEF}; + pr_info("%s :Enter\n", __func__); + + /* + * Ven Reset before sending core Reset + * This is to check core reset is allowed or not. + * If not allowed then previous FW download is interrupted in between + * */ + pr_info("%s :Ven Reset \n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + ret = i2c_master_send(pn544_dev->client, cmd_reset_nci, 4); + + if (ret == 4) { + pr_info("%s : core reset write success\n", __func__); + } else { + + /* + * Core reset failed. + * set the DWNLD_REQ , do ven reset + * send firmware download info command + * */ + pr_err("%s : write failed\n", __func__); + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + ret = i2c_master_send(pn544_dev->client, get_version_cmd, get_version_len); + if (ret != get_version_len) { + ret = -EIO; + pr_err("%s : write_failed \n", __func__); + } + else { + pr_info("%s :data sent\n", __func__); + } + + ret = 0; + + while (retry_count < 10) { + + /* + * Wait for read interrupt + * If spurious interrupt is received retry again + * */ + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + enable_irq_wake(pn544_dev->client->irq); + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + pn544_disable_irq(pn544_dev); + + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + retry_count ++; + } + + if(ret) { + return; + } + + /* + * Read response data and copy into hw_type_info + * */ + ret = i2c_master_recv(pn544_dev->client, read_data, 14); + + if(ret) { + memcpy(hw_info.data, read_data, ret); + hw_info.len = ret; + pr_info("%s :data received len : %d\n", __func__,hw_info.len); + } + else { + pr_err("%s :Read Failed\n", __func__); + } + } +} +#endif /* * module load/unload record keeping */ diff --git a/pn8xT/pn553-i2c/pn553.h b/pn8xT/pn553-i2c/pn553.h index 49c03db105..7bbd7ada3e 100644 --- a/pn8xT/pn553-i2c/pn553.h +++ b/pn8xT/pn553-i2c/pn553.h @@ -134,4 +134,22 @@ struct pn544_i2c_platform_data { unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ unsigned int iso_rst_gpio; /* gpio used for ISO hard reset P73*/ }; + +struct hw_type_info { + /* + * Response of get_version_cmd will be stored in data + * byte structure : + * byte 0-1 : Header + * byte 2 : Status + * byte 3 : Hardware Version + * byte 4 : ROM code + * byte 5 : 0x00 constant + * byte 6-7 : Protected data version + * byte 8-9 : Trim data version + * byte 10-11 : FW version + * byte 12-13 : CRC + * */ + char data[20]; + int len; +}; #endif From f39b4842a4f24c36fdd91412a6b75809d4ec47a3 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Thu, 14 Sep 2017 15:36:31 +0530 Subject: [PATCH 019/100] NFC service died when SPI + DWP-reset/NFC ON/OFF --- pn8xT/pn553-i2c/pn553.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c index 26ef41a757..482834b055 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn8xT/pn553-i2c/pn553.c @@ -390,19 +390,35 @@ static int pn544_dev_open(struct inode *inode, struct file *filp) return 0; } +static int set_nfc_pid(unsigned long arg) +{ + pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); + pn544_dev->nfc_service_pid = arg; + return 0; +} + long pn544_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); - if (cmd == P544_GET_ESE_ACCESS) + /* Free pass autobahn area, not protected. Use it carefullly. START */ + switch(cmd) { - return get_ese_lock(P61_STATE_WIRED, arg); - } - else if(cmd == P544_REL_SVDD_WAIT) - { - return release_svdd_wait(); + case P544_GET_ESE_ACCESS: + return get_ese_lock(P61_STATE_WIRED, arg); + break; + case P544_REL_SVDD_WAIT: + return release_svdd_wait(); + break; + case P544_SET_NFC_SERVICE_PID: + return set_nfc_pid(arg); + break; + default: + break; } + /* Free pass autobahn area, not protected. Use it carefullly. END */ + p61_access_lock(pn544_dev); switch (cmd) { case PN544_SET_PWR: @@ -871,13 +887,6 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } } break; - case P544_SET_NFC_SERVICE_PID: - { - pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); - pn544_dev->nfc_service_pid = arg; - - } - break; case P544_SET_POWER_SCHEME: { if(arg == PN67T_PWR_SCHEME) From 9c33e057cd1610cac2c956660789479af758123e Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Thu, 14 Sep 2017 15:37:36 +0530 Subject: [PATCH 020/100] NFC service died when SPI + DWP-reset/NFC ON/OFF --- pn6xT/pn54x-i2c/built-in.o | Bin 188560 -> 0 bytes pn6xT/pn54x-i2c/pn54x.o | Bin 188568 -> 0 bytes pn8xT/pn553-i2c/built-in.o | Bin 199640 -> 0 bytes pn8xT/pn553-i2c/pn553.o | Bin 199648 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 pn6xT/pn54x-i2c/built-in.o delete mode 100644 pn6xT/pn54x-i2c/pn54x.o delete mode 100644 pn8xT/pn553-i2c/built-in.o delete mode 100644 pn8xT/pn553-i2c/pn553.o diff --git a/pn6xT/pn54x-i2c/built-in.o b/pn6xT/pn54x-i2c/built-in.o deleted file mode 100644 index fb26d66f7d0f277a3377243a0cbc4123a44e1555..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188560 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

xGG2q{YWsLaXyfvZyql3MnmG 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 Nzdq-)EdN{n{{#O|!QKD> diff --git a/pn6xT/pn54x-i2c/pn54x.o b/pn6xT/pn54x-i2c/pn54x.o deleted file mode 100644 index 6df2414bfcb070c59614939b5b4f316c4ee58da1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188568 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 diff --git a/pn8xT/pn553-i2c/built-in.o b/pn8xT/pn553-i2c/built-in.o deleted file mode 100644 index cf9a6eb192d4014104abba2cd30ce38344fa8aa1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199640 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 diff --git a/pn8xT/pn553-i2c/pn553.o b/pn8xT/pn553-i2c/pn553.o deleted file mode 100644 index b83943d093983fdd140f1709c9efbc400beb9038..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199648 zcmeFad3;sX^)`Oax%cK?LJ~sA3?wHZ7s4Fo5QAKXNI=k#M46N%B!Pq}F#!zKYEWyj z);1_AwGIK>igd!N6|B{Wt);DPt!hhV2!m-UiRp{CwJ=Tk-vZrzWbR>4SAC%^dFyYB9H!3t8_n;X`g`Titi$!UL=Im$**Ejb>Asl} z%bH5Leq)Pebyvrid+O@Yuj{PP8z(ROVYEK!uyaVH`jvE`T$cej0*(V%7(`?jp$TyvmxgWgz`MYlG_hlTo+Oi%vZpsW;R=SOH zJxp6%+j;>0?x9Z#EcI7Gzt*|e?!M7Q9`f+F%bp+EZriET9bo2}i!|n$3;CB#8GVJ3 z6VN~AC6tXkyN~;D)>-!7BbHT5K7IGjs<~*lC-%d4yR_}%d>8TUVw?5*(hs~d#5%z| z?*P}A&6|ljPpyZYR^ME0JJ9rthp#O2&162W4(|+!oY1y(l$4E&cArQ>SjN zUlWf_ z!~P#Ye&*Hou5S2y2{OtLhX$6ppVzg7Q&zj19J_P;zu`8^5>k}ge`|L4jb2{zNN+|P zz7?{jb(=c%nYMh%m&3Zsxc?P&JlN=%x>!BOeOc1yP3)0=Z~DPhaz z^XHs+9Q2vS=X;Iw?me+#KKfe)#_E&%Px%IXY^-veBFOZx-?HBC`0Ozk4zp@@pwF&x zB%bana5Z-Sj$;>TnfT4O{Flr@Jh;-a4mTienw2qTD`>{KUdLJ#VY|5)cSxfi>Z5+6 zOMDt1M>K{!CS#}&F?OzN|GKc<u2sDCoC$6=GbhK@9XSjvPk+>0un0i*};S)t9H& z6o8)F?d-Z{v6Y6hb~DbOyzFrkHy(+OPmV#3MaCp++?*3`(0bs3eb%lWPWLnHgHCRb z^ka!(mh~X@GoAXWx86p~w5{|9Cd`T2=b$XgcyXdW!8#nDkNhYv@ytB7!*2DH_F?#r zK5I;X|Bg7jni3<2gV58QrtPveMd!PEZKvJ6N1Vg;=)=sj!|~Bpu{Qy2a{rphiJMRt z@|Zq=?UaI86T;ZXpKHy2Hruk&5T7|tMTYjX&IOj}+8uGa(~ck?`C0gT7q;5)l`~x9 znC0pi>qAW7{M~PS*9+fL&ldU({`(qq)WhcP+t7Ddw;S<`y6w0Hzo^rWJK-O1P_R#@3rrMqiqlTYA(_|687G;`7}8-{slP zy1@26jEQJ@yZ^hqYmirb2w(oz_~|HNjXl=JJ7LH9&f06f6KH{@$bG%63q^#}Ny!om2_WX2vyQGB}FD>zL zzpkBR%|Ra0rB9W>cJ^23l0LFq;!(QHM;r&tPu{*Ga}R@#??;mV$FS#W%mbA9n&Z2k zx-mwcIaKPK`5=7Jdz<7F8_*}GQjTjX%2BuY2X!HxY}yTRc8v7FKFv#+Kb$;u>*M%k zUdl2i42FEa13jq`spos3`ypeY-RgDTqRqSOz43)UD%gxO)NhOzyBK3nUiPEt+C


&N(bYhdI=Y(4z2#AI)+Lw{42v1<=( zX3XXq<6WO~-~`Ibn&;bf+?Rv7Fzdj}zRUw$XGmG@9o3e-zhkz~+VD8naFOonmwcIG zTNdWMhkY2+1$R_)4NtkD_@(R)%yZdS%h<=7J)3n9I}y|M7jv9R-@P9?5dU}OzU;}% z+GN)w^egJyeYMUZ^^!-|ExmDeMVhSIczhIPN88u-U3bOiFiA z53jDh3n3GSkD~7Vad~iP)%7uAulQ%z&oM`EU1gW}X4+Hd&1}G&XupE^#` zIZwtIWL^eO(@mPOk7-gzj785+^pEFL8*N0}UU01RZ2{}Scwc#blK#m2(7Bhf;uGvU z@+mgZPPS1#+A6-CJUd{M*kQ9y=+E?NFZLSNMY6ZVxYU0B7}l46gsm^8SZ`o!9qlK3 z7g)82R#r|Ie?_{huZ6GU>vA09)vM2w$WMQ>E!f|7oS{7|>3`Pxy$;3=`$ISPmKf9U z^-k3D(1@-XOm{Zo4{J;4KCM0Xf@dMmK-dw_OE#FcnD&=`6Zr7dt?yy|`CZsHJyX{a z@%^JTR6kwpu&&Z}haGESN0(3SU|nfTp`*4GL}KfcV^-x1?FZLre}Nnp3RokcA4!b9 zrn&%Wut{P)?PY$>7qpYkc zZ0Pf$?R?g>LX<`S%r)&4?;F}vVC{_B!?m1Of7adjK>H)>$oPVN;3w5*8vTkgX$#AY z_K`ER3vG4jvygQO`@ai2X$#v%+XHsN_k-eWif4tzO19YrPdP;|ehWHcg|wHgwx4qX5{`-)G{2S067%$M-qf(N~68 zz_uwv+r-tM{+GIbLjUvhQI39LIcu>0rQNJc7HGzry=SV6i4l(@e$XBpW3v$XMHl+! z6&TZ9PNno&Z+xDq4@#^+UT+M3QXgbHh#w@D!dIpZ`X{6A@Y|g6I&LV_WZJ~Er?jQF zf3HVfU-=K}m1e!M1MP6gUqAh3)9w$>_3dJxG3P@v_WQ+$vA9!-dP!Qh&P$Am^N@CE zLgjR(GY)z6jMwuLeQd>I4d+Ac9~lSY`*kDIy?z)!R&&wcU(7^XpifAj?A6$`jQuSa zbwS_m%Bq~P$EwnK0QPZT|NiKD#qcr8sm_M2i_YL5Ge_*EpWaL8zL9>q>jRbT1EoRT>o9LG7OGm`PRyZU#Ib$C3=q@L^%ep%PC zyxcf_)MYt6&%EeZf49xNbGk2MYee>$e#}Q+pBaXFKIC-YxH8Z+gR$E38$Iv|({JoU4dmM7K%|_cb;QYi&)jhg5_Pu=c-_d`cx-|=PgT$p&&5t~i|6Mb7 zxNi04T>6rAqyBT@&k)M>+861&3S2+d)w$x!TZdT>(Es(2jX?JAkYzq^uI5-}odf^(@#n1x8n9NLL*JPgk%F<5=|97qZN|P0 zyXZIia69bs^b}-h+z{J2mi>sQ>4=%ImHxtcft2CJ)wx_7>zYw~`ThxMha2}nj`4Oc z`V4LQm|u+Uy@ORZV-@vFxwPvOV&e|#W$Z)WIIX=RdS2o64T(dreQyf%L)T*FLu~0k zeoE{yd3TM9_6=S4dgG0DWNx%hG&3L9$EGi3_RHQ{;&7FzSGkQ~h@hj`XJuPkExMQrSM|(7&Z&B78ix&f*DIfR2%*%MtkG>hd zZ;wA4<@qDz{;&RR?rI;`zIocz(*G+h|1Y!Wfs>crCug=i??9~SIWfXIf%_>qd$I4e ze7ujL=hpAy9JoPZ2JW%oOuY9}i}6YN4}N!}VddNt_Z_%imDmzS-?{&8dzX{SGboc;Zc+Wp`L>oDi92Rg08hp(1#wVQI};lA1d*Q}T4^bVoEUHc|VnY;H* zh@oQpE#;V;@QUik$P;R)Xx zpS-u|-4n1iPfr1K@GPvLPtN^BK6bwUSoEySD@*frKf`=1`_p9O?egS$^}L!f`LutX zt?M>7Y^-Z(*xa34@b#C9>Sl70>ZS7jCefp%jhQ`L`&d$26n>V&KZZNqS z8>ZGZHE*lCw4-%PvlYXw9hbz^#ie&NH#AwIZ(Z{iPiN)Z)&Gs$L;!MroI=QiKQ$r^zjS6pWqCd8FY;JB6mmqV)Muwm5?xhVInq3a~=B5Ip zl?-ZiPuDw@?cCYEwWGCdYp2^ve|Btb-{Lkk(^Jj#BZ@9_<4W#mZrpZy$tr^MX4JL` z)oXJ%HEiCl)@v=1-z^R|jfOrH`EggkCGn21r(Yo9=@UKKx_Mi}M)XJtUvAr4H!jji zS{=IQ){c(m&0CC&dwQoaOpSl+R9#U%d)k@UVt2S{9Qz;o-1yCnt?V*un#+~*l zu^{9z{Yjb#E`?2MkECnMF}WFSvT*Xex^pf#Z(bdUL@U-0KVq(o71*|QW3!7{s=-sT zxowNvum*`J7;^{_ zrg~&_CLMn^yL{cHmslT5+q88{bJuCf>^<6Tlm{)-rg(nc)Y{ot*U`MLl>^WCJkipj z-8m6WI&7N&ur3p3Hg6VF+OD6fkIFI#)tr6>f^^U~HWEiV0kX+sCX79+mvF;9nU z*P5QOrlCoU3UAzMB+A^X^WgTHirTuGs)cn`%c|Y+Q7tZPpd9 zzx3ZSS?r)oa>36&Ie*!Ci{~4;vPJXGuX5*OGodzm1wT^bPgLC0+Nqk^adZLk2`2nkeGXPt)Kt_hs9Jb_ z-Qx3?xpCbwo>jSUL1mQp3FVzB7}T~jGcKXy$x2SvfLL!vLl_)L5$%bcjV;Zanz

lRlmm@{vM_K10v6-z3{{r7n*mZK{zxuCA*zsP8!R7`tw zO$AIxJjaxZ0FM=*8E=?{Fy6|rK-`L@3m3cpRi?J~Gv}!}QyDTxx3_O>ZIn6P>mF0S%Jy8;8fU3;KlZmgP{unL#uG{<6M_NevuzQde9K=!~HhyzFC&0 zq+cs3BC08wdzj(`Vlr}+?RVnzstq0*HG6Og3)0j{F>=Ah$gQcB)U4z(TB79gSn7%xxiY4A z70IA9faFL^dc@0|Ht0{D%Ct0|D62q5OEfk2=TUNap2L>H#gohLj56ITqU89yqU7}J zqU2dPXf*084n)bd_eGU$j9K-$sDIL~jgfamosxEEjJzvG?sKDh?|A@b4)Ujc7kBln zR9c*NP@2S;aNp0!52ZbDD$0M5&E%Q*{l6i7FmYv%aYPt~-i~DIV7_3898>78zZT8#3`vvuHxGhlhAZ)#OpqenU;YpCe&{MdkMSH=J>;ELFIOVm5NEyZH1J1^X7emrhs%WgzgGh&zP9>eH^kCB2 z>9|1i1`G+|J2X4Vt< zm0~ipNm?0LvRauriD(lwB{P?FlFAGvt!8BoW2`unDMJ+daENlt9GFK4<2+o@n-hQy~2i z9S>2MGx`osW9FEBAdNX=*-FNoaimQx$FuJn(4LYP?w_gUff}8#9e(4Hs5sMx*r@lp(xh24xC*&7kZ+##GCC-=Lhp03ge+uFn+|GH6)fsS)U~ zr=jfAkb4>`HfXryD={c9z~xb?L2lr=S?K5njg@s`)oEzCLE{1ps`Unq7u0UhM9J5E z8ro^lq`)bZ&|}c#z$uLM{RT}7l)_8L44NUR-=LX+m(wikHG|F$FhIP28v4+n%D~+W zfq}fWomS$aKqXZ6hSY(J12sVV4LUC{6wW2CWk`-=Ot@L5S#;25kyFkEfFs8+1uv2qHz5L7jmf zlu&QbO=4M#LAM0H3SPTGw*|fd)Me0}f%|~E4eAX%0<_bheSx0<^%(Ru@yi~Az8?4m zc)bRFBVeOd_8au=z;)>49{NteMJG6Dc;A&y@PI)F1syWzfxt27>@(>5GQ^G=bU5%b zc*hL-LExW2{RaI|2ctoc22OzYzCn)%P61ho+I~j@zn+K|Gw2D)SDKjD(YV!0d?vs} zU!~za7sy{=S<4Ojec-M6#)++9u=^2=6x1GX8WA^B(03jb}Ogim!RG+Y;Ux3&LL^p zXb3Dt77$>+8Q|{?DQ1upEHZv=oPukJ-*U$ng zgKYSlQQ46sEo;;oTx5|pbkr?KDQ2QI?yI(}*8IcLIUGgfunZPtgon950?6_YoAV)l zr4qyDGD%l?{$UXg>YUf&axA9gAph`z6TuOU!;=oi_`|bukyw=K1oB428Y-`d zA;dIPUYGz46^6Wf4dlgyyaKlS$TDg#z#mpkdHH*Qa;VZvv-77N2b7fj8I0G4o=MuT z>1CvKIhtQC;+j5-bdMEy6F>Zu_8f#h{62v6VR2kbeuTk3qifPkD}N3L0qDskR{mVl zA<&bo{CT8PK~J{w=abF`J;lneAnk&lYUQ6px)}5{D}Mp$642AF{7TZLpl4Y53rR;n zmsYb=sQP1T5`pLl9U4Cc~DRgOrTOj6X381fXgD4p>$`mV| z&4w*eT24-;Dm{#rlqx-(Q+mV;Nh~*++ES(3tC~@CKvsEBOnrO^$$C9}&~8aL+m`Ts_Fw1{WU#F8 z_iX8<3huYRfj*}jn(zbmfGX%$&Vx2*0o}udzi-oF5#>B&v!+!F4hdMU;IOE!SMabs z1Wnka;1N;KqTo?6txLgUHk-6tL7%;|4n0D_5#jVGctTX~R`4VHCW!4(@MHT8x)+11iXJ=<{L)*$$go_kiJ{j&vyH+@rw#3OGS+5 zr#L&IdXI9-#17-^vmADj{mPjooTnAcc6gX{OhLq9=Xp)R90Bj=qc&D}u7Hp|_UEWp zwr*F$3mg~qDmJLn;Ur&T&_Y2|4O%3q)Sz>nf5H6`gBCk)Ho{c~Epd(xhkFcKsy5hT z{|Ci}bT1fQ?mPmM%q}^+N>IAtUF1wd4YCbdBMsv^=slY;#3ay+%%IUqX2r-U51~V8 z>eO$6ltG?7YQzA%Wg-K6R8ee@j|wwcr;Je}RU{ZX=4A_w8dDt2HkNFo&n?bb;W3Kk zBt>->59QRW`ih6K4N_q;%M*)64_uF2Vo~wvLHBqXMyJAy#=6mIqd}^M(L+Q;tR9_C zZP`Xo()W-z7&?S&EzpILOqbF1514{y1+)XR&9mshlUncBHDAj~iX=rT9B2P$3b3=gV5fWxi)yJk#**MxXcAs+z=l~OT#KaI7 z;JaYx1|&&%c+DxQwevtqH!ixs_7@{qZ=z(EDu1RPRusenEOT>_3O*e>8{ z1)mXcEFSd7gV*B0>k2NDJn!eN>DXWuDX?@{8x%6=auG~D4Ve&Aq&)XDo(VWbSJ+>K z$4$T~y2hRiWX`0DuC@09?a??;w9{@z@8~t?db=9E!<<67f)3`(6agoS3{P-sH>8Yaqs znvlVPuj|kWnKFcRKuyRR3Gu8@(TvaI7sg|~T*`o;DyFR(FTDCf>_iSUGP#=|62Chk+JeNF+||DM^Vj(kjbHXwYsQ{l75<3 z!F7%rQbn~Rsm>adS~PtO7 2A)i=Sj5zSh|tn-zweQpHeiP9G^y-Mi| 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 lBhyRq$^85v_7H57Ho}rle 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 S>rUHmJ=tDA1`A_u|NjI0xnbM@ From a95ba8972a49c52147db392c65e12d139cceb7e4 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Mon, 18 Sep 2017 15:49:56 +0530 Subject: [PATCH 021/100] SEAccessKit_AR8.1.0_OpnSrc --- pn6xT/pn54x-i2c/modules.order | 0 pn8xT/pn553-i2c/modules.order | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 pn6xT/pn54x-i2c/modules.order delete mode 100644 pn8xT/pn553-i2c/modules.order diff --git a/pn6xT/pn54x-i2c/modules.order b/pn6xT/pn54x-i2c/modules.order deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pn8xT/pn553-i2c/modules.order b/pn8xT/pn553-i2c/modules.order deleted file mode 100644 index e69de29bb2..0000000000 From acdce172542eacf58a0c9c61c277ea77c49e2da9 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Tue, 26 Sep 2017 17:56:25 +0530 Subject: [PATCH 022/100] Secure timer callback moved to bottom half execution --- pn8xT/pn553-i2c/pn553.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c index 482834b055..9207e29417 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn8xT/pn553-i2c/pn553.c @@ -60,6 +60,7 @@ #include #include #include +#include /* HiKey Compilation fix */ #define HiKey_620_COMPILATION_FIX 1 #ifndef HiKey_620_COMPILATION_FIX @@ -69,7 +70,7 @@ #include #include "pn553.h" -#define NEXUS5x 0 +#define NEXUS5x 1 #define HWINFO 0 #if NEXUS5x #undef ISO_RST @@ -104,6 +105,8 @@ struct pn544_dev { long nfc_service_pid; /*used to signal the nfc the nfc service */ chip_pwr_scheme_t chip_pwr_scheme; unsigned int secure_timer_cnt; + struct workqueue_struct *pSecureTimerCbWq; + struct work_struct wq_task; }; /* HiKey Compilation fix */ #ifndef HiKey_620_COMPILATION_FIX @@ -125,6 +128,8 @@ static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long ar #if HWINFO static void check_hw_info(void); #endif +#define SECURE_TIMER_WORK_QUEUE "SecTimerCbWq" + static void pn544_disable_irq(struct pn544_dev *pn544_dev) { unsigned long flags; @@ -926,7 +931,7 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } EXPORT_SYMBOL(pn544_dev_ioctl); -static void secure_timer_callback( unsigned long data ) +static void secure_timer_workqueue(struct work_struct *Wq) { p61_access_state_t current_state = P61_STATE_INVALID; printk( KERN_INFO "secure_timer_callback: called (%lu).\n", jiffies); @@ -950,6 +955,16 @@ static void secure_timer_callback( unsigned long data ) pn544_dev->secure_timer_cnt = 0; /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: END */ release_ese_lock(P61_STATE_WIRED); + return; +} + +static void secure_timer_callback( unsigned long data ) +{ + /* Flush and push the timer callback event to the bottom half(work queue) + to be executed later, at a safer time */ + flush_workqueue(pn544_dev->pSecureTimerCbWq); + queue_work(pn544_dev->pSecureTimerCbWq, &pn544_dev->wq_task); + return; } static long start_seccure_timer(unsigned long timer_value) @@ -1256,7 +1271,8 @@ static int pn544_probe(struct i2c_client *client, sema_init(&ese_access_sema, 1); mutex_init(&pn544_dev->p61_state_mutex); spin_lock_init(&pn544_dev->irq_enabled_lock); - + pn544_dev->pSecureTimerCbWq = create_workqueue(SECURE_TIMER_WORK_QUEUE); + INIT_WORK(&pn544_dev->wq_task, secure_timer_workqueue); pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; pn544_dev->pn544_device.name = "pn553"; pn544_dev->pn544_device.fops = &pn544_dev_fops; @@ -1331,6 +1347,7 @@ static int pn544_remove(struct i2c_client *client) gpio_free(pn544_dev->irq_gpio); gpio_free(pn544_dev->ven_gpio); gpio_free(pn544_dev->ese_pwr_gpio); + destroy_workqueue(pn544_dev->pSecureTimerCbWq); #ifdef ISO_RST gpio_free(pn544_dev->iso_rst_gpio); #endif From 4fb8563652a8e6ac6e3f03964338f11cd39e12aa Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Mon, 16 Oct 2017 16:19:15 +0530 Subject: [PATCH 023/100] VEN & eSE SVDD power is not high during Secure Timer is Running --- pn8xT/pn553-i2c/pn553.c | 37 ++++++++++++++++++++++++++++++++++--- pn8xT/pn553-i2c/pn553.h | 11 ++++++++++- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c index 9207e29417..d8029965cf 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn8xT/pn553-i2c/pn553.c @@ -70,7 +70,7 @@ #include #include "pn553.h" -#define NEXUS5x 1 +#define NEXUS5x 0 #define HWINFO 0 #if NEXUS5x #undef ISO_RST @@ -119,6 +119,7 @@ static bool sIsWakeLocked = false; static struct pn544_dev *pn544_dev; static struct semaphore ese_access_sema; static struct semaphore svdd_sync_onoff_sema; +static struct completion dwp_onoff_sema; static struct timer_list secure_timer; static void release_ese_lock(p61_access_state_t p61_current_state); int get_ese_lock(p61_access_state_t p61_current_state, int timeout); @@ -382,6 +383,31 @@ static int release_svdd_wait(void) pr_info("%s: Exit\n", __func__); return 0; } + +static void dwp_OnOff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 100; //100 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + if(nfc_service_pid) + { + if (0 == signal_handler(origin, nfc_service_pid)) + { + init_completion(&dwp_onoff_sema); + if(wait_for_completion_timeout(&dwp_onoff_sema, tempJ) != 0) + { + pr_info("Dwp On/off wait protection: Timeout"); + } + pr_info("Dwp On/Off wait protection : released"); + } + } +} +static int release_dwpOnOff_wait(void) +{ + pr_info("%s: Enter \n", __func__); + complete(&dwp_onoff_sema); + return 0; +} + static int pn544_dev_open(struct inode *inode, struct file *filp) { struct pn544_dev *pn544_dev = container_of(filp->private_data, @@ -419,6 +445,9 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, case P544_SET_NFC_SERVICE_PID: return set_nfc_pid(arg); break; + case P544_REL_DWPONOFF_WAIT: + return release_dwpOnOff_wait(); + break; default: break; } @@ -540,7 +569,8 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, if (!(current_state & P61_STATE_JCP_DWNLD)){ if(pn544_dev->nfc_service_pid){ pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); + /*signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid);*/ + dwp_OnOff(pn544_dev->nfc_service_pid, P61_STATE_SPI); } else{ pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); @@ -720,7 +750,8 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, if (current_state & P61_STATE_WIRED){ if(pn544_dev->nfc_service_pid){ pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + /*signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid);*/ + dwp_OnOff(pn544_dev->nfc_service_pid, P61_STATE_SPI_PRIO); } else{ pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); diff --git a/pn8xT/pn553-i2c/pn553.h b/pn8xT/pn553-i2c/pn553.h index 7bbd7ada3e..296f3cda91 100644 --- a/pn8xT/pn553-i2c/pn553.h +++ b/pn8xT/pn553-i2c/pn553.h @@ -92,8 +92,17 @@ * */ #define PN544_SET_DWNLD_STATUS _IOW(PN544_MAGIC, 0x09, long) +/* + NFC will call the ioctl to release the dwp on/off protection +*/ +#define P544_REL_DWPONOFF_WAIT _IOW(PN544_MAGIC, 0x0A, long) + +/* + NFC will call the ioctl to start Secure Timer +*/ + +#define P544_SECURE_TIMER_SESSION _IOW(PN544_MAGIC, 0x0B, long) -#define P544_SECURE_TIMER_SESSION _IOW(PN544_MAGIC, 0x0A, long) #define MAX_ESE_ACCESS_TIME_OUT_MS 200 /*100 milliseconds*/ typedef enum p61_access_state{ From 23f9d47d6879328e05c34a764d2bfa3508f77701 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Mon, 20 Nov 2017 11:10:47 +0530 Subject: [PATCH 024/100] NFC_NCIHALx_AR18C0.8.2.9_O_OpnSrc --- pn8xT/pn553-i2c/pn553.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pn8xT/pn553-i2c/pn553.c b/pn8xT/pn553-i2c/pn553.c index d8029965cf..7f22b3ea04 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn8xT/pn553-i2c/pn553.c @@ -546,6 +546,14 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, msleep(50); pr_info("%s ISO RESET from DWP DONE\n", __func__); #endif + } else if (arg == 4) { + pr_info("%s FW dwldioctl called from NFC \n", __func__); + /*NFC Service called FW dwnld*/ + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + msleep(10); + } } else { pr_err("%s bad arg %lu\n", __func__, arg); From 717066fe9bc9980cc81a6e53b769d2d02b3cd003 Mon Sep 17 00:00:00 2001 From: nxf24591 Date: Wed, 21 Feb 2018 17:45:25 +0530 Subject: [PATCH 025/100] NFC_NCIHALx_AR2000.09.00.02_OpnSrc --- {pn8xT/pn553-i2c => pn553-i2c}/Kconfig | 0 {pn8xT/pn553-i2c => pn553-i2c}/Makefile | 0 {pn8xT/pn553-i2c => pn553-i2c}/pn553.c | 40 +- {pn8xT/pn553-i2c => pn553-i2c}/pn553.h | 0 pn6xT/pn54x-i2c/Kconfig | 13 - pn6xT/pn54x-i2c/Makefile | 8 - pn6xT/pn54x-i2c/pn54x.c | 1037 ----------------------- pn6xT/pn54x-i2c/pn54x.h | 113 --- 8 files changed, 38 insertions(+), 1173 deletions(-) rename {pn8xT/pn553-i2c => pn553-i2c}/Kconfig (100%) rename {pn8xT/pn553-i2c => pn553-i2c}/Makefile (100%) rename {pn8xT/pn553-i2c => pn553-i2c}/pn553.c (98%) rename {pn8xT/pn553-i2c => pn553-i2c}/pn553.h (100%) delete mode 100644 pn6xT/pn54x-i2c/Kconfig delete mode 100644 pn6xT/pn54x-i2c/Makefile delete mode 100644 pn6xT/pn54x-i2c/pn54x.c delete mode 100644 pn6xT/pn54x-i2c/pn54x.h diff --git a/pn8xT/pn553-i2c/Kconfig b/pn553-i2c/Kconfig similarity index 100% rename from pn8xT/pn553-i2c/Kconfig rename to pn553-i2c/Kconfig diff --git a/pn8xT/pn553-i2c/Makefile b/pn553-i2c/Makefile similarity index 100% rename from pn8xT/pn553-i2c/Makefile rename to pn553-i2c/Makefile diff --git a/pn8xT/pn553-i2c/pn553.c b/pn553-i2c/pn553.c similarity index 98% rename from pn8xT/pn553-i2c/pn553.c rename to pn553-i2c/pn553.c index 7f22b3ea04..ccf5876699 100644 --- a/pn8xT/pn553-i2c/pn553.c +++ b/pn553-i2c/pn553.c @@ -81,6 +81,9 @@ #define SIG_NFC 44 #define MAX_BUFFER_SIZE 512 #define MAX_SECURE_SESSIONS 1 +/* VEN is kept ON all the time if you define the macro VEN_ALWAYS_ON. +Used for SN100 usecases */ +#define VEN_ALWAYS_ON /* Macro added to disable SVDD power toggling */ /* #define JCOP_4X_VALIDATION */ @@ -476,17 +479,21 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, /* power on with firmware download (requires hw reset) */ pr_info("%s power on with firmware\n", __func__); + #ifndef VEN_ALWAYS_ON gpio_set_value(pn544_dev->ven_gpio, 1); msleep(10); + #endif if (pn544_dev->firm_gpio) { p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); gpio_set_value(pn544_dev->firm_gpio, 1); } + #ifndef VEN_ALWAYS_ON msleep(10); gpio_set_value(pn544_dev->ven_gpio, 0); msleep(10); gpio_set_value(pn544_dev->ven_gpio, 1); msleep(10); + #endif } } else if (arg == 1) { /* power on */ @@ -502,9 +509,11 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } pn544_dev->nfc_ven_enabled = true; + #ifndef VEN_ALWAYS_ON if (pn544_dev->spi_ven_enabled == false || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { gpio_set_value(pn544_dev->ven_gpio, 1); } + #endif } else if (arg == 0) { /* power off */ pr_info("%s power off\n", __func__); @@ -517,10 +526,12 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, pn544_dev->nfc_ven_enabled = false; /* Don't change Ven state if spi made it high */ + #ifndef VEN_ALWAYS_ON if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { gpio_set_value(pn544_dev->ven_gpio, 0); } + #endif /* HiKey Compilation fix */ #ifndef HiKey_620_COMPILATION_FIX if (sIsWakeLocked == true) { @@ -588,13 +599,14 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) break; - + #ifndef VEN_ALWAYS_ON if (pn544_dev->nfc_ven_enabled == false) { /* provide power to NFCC if, NFC service not provided */ gpio_set_value(pn544_dev->ven_gpio, 1); msleep(10); } + #endif /* pull the gpio to high once NFCC is power on*/ gpio_set_value(pn544_dev->ese_pwr_gpio, 1); @@ -648,10 +660,12 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); } #ifndef JCOP_4X_VALIDATION + #ifndef VEN_ALWAYS_ON if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { gpio_set_value(pn544_dev->ven_gpio, 0); msleep(10); - } + } + #endif #endif }else if(current_state & P61_STATE_SPI){ p61_update_access_state(pn544_dev, P61_STATE_SPI, false); @@ -711,11 +725,13 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } } pn544_dev->spi_ven_enabled = false; +#ifndef VEN_ALWAYS_ON if (pn544_dev->nfc_ven_enabled == false && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) && !(pn544_dev->secure_timer_cnt)) { gpio_set_value(pn544_dev->ven_gpio, 0); msleep(10); } +#endif } else { pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", __func__, pn544_dev->p61_current_state); @@ -728,11 +744,13 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, if (pn544_dev->spi_ven_enabled == false) { pn544_dev->spi_ven_enabled = true; + #ifndef VEN_ALWAYS_ON if ((pn544_dev->nfc_ven_enabled == false) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) { /* provide power to NFCC if, NFC service not provided */ gpio_set_value(pn544_dev->ven_gpio, 1); msleep(10); } + #endif } if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) { @@ -768,11 +786,13 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, pn544_dev->spi_ven_enabled = true; if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) { + #ifndef VEN_ALWAYS_ON if (pn544_dev->nfc_ven_enabled == false) { /* provide power to NFCC if, NFC service not provided */ gpio_set_value(pn544_dev->ven_gpio, 1); msleep(10); } + #endif /* pull the gpio to high once NFCC is power on*/ gpio_set_value(pn544_dev->ese_pwr_gpio, 1); @@ -985,11 +1005,13 @@ static void secure_timer_workqueue(struct work_struct *Wq) gpio_set_value(pn544_dev->ese_pwr_gpio, 0); /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ usleep_range(2500, 3000); + #ifndef VEN_ALWAYS_ON if(pn544_dev->nfc_service_pid == 0x00) { gpio_set_value(pn544_dev->ven_gpio, 0); printk( KERN_INFO "secure_timer_callback :make ven_gpio low, state = %d", current_state); } + #endif } pn544_dev->secure_timer_cnt = 0; /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: END */ @@ -1279,11 +1301,19 @@ static int pn544_probe(struct i2c_client *client, pr_err("%s :not able to set irq_gpio as input\n", __func__); goto err_ven; } + #ifndef VEN_ALWAYS_ON ret = gpio_direction_output(pn544_dev->ven_gpio, 0); if (ret < 0) { pr_err("%s : not able to set ven_gpio as output\n", __func__); goto err_firm; } + #else + ret = gpio_direction_output(pn544_dev->ven_gpio, 1); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_firm; + } + #endif ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); if (ret < 0) { pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); @@ -1343,6 +1373,12 @@ static int pn544_probe(struct i2c_client *client, enable_irq_wake(pn544_dev->client->irq); pn544_disable_irq(pn544_dev); i2c_set_clientdata(client, pn544_dev); +#ifdef VEN_ALWAYS_ON + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(3); + gpio_set_value(pn544_dev->ven_gpio, 1); +#endif + #if HWINFO /* * This function is used only if diff --git a/pn8xT/pn553-i2c/pn553.h b/pn553-i2c/pn553.h similarity index 100% rename from pn8xT/pn553-i2c/pn553.h rename to pn553-i2c/pn553.h diff --git a/pn6xT/pn54x-i2c/Kconfig b/pn6xT/pn54x-i2c/Kconfig deleted file mode 100644 index e42ba0d9dc..0000000000 --- a/pn6xT/pn54x-i2c/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# Nxp Nci protocol (I2C) devices -# - -menuconfig NFC_PN54X_DEVICES - bool "Nxp pn54x NCI protocol driver (I2C) devices" - default y - ---help--- - You'll have to say Y if your computer contains an I2C device that - you want to use under Linux. - - You can say N here if you don't have any SPI connected to your computer. - diff --git a/pn6xT/pn54x-i2c/Makefile b/pn6xT/pn54x-i2c/Makefile deleted file mode 100644 index 6c257880c6..0000000000 --- a/pn6xT/pn54x-i2c/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for nfc devices -# - -obj-$(CONFIG_NFC_PN54X_DEVICES) += pn54x.o - -ccflags-$(CONFIG_NFC_PN54X_DEVICES_DEBUG) := -DDEBUG - diff --git a/pn6xT/pn54x-i2c/pn54x.c b/pn6xT/pn54x-i2c/pn54x.c deleted file mode 100644 index b5ea40f78c..0000000000 --- a/pn6xT/pn54x-i2c/pn54x.c +++ /dev/null @@ -1,1037 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -/****************************************************************************** - * - * The original Work has been changed by NXP Semiconductors. - * - * Copyright (C) 2013-2014 NXP Semiconductors - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pn54x.h" - -#define NEXUS5x 0 -#define DRAGON_NFC 1 -#define SIG_NFC 44 -#define MAX_BUFFER_SIZE 512 - -struct pn544_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct i2c_client *client; - struct miscdevice pn544_device; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int irq_gpio; - unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ - struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ - p61_access_state_t p61_current_state; /* stores the current P61 state */ - bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ - bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ - bool irq_enabled; - spinlock_t irq_enabled_lock; - long nfc_service_pid; /*used to signal the nfc the nfc service */ -}; -struct wake_lock nfc_wake_lock; -static bool sIsWakeLocked = false; -static struct pn544_dev *pn544_dev; -static struct semaphore ese_access_sema; -static struct semaphore svdd_sync_onoff_sema; -static void release_ese_lock(p61_access_state_t p61_current_state); -int get_ese_lock(p61_access_state_t p61_current_state, int timeout); -static void pn544_disable_irq(struct pn544_dev *pn544_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); - if (pn544_dev->irq_enabled) { - disable_irq_nosync(pn544_dev->client->irq); - disable_irq_wake(pn544_dev->client->irq); - pn544_dev->irq_enabled = false; - } - spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); -} - -static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) -{ - struct pn544_dev *pn544_dev = dev_id; - - pn544_disable_irq(pn544_dev); - if (sIsWakeLocked == false) - { - wake_lock(&nfc_wake_lock); - sIsWakeLocked = true; - } else { - pr_debug("%s already wake locked!\n", __func__); - } - /* Wake up waiting readers */ - wake_up(&pn544_dev->read_wq); - - return IRQ_HANDLED; -} - -static ssize_t pn544_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev = filp->private_data; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - pr_debug("%s : reading %zu bytes.\n", __func__, count); - - mutex_lock(&pn544_dev->read_mutex); - - if (!gpio_get_value(pn544_dev->irq_gpio)) { - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto fail; - } - - while (1) { - pn544_dev->irq_enabled = true; - enable_irq(pn544_dev->client->irq); - enable_irq_wake(pn544_dev->client->irq); - ret = wait_event_interruptible( - pn544_dev->read_wq, - !pn544_dev->irq_enabled); - - pn544_disable_irq(pn544_dev); - - if (ret) - goto fail; - - if (gpio_get_value(pn544_dev->irq_gpio)) - break; - - pr_warning("%s: spurious interrupt detected\n", __func__); - } - } - - /* Read data */ - ret = i2c_master_recv(pn544_dev->client, tmp, count); - if (sIsWakeLocked == true) { - wake_unlock(&nfc_wake_lock); - sIsWakeLocked = false; - } - mutex_unlock(&pn544_dev->read_mutex); - - /* pn544 seems to be slow in handling I2C read requests - * so add 1ms delay after recv operation */ -#if !NEXUS5x - udelay(1000); -#endif - - if (ret < 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - return ret; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - return -EIO; - } - if (copy_to_user(buf, tmp, ret)) { - pr_warning("%s : failed to copy to user space\n", __func__); - return -EFAULT; - } - return ret; - - fail: - mutex_unlock(&pn544_dev->read_mutex); - return ret; -} - -static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - pn544_dev = filp->private_data; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - return -EFAULT; - } - - pr_debug("%s : writing %zu bytes.\n", __func__, count); - /* Write data */ - ret = i2c_master_send(pn544_dev->client, tmp, count); - if (ret != count) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - ret = -EIO; - } - - /* pn544 seems to be slow in handling I2C write requests - * so add 1ms delay after I2C send oparation */ - udelay(1000); - - return ret; -} - -static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) -{ - pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); - if (current_state) - { - if(set){ - if(pn544_dev->p61_current_state == P61_STATE_IDLE) - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->p61_current_state |= current_state; - } - else{ - pn544_dev->p61_current_state ^= current_state; - if(!pn544_dev->p61_current_state) - pn544_dev->p61_current_state = P61_STATE_IDLE; - } - } - pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); -} - -static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) -{ - - if (current_state == NULL) { - //*current_state = P61_STATE_INVALID; - pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); - } else { - *current_state = pn544_dev->p61_current_state; - } -} -static void p61_access_lock(struct pn544_dev *pn544_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_lock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} -static void p61_access_unlock(struct pn544_dev *pn544_dev) -{ - pr_info("%s: Enter\n", __func__); - mutex_unlock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); -} - -static int signal_handler(p61_access_state_t state, long nfc_pid) -{ - struct siginfo sinfo; - pid_t pid; - struct task_struct *task; - int sigret = 0; - int ret = 0; - pr_info("%s: Enter\n", __func__); - - memset(&sinfo, 0, sizeof(struct siginfo)); - sinfo.si_signo = SIG_NFC; - sinfo.si_code = SI_QUEUE; - sinfo.si_int = state; - pid = nfc_pid; - - task = pid_task(find_vpid(pid), PIDTYPE_PID); - if(task) - { - pr_info("%s.\n", task->comm); - sigret = force_sig_info(SIG_NFC, &sinfo, task); - if(sigret < 0){ - pr_info("send_sig_info failed..... sigret %d.\n", sigret); - ret = -1; - } - } - else - { - pr_info("finding task from PID failed\r\n"); - ret = -1; - } - pr_info("%s: Exit ret = %d\n", __func__, ret); - return ret; -} -static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) -{ - int timeout = 100; //100 ms timeout - unsigned long tempJ = msecs_to_jiffies(timeout); - pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); - if(nfc_service_pid) - { - if (0 == signal_handler(origin, nfc_service_pid)) - { - sema_init(&svdd_sync_onoff_sema, 0); - pr_info("Waiting for svdd protection response"); - if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) - { - pr_info("svdd wait protection: Timeout"); - } - pr_info("svdd wait protection : released"); - } - } - pr_info("%s: Exit\n", __func__); -} -static int release_svdd_wait(void) -{ - pr_info("%s: Enter \n", __func__); - up(&svdd_sync_onoff_sema); - pr_info("%s: Exit\n", __func__); - return 0; -} -static int pn544_dev_open(struct inode *inode, struct file *filp) -{ - struct pn544_dev *pn544_dev = container_of(filp->private_data, - struct pn544_dev, - pn544_device); - - filp->private_data = pn544_dev; - - pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); - - return 0; -} - -long pn544_dev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); - - if (cmd == P544_GET_ESE_ACCESS) - { - return get_ese_lock(P61_STATE_WIRED, arg); - } - else if(cmd == P544_REL_SVDD_WAIT) - { - return release_svdd_wait(); - } - p61_access_lock(pn544_dev); - switch (cmd) { - case PN544_SET_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 2) { - if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) - { - /* NFCC fw/download should not be allowed if p61 is used - * by SPI - */ - pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - pn544_dev->nfc_ven_enabled = true; - if (pn544_dev->spi_ven_enabled == false) - { - /* power on with firmware download (requires hw reset) - */ - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - } - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } else if (arg == 1) { - /* power on */ - pr_info("%s power on\n", __func__); - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = true; - if (pn544_dev->spi_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 1); - } - } else if (arg == 0) { - /* power off */ - pr_info("%s power off\n", __func__); - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = false; - /* Don't change Ven state if spi made it high */ - if (pn544_dev->spi_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 0); - } - if (sIsWakeLocked == true) { - wake_unlock(&nfc_wake_lock); - sIsWakeLocked = false; - } - } else { - pr_err("%s bad arg %lu\n", __func__, arg); - /* changed the p61 state to idle*/ - p61_access_unlock(pn544_dev); - return -EINVAL; - } - } - break; - case P61_SET_SPI_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) { - pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - /*To handle triple mode protection signal - NFC service when SPI session started*/ - if ((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) - { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } else { - pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); - if(current_state & P61_STATE_SPI_PRIO){ - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - if (!(current_state & P61_STATE_WIRED)) - { - if((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | - P61_STATE_SPI_PRIO_END); - } - else - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - else if ((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else - { - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - if(current_state & P61_STATE_JCOP_DWNLD) - p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); - pn544_dev->spi_ven_enabled = false; - if (pn544_dev->nfc_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - }else if(current_state & P61_STATE_SPI){ - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - if (!(current_state & P61_STATE_WIRED)) - { - if((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } - else - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - /*If JCOP3.2 or 3.3 for handling triple mode - protection signal NFC service */ - else - { - if ((current_state & P61_STATE_JCOP_DWNLD) == 0) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - } - if(current_state & P61_STATE_JCOP_DWNLD) - p61_update_access_state(pn544_dev, P61_STATE_JCOP_DWNLD, false); - pn544_dev->spi_ven_enabled = false; - if (pn544_dev->nfc_ven_enabled == false) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - } else { - pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - }else if (arg == 2) { - pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); - if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - if (pn544_dev->spi_ven_enabled == false) - { - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - msleep(10); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } else { - pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 3) { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); - //if (current_state & P61_STATE_WIRED) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - }else { - pr_info("%s : Prio Session Start power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 4) { - if (current_state & P61_STATE_SPI_PRIO) - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - /*after SPI prio timeout, the state is changing from SPI prio to SPI */ - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - //if (current_state & P61_STATE_WIRED) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - } - else - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Device or resource busy */ - } - } else if(arg == 5){ - release_ese_lock(P61_STATE_SPI); - } - else { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - - case P61_SET_PWR_STATUS: - { - pr_info("%s: P61_SET_PWR_STATUS = %lx",__func__, arg); - p61_update_access_state(pn544_dev, arg, true); - } - break; - case P61_GET_PWR_STATUS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); - put_user(current_state, (int __user *)arg); - } - break; - case P61_SET_WIRED_ACCESS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) - { - if (current_state) - { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); - if (current_state & P61_STATE_SPI_PRIO) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } - } else { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); - if (current_state & P61_STATE_WIRED){ - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); - } - } else { - pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - } - else if(arg == 2) - { - pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_DWP_SVDD_SYNC_END); - } - else if(arg == 3) - { - pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } - else if(arg == 4) - { - release_ese_lock(P61_STATE_WIRED); - } - else { - pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - case P544_SET_NFC_SERVICE_PID: - { - pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); - pn544_dev->nfc_service_pid = arg; - - } - break; - default: - pr_err("%s bad ioctl %u\n", __func__, cmd); - p61_access_unlock(pn544_dev); - return -EINVAL; - } - p61_access_unlock(pn544_dev); - pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); - return 0; -} -EXPORT_SYMBOL(pn544_dev_ioctl); - -int get_ese_lock(p61_access_state_t p61_current_state, int timeout) -{ - unsigned long tempJ = msecs_to_jiffies(timeout); - if(down_timeout(&ese_access_sema, tempJ) != 0) - { - printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); - return -EBUSY; - } - return 0; -} -EXPORT_SYMBOL(get_ese_lock); - -static void release_ese_lock(p61_access_state_t p61_current_state) -{ - up(&ese_access_sema); -} - - -static const struct file_operations pn544_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = pn544_dev_read, - .write = pn544_dev_write, - .open = pn544_dev_open, - .unlocked_ioctl = pn544_dev_ioctl, -}; -#if DRAGON_NFC -static int pn544_parse_dt(struct device *dev, - struct pn544_i2c_platform_data *data) -{ - struct device_node *np = dev->of_node; - int errorno = 0; - -#if !NEXUS5x - data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); - if ((!gpio_is_valid(data->irq_gpio))) - return -EINVAL; - - data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); - if ((!gpio_is_valid(data->ven_gpio))) - return -EINVAL; - - data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); - if ((!gpio_is_valid(data->firm_gpio))) - return -EINVAL; - - data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); - if ((!gpio_is_valid(data->ese_pwr_gpio))) - return -EINVAL; -#else - data->ven_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_ven", 0, NULL); - data->firm_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_mode", 0, NULL); - data->irq_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_irq", 0, NULL); -#endif - pr_info("%s: %d, %d, %d, %d %d\n", __func__, - data->irq_gpio, data->ven_gpio, data->firm_gpio, data->ese_pwr_gpio, errorno); - - return errorno; -} -#endif - -static int pn544_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - struct pn544_i2c_platform_data *platform_data; - //struct pn544_dev *pn544_dev; - -#if !DRAGON_NFC - platform_data = client->dev.platform_data; -#else - struct device_node *node = client->dev.of_node; - - if (node) { - platform_data = devm_kzalloc(&client->dev, - sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); - if (!platform_data) { - dev_err(&client->dev, - "nfc-nci probe: Failed to allocate memory\n"); - return -ENOMEM; - } - ret = pn544_parse_dt(&client->dev, platform_data); - if (ret) - { - pr_info("%s pn544_parse_dt failed", __func__); - } - client->irq = gpio_to_irq(platform_data->irq_gpio); - if (client->irq < 0) - { - pr_info("%s gpio to irq failed", __func__); - } - } else { - platform_data = client->dev.platform_data; - } -#endif - if (platform_data == NULL) { - pr_err("%s : nfc probe fail\n", __func__); - return -ENODEV; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - return -ENODEV; - } -#if !DRAGON_NFC - ret = gpio_request(platform_data->irq_gpio, "nfc_int"); - if (ret) - return -ENODEV; - ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); - if (ret) - goto err_ven; - ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); - if (ret) - goto err_ese_pwr; - if (platform_data->firm_gpio) { - ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); - if (ret) - goto err_firm; - } -#endif - pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); - if (pn544_dev == NULL) { - dev_err(&client->dev, - "failed to allocate memory for module data\n"); - ret = -ENOMEM; - goto err_exit; - } - - pn544_dev->irq_gpio = platform_data->irq_gpio; - pn544_dev->ven_gpio = platform_data->ven_gpio; - pn544_dev->firm_gpio = platform_data->firm_gpio; - pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; - pn544_dev->p61_current_state = P61_STATE_IDLE; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - pn544_dev->client = client; - - ret = gpio_direction_input(pn544_dev->irq_gpio); - if (ret < 0) { - pr_err("%s :not able to set irq_gpio as input\n", __func__); - goto err_ven; - } - ret = gpio_direction_output(pn544_dev->ven_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_firm; - } - ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); - goto err_ese_pwr; - } - if (platform_data->firm_gpio) { - ret = gpio_direction_output(pn544_dev->firm_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set firm_gpio as output\n", - __func__); - goto err_exit; - } - } - - /* init mutex and queues */ - init_waitqueue_head(&pn544_dev->read_wq); - mutex_init(&pn544_dev->read_mutex); - sema_init(&ese_access_sema, 1); - mutex_init(&pn544_dev->p61_state_mutex); - spin_lock_init(&pn544_dev->irq_enabled_lock); - - pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; - pn544_dev->pn544_device.name = "pn54x"; - pn544_dev->pn544_device.fops = &pn544_dev_fops; - - ret = misc_register(&pn544_dev->pn544_device); - if (ret) { - pr_err("%s : misc_register failed\n", __FILE__); - goto err_misc_register; - } - wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); - - /* request irq. the irq is set whenever the chip has data available - * for reading. it is cleared when all data has been read. - */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - pn544_dev->irq_enabled = true; - ret = request_irq(client->irq, pn544_dev_irq_handler, - IRQF_TRIGGER_HIGH, client->name, pn544_dev); - if (ret) { - dev_err(&client->dev, "request_irq failed\n"); - goto err_request_irq_failed; - } - pr_info("%s : Enabling IRQ Wake\n", __func__); - enable_irq_wake(pn544_dev->client->irq); - pn544_disable_irq(pn544_dev); - i2c_set_clientdata(client, pn544_dev); - - return 0; - - err_request_irq_failed: - misc_deregister(&pn544_dev->pn544_device); - err_misc_register: - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - kfree(pn544_dev); - err_exit: - if (pn544_dev->firm_gpio) - gpio_free(platform_data->firm_gpio); - err_firm: - gpio_free(platform_data->ese_pwr_gpio); - err_ese_pwr: - gpio_free(platform_data->ven_gpio); - err_ven: - gpio_free(platform_data->irq_gpio); - return ret; -} - -static int pn544_remove(struct i2c_client *client) -{ - struct pn544_dev *pn544_dev; - - pn544_dev = i2c_get_clientdata(client); - free_irq(client->irq, pn544_dev); - misc_deregister(&pn544_dev->pn544_device); - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - gpio_free(pn544_dev->irq_gpio); - gpio_free(pn544_dev->ven_gpio); - gpio_free(pn544_dev->ese_pwr_gpio); - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - - if (pn544_dev->firm_gpio) - gpio_free(pn544_dev->firm_gpio); - kfree(pn544_dev); - - return 0; -} - -static const struct i2c_device_id pn544_id[] = { -#if NEXUS5x - { "pn548", 0 }, -#else - { "pn544", 0 }, -#endif - { } -}; -#if DRAGON_NFC -static struct of_device_id pn544_i2c_dt_match[] = { - { -#if NEXUS5x - .compatible = "nxp,pn548", -#else - .compatible = "nxp,pn544", -#endif - }, - {} -}; -#endif -static struct i2c_driver pn544_driver = { - .id_table = pn544_id, - .probe = pn544_probe, - .remove = pn544_remove, - .driver = { - .owner = THIS_MODULE, -#if NEXUS5x - .name = "pn548", -#else - .name = "pn544", -#endif -#if DRAGON_NFC - .of_match_table = pn544_i2c_dt_match, -#endif - }, -}; - -/* - * module load/unload record keeping - */ - -static int __init pn544_dev_init(void) -{ - pr_info("Loading pn544 driver\n"); - return i2c_add_driver(&pn544_driver); -} -module_init(pn544_dev_init); - -static void __exit pn544_dev_exit(void) -{ - pr_info("Unloading pn544 driver\n"); - i2c_del_driver(&pn544_driver); -} -module_exit(pn544_dev_exit); - -MODULE_AUTHOR("Sylvain Fonteneau"); -MODULE_DESCRIPTION("NFC PN544 driver"); -MODULE_LICENSE("GPL"); diff --git a/pn6xT/pn54x-i2c/pn54x.h b/pn6xT/pn54x-i2c/pn54x.h deleted file mode 100644 index 29cba731f4..0000000000 --- a/pn6xT/pn54x-i2c/pn54x.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/****************************************************************************** - * - * The original Work has been changed by NXP Semiconductors. - * - * Copyright (C) 2013-2014 NXP Semiconductors - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#define PN544_MAGIC 0xE9 - -/* - * PN544 power control via ioctl - * PN544_SET_PWR(0): power off - * PN544_SET_PWR(1): power on - * PN544_SET_PWR(2): reset and power on with firmware download enabled - */ -#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, long) - -/* - * SPI Request NFCC to enable p61 power, only in param - * Only for SPI - * level 1 = Enable power - * level 0 = Disable power - */ -#define P61_SET_SPI_PWR _IOW(PN544_MAGIC, 0x02, long) - -/* SPI or DWP can call this ioctl to get the current - * power state of P61 - * -*/ -#define P61_GET_PWR_STATUS _IOR(PN544_MAGIC, 0x03, long) - -/* DWP side this ioctl will be called - * level 1 = Wired access is enabled/ongoing - * level 0 = Wired access is disalbed/stopped -*/ -#define P61_SET_WIRED_ACCESS _IOW(PN544_MAGIC, 0x04, long) - -/* - NFC Init will call the ioctl to register the PID with the i2c driver -*/ -#define P544_SET_NFC_SERVICE_PID _IOW(PN544_MAGIC, 0x05, long) - -/* - NFC and SPI will call the ioctl to get the i2c/spi bus access -*/ -#define P544_GET_ESE_ACCESS _IOW(PN544_MAGIC, 0x06, long) - -/* - NFC will call the ioctl to release the svdd protection -*/ -#define P544_REL_SVDD_WAIT _IOW(PN544_MAGIC, 0x08, long) - -/* SPI or DWP can call this ioctl to set the current - * power state of P61 - * -*/ -#define P61_SET_PWR_STATUS _IOR(PN544_MAGIC, 0x09, long) - -typedef enum p61_access_state{ - P61_STATE_INVALID = 0x0000, - P61_STATE_IDLE = 0x0100, /* p61 is free to use */ - P61_STATE_WIRED = 0x0200, /* p61 is being accessed by DWP (NFCC)*/ - P61_STATE_SPI = 0x0400, /* P61 is being accessed by SPI */ - P61_STATE_DWNLD = 0x0800, /* NFCC fw download is in progress */ - P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ - P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ - P61_STATE_SPI_END = 0x4000, - P61_STATE_JCOP_DWNLD = 0x8000, /* Jcop download is in progress */ - P61_STATE_SPI_SVDD_SYNC_START = 0x0001, /*ESE_VDD Low req by SPI*/ - P61_STATE_SPI_SVDD_SYNC_END = 0x0002, /*ESE_VDD is Low by SPI*/ - P61_STATE_DWP_SVDD_SYNC_START = 0x0004, /*ESE_VDD Low req by Nfc*/ - P61_STATE_DWP_SVDD_SYNC_END = 0x0008, /*ESE_VDD is Low by Nfc*/ -}p61_access_state_t; - - -struct pn544_i2c_platform_data { - unsigned int irq_gpio; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ -}; From c3ae8c8934cc877faae5dac818632786614c9169 Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Thu, 5 Apr 2018 15:32:57 +0530 Subject: [PATCH 026/100] MW recovery for FW download teardown. --- pn553-i2c/pn553.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c index ccf5876699..e2354b08ea 100644 --- a/pn553-i2c/pn553.c +++ b/pn553-i2c/pn553.c @@ -479,21 +479,18 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, /* power on with firmware download (requires hw reset) */ pr_info("%s power on with firmware\n", __func__); - #ifndef VEN_ALWAYS_ON gpio_set_value(pn544_dev->ven_gpio, 1); msleep(10); - #endif if (pn544_dev->firm_gpio) { p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); gpio_set_value(pn544_dev->firm_gpio, 1); } - #ifndef VEN_ALWAYS_ON + msleep(10); gpio_set_value(pn544_dev->ven_gpio, 0); msleep(10); gpio_set_value(pn544_dev->ven_gpio, 1); msleep(10); - #endif } } else if (arg == 1) { /* power on */ From 84b84f3d83ae77598754302ac7c0f5d13845275a Mon Sep 17 00:00:00 2001 From: nxpandroid Date: Fri, 29 Jun 2018 13:15:59 +0530 Subject: [PATCH 027/100] NFC_NCIHALx_AR2000.09.00.08_RC1 --- pn553-i2c/pn553.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c index e2354b08ea..2f62da7ab4 100644 --- a/pn553-i2c/pn553.c +++ b/pn553-i2c/pn553.c @@ -1371,6 +1371,10 @@ static int pn544_probe(struct i2c_client *client, pn544_disable_irq(pn544_dev); i2c_set_clientdata(client, pn544_dev); #ifdef VEN_ALWAYS_ON + msleep(5); /* VBAT--> VDDIO(HIGH) + Guardtime of min 5ms --> VEN(HIGH) */ + /* VEN toggle(reset) to proceed */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(3); gpio_set_value(pn544_dev->ven_gpio, 0); msleep(3); gpio_set_value(pn544_dev->ven_gpio, 1); From 4c9c334d17005710a9f7730c5e492545d06249bc Mon Sep 17 00:00:00 2001 From: nxf24591 Date: Thu, 2 Aug 2018 12:29:04 +0530 Subject: [PATCH 028/100] NFC_NCIHALx_AR2000.09.00.0A --- pn553-i2c/pn553.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c index 2f62da7ab4..c7bbecdf15 100644 --- a/pn553-i2c/pn553.c +++ b/pn553-i2c/pn553.c @@ -562,8 +562,14 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, gpio_set_value(pn544_dev->firm_gpio, 1); msleep(10); } - } - else { + } else if (arg == 5) { + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + pr_info("%s VEN reset DONE >>>>>>>\n", __func__); + } else { pr_err("%s bad arg %lu\n", __func__, arg); /* changed the p61 state to idle*/ p61_access_unlock(pn544_dev); From eefe9254485e0ba7c5284dfe9edc396357a1b1e1 Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Mon, 22 Oct 2018 19:15:16 +0530 Subject: [PATCH 029/100] NFC_NCIHALx_AR2000.09.00.11_OpnSrc --- pn553-i2c/pn553.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c index c7bbecdf15..76032c1d61 100644 --- a/pn553-i2c/pn553.c +++ b/pn553-i2c/pn553.c @@ -569,7 +569,12 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, gpio_set_value(pn544_dev->ven_gpio, 1); msleep(10); pr_info("%s VEN reset DONE >>>>>>>\n", __func__); - } else { + } else if (arg == 6) { + if (pn544_dev->firm_gpio) { + gpio_set_value(pn544_dev->firm_gpio, 0); + } + pr_info("%s FW GPIO set to 0x00 >>>>>>>\n", __func__); + }else { pr_err("%s bad arg %lu\n", __func__, arg); /* changed the p61 state to idle*/ p61_access_unlock(pn544_dev); From 2910eb586b36e0c847cddfde0a8588781208c903 Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Mon, 5 Nov 2018 16:28:48 +0530 Subject: [PATCH 030/100] NFC_NCIHALx_AR2000.09.00.13_OpnSrc --- pn553-i2c/pn553.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c index 76032c1d61..af7df3fa5d 100644 --- a/pn553-i2c/pn553.c +++ b/pn553-i2c/pn553.c @@ -1384,10 +1384,8 @@ static int pn544_probe(struct i2c_client *client, #ifdef VEN_ALWAYS_ON msleep(5); /* VBAT--> VDDIO(HIGH) + Guardtime of min 5ms --> VEN(HIGH) */ /* VEN toggle(reset) to proceed */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(3); gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(3); + msleep(5); gpio_set_value(pn544_dev->ven_gpio, 1); #endif From 2a22a0e8e33b07532d0b358c2ba4587e0a359210 Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Fri, 24 May 2019 17:09:11 +0530 Subject: [PATCH 031/100] Updated corresponding to - NFC_AR_00_6000_10.00.06_OpnSrc --- pn553-i2c/pn553.c | 132 +++++++++++++++++++++++++++++++++++++++++----- pn553-i2c/pn553.h | 13 +++++ 2 files changed, 131 insertions(+), 14 deletions(-) diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c index af7df3fa5d..3605fb8034 100644 --- a/pn553-i2c/pn553.c +++ b/pn553-i2c/pn553.c @@ -20,7 +20,7 @@ * * The original Work has been changed by NXP Semiconductors. * - * Copyright (C) 2013-2014 NXP Semiconductors + * Copyright (C) 2013-2019 NXP Semiconductors * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -81,6 +81,10 @@ #define SIG_NFC 44 #define MAX_BUFFER_SIZE 512 #define MAX_SECURE_SESSIONS 1 +#define MSG_PROP_GID 0x4F +#define ESE_CLD_RST_OID 0x1E +#define ESE_CLD_RST_RSP_SIZE 0x04 + /* VEN is kept ON all the time if you define the macro VEN_ALWAYS_ON. Used for SN100 usecases */ #define VEN_ALWAYS_ON @@ -110,6 +114,18 @@ struct pn544_dev { unsigned int secure_timer_cnt; struct workqueue_struct *pSecureTimerCbWq; struct work_struct wq_task; + /* Bit value Status Remark + * b0 : 1 -> NFC_ON Driver Open should set the flag + * 0 NFC_OFF Driver release should reset this flag + * b1 : 1 -> FWDNLD If FWDNLD is going on. + * 0 Normal operation + * b2 : 1 -> ese_cold_reset sequence has been triggered from the SPI driver + * 0 -> ese_cold_reset cmd has been written by the NFC HAL + * bits b3 to b7 : Reserved for the future use. + * NOTE: Driver probe function should reset b0-b2 flags. + * The value of b3-b7 flags is undetermined. + * */ + volatile uint8_t state_flags; }; /* HiKey Compilation fix */ #ifndef HiKey_620_COMPILATION_FIX @@ -123,6 +139,8 @@ static struct pn544_dev *pn544_dev; static struct semaphore ese_access_sema; static struct semaphore svdd_sync_onoff_sema; static struct completion dwp_onoff_sema; +static struct completion ese_cold_reset_sema; +static int8_t ese_cold_reset_rsp[ESE_CLD_RST_RSP_SIZE]; static struct timer_list secure_timer; static void release_ese_lock(p61_access_state_t p61_current_state); int get_ese_lock(p61_access_state_t p61_current_state, int timeout); @@ -147,6 +165,11 @@ static void pn544_disable_irq(struct pn544_dev *pn544_dev) spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); } +static int pn544_dev_release(struct inode *inode, struct file *filp) { + pn544_dev->state_flags = 0x00; + pr_info(KERN_ALERT "Exit %s: NFC driver release \n", __func__); + return 0; +} static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) { struct pn544_dev *pn544_dev = dev_id; @@ -169,6 +192,26 @@ static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static void rcv_ese_cldrst_status(void) +{ + int ret = -1; + char tmp[MAX_BUFFER_SIZE]; + size_t rcount = (size_t)ese_cold_reset_rsp[2]; + /* Read data: No need to wait for the interrupt */ + ret = i2c_master_recv(pn544_dev->client, tmp, rcount); + if(ret == rcount){ + ese_cold_reset_rsp[3] = tmp[0]; + pr_info("%s NxpNciR : len = 4 > %02X%02X%02X%02X\n", __func__,ese_cold_reset_rsp[0], + ese_cold_reset_rsp[1],ese_cold_reset_rsp[2],ese_cold_reset_rsp[3]); + }else{ + pr_err("%s : Failed to receive payload of the cold_rst_cmd\n",__func__); + ese_cold_reset_rsp[3] = -EIO; + } + if(pn544_dev->state_flags &(P544_FLAG_NFC_ON)){ + complete(&ese_cold_reset_sema); + } +} + static ssize_t pn544_dev_read(struct file *filp, char __user *buf, size_t count, loff_t *offset) { @@ -218,6 +261,17 @@ static ssize_t pn544_dev_read(struct file *filp, char __user *buf, sIsWakeLocked = false; } #endif + + /* if the received response for COLD_RESET_COMMAND + * Consume it in driver*/ + if((pn544_dev->state_flags & P544_FLAG_ESE_COLD_RESET_FROM_DRIVER) && + MSG_PROP_GID == tmp[0] && ESE_CLD_RST_OID == tmp[1]){ + memset(&ese_cold_reset_rsp, 0, sizeof(ese_cold_reset_rsp)); + memcpy(ese_cold_reset_rsp, tmp, 3); + rcv_ese_cldrst_status(); + mutex_unlock(&pn544_dev->read_mutex); + return 0; + } mutex_unlock(&pn544_dev->read_mutex); /* pn544 seems to be slow in handling I2C read requests @@ -270,7 +324,6 @@ static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, pr_err("%s : i2c_master_send returned %d\n", __func__, ret); ret = -EIO; } - /* pn544 seems to be slow in handling I2C write requests * so add 1ms delay after I2C send oparation */ udelay(1000); @@ -309,17 +362,71 @@ static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t } static void p61_access_lock(struct pn544_dev *pn544_dev) { - pr_info("%s: Enter\n", __func__); mutex_lock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); } static void p61_access_unlock(struct pn544_dev *pn544_dev) { - pr_info("%s: Enter\n", __func__); mutex_unlock(&pn544_dev->p61_state_mutex); - pr_info("%s: Exit\n", __func__); } +long p61_cold_reset(void) +{ + long ret = 0; + unsigned int loop=0x03; + struct file filp; + int timeout = 2000; /* 2s timeout :NCI cmd timeout*/ + unsigned long tempJ = msecs_to_jiffies(timeout); + uint8_t cmd_ese_cold_reset[] = {0x2F, 0x1E, 0x00}; + filp.private_data = pn544_dev; + pr_info("%s: Enter", __func__); + + if(pn544_dev->state_flags & P544_FLAG_FW_DNLD){ + /* If FW DNLD, Operation is not permitted */ + pr_err("%s : Operation is not permitted during fwdnld\n", __func__); + return -EPERM; + } + /* pn544_dev_read() should return the rsp if JNI has requested the cold reset*/ + pn544_dev->state_flags |= (P544_FLAG_ESE_COLD_RESET_FROM_DRIVER); + init_completion(&ese_cold_reset_sema); + /* write command to I2C line*/ + do{ + ret = i2c_master_send(pn544_dev->client, cmd_ese_cold_reset, sizeof(cmd_ese_cold_reset)); + if (ret == sizeof(cmd_ese_cold_reset)) { + break; + } + loop--; + usleep_range(5000, 6000); + }while(loop); + if(!loop && (ret != sizeof(cmd_ese_cold_reset)) ){ + pr_err("%s : i2c_master_send returned %ld\n", __func__, ret); + pn544_dev->state_flags &= ~(P544_FLAG_ESE_COLD_RESET_FROM_DRIVER); + return -EIO; + } + + pr_info("%s: NxpNciX: %ld > %02X%02X%02X \n", __func__, ret,cmd_ese_cold_reset[0], + cmd_ese_cold_reset[1],cmd_ese_cold_reset[2]); + ret = 0x00; + if(pn544_dev->state_flags & P544_FLAG_NFC_ON)/* NFC_ON */ + { + /* Read is pending from the NFC service which will complete the ese_cold_reset_sema */ + if(wait_for_completion_timeout(&ese_cold_reset_sema, tempJ) == 0){ + pr_err("%s: Timeout", __func__); + ese_cold_reset_rsp[3] = -EAGAIN; // Failure case + } + }else { /* NFC_OFF */ + /* call the pn544_dev_read() */ + filp.f_flags &= ~O_NONBLOCK; + ret = pn544_dev_read(&filp, NULL,3, 0); + } + if(0x00 == ret) /* success case */ + ret = ese_cold_reset_rsp[3]; + pn544_dev->state_flags &= ~(P544_FLAG_ESE_COLD_RESET_FROM_DRIVER); + /* Return the status to the SPI Driver */ + pr_info("%s: exit, Status:%ld", __func__,ret); + return ret; +} +EXPORT_SYMBOL(p61_cold_reset); + static int signal_handler(p61_access_state_t state, long nfc_pid) { struct siginfo sinfo; @@ -377,13 +484,11 @@ static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) pr_info("svdd wait protection : released"); } } - pr_info("%s: Exit\n", __func__); } static int release_svdd_wait(void) { pr_info("%s: Enter \n", __func__); up(&svdd_sync_onoff_sema); - pr_info("%s: Exit\n", __func__); return 0; } @@ -418,7 +523,7 @@ static int pn544_dev_open(struct inode *inode, struct file *filp) pn544_device); filp->private_data = pn544_dev; - + pn544_dev->state_flags |= (P544_FLAG_NFC_ON); pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); return 0; @@ -434,8 +539,6 @@ static int set_nfc_pid(unsigned long arg) long pn544_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); - /* Free pass autobahn area, not protected. Use it carefullly. START */ switch(cmd) { @@ -494,7 +597,6 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } } else if (arg == 1) { /* power on */ - pr_info("%s power on\n", __func__); if (pn544_dev->firm_gpio) { if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); @@ -513,7 +615,6 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, #endif } else if (arg == 0) { /* power off */ - pr_info("%s power off\n", __func__); if (pn544_dev->firm_gpio) { if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); @@ -560,6 +661,7 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, if (pn544_dev->firm_gpio) { p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); gpio_set_value(pn544_dev->firm_gpio, 1); + pn544_dev->state_flags |= (P544_FLAG_FW_DNLD); msleep(10); } } else if (arg == 5) { @@ -572,6 +674,7 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, } else if (arg == 6) { if (pn544_dev->firm_gpio) { gpio_set_value(pn544_dev->firm_gpio, 0); + pn544_dev->state_flags &= ~(P544_FLAG_FW_DNLD); } pr_info("%s FW GPIO set to 0x00 >>>>>>>\n", __func__); }else { @@ -993,7 +1096,6 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, return -EINVAL; } p61_access_unlock(pn544_dev); - pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); return 0; } EXPORT_SYMBOL(pn544_dev_ioctl); @@ -1172,6 +1274,7 @@ static const struct file_operations pn544_dev_fops = { .read = pn544_dev_read, .write = pn544_dev_write, .open = pn544_dev_open, + .release = pn544_dev_release, .unlocked_ioctl = pn544_dev_ioctl, }; #if DRAGON_NFC @@ -1304,6 +1407,7 @@ static int pn544_probe(struct i2c_client *client, pn544_dev->client = client; pn544_dev->secure_timer_cnt = 0; + pn544_dev->state_flags = 0x00; ret = gpio_direction_input(pn544_dev->irq_gpio); if (ret < 0) { pr_err("%s :not able to set irq_gpio as input\n", __func__); diff --git a/pn553-i2c/pn553.h b/pn553-i2c/pn553.h index 296f3cda91..a77e6d6d5c 100644 --- a/pn553-i2c/pn553.h +++ b/pn553-i2c/pn553.h @@ -105,6 +105,19 @@ #define MAX_ESE_ACCESS_TIME_OUT_MS 200 /*100 milliseconds*/ +/* + NFC_ON: Driver is being used by the NFC service +*/ +#define P544_FLAG_NFC_ON 0x01 +/* + FW_DNLD: NFC_ON and FW download is going on +*/ +#define P544_FLAG_FW_DNLD 0x02 +/* + FW_DNLD: NFC_ON and FW download is going on +*/ +#define P544_FLAG_ESE_COLD_RESET_FROM_DRIVER 0x04 + typedef enum p61_access_state{ P61_STATE_INVALID = 0x0000, P61_STATE_IDLE = 0x0100, /* p61 is free to use */ From a90c2f8052383ed1ce92faab743310d8a0c63097 Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Fri, 28 Jun 2019 15:49:31 +0530 Subject: [PATCH 032/100] Updated corresponding to - NFC_AR_00_6000_10.00.08_OpnSrc --- pn553-i2c/pn553.c | 14 ++++++++++++-- pn553-i2c/pn553.h | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c index 3605fb8034..7fc6958103 100644 --- a/pn553-i2c/pn553.c +++ b/pn553-i2c/pn553.c @@ -167,7 +167,9 @@ static void pn544_disable_irq(struct pn544_dev *pn544_dev) static int pn544_dev_release(struct inode *inode, struct file *filp) { pn544_dev->state_flags = 0x00; - pr_info(KERN_ALERT "Exit %s: NFC driver release \n", __func__); + if (pn544_dev->firm_gpio) + gpio_set_value(pn544_dev->firm_gpio, 0); + pr_info(KERN_ALERT "Exit %s: NFC driver release nfc hal \n", __func__); return 0; } static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) @@ -244,7 +246,12 @@ static ssize_t pn544_dev_read(struct file *filp, char __user *buf, if (ret) goto fail; - + if(pn544_dev->state_flags & P544_FLAG_NFC_VEN_RESET) { + pr_warning("%s: releasing read \n", __func__); + pn544_dev->state_flags &= ~P544_FLAG_NFC_VEN_RESET; + ret = -EL3RST; + goto fail; + } if (gpio_get_value(pn544_dev->irq_gpio)) break; @@ -665,6 +672,9 @@ long pn544_dev_ioctl(struct file *filp, unsigned int cmd, msleep(10); } } else if (arg == 5) { + pn544_dev->state_flags |= P544_FLAG_NFC_VEN_RESET; + pn544_disable_irq(pn544_dev); + wake_up(&pn544_dev->read_wq); msleep(10); gpio_set_value(pn544_dev->ven_gpio, 0); msleep(10); diff --git a/pn553-i2c/pn553.h b/pn553-i2c/pn553.h index a77e6d6d5c..ccc2830bc3 100644 --- a/pn553-i2c/pn553.h +++ b/pn553-i2c/pn553.h @@ -117,6 +117,10 @@ FW_DNLD: NFC_ON and FW download is going on */ #define P544_FLAG_ESE_COLD_RESET_FROM_DRIVER 0x04 +/* + FW_DNLD: NFC_ON and FW download with VEN reset +*/ +#define P544_FLAG_NFC_VEN_RESET 0x08 typedef enum p61_access_state{ P61_STATE_INVALID = 0x0000, From cb2bb40fc5c35011c33c15e5736e7f059c2aea37 Mon Sep 17 00:00:00 2001 From: Nanjesh Date: Fri, 28 Feb 2020 19:06:57 +0530 Subject: [PATCH 033/100] Updated corresponding to - NFC_AR_00_6000_11.01.00_OpnSrc --- nfc/Kconfig | 29 + nfc/Makefile | 11 + nfc/cold_reset.h | 28 + nfc/common.c | 667 +++++++++++++++++ nfc/common.h | 229 ++++++ nfc/i2c_drv.c | 465 ++++++++++++ nfc/i2c_drv.h | 47 ++ nfc/i3c_drv.c | 766 +++++++++++++++++++ nfc/i3c_drv.h | 109 +++ nfc/sn110.c | 38 + nfc/sn110.h | 23 + pn553-i2c/Kconfig | 13 - pn553-i2c/Makefile | 8 - pn553-i2c/pn553.c | 1734 -------------------------------------------- pn553-i2c/pn553.h | 181 ----- 15 files changed, 2412 insertions(+), 1936 deletions(-) create mode 100644 nfc/Kconfig create mode 100644 nfc/Makefile create mode 100644 nfc/cold_reset.h create mode 100644 nfc/common.c create mode 100644 nfc/common.h create mode 100644 nfc/i2c_drv.c create mode 100644 nfc/i2c_drv.h create mode 100644 nfc/i3c_drv.c create mode 100644 nfc/i3c_drv.h create mode 100644 nfc/sn110.c create mode 100644 nfc/sn110.h delete mode 100644 pn553-i2c/Kconfig delete mode 100644 pn553-i2c/Makefile delete mode 100644 pn553-i2c/pn553.c delete mode 100644 pn553-i2c/pn553.h diff --git a/nfc/Kconfig b/nfc/Kconfig new file mode 100644 index 0000000000..f87a2b7818 --- /dev/null +++ b/nfc/Kconfig @@ -0,0 +1,29 @@ +# +# near field communication configuration +# + +config NXP_NFC_I2C + tristate "NFC on I2C Interface" + depends on I2C + ---help--- + This selects Near field controller on I2C Interface. + + If you want NFC support, you should say Y here and + also to your specific host controller driver. + +config NXP_NFC_I3C + tristate "NFC on I3C Interface" + depends on I3C + ---help--- + This selects Near field controller on I3C Interface. + + If you want NFC support, you should say Y here and + also to your specific host controller driver. + +config NXP_NFC_SN110 + bool "Nxp NFC sn110 Controller" + ---help--- + You'll have to say Y if your computer contains an sn110 i2C device that + you want to use under Linux. + + You can say N here if you don't have any sn110 I2C connected to your computer. diff --git a/nfc/Makefile b/nfc/Makefile new file mode 100644 index 0000000000..8dc087ee68 --- /dev/null +++ b/nfc/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for nfc devices +# +ifdef CONFIG_NXP_NFC_I2C +obj-y += common.o +else ifdef CONFIG_NXP_NFC_I3C +obj-y += common.o +endif +obj-$(CONFIG_NXP_NFC_I2C) += i2c_drv.o +obj-$(CONFIG_NXP_NFC_I3C) += i3c_drv.o +obj-$(CONFIG_NXP_NFC_SN110) += sn110.o diff --git a/nfc/cold_reset.h b/nfc/cold_reset.h new file mode 100644 index 0000000000..35afe748dc --- /dev/null +++ b/nfc/cold_reset.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (C) 2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#ifndef _NFC_COLD_RESET_H_ +#define _NFC_COLD_RESET_H_ + +typedef enum ese_cold_reset_origin { + ESE_COLD_RESET_SOURCE_SPI, + ESE_COLD_RESET_SOURCE_UWB, +} ese_cold_reset_origin_t; + +#endif /* NFC_COLD_RESET_H_ */ diff --git a/nfc/common.c b/nfc/common.c new file mode 100644 index 0000000000..6c3f5c2a80 --- /dev/null +++ b/nfc/common.c @@ -0,0 +1,667 @@ +/****************************************************************************** + * Copyright (C) 2019-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#include +#include +#include +#include "../nfc/cold_reset.h" +#include "common.h" + +nfc_dev_t *nfc_dev_platform = NULL; + +int nfc_parse_dt(struct device *dev, platform_gpio_t *nfc_gpio, + uint8_t interface) +{ + struct device_node *np = dev->of_node; + + if (!np) { + pr_err("nfc of_node NULL\n"); + return -EINVAL; + } + //required for i2c based chips only + if (interface == PLATFORM_IF_I2C) { + nfc_gpio->irq = of_get_named_gpio(np, DTS_IRQ_GPIO_STR, 0); + if ((!gpio_is_valid(nfc_gpio->irq))) { + pr_err("nfc irq gpio invalid %d\n", nfc_gpio->irq); + return -EINVAL; + } + pr_info("%s: irq %d\n", __func__, nfc_gpio->irq); + } + nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); + if ((!gpio_is_valid(nfc_gpio->ven))) { + pr_err("nfc ven gpio invalid %d\n", nfc_gpio->ven); + return -EINVAL; + } + + nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); + if ((!gpio_is_valid(nfc_gpio->dwl_req))) { + pr_err("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req); + return -EINVAL; + } + //required for old platform only + nfc_gpio->ese_pwr = of_get_named_gpio(np, DTS_ESE_GPIO_STR, 0); + if ((!gpio_is_valid(nfc_gpio->ese_pwr))) { + pr_err("nfc ese_pwr gpio invalid %d\n", nfc_gpio->ese_pwr); + nfc_gpio->ese_pwr = -EINVAL; + } + + pr_info("%s: %d, %d, %d, %d\n", __func__, + nfc_gpio->irq, nfc_gpio->ven, nfc_gpio->dwl_req, + nfc_gpio->ese_pwr); + return 0; +} + +void gpio_set_ven(nfc_dev_t *nfc_dev, int value) +{ + if (nfc_dev->ven_policy == VEN_ALWAYS_ENABLED) { + value |= 1; + } + if (gpio_get_value(nfc_dev->gpio.ven) != value) { + gpio_set_value(nfc_dev->gpio.ven, value); + /* hardware dependent delay */ + usleep_range(10000, 10100); + } +} + +int configure_gpio(unsigned int gpio, int flag) +{ + int ret; + pr_debug("%s: nfc gpio [%d] flag [%01x]\n", __func__, gpio, flag); + if (gpio_is_valid(gpio)) { + ret = gpio_request(gpio, "nfc_gpio"); + if (ret) { + pr_err("%s: unable to request nfc gpio [%d]\n", + __func__, gpio); + return ret; + } + /*set direction and value for output pin */ + if (flag & GPIO_OUTPUT) + ret = gpio_direction_output(gpio, (GPIO_HIGH & flag)); + else + ret = gpio_direction_input(gpio); + + if (ret) { + pr_err + ("%s: unable to set direction for nfc gpio [%d]\n", + __func__, gpio); + gpio_free(gpio); + return ret; + } + /*Consider value as control for input IRQ pin */ + if (flag & GPIO_IRQ) { + ret = gpio_to_irq(gpio); + if (ret < 0) { + pr_err + ("%s: unable to set irq for nfc gpio [%d]\n", + __func__, gpio); + gpio_free(gpio); + return ret; + } + pr_debug + ("%s: gpio_to_irq successful [%d]\n", + __func__, gpio); + return ret; + } + } else { + pr_err("%s: invalid gpio\n", __func__); + ret = -EINVAL; + } + return ret; +} + +void gpio_free_all(nfc_dev_t *nfc_dev) +{ + if (gpio_is_valid(nfc_dev->gpio.ese_pwr)) { + gpio_free(nfc_dev->gpio.ese_pwr); + } + if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { + gpio_free(nfc_dev->gpio.dwl_req); + } + if (gpio_is_valid(nfc_dev->gpio.irq)) { + gpio_free(nfc_dev->gpio.irq); + } + if (gpio_is_valid(nfc_dev->gpio.ven)) { + gpio_free(nfc_dev->gpio.ven); + } +} + +void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count) +{ + pr_debug("%s: entry\n", __func__); + device_destroy(nfc_dev->nfc_class, nfc_dev->devno); + cdev_del(&nfc_dev->c_dev); + class_destroy(nfc_dev->nfc_class); + unregister_chrdev_region(nfc_dev->devno, count); +} + +int nfc_misc_register(nfc_dev_t *nfc_dev, + const struct file_operations *nfc_fops, + int count, char *devname, char *classname) +{ + int ret = 0; + ret = alloc_chrdev_region(&nfc_dev->devno, 0, count, devname); + if (ret < 0) { + pr_err("%s: failed to alloc chrdev region ret %d\n", + __func__, ret); + return ret; + } + nfc_dev->nfc_class = class_create(THIS_MODULE, classname); + if (IS_ERR(nfc_dev->nfc_class)) { + ret = PTR_ERR(nfc_dev->nfc_class); + pr_err("%s: failed to register device class ret %d\n", + __func__, ret); + unregister_chrdev_region(nfc_dev->devno, count); + return ret; + } + cdev_init(&nfc_dev->c_dev, nfc_fops); + ret = cdev_add(&nfc_dev->c_dev, nfc_dev->devno, count); + if (ret < 0) { + pr_err("%s: failed to add cdev ret %d\n", __func__, ret); + class_destroy(nfc_dev->nfc_class); + unregister_chrdev_region(nfc_dev->devno, count); + return ret; + } + nfc_dev->nfc_device = device_create(nfc_dev->nfc_class, NULL, + nfc_dev->devno, nfc_dev, devname); + if (IS_ERR(nfc_dev->nfc_device)) { + ret = PTR_ERR(nfc_dev->nfc_device); + pr_err("%s: failed to create the device ret %d\n", + __func__, ret); + cdev_del(&nfc_dev->c_dev); + class_destroy(nfc_dev->nfc_class); + unregister_chrdev_region(nfc_dev->devno, count); + return ret; + } + return 0; +} + +static void enable_interrupt(nfc_dev_t *nfc_dev) +{ + if (nfc_dev->interface == PLATFORM_IF_I2C) + i2c_enable_irq(&nfc_dev->i2c_dev); + else { +#ifdef CONFIG_NXP_NFC_I3C + i3c_enable_ibi(&nfc_dev->i3c_dev); +#endif //CONFIG_NXP_NFC_I3C + } +} + +static void disable_interrupt(nfc_dev_t *nfc_dev) +{ + if (nfc_dev->interface == PLATFORM_IF_I2C) + i2c_disable_irq(&nfc_dev->i2c_dev); + else { +#ifdef CONFIG_NXP_NFC_I3C + i3c_disable_ibi(&nfc_dev->i3c_dev); +#endif //CONFIG_NXP_NFC_I3C + } +} + +static int send_cold_reset_cmd(nfc_dev_t *nfc_dev) +{ + int ret = 0; + char cmd[COLD_RESET_CMD_LEN]; + + cmd[0] = COLD_RESET_CMD_GID; + cmd[1] = COLD_RESET_OID; + cmd[2] = COLD_RESET_CMD_PAYLOAD_LEN; + if (nfc_dev->interface == PLATFORM_IF_I2C) { + ret = i2c_write(&nfc_dev->i2c_dev, cmd, + COLD_RESET_CMD_LEN, MAX_RETRY_COUNT); + } else { + //TODO: Handling Cold reset for I3C + //ret = i3c_write(nfc_dev->i3c_dev, cmd, COLD_RESET_CMD_LEN); + } + if (ret != COLD_RESET_CMD_LEN) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + nfc_dev->cold_reset.timer_started = false; + return -EIO; + } + pr_info("%s: NxpNciX: %d > %02X%02X%02X \n", __func__, ret, cmd[0], + cmd[1], cmd[2]); + return ret; +} + +void read_cold_reset_rsp(nfc_dev_t *nfc_dev, char *buf) +{ + int ret = -1; + char rsp[COLD_RESET_RSP_LEN]; + i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + cold_reset_t *cold_reset = &nfc_dev->cold_reset; + cold_reset->status = -EIO; + /* + * read header also if NFC is disabled + * for enable case, will be taken care by nfc read thread + */ + if (!cold_reset->nfc_enabled) { + if (nfc_dev->interface == PLATFORM_IF_I2C) { + ret = i2c_read(i2c_dev, rsp, NCI_HDR_LEN); + } else { + //TODO: Handling Cold reset for I3C + //ret = i3c_read(i3c_dev, rsp, NCI_HDR_LEN); + } + if (ret != NCI_HDR_LEN) { + pr_err("%s: failure to read cold reset rsp header\n", + __func__); + return; + } + } else { + memcpy(rsp, buf, NCI_HDR_LEN); + } + if ((NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_OFFSET]) != COLD_RESET_RSP_LEN) { + pr_err("%s: - invalid response for cold_reset\n", __func__); + return; + } + if (nfc_dev->interface == PLATFORM_IF_I2C) { + ret = i2c_read(i2c_dev, &rsp[NCI_PAYLOAD_IDX], rsp[2]); + } else { + //TODO:Handling Cold Reset for I3C + //ret = i3c_read(nfc_dev->i3c_dev, &rsp[NCI_PAYLOAD_IDX], rsp[2]); + } + if (ret != rsp[2]) { + pr_err("%s: failure to read cold reset rsp header\n", __func__); + return; + } + pr_info("%s NxpNciR : len = 4 > %02X%02X%02X%02X\n", __func__, rsp[0], + rsp[1], rsp[2], rsp[3]); + cold_reset->status = rsp[NCI_PAYLOAD_IDX]; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) +static void ese_cold_reset_gaurd_timer_callback(unsigned long data) +{ + (void)data; +#else +static void ese_cold_reset_gaurd_timer_callback(struct timer_list *unused) +{ +#endif + pr_info("%s: Enter\n",__func__); + nfc_dev_platform->cold_reset.timer_started = false; + return; +} + +static long start_ese_cold_reset_guard_timer(void) +{ + long ret = -EINVAL; + if (timer_pending(&nfc_dev_platform->cold_reset.timer) == 1) { + pr_info("ese_cold_reset_guard_timer: delete pending timer \n"); + /* delete timer if already pending */ + del_timer(&nfc_dev_platform->cold_reset.timer); + } + nfc_dev_platform->cold_reset.timer_started = true; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) + init_timer(&nfc_dev_platform->cold_reset.timer); + setup_timer( &nfc_dev_platform->cold_reset.timer, ese_cold_reset_gaurd_timer_callback, 0); +#else + timer_setup(&nfc_dev_platform->cold_reset.timer, ese_cold_reset_gaurd_timer_callback, 0); +#endif + ret = mod_timer(&nfc_dev_platform->cold_reset.timer, + jiffies + msecs_to_jiffies(ESE_COLD_RESET_GUARD_TIME)); + return ret; +} + +static int perform_ese_cold_reset(nfc_dev_t *nfc_dev, + ese_cold_reset_origin_t origin) +{ + int ret = 0; + + if (gpio_get_value(nfc_dev->gpio.dwl_req)) { + pr_err("FW download in-progress\n"); + return -EBUSY; + } + if (!gpio_get_value(nfc_dev->gpio.ven)) { + pr_err("VEN LOW - NFCC powered off\n"); + return -ENODEV; + } + + mutex_lock(&nfc_dev->cold_reset.sync_mutex); + if (!nfc_dev->cold_reset.timer_started) { + ret = start_ese_cold_reset_guard_timer(); + if (ret) { + pr_err("%s: Error in mod_timer\n", __func__); + mutex_unlock(&nfc_dev->cold_reset.sync_mutex); + return ret; + } + /* set default value for status as failure */ + nfc_dev->cold_reset.status = -EIO; + ret = send_cold_reset_cmd(nfc_dev); + if (ret <= 0) { + pr_err("failed to send cold reset command\n"); + mutex_unlock(&nfc_dev->cold_reset.sync_mutex); + return ret; + } + ret = 0; + nfc_dev->cold_reset.rsp_pending = true; + /* check if NFC is enabled */ + if (nfc_dev->cold_reset.nfc_enabled) { + /* Pending read from NFC_HAL will read the cold reset rsp and signal read_wq */ + if (!wait_event_interruptible_timeout + (nfc_dev->cold_reset.read_wq, + nfc_dev->cold_reset.rsp_pending == false, + msecs_to_jiffies(ESE_COLD_RESET_CMD_RSP_TIMEOUT))) + { + pr_err("%s:Cold Reset Response Timeout\n", + __func__); + } + } else { + /* Read data as NFC thread is not active */ + enable_interrupt(nfc_dev); + read_cold_reset_rsp(nfc_dev, NULL); + nfc_dev->cold_reset.rsp_pending = false; + // TODO: Handling Cold reset for I3C + // ret = i3c_read(i3c_dev, rsp, NCI_HDR_LEN); + } + if (!ret) { /* wait for reboot guard timer */ + if (wait_event_interruptible_timeout + (nfc_dev->cold_reset.read_wq, true, + msecs_to_jiffies(ESE_COLD_RESET_REBOOT_GUARD_TIME)) + == 0) { + pr_err("%s: guard Timeout interrupted", + __func__); + } + } + } + mutex_unlock(&nfc_dev->cold_reset.sync_mutex); + if (ret == 0) /* success case */ + ret = nfc_dev->cold_reset.status; + return ret; +} + +/* + * Power management of the eSE + * eSE and NFCC both are powered using VEN gpio, + * VEN HIGH - eSE and NFCC both are powered on + * VEN LOW - eSE and NFCC both are power down + */ +int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg) +{ + int ret = 0; + if (arg == ESE_POWER_ON) { + /** + * Let's store the NFC VEN pin state + * will check stored value in case of eSE power off request, + * to find out if NFC MW also sent request to set VEN HIGH + * VEN state will remain HIGH if NFC is enabled otherwise + * it will be set as LOW + */ + nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_dev->gpio.ven); + if (!nfc_dev->nfc_ven_enabled) { + pr_debug("eSE HAL service setting ven HIGH\n"); + gpio_set_ven(nfc_dev, 1); + } else { + pr_debug("ven already HIGH\n"); + } + } else if (arg == ESE_POWER_OFF) { + if (!nfc_dev->nfc_ven_enabled) { + pr_debug("NFC not enabled, disabling ven\n"); + gpio_set_ven(nfc_dev, 0); + } else { + pr_debug("keep ven high as NFC is enabled\n"); + } + } else if (IS_COLD_RESET_REQ(arg) && + nfc_dev->interface == PLATFORM_IF_I2C) { + ret = perform_ese_cold_reset(nfc_dev, arg); + } else if (arg == ESE_POWER_STATE) { + // eSE power state + ret = gpio_get_value(nfc_dev->gpio.ven); + } else { + pr_err("%s bad arg %lu\n", __func__, arg); + ret = -ENOIOCTLCMD; + } + return ret; +} + +EXPORT_SYMBOL(nfc_ese_pwr); + +/* + * This function shall be called from SPI, UWB, NFC driver to perform eSE cold reset. + */ +int ese_cold_reset(ese_cold_reset_origin_t origin) +{ + int ret = 0; + unsigned long arg; + pr_info("%s: Enter origin:%d", __func__, origin); + + switch (origin) { + case ESE_COLD_RESET_SOURCE_SPI: + arg = ESE_COLD_RESET_SPI; + break; + case ESE_COLD_RESET_SOURCE_UWB: + arg = ESE_COLD_RESET_UWB; + break; + default: + pr_info("%s: Invalid argument", __func__); + return -EINVAL; + } + if (nfc_dev_platform == NULL) + return -ENODEV; + ret = nfc_ese_pwr(nfc_dev_platform, arg); + pr_info("%s:%d exit, Status:%d", __func__, origin, ret); + return ret; +} + +EXPORT_SYMBOL(ese_cold_reset); + +/* + * nfc_ioctl_power_states() - power control + * @filp: pointer to the file descriptor + * @arg: mode that we want to move to + * + * Device power control. Depending on the arg value, device moves to + * different states + * (arg = 0): NFC_ENABLE GPIO = 0, FW_DL GPIO = 0 + * (arg = 1): NFC_ENABLE GPIO = 1, FW_DL GPIO = 0 + * (arg = 2): FW_DL GPIO = 1 + * + * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case + */ +static int nfc_ioctl_power_states(nfc_dev_t *nfc_dev, unsigned long arg) +{ + int ret = 0; + if (arg == NFC_POWER_OFF) { + /* + * We are attempting a hardware reset so let us disable + * interrupts to avoid spurious notifications to upper + * layers. + */ + disable_interrupt(nfc_dev); + pr_debug("gpio firm disable\n"); + if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { + gpio_set_value(nfc_dev->gpio.dwl_req, 0); + usleep_range(10000, 10100); + } + if (gpio_is_valid(nfc_dev->gpio.ese_pwr)) { + if (!gpio_get_value(nfc_dev->gpio.ese_pwr)) { + pr_debug("disabling ven\n"); + gpio_set_ven(nfc_dev, 0); + } else { + pr_debug("keeping ven high\n"); + } + } else { + pr_debug("ese_pwr invalid, set ven to low\n"); + gpio_set_ven(nfc_dev, 0); + } + nfc_dev->nfc_ven_enabled = false; + } else if (arg == NFC_POWER_ON) { + enable_interrupt(nfc_dev); + pr_debug("gpio_set_value enable: %s:\n", __func__); + if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { + gpio_set_value(nfc_dev->gpio.dwl_req, 0); + usleep_range(10000, 10100); + } + gpio_set_ven(nfc_dev, 1); + nfc_dev->nfc_ven_enabled = true; +#ifdef CONFIG_NXP_NFC_I3C + if (nfc_dev->interface == PLATFORM_IF_I3C) + nfc_dev->i3c_dev.read_hdr = NCI_HDR_LEN; +#endif //CONFIG_NXP_NFC_I3C + } else if (arg == NFC_FW_DWL_VEN_TOGGLE) { + /* + * We are switching to Dowload Mode, toggle the enable pin + * in order to set the NFCC in the new mode + */ + if (gpio_is_valid(nfc_dev->gpio.ese_pwr)) { + if (gpio_get_value(nfc_dev->gpio.ese_pwr)) { + pr_err + ("FW download forbidden while ese is on\n"); + return -EBUSY; /* Device or resource busy */ + } + } + gpio_set_value(nfc_dev->gpio.ven, 1); + if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { + gpio_set_value(nfc_dev->gpio.dwl_req, 1); + usleep_range(10000, 10100); + } + if (nfc_dev->interface == PLATFORM_IF_I2C) { + gpio_set_value(nfc_dev->gpio.ven, 0); + usleep_range(10000, 10100); + } + gpio_set_value(nfc_dev->gpio.ven, 1); + usleep_range(10000, 10100); + } else if (arg == NFC_FW_DWL_HIGH) { + /* + * Setting firmware download gpio to HIGH + * before FW download start + */ + pr_debug("set fw gpio high\n"); + if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { + gpio_set_value(nfc_dev->gpio.dwl_req, 1); + usleep_range(10000, 10100); + } else + pr_debug("gpio.dwl_req is invalid\n"); + } else if (arg == NFC_VEN_FORCED_HARD_RESET + && nfc_dev->interface == PLATFORM_IF_I2C) { + /* + * TODO: Enable Ven reset for I3C, after hot join integration + */ + gpio_set_value(nfc_dev->gpio.ven, 0); + usleep_range(10000, 10100); + gpio_set_value(nfc_dev->gpio.ven, 1); + usleep_range(10000, 10100); + pr_info("%s VEN forced reset done\n", __func__); + } else if (arg == NFC_FW_DWL_LOW) { + /* + * Setting firmware download gpio to LOW + * FW download finished + */ + pr_debug("set fw gpio LOW\n"); + if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { + gpio_set_value(nfc_dev->gpio.dwl_req, 0); + usleep_range(10000, 10100); + } else { + pr_debug("gpio.dwl_req is invalid\n"); + } +#ifdef CONFIG_NXP_NFC_I3C + if (nfc_dev->interface == PLATFORM_IF_I3C) + nfc_dev->i3c_dev.read_hdr = NCI_HDR_LEN; +#endif //CONFIG_NXP_NFC_I3C +#ifdef CONFIG_NXP_NFC_I3C + } else if (arg == NFC_FW_HDR_LEN) { + if (nfc_dev->interface == PLATFORM_IF_I3C) + nfc_dev->i3c_dev.read_hdr = FW_HDR_LEN; +#endif //CONFIG_NXP_NFC_I3C + } else { + pr_err("%s bad arg %lu\n", __func__, arg); + ret = -ENOIOCTLCMD; + } + return ret; +} + +/** @brief IOCTL function to be used to set or get data from upper layer. + * + * @param pfile fil node for opened device. + * @cmd IOCTL type from upper layer. + * @arg IOCTL arg from upper layer. + * + * @return 0 on success, error code for failures. + */ +long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct nfc_dev *nfc_dev = pfile->private_data; + if (!nfc_dev) + return -ENODEV; + + pr_debug("%s cmd = %x arg = %zx\n", __func__, cmd, arg); + switch (cmd) { + case NFC_SET_PWR: + ret = nfc_ioctl_power_states(nfc_dev, arg); + break; + case ESE_SET_PWR: + ret = nfc_ese_pwr(nfc_dev, arg); + break; + case ESE_GET_PWR: + ret = nfc_ese_pwr(nfc_dev, 3); + break; + case NFC_GET_PLATFORM_TYPE: + ret = nfc_dev->interface; + break; + default: + pr_err("%s bad cmd %lu\n", __func__, arg); + ret = -ENOIOCTLCMD; + }; + return ret; +} + +int nfc_dev_open(struct inode *inode, struct file *filp) +{ + nfc_dev_t *nfc_dev = container_of(inode->i_cdev, nfc_dev_t, c_dev); + if (!nfc_dev) + return -ENODEV; + pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); + + mutex_lock(&nfc_dev->dev_ref_mutex); + + filp->private_data = nfc_dev; + + if (nfc_dev->dev_ref_count == 0) { + if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { + gpio_set_value(nfc_dev->gpio.dwl_req, 0); + usleep_range(10000, 10100); + } + nfc_dev->cold_reset.nfc_enabled = true; + enable_interrupt(nfc_dev); + } + nfc_dev->dev_ref_count = nfc_dev->dev_ref_count + 1; + mutex_unlock(&nfc_dev->dev_ref_mutex); + return 0; +} + +int nfc_dev_close(struct inode *inode, struct file *filp) +{ + nfc_dev_t *nfc_dev = container_of(inode->i_cdev, nfc_dev_t, c_dev); + if (!nfc_dev) + return -ENODEV; + pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); + mutex_lock(&nfc_dev->dev_ref_mutex); + if (nfc_dev->dev_ref_count == 1) { + disable_interrupt(nfc_dev); + if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { + gpio_set_value(nfc_dev->gpio.dwl_req, 0); + usleep_range(10000, 10100); + } + nfc_dev->cold_reset.nfc_enabled = false; + } + if (nfc_dev->dev_ref_count > 0) + nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; + + filp->private_data = NULL; + + mutex_unlock(&nfc_dev->dev_ref_mutex); + return 0; +} diff --git a/nfc/common.h b/nfc/common.h new file mode 100644 index 0000000000..49f6e2b49b --- /dev/null +++ b/nfc/common.h @@ -0,0 +1,229 @@ +/****************************************************************************** + * Copyright (C) 2019-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#ifndef _COMMON_H_ +#define _COMMON_H_ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_NXP_NFC_I2C +#include "i2c_drv.h" +#endif +#ifdef CONFIG_NXP_NFC_I3C +#include "i3c_drv.h" +#endif + +#define DEV_COUNT 1 /* Max device count for this driver */ +#define CLASS_NAME "nfc" /* i2c device class */ + +// NFC character device name, this will be in /dev/ +#define NFC_CHAR_DEV_NAME "pn553" +#define NCI_HDR_LEN 3 /* HDR length of NCI packet */ +#define NCI_PAYLOAD_LEN_OFFSET 2 +#define NCI_PAYLOAD_IDX 3 +#define MAX_NCI_PAYLOAD_LEN (255) +#define MAX_BUFFER_SIZE (NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN) +#define MAX_RETRY_COUNT (3) +#define NO_RETRY (1) +#define MAX_IRQ_WAIT_TIME (90) +#define WAKEUP_SRC_TIMEOUT (2000) + +/* ESE_COLD_RESET MACROS */ +#define COLD_RESET_CMD_LEN 3 +#define COLD_RESET_RSP_LEN 4 +#define COLD_RESET_CMD_GID 0x2F +#define COLD_RESET_CMD_PAYLOAD_LEN 0x00 +#define COLD_RESET_RSP_GID 0x4F +#define COLD_RESET_OID 0x1E +/* + * ESE_RESET: Bit mask to check if ese_reset_guard timer is started (bit b7) + * */ +#define ESE_COLD_RESET_GUARD_TIMER_MASK (0x80) +/* + * ESE_RESET: Guard time to allow eSE cold reset from the driver + * */ +#define ESE_COLD_RESET_GUARD_TIME (3000) //3s +/* + * ESE_RESET: NCI command response timeout +*/ +#define ESE_COLD_RESET_CMD_RSP_TIMEOUT (2000) //2s +/* + * ESE_RESET: Guard time to reboot the JCOP +*/ +#define ESE_COLD_RESET_REBOOT_GUARD_TIME (50) //50ms +/* + * ESE_RESET: Checks if eSE cold reset has been requested + */ +#define IS_COLD_RESET_REQ(arg) ((arg == ESE_COLD_RESET_NFC) || \ + (arg == ESE_COLD_RESET_SPI) || (arg == ESE_COLD_RESET_UWB)) +/* + * ESE_RESET: macro evaluates to 1 if eSE cold reset response is received + * */ +#define IS_COLD_RESET_RSP(buf) ((COLD_RESET_RSP_GID == buf[0]) && (COLD_RESET_OID == buf[1])) + +#define NFC_MAGIC 0xE9 + +/*Ioctls*/ +// The type should be aligned with MW HAL definitions +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, long) +#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, long) +#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, long) +#define NFC_GET_PLATFORM_TYPE _IO(NFC_MAGIC, 0x0B) + +#define DTS_IRQ_GPIO_STR "nxp,pn544-irq" +#define DTS_VEN_GPIO_STR "nxp,pn544-ven" +#define DTS_FWDN_GPIO_STR "nxp,pn544-fw-dwnld" +#define DTS_ESE_GPIO_STR "nxp,pn544-ese-pwr" + +enum ese_ioctl_request { + /* eSE POWER ON */ + ESE_POWER_ON = 0, + /* eSE POWER OFF */ + ESE_POWER_OFF, + /* eSE POWER STATE */ + ESE_POWER_STATE, + /* eSE COLD RESET */ + ESE_COLD_RESET_NFC, + ESE_COLD_RESET_SPI, + ESE_COLD_RESET_UWB, +}; + +enum nfcc_ioctl_request { + /* NFC disable request with VEN LOW */ + NFC_POWER_OFF = 0, + /* NFC enable request with VEN Toggle */ + NFC_POWER_ON, + /* firmware download request with VEN Toggle */ + NFC_FW_DWL_VEN_TOGGLE, + /* ISO reset request */ + NFC_ISO_RESET, + /* request for firmware download gpio HIGH */ + NFC_FW_DWL_HIGH, + /* VEN hard reset request */ + NFC_VEN_FORCED_HARD_RESET, + /* request for firmware download gpio LOW */ + NFC_FW_DWL_LOW, + /*for HDR size change in FW mode */ + NFC_FW_HDR_LEN, + /* Cold reset request for eSE */ + NFC_ESE_COLD_RST, +}; + +/*nfc platform interface type*/ +enum interface_flags { + /*I2C physical IF for NFCC */ + PLATFORM_IF_I2C = 0, + /*I3C physical IF for NFCC */ + PLATFORM_IF_I3C, +}; +/*nfc platform interface type*/ +enum ven_policy_flags { + /*VEN usage in lagacy platform */ + VEN_LEGACY = 0, + /*VEN reset only to recover from failure usecases */ + VEN_ALWAYS_ENABLED, +}; +/* Power state for IBI handing, mainly needed to defer the IBI handling + for the IBI received in suspend state to do it later in resume call*/ +enum pm_state_flags { + PM_STATE_NORMAL = 0, + PM_STATE_SUSPEND, + PM_STATE_IBI_BEFORE_RESUME, +}; + +/* Enum for GPIO values*/ +enum gpio_values { + GPIO_INPUT = 0x0, + GPIO_OUTPUT = 0x1, + GPIO_HIGH = 0x2, + GPIO_OUTPUT_HIGH = 0x3, + GPIO_IRQ = 0x4, +}; + +// NFC GPIO variables +typedef struct platform_gpio { + unsigned int irq; + unsigned int ven; + unsigned int dwl_req; + unsigned int ese_pwr; +} platform_gpio_t; + +//Features specific Parameters +typedef struct cold_reset { + wait_queue_head_t read_wq; + bool rsp_pending; + unsigned int ntf; + uint8_t status; + /* NFC device opened by MW */ + bool nfc_enabled; + /* eSe cold reset guard timer is started */ + bool timer_started; + struct mutex sync_mutex; + struct timer_list timer; +} cold_reset_t; + +/* Device specific structure */ +typedef struct nfc_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct mutex ese_access_mutex; + struct mutex dev_ref_mutex; + unsigned int dev_ref_count; + struct class *nfc_class; + struct device *nfc_device; + struct cdev c_dev; + dev_t devno; + /* Interface flag */ + uint8_t interface; + + /*store the ven functioning */ + uint8_t ven_policy; + /* NFC VEN pin state */ + bool nfc_ven_enabled; + union { +#ifdef CONFIG_NXP_NFC_I2C + i2c_dev_t i2c_dev; +#endif +#ifdef CONFIG_NXP_NFC_I3C + i3c_dev_t i3c_dev; +#endif + }; + platform_gpio_t gpio; + cold_reset_t cold_reset; +} nfc_dev_t; + +int nfc_dev_open(struct inode *inode, struct file *filp); +int nfc_dev_close(struct inode *inode, struct file *filp); +long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); +int nfc_parse_dt(struct device *dev, platform_gpio_t *nfc_gpio, + uint8_t interface); +int nfc_misc_register(nfc_dev_t *nfc_dev, + const struct file_operations *nfc_fops, + int count, char *devname, char *classname); +void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count); +int configure_gpio(unsigned int gpio, int flag); +void read_cold_reset_rsp(nfc_dev_t *nfc_dev, char *buf); +void gpio_set_ven(nfc_dev_t *nfc_dev, int value); +void gpio_free_all(nfc_dev_t *nfc_dev); +#endif //_COMMON_H_ diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c new file mode 100644 index 0000000000..5d1e1393c5 --- /dev/null +++ b/nfc/i2c_drv.c @@ -0,0 +1,465 @@ +/****************************************************************************** + * Copyright (C) 2013-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "../nfc/cold_reset.h" +#include "common.h" +#include "sn110.h" + +extern nfc_dev_t *nfc_dev_platform; + +/** + * i2c_disable_irq() + * + * Check if interrupt is disabled or not + * and disable interrupt + * + * Return: void + */ +void i2c_disable_irq(i2c_dev_t *i2c_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&i2c_dev->irq_enabled_lock, flags); + if (i2c_dev->irq_enabled) { + disable_irq_nosync(i2c_dev->client->irq); + i2c_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&i2c_dev->irq_enabled_lock, flags); +} + +/** + * i2c_enable_irq() + * + * Check if interrupt is enabled or not + * and enable interrupt + * + * Return: void + */ +void i2c_enable_irq(i2c_dev_t *i2c_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&i2c_dev->irq_enabled_lock, flags); + if (!i2c_dev->irq_enabled) { + i2c_dev->irq_enabled = true; + enable_irq(i2c_dev->client->irq); + } + spin_unlock_irqrestore(&i2c_dev->irq_enabled_lock, flags); +} + +static irqreturn_t i2c_irq_handler(int irq, void *dev_id) +{ + nfc_dev_t *nfc_dev = dev_id; + i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + if (device_may_wakeup(&i2c_dev->client->dev)) + pm_wakeup_event(&i2c_dev->client->dev, WAKEUP_SRC_TIMEOUT); + + i2c_disable_irq(i2c_dev); + wake_up(&nfc_dev->read_wq); + + return IRQ_HANDLED; +} + +int i2c_read(i2c_dev_t *i2c_dev, char *buf, size_t count) +{ + int ret; + pr_debug("%s : reading %zu bytes.\n", __func__, count); + /* Read data */ + ret = i2c_master_recv(i2c_dev->client, buf, count); + if (ret <= 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + goto err; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + ret = -EIO; + } + /* delay for the slow nfc devices between susequent read operation */ + usleep_range(1000, 1100); +err: + return ret; +} + +int i2c_write(i2c_dev_t *i2c_dev, char *buf, size_t count, int max_retry_cnt) +{ + int ret = -EINVAL; + int retry_cnt; + + pr_debug("%s : writing %zu bytes.\n", __func__, count); + + for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) { + ret = i2c_master_send(i2c_dev->client, buf, count); + if (ret <= 0) { + pr_warn + ("%s: write failed, Maybe in Standby Mode - Retry(%d)\n", + __func__, retry_cnt); + usleep_range(1000, 1100); + } else if (ret == count) + break; + } + return ret; +} + +ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + int ret; + char tmp[MAX_BUFFER_SIZE]; + nfc_dev_t *nfc_dev = filp->private_data; + i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + mutex_lock(&nfc_dev->read_mutex); + if (!gpio_get_value(nfc_dev->gpio.irq)) { + if (filp->f_flags & O_NONBLOCK) { + pr_err(":f_falg has O_NONBLOCK. EAGAIN\n"); + ret = -EAGAIN; + goto err; + } + while (1) { + ret = 0; + if (!i2c_dev->irq_enabled) { + i2c_dev->irq_enabled = true; + enable_irq(i2c_dev->client->irq); + } + ret = wait_event_interruptible(nfc_dev->read_wq, + !i2c_dev->irq_enabled); + if (ret) { + pr_err("error wakeup of read wq\n"); + goto err; + } + + i2c_disable_irq(i2c_dev); + if (!gpio_get_value(nfc_dev->gpio.ven)) { + pr_info("%s: releasing read\n", __func__); + ret = -EIO; + goto err; + } + if (gpio_get_value(nfc_dev->gpio.irq)) + break; + pr_warn("%s: spurious interrupt detected\n", __func__); + } + } + + memset(tmp, 0x00, count); + /* Read data */ + ret = i2c_read(i2c_dev, tmp, count); + if (ret <= 0) { + pr_err("%s: i2c_read returned %d\n", __func__, ret); + goto err; + } + /* check if it's response of cold reset command + * NFC HAL process shouldn't receive this data as + * command was sent by driver + */ + if (nfc_dev->cold_reset.rsp_pending && IS_COLD_RESET_RSP(tmp)) { + read_cold_reset_rsp(nfc_dev, tmp); + nfc_dev->cold_reset.rsp_pending = false; + wake_up_interruptible(&nfc_dev->cold_reset.read_wq); + mutex_unlock(&nfc_dev->read_mutex); + /* + * NFC process doesn't know about cold reset command + * being sent as it was initiated by eSE process + * we shouldn't return any data to NFC process + */ + return 0; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warn("%s : failed to copy to user space\n", __func__); + ret = -EFAULT; + } + +err: + mutex_unlock(&nfc_dev->read_mutex); + return ret; +} + +ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + int ret; + char tmp[MAX_BUFFER_SIZE]; + nfc_dev_t *nfc_dev = filp->private_data; + i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + ret = i2c_write(i2c_dev, tmp, count, NO_RETRY); + if (ret != count) { + pr_err("%s: failed to write %d\n", __func__, ret); + ret = -EIO; + } + + return ret; +} + +static const struct file_operations nfc_i2c_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = nfc_i2c_dev_read, + .write = nfc_i2c_dev_write, + .open = nfc_dev_open, + .release = nfc_dev_close, + .unlocked_ioctl = nfc_dev_ioctl, +}; + +int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + nfc_dev_t *nfc_dev = NULL; + i2c_dev_t *i2c_dev = NULL; + platform_gpio_t nfc_gpio; + pr_debug("%s: enter\n", __func__); + /*retrive details of gpios from dt */ + ret = nfc_parse_dt(&client->dev, &nfc_gpio, PLATFORM_IF_I2C); + if (ret) { + pr_err("%s : failed to parse dt\n", __func__); + goto err; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + ret = -ENODEV; + goto err; + } + nfc_dev = kzalloc(sizeof(nfc_dev_t), GFP_KERNEL); + if (nfc_dev == NULL) { + ret = -ENOMEM; + goto err; + } + nfc_dev_platform = nfc_dev; + nfc_dev->interface = PLATFORM_IF_I2C; + nfc_dev->i2c_dev.client = client; + i2c_dev = &nfc_dev->i2c_dev; + + ret = configure_gpio(nfc_gpio.ven, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc reset gpio [%d]\n", + __func__, nfc_gpio.ven); + goto err; + } + ret = configure_gpio(nfc_gpio.irq, GPIO_IRQ); + if (ret <= 0) { + pr_err("%s: unable to request nfc irq gpio [%d]\n", + __func__, nfc_gpio.irq); + goto err; + } + client->irq = ret; + ret = configure_gpio(nfc_gpio.dwl_req, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc firm downl gpio [%d]\n", + __func__, nfc_gpio.dwl_req); + goto err; + } + ret = configure_gpio(nfc_gpio.ese_pwr, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc ese pwr gpio [%d]\n", + __func__, nfc_gpio.ese_pwr); + } + nfc_dev->gpio.ven = nfc_gpio.ven; + nfc_dev->gpio.irq = nfc_gpio.irq; + nfc_dev->gpio.dwl_req = nfc_gpio.dwl_req; + nfc_dev->gpio.ese_pwr = nfc_gpio.ese_pwr; + + /* init mutex and queues */ + init_waitqueue_head(&nfc_dev->read_wq); + init_waitqueue_head(&nfc_dev->cold_reset.read_wq); + mutex_init(&nfc_dev->read_mutex); + mutex_init(&nfc_dev->dev_ref_mutex); + mutex_init(&nfc_dev->ese_access_mutex); + mutex_init(&nfc_dev->cold_reset.sync_mutex); + spin_lock_init(&i2c_dev->irq_enabled_lock); + + ret = nfc_misc_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT, + NFC_CHAR_DEV_NAME, CLASS_NAME); + if (ret) { + pr_err("%s: nfc_misc_register failed\n", __func__); + goto err_mutex_destroy; + } + /* interrupt initializations */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + i2c_dev->irq_enabled = true; + ret = request_irq(client->irq, i2c_irq_handler, + IRQF_TRIGGER_HIGH, client->name, nfc_dev); + if (ret) { + pr_err("%s: request_irq failed\n", __func__); + goto err_nfc_misc_unregister; + } + i2c_disable_irq(i2c_dev); + device_init_wakeup(&client->dev, true); + device_set_wakeup_capable(&client->dev, true); + i2c_set_clientdata(client, nfc_dev); + i2c_dev->irq_wake_up = false; + nfc_dev->cold_reset.rsp_pending = false; + nfc_dev->cold_reset.nfc_enabled = false; + + /*call to platform specific probe */ + ret = sn110_i2c_probe(nfc_dev); + if (ret != 0) { + pr_err("%s: probing platform failed\n", __func__); + goto err_request_free_irq; + }; + pr_info("%s probing nfc i2c successfully", __func__); + return 0; +err_request_free_irq: + free_irq(client->irq, nfc_dev); +err_nfc_misc_unregister: + nfc_misc_unregister(nfc_dev, DEV_COUNT); +err_mutex_destroy: + mutex_destroy(&nfc_dev->dev_ref_mutex); + mutex_destroy(&nfc_dev->read_mutex); + mutex_destroy(&nfc_dev->ese_access_mutex); + mutex_destroy(&nfc_dev->cold_reset.sync_mutex); +err: + gpio_free_all(nfc_dev); + if (nfc_dev) + kfree(nfc_dev); + pr_err("%s: probing not successful, check hardware\n", __func__); + return ret; +} + +int nfc_i2c_dev_remove(struct i2c_client *client) +{ + int ret = 0; + nfc_dev_t *nfc_dev = NULL; + pr_info("%s: remove device\n", __func__); + nfc_dev = i2c_get_clientdata(client); + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + ret = -ENODEV; + return ret; + } + free_irq(client->irq, nfc_dev); + nfc_misc_unregister(nfc_dev, DEV_COUNT); + mutex_destroy(&nfc_dev->read_mutex); + mutex_destroy(&nfc_dev->ese_access_mutex); + mutex_destroy(&nfc_dev->cold_reset.sync_mutex); + gpio_free_all(nfc_dev); + if (nfc_dev) + kfree(nfc_dev); + return ret; +} + +int nfc_i2c_dev_suspend(struct device *device) +{ + struct i2c_client *client = to_i2c_client(device); + nfc_dev_t *nfc_dev = i2c_get_clientdata(client); + i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + + if (device_may_wakeup(&client->dev) && i2c_dev->irq_enabled) { + if (!enable_irq_wake(client->irq)) + i2c_dev->irq_wake_up = true; + } + return 0; +} + +int nfc_i2c_dev_resume(struct device *device) +{ + struct i2c_client *client = to_i2c_client(device); + nfc_dev_t *nfc_dev = i2c_get_clientdata(client); + i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + + if (device_may_wakeup(&client->dev) && i2c_dev->irq_wake_up) { + if (!disable_irq_wake(client->irq)) + i2c_dev->irq_wake_up = false; + } + return 0; +} + +static const struct i2c_device_id nfc_i2c_dev_id[] = { + {NFC_I2C_DEV_ID, 0}, + {} +}; + +static const struct of_device_id nfc_i2c_dev_match_table[] = { + {.compatible = NFC_I2C_DRV_STR,}, + {} +}; + +static const struct dev_pm_ops nfc_i2c_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(nfc_i2c_dev_suspend, nfc_i2c_dev_resume) +}; + +static struct i2c_driver nfc_i2c_dev_driver = { + .id_table = nfc_i2c_dev_id, + .probe = nfc_i2c_dev_probe, + .remove = nfc_i2c_dev_remove, + .driver = { + .name = NFC_I2C_DRV_STR, + .pm = &nfc_i2c_dev_pm_ops, + .of_match_table = nfc_i2c_dev_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; + +MODULE_DEVICE_TABLE(of, nfc_i2c_dev_match_table); + +static int __init nfc_i2c_dev_init(void) +{ + int ret = 0; + pr_info("Loading NXP NFC I2C driver\n"); + ret = i2c_add_driver(&nfc_i2c_dev_driver); + return ret; +} + +module_init(nfc_i2c_dev_init); + +static void __exit nfc_i2c_dev_exit(void) +{ + pr_info("Unloading NXP NFC I2C driver\n"); + i2c_del_driver(&nfc_i2c_dev_driver); +} + +module_exit(nfc_i2c_dev_exit); + +MODULE_DESCRIPTION("NXP NFC I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/nfc/i2c_drv.h b/nfc/i2c_drv.h new file mode 100644 index 0000000000..eef57dc8d3 --- /dev/null +++ b/nfc/i2c_drv.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * Copyright (C) 2019-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#ifndef _I2C_DRV_H_ +#define _I2C_DRV_H_ +#include + +/*kept same as dts */ +#define NFC_I2C_DRV_STR "nxp,pn544" +#define NFC_I2C_DEV_ID "pn553" + +//Interface specific parameters +typedef struct i2c_dev { + struct i2c_client *client; + /*IRQ parameters */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + /* NFC_IRQ wake-up state */ + bool irq_wake_up; +} i2c_dev_t; + +long nfc_i2c_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); +int nfc_i2c_dev_probe(struct i2c_client *client, + const struct i2c_device_id *id); +int nfc_i2c_dev_remove(struct i2c_client *client); +int nfc_i2c_dev_suspend(struct device *device); +int nfc_i2c_dev_resume(struct device *device); +void i2c_disable_irq(i2c_dev_t *i2c_dev); +void i2c_enable_irq(i2c_dev_t *i2c_dev); +int i2c_write(i2c_dev_t *i2c_dev, char *buf, size_t count, int max_retry_cnt); +int i2c_read(i2c_dev_t *i2c_dev, char *buf, size_t count); +#endif //_I2C_DRV_H_ diff --git a/nfc/i3c_drv.c b/nfc/i3c_drv.c new file mode 100644 index 0000000000..063308c268 --- /dev/null +++ b/nfc/i3c_drv.c @@ -0,0 +1,766 @@ +/****************************************************************************** + * Copyright (C) 2019-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "sn110.h" + +/** @brief This API used to write I3C data to I3C device. + * + * @param dev the i3c_dev for the i3c device. + * @param buf the data to write + * @param count the number of bytes of data to be written. + * @return ret number of bytes written ,negative error core otherwise. + */ +ssize_t i3c_write(i3c_dev_t *i3c_dev, const char *buf, const size_t count, + int max_retry_cnt) +{ + int ret = -EIO; + int retry_count = 0; + struct i3c_priv_xfer write_buf = { + .rnw = NFC_I3C_WRITE, + .len = count, + .data.out = buf + }; + do { + ret = i3c_device_do_priv_xfers(i3c_dev->device, &write_buf, + (sizeof(write_buf) / + sizeof(struct i3c_priv_xfer))); + + pr_debug("%s exit ret = %x\n", __func__, ret); + if (!ret) { + ret = count; + break; + } + pr_err("%s errno = %x\n", __func__, write_buf.err); + retry_count++; + + usleep_range(1000, 1100); + } while (retry_count < max_retry_cnt); + return ret; +} + +/** @brief This API used to read data from I3C device. + * + * @param dev the i3c_dev for the slave. + * @param buf the buffer to copy the data. + * @param count the number of bytes to be read. + * + * @return number of bytes read ,negative error code otherwise. + */ +ssize_t i3c_read(i3c_dev_t *i3c_dev, char *buf, size_t count) +{ + int ret = -EIO; + struct i3c_priv_xfer read_buf = { + .rnw = NFC_I3C_READ, + .len = count, + .data.in = buf + }; + + ret = i3c_device_do_priv_xfers(i3c_dev->device, &read_buf, + (sizeof(read_buf) / + sizeof(struct i3c_priv_xfer))); + pr_debug("%s exit ret = %x\n", __func__, ret); + if (!ret) + ret = count; + else + pr_err("%s errno = %x\n", __func__, read_buf.err); + + return ret; +} + +/** @brief This API can be used to write data to nci buf. + * The API will overwrite the existing memory if + * it reaches the end of total allocated memory. + * @param dev the dev structure for driver. + * @param readbuf the buffer to be copied data from + * @param count the number of bytes to copy to nci_buffer. + * @return number of bytes copied to nci buffer , error code otherwise + */ +static ssize_t i3c_kbuf_store(i3c_dev_t *i3c_dev, const char *buf, + const size_t count) +{ + size_t buf_offset = 0; + size_t requested_size = count; + size_t available_size = 0; + + if (i3c_dev == NULL) + return -ENODEV; + else if (buf == NULL || count == 0) + return -EINVAL; + + pr_debug("%s enter\n", __func__); + if (count > i3c_dev->buf.total_size) { + pr_err("%s No memory to copy the data\n", __func__); + return -ENOMEM; + } + + pr_debug("%s:total_size %zx write_off = %x read_off = %x\n", + __func__, i3c_dev->buf.total_size, i3c_dev->buf.write_offset, + i3c_dev->buf.read_offset); + + mutex_lock(&i3c_dev->nci_buf_mutex); + + available_size = i3c_dev->buf.total_size - i3c_dev->buf.write_offset; + + /* + * When available buffer is less than requested count, + * copy the data upto available memory. + * The remaining data is copied to the start of memory. + * The write offset is incremented by the remaining copied bytes + * from the beginning. + */ + + if (requested_size > available_size) { + pr_warn + ("%s:out of mem req_size = %zx avail = %zx\n", + __func__, requested_size, available_size); + memcpy(i3c_dev->buf.kbuf + i3c_dev->buf.write_offset, + buf + buf_offset, available_size); + requested_size = requested_size - available_size; + i3c_dev->buf.write_offset = 0; + buf_offset = available_size; + pr_debug("%s: requested_size = %zx available_size = %zx\n", + __func__, requested_size, available_size); + } + if (requested_size) { + memcpy(i3c_dev->buf.kbuf + i3c_dev->buf.write_offset, + buf + buf_offset, requested_size); + i3c_dev->buf.write_offset += requested_size; + if (i3c_dev->buf.write_offset == i3c_dev->buf.total_size) + i3c_dev->buf.write_offset = 0; + } + complete(&i3c_dev->read_cplt); + mutex_unlock(&i3c_dev->nci_buf_mutex); + pr_debug("%s: total bytes req_size = %zx avail_size = %zx\n", + __func__, requested_size, available_size); + + return count; +} + +/** @brief This API can be used to retrieve data from driver buffer. + * + * When data is not available, it waits for required data to be present. + * When data is present it copies the data into buffer reuested by read. + * @param dev the dev structure for driver. + * @param buf the buffer to copy the data. + * @param count the number of bytes to be read. + * @return number of bytes copied , error code for failures . + */ +static ssize_t i3c_nci_kbuf_retrieve(i3c_dev_t *i3c_dev, char *buf, + size_t count) +{ + int ret = 0; + size_t requested_size = count; + size_t available_size = 0; + size_t copied_size = 0; + if (i3c_dev == NULL) + return -ENODEV; + else if (buf == NULL || count == 0) + return -EINVAL; + pr_debug("%s enter\n", __func__); + + /* + * When the requested data count is more than available data to read, + * wait on completion till the requested bytes are available. + * If write offset is more than read offset and available data is + * more than requested count, copy the requested bytes directly and + * increment the read_offset. + * If read offset is more than write offset, + * available size is total_size size - read_offset + * and upto write offset from the beginning of buffer. + */ + + do { + + pr_debug("%s: read_offset = %x write_offset = %x\n", __func__, + i3c_dev->buf.read_offset, i3c_dev->buf.write_offset); + + mutex_lock(&i3c_dev->nci_buf_mutex); + if (i3c_dev->buf.read_offset <= i3c_dev->buf.write_offset) + available_size = + i3c_dev->buf.write_offset - + i3c_dev->buf.read_offset; + else + available_size = + (i3c_dev->buf.total_size - + i3c_dev->buf.read_offset) + + i3c_dev->buf.write_offset; + mutex_unlock(&i3c_dev->nci_buf_mutex); + if (available_size >= requested_size) + break; + + reinit_completion(&i3c_dev->read_cplt); + ret = wait_for_completion_interruptible(&i3c_dev->read_cplt); + if (ret != 0) { + pr_err("didnt get completion, interrupted!! ret %d\n", + ret); + return -EINVAL; + } + } while (available_size < requested_size); + + mutex_lock(&i3c_dev->nci_buf_mutex); + + if (i3c_dev->buf.write_offset >= i3c_dev->buf.read_offset + + requested_size) { + /* + * Write offset is more than read offset + count , copy the data + * directly and increment the read offset + */ + memcpy(buf, i3c_dev->buf.kbuf + i3c_dev->buf.read_offset, + requested_size); + i3c_dev->buf.read_offset += requested_size; + } else { + copied_size = + i3c_dev->buf.total_size - i3c_dev->buf.read_offset; + if (copied_size > requested_size) + copied_size = requested_size; + /* + * Read offset is more than write offset. Copy requested data + * from read_offset to the total size and increment the read + * offset. If requested data is still greater than zero, + * copy the data from beginning of buffer. + */ + memcpy(buf, i3c_dev->buf.kbuf + i3c_dev->buf.read_offset, + copied_size); + requested_size = requested_size - copied_size; + i3c_dev->buf.read_offset += copied_size; + if (requested_size) { + pr_debug("%s remaining copied bytes\n", __func__); + memcpy(buf + copied_size, i3c_dev->buf.kbuf, + requested_size); + i3c_dev->buf.read_offset = requested_size; + } + } + mutex_unlock(&i3c_dev->nci_buf_mutex); + pr_debug("%s , count = %zx exit\n", __func__, count); + return count; +} + +/** @brief This API can be used to read data from I3C device from HAL layer. + * + * This read function is registered during probe. + * When data is not available, it waits for required data to be present. + * @param filp the device file handle opened by HAL. + * @param buf the buffer to read the data. + * @param count the number of bytes to be read. + * @param offset the offset in the buf. + * @return Number of bytes read from I3C device ,error code for failures. + */ +ssize_t nfc_i3c_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + int ret; + char tmp[MAX_BUFFER_SIZE]; + nfc_dev_t *nfc_dev = filp->private_data; + i3c_dev_t *i3c_dev = &nfc_dev->i3c_dev; + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + memset(tmp, 0x00, count); + pr_debug("%s : reading %zu bytes\n", __func__, count); + + mutex_lock(&nfc_dev->read_mutex); + ret = i3c_nci_kbuf_retrieve(i3c_dev, tmp, count); + if (ret != count) { + pr_err("%s: buf read from I3C device returned error (%d)\n", + __func__, ret); + ret = -EIO; + } else if (copy_to_user(buf, tmp, ret)) { + pr_warn("%s : failed to copy to user space\n", __func__); + ret = -EFAULT; + } + + mutex_unlock(&nfc_dev->read_mutex); + + return ret; +} + +/** @brief This API can be used to write data to I3C device. + * + * @param dev the i3c_dev for the slave. + * @param buf the buffer to copy the data. + * @param count the number of bytes to be read. + * @return ret count number of btes written, error code for failures. + */ +ssize_t nfc_i3c_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + int ret; + char tmp[MAX_BUFFER_SIZE]; + nfc_dev_t *nfc_dev = filp->private_data; + i3c_dev_t *i3c_dev = &nfc_dev->i3c_dev; + if (count > MAX_BUFFER_SIZE) { + pr_err("%s: requested writes size(%d) more then expected\n", + __func__, count); + return -ENOMEM; + } + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + ret = PTR_ERR(tmp); + return ret; + } + + ret = i3c_write(i3c_dev, tmp, count, NO_RETRY); + if (ret != count) { + pr_err("%s: failed to write %d\n", __func__, ret); + ret = -EIO; + } + pr_debug("%s : i3c-%d: NfcNciTx %x %x %x\n", __func__, + iminor(file_inode(filp)), tmp[0], tmp[1], tmp[2]); + pr_debug("%s : ret = %x\n", __func__, ret); + return ret; +} + +/** @brief This API shall be called from workqueue queue from IBI handler. + * First it will read HDR byte from I3C chip.Based on the length byte + * it will read the next length bytes.Then it will write these bytes + * to nci write buf. + * @param work the work added into the workqueue. + * + * @return void + */ +static void i3c_workqueue_handler(struct work_struct *work) +{ + int ret = 0; + int length_byte = 0; + unsigned char *tmp = NULL; + unsigned char hdr_len = NCI_HDR_LEN; + i3c_dev_t *i3c_dev = container_of(work, i3c_dev_t, work); + + if (!i3c_dev) { + pr_err("%s: dev not found\n", __func__); + return; + } + hdr_len = i3c_dev->read_hdr; + tmp = i3c_dev->read_kbuf; + if (!tmp) { + pr_err("%s: No memory to copy read data\n", __func__); + return; + } + pr_info("%s: hdr_len = %d\n", __func__, hdr_len); + memset(tmp, 0x00, i3c_dev->read_kbuf_len); + + ret = i3c_read(i3c_dev, tmp, hdr_len); + if (ret < 0) { + pr_err("%s: i3c_read returned error %d\n", __func__, ret); + return; + } + if (hdr_len == FW_HDR_LEN) + length_byte = tmp[hdr_len - 1] + FW_CRC_LEN; + else + length_byte = tmp[hdr_len - 1]; + ret = i3c_read(i3c_dev, tmp + hdr_len, length_byte); + if (ret < 0) { + pr_err("%s: i3c_read returned error %d\n", __func__, ret); + i3c_kbuf_store(i3c_dev, tmp, hdr_len); + return; + } + i3c_kbuf_store(i3c_dev, tmp, hdr_len + length_byte); +} + +/** @brief This API is used to handle IBI coming from the I3C device. + * This will add work into the workqueue , which will call workqueue + * handler to read data from I3C device. + * @param device I3C device. + * @param payload payload shall be NULL for NFC device. + * @return void. + */ +static void i3c_ibi_handler(struct i3c_device *device, + const struct i3c_ibi_payload *payload) +{ + nfc_dev_t *nfc_dev = i3cdev_get_drvdata(device); + i3c_dev_t *i3c_dev = &nfc_dev->i3c_dev; + pr_debug("%s: Received read IBI request from slave", __func__); + if (device_may_wakeup(&device->dev)) + pm_wakeup_event(&device->dev, WAKEUP_SRC_TIMEOUT); + + if (atomic_read(&i3c_dev->pm_state) == PM_STATE_NORMAL) { + if (!queue_work(i3c_dev->wq, &i3c_dev->work)) + pr_debug("%s: queue work success\n", __func__); + } else { + /*assume suspend state and expect only 1 IBI in suspend state */ + atomic_set(&i3c_dev->pm_state, PM_STATE_IBI_BEFORE_RESUME); + } +} + +/** @brief This API can be used to enable IBI from the I3C device. + * @param i3c_dev the i3c_dev for the slave. + * @return 0 on success, error code for failures. + */ +int i3c_enable_ibi(i3c_dev_t *i3c_dev) +{ + int ret = 0; + int retry_count = 0; + + if (!i3c_dev->ibi_enabled) { + do { + ret = i3c_device_enable_ibi(i3c_dev->device); + if (!ret) { + i3c_dev->ibi_enabled = true; + break; + } + + pr_debug("en_ibi ret %d retrying..\n", ret); + retry_count++; + usleep_range(RETRY_WAIT_TIME_USEC, + (RETRY_WAIT_TIME_USEC + 100)); + } while (retry_count < RETRY_COUNT_IBI); + } else { + pr_debug("%s: already enabled\n", __func__); + } + return ret; +} + +/** @brief This API can be used to disable IBI from the I3C device. + * @param i3c_dev the i3c_dev for the slave. + * @return 0 on success, error code for failures. + */ +int i3c_disable_ibi(i3c_dev_t *i3c_dev) +{ + int ret = 0; + int retry_count = 0; + + if (i3c_dev->ibi_enabled) { + do { + ret = i3c_device_disable_ibi(i3c_dev->device); + if (!ret) { + i3c_dev->ibi_enabled = false; + break; + } + pr_debug("dis_ibi ret %d retrying..\n", ret); + retry_count++; + usleep_range(RETRY_WAIT_TIME_USEC, + (RETRY_WAIT_TIME_USEC + 100)); + } while (retry_count < RETRY_COUNT_IBI); + } else { + pr_debug("%s: already disabled\n", __func__); + } + return ret; +} + +/** @brief This API can be used to request IBI from the I3C device. + * This function will request IBI from master controller for the device + * and register ibi handler, enable IBI . + * @param i3c_dev the i3c_dev for the slave. + * @return 0 on success, error code for failures. + */ +static int i3c_request_ibi(i3c_dev_t *i3c_dev) +{ + int ret = 0; + struct i3c_ibi_setup ibireq = { + .handler = i3c_ibi_handler, + .max_payload_len = MAX_IBI_PAYLOAD_LEN, + .num_slots = NUM_NFC_IBI_SLOT, + }; + ret = i3c_device_request_ibi(i3c_dev->device, &ibireq); + pr_debug("%s Request IBI status = %d\n", __func__, ret); + return ret; +} + +/** @brief This API can be used to create a workqueue for + * handling IBI request from I3C device. + * + * @param dev the i3c_dev for the slave. + * @return 0 on success, error code for failures. + */ +static int i3c_init_workqueue(i3c_dev_t *i3c_dev) +{ + i3c_dev->wq = alloc_workqueue(I3C_WORKQUEUE_NAME, 0, 0); + if (!i3c_dev->wq) + return -ENOMEM; + + INIT_WORK(&i3c_dev->work, i3c_workqueue_handler); + pr_debug("%s ibi workqueue created successfully\n", __func__); + return 0; +} + +/** @brief This API can be used to set the NCI buf to zero. + * + * @param dev the dev for the driver. + * @return 0 on success, error code for failures. + */ +static int i3c_reset_nci_buf(i3c_dev_t *i3c_dev) +{ + i3c_dev->buf.write_offset = 0; + i3c_dev->buf.read_offset = 0; + memset(i3c_dev->buf.kbuf, 0, i3c_dev->buf.total_size); + return 0; +} + +static const struct file_operations nfc_i3c_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = nfc_i3c_dev_read, + .write = nfc_i3c_dev_write, + .open = nfc_dev_open, + .release = nfc_dev_close, + .unlocked_ioctl = nfc_dev_ioctl, +}; + +/** @brief This API can be used to probe I3c device. + * + * @param device the i3c_dev for the slave. + * @return 0 on success, error code for failures. + */ +int nfc_i3c_dev_probe(struct i3c_device *device) +{ + int ret = 0; + nfc_dev_t *nfc_dev = NULL; + platform_gpio_t nfc_gpio; + pr_debug("%s: enter\n", __func__); + /*retrive details of gpios from dt */ + ret = nfc_parse_dt(&device->dev, &nfc_gpio, PLATFORM_IF_I3C); + if (ret) { + pr_err("%s : failed to parse dt\n", __func__); + goto err; + } + nfc_dev = kzalloc(sizeof(nfc_dev_t), GFP_KERNEL); + if (nfc_dev == NULL) { + ret = -ENOMEM; + goto err; + } + + /* + * Memory allocation for the read from the I3C before + * storing it in Kbuf store + */ + nfc_dev->i3c_dev.read_hdr = NCI_HDR_LEN; + nfc_dev->i3c_dev.read_kbuf_len = MAX_BUFFER_SIZE; + nfc_dev->i3c_dev.read_kbuf = kzalloc(MAX_BUFFER_SIZE, + GFP_DMA | GFP_KERNEL); + if (!nfc_dev->i3c_dev.read_kbuf) { + ret = -ENOMEM; + goto err; + } + + /* + * Kbuf memory for storing NCI/Firmware Mode Buffers before + * actual read from the user + */ + nfc_dev->i3c_dev.buf.kbuf = (char *)__get_free_pages(GFP_KERNEL, 0); + if (!nfc_dev->i3c_dev.buf.kbuf) { + ret = -ENOMEM; + goto err; + } + nfc_dev->i3c_dev.buf.total_size = PAGE_SIZE; + i3c_reset_nci_buf(&nfc_dev->i3c_dev); + nfc_dev->interface = PLATFORM_IF_I3C; + nfc_dev->i3c_dev.device = device; + + ret = configure_gpio(nfc_gpio.ven, GPIO_OUTPUT_HIGH); + if (ret) { + pr_err("%s: unable to request nfc reset gpio [%d]\n", + __func__, nfc_gpio.ven); + goto err; + } + ret = configure_gpio(nfc_gpio.dwl_req, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc firm downl gpio [%d]\n", + __func__, nfc_gpio.dwl_req); + goto err; + } + + nfc_dev->gpio.ven = nfc_gpio.ven; + nfc_dev->gpio.irq = nfc_gpio.irq; + nfc_dev->gpio.dwl_req = -EINVAL; + nfc_dev->gpio.ese_pwr = -EINVAL; + + /* init mutex and queues */ + init_completion(&nfc_dev->i3c_dev.read_cplt); + mutex_init(&nfc_dev->i3c_dev.nci_buf_mutex); + mutex_init(&nfc_dev->dev_ref_mutex); + mutex_init(&nfc_dev->read_mutex); + ret = i3c_init_workqueue(&nfc_dev->i3c_dev); + if (ret) { + pr_err("%s: alloc workqueue failed\n", __func__); + goto err_mutex_destroy; + } + ret = nfc_misc_register(nfc_dev, &nfc_i3c_dev_fops, DEV_COUNT, + NFC_CHAR_DEV_NAME, CLASS_NAME); + if (ret) { + pr_err("%s: nfc_misc_register failed\n", __func__); + goto err_mutex_destroy; + } + i3cdev_set_drvdata(device, nfc_dev); + + ret = i3c_request_ibi(&nfc_dev->i3c_dev); + if (ret) { + pr_err("%s: i3c_request_ibi failed\n", __func__); + goto err_nfc_misc_unregister; + } + atomic_set(&nfc_dev->i3c_dev.pm_state, PM_STATE_NORMAL); + + device_init_wakeup(&device->dev, true); + device_set_wakeup_capable(&device->dev, true); + /*call to platform specific probe */ + ret = sn110_i3c_probe(nfc_dev); + if (ret != 0) { + pr_err("%s: probing platform failed\n", __func__); + goto err_nfc_misc_unregister; + }; + pr_info("%s probing nfc i3c successfully", __func__); + return 0; +err_nfc_misc_unregister: + nfc_misc_unregister(nfc_dev, DEV_COUNT); +err_mutex_destroy: + mutex_destroy(&nfc_dev->read_mutex); + mutex_destroy(&nfc_dev->dev_ref_mutex); + mutex_destroy(&nfc_dev->i3c_dev.nci_buf_mutex); +err: + gpio_free_all(nfc_dev); + if (nfc_dev->i3c_dev.buf.kbuf) + free_pages((unsigned long)nfc_dev->i3c_dev.buf.kbuf, 0); + if (nfc_dev->i3c_dev.read_kbuf) + kfree(nfc_dev->i3c_dev.read_kbuf); + if (nfc_dev) + kfree(nfc_dev); + pr_err("%s: probing not successful, check hardware\n", __func__); + return ret; +} + +/** @brief This API is automatically called on shutdown or crash. + * + * @param device the i3c_dev for the slave. + * @return 0 on success, error code for failures. + */ +int nfc_i3c_dev_remove(struct i3c_device *device) +{ + nfc_dev_t *nfc_dev = i3cdev_get_drvdata(device); + i3c_dev_t *i3c_dev = NULL; + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + return -ENODEV; + } + i3c_dev = &nfc_dev->i3c_dev; + i3c_device_disable_ibi(device); + i3c_device_free_ibi(device); + if (i3c_dev->wq) + destroy_workqueue(i3c_dev->wq); + nfc_misc_unregister(nfc_dev, DEV_COUNT); + mutex_destroy(&nfc_dev->read_mutex); + mutex_destroy(&nfc_dev->dev_ref_mutex); + mutex_destroy(&i3c_dev->nci_buf_mutex); + gpio_free_all(nfc_dev); + kfree(i3c_dev->read_kbuf); + free_pages((unsigned long)i3c_dev->buf.kbuf, 0); + kfree(nfc_dev); + return 0; +} + +int nfc_i3c_dev_suspend(struct device *pdev) +{ + struct i3c_device *device = dev_to_i3cdev(pdev); + nfc_dev_t *nfc_dev = i3cdev_get_drvdata(device); + pr_debug("%s: enter\n", __func__); + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + return -ENODEV; + } + + if (device_may_wakeup(&device->dev) && nfc_dev->i3c_dev.ibi_enabled) + atomic_set(&nfc_dev->i3c_dev.pm_state, PM_STATE_SUSPEND); + + return 0; +} + +int nfc_i3c_dev_resume(struct device *pdev) +{ + struct i3c_device *device = dev_to_i3cdev(pdev); + nfc_dev_t *nfc_dev = i3cdev_get_drvdata(device); + i3c_dev_t *i3c_dev = NULL; + pr_debug("%s: enter\n", __func__); + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + return -ENODEV; + } + i3c_dev = &nfc_dev->i3c_dev; + if (device_may_wakeup(&device->dev)) { + + if (atomic_read(&i3c_dev->pm_state) == + PM_STATE_IBI_BEFORE_RESUME) { + /*queue the deferered work to work queue */ + if (!queue_work(i3c_dev->wq, &i3c_dev->work)) + pr_debug("%s: Added workqueue successfully\n", + __func__); + } + atomic_set(&i3c_dev->pm_state, PM_STATE_NORMAL); + } + + return 0; +} + +static const struct i3c_device_id nfc_i3c_dev_id[] = { + I3C_DEVICE(NFC_I3C_MANU_ID, NFC_I3C_PART_ID, 0), + {}, +}; + +static const struct of_device_id nfc_i3c_dev_match_table[] = { + { + .compatible = NFC_I3C_DRV_STR + }, + {} +}; + +static const struct dev_pm_ops nfc_i3c_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(nfc_i3c_dev_suspend, nfc_i3c_dev_resume) +}; + +static struct i3c_driver nfc_i3c_dev_driver = { + .id_table = nfc_i3c_dev_id, + .probe = nfc_i3c_dev_probe, + .remove = nfc_i3c_dev_remove, + .driver = { + .owner = THIS_MODULE, + .name = NFC_I3C_DRV_STR, + .pm = &nfc_i3c_dev_pm_ops, + .of_match_table = nfc_i3c_dev_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; + +MODULE_DEVICE_TABLE(of, nfc_i3c_dev_match_table); + +static int __init nfc_dev_i3c_init(void) +{ + int ret = 0; + pr_info("Loading NXP NFC I3C driver\n"); + ret = i3c_driver_register_with_owner(&nfc_i3c_dev_driver, THIS_MODULE); + pr_debug("NFC i3c driver register ret = %d\n", ret); + return ret; +} + +module_init(nfc_dev_i3c_init); + +static void __exit nfc_i3c_dev_exit(void) +{ + pr_info("Unloading NXP NFC I3C driver\n"); + i3c_driver_unregister(&nfc_i3c_dev_driver); +} + +module_exit(nfc_i3c_dev_exit); + +MODULE_DESCRIPTION("NXP NFC I3C driver"); +MODULE_LICENSE("GPL"); diff --git a/nfc/i3c_drv.h b/nfc/i3c_drv.h new file mode 100644 index 0000000000..5ed2e77ca5 --- /dev/null +++ b/nfc/i3c_drv.h @@ -0,0 +1,109 @@ +/****************************************************************************** + * Copyright (C) 2019-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#ifndef _I3C_DRV_H_ +#define _I3C_DRV_H_ + +#include +#include + +//to to kept same as dt +#define NFC_I3C_DRV_STR "nxp,pn544_i3c" +#define NFC_I3C_MANU_ID (0x011B) +#define NFC_I3C_PART_ID (0) + +//Byte indicating I3C Read +#define NFC_I3C_READ 1 + +//Byte indicating I3C Write +#define NFC_I3C_WRITE 0 + +// Maximum no of IBI slot +#define NUM_NFC_IBI_SLOT 1 + +// Maximum IBI payload length +#define MAX_IBI_PAYLOAD_LEN 0 + +// CRC len to be read +#define FW_CRC_LEN 2 + +// FW DNLD HDR length +#define FW_HDR_LEN 2 + +// Time to wait before retrying I3C writes, in micro seconds +#define RETRY_WAIT_TIME_USEC (2000) + +// Retry count for enable/disable IBI CCC +#define RETRY_COUNT_IBI (3) + +// I3C WorkQueue name +#define I3C_WORKQUEUE_NAME "i3c_workq" +/** + * struct nci_buf - NCI buffer used to store and retrieve read data from device. + * @read_offset: The offset pointing to data available to read in nci buf. + * @write_offset: The offset pointing to free buf available to write. + * @total_size: Size of nci buf. + * @kbuf: allocated nci buf. + */ +struct nci_buf { + unsigned int read_offset; + unsigned int write_offset; + size_t total_size; + char *kbuf; +}; + +/** + * struct i3c_dev Structure representing device and driver data. + * @i3c_device Structure to represent I3C device. + * @wq: NCI workqueue for handling IBI request. + * @work: Work added to workqueue to read data from IBI handler. + * @buf Driver buf store read data from device.Read call will + * fetch from this buffer. + * @nci_buf_mutex: mutex to protect NCI buf retrieve/store . + * @read_cplt: Completion to wait for read data to be available. + * @read_kbuf_len: Temp buf len to hold I3C data. + * @read_kbuf: Temp buf to hold I3C data. + * @read_hdr Header size for reads. + * @ibi_enabled: IBI enabled or not. + * @pm_state: PM state of NFC I3C device. + */ +typedef struct i3c_dev { + struct i3c_device *device; + struct workqueue_struct *wq; + struct work_struct work; + struct nci_buf buf; + struct mutex nci_buf_mutex; + struct completion read_cplt; + size_t read_kbuf_len; + char *read_kbuf; + unsigned char read_hdr; + bool ibi_enabled; + atomic_t pm_state; + +} i3c_dev_t; + +int nfc_i3c_dev_probe(struct i3c_device *device); +int nfc_i3c_dev_remove(struct i3c_device *device); +int nfc_i3c_dev_suspend(struct device *device); +int nfc_i3c_dev_resume(struct device *device); +int i3c_enable_ibi(i3c_dev_t *i3c_dev); +int i3c_disable_ibi(i3c_dev_t *i3c_dev); +ssize_t i3c_write(i3c_dev_t *i3c_dev, const char *buf, const size_t count, + int max_retry_cnt); +ssize_t i3c_read(i3c_dev_t *, char *buf, size_t count); +#endif //_I3C_DRV_H_ diff --git a/nfc/sn110.c b/nfc/sn110.c new file mode 100644 index 0000000000..605ccf12a8 --- /dev/null +++ b/nfc/sn110.c @@ -0,0 +1,38 @@ +/****************************************************************************** + * Copyright (C) 2019-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#include +#include "common.h" +#include "sn110.h" + +int sn110_i2c_probe(nfc_dev_t *nfc_dev) +{ + pr_debug("%s: enter\n", __func__); + usleep_range(5000, 5100); + gpio_set_value(nfc_dev->gpio.ven, 1); + usleep_range(5000, 5100); + nfc_dev->ven_policy = VEN_ALWAYS_ENABLED; + return 0; +} + +int sn110_i3c_probe(nfc_dev_t *nfc_dev) +{ + pr_debug("%s: enter\n", __func__); + nfc_dev->ven_policy = VEN_ALWAYS_ENABLED; + return 0; +} diff --git a/nfc/sn110.h b/nfc/sn110.h new file mode 100644 index 0000000000..93de1bebfb --- /dev/null +++ b/nfc/sn110.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (C) 2019-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#ifndef _NFC_SN110_H_ +#define _NFC_SN110_H_ +int sn110_i2c_probe(nfc_dev_t *nfc_dev); +int sn110_i3c_probe(nfc_dev_t *nfc_dev); +#endif //_NFC_SN110_H_ diff --git a/pn553-i2c/Kconfig b/pn553-i2c/Kconfig deleted file mode 100644 index 878e4a8169..0000000000 --- a/pn553-i2c/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# Nxp Nci protocol (I2C) devices -# - -config NFC_PN553_DEVICES - bool "Nxp pn553 NCI protocol driver (I2C) devices" - default y - ---help--- - You'll have to say Y if your computer contains an I2C device that - you want to use under Linux. - - You can say N here if you don't have any SPI connected to your computer. - diff --git a/pn553-i2c/Makefile b/pn553-i2c/Makefile deleted file mode 100644 index 0534eed532..0000000000 --- a/pn553-i2c/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for nfc devices -# - -obj-$(CONFIG_NFC_PN553_DEVICES) += pn553.o - -ccflags-$(CONFIG_NFC_PN553_DEVICES) := -DDEBUG - diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c deleted file mode 100644 index 7fc6958103..0000000000 --- a/pn553-i2c/pn553.c +++ /dev/null @@ -1,1734 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -/****************************************************************************** - * - * The original Work has been changed by NXP Semiconductors. - * - * Copyright (C) 2013-2019 NXP Semiconductors - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* HiKey Compilation fix */ -#define HiKey_620_COMPILATION_FIX 1 -#ifndef HiKey_620_COMPILATION_FIX -#include -#endif - -#include -#include "pn553.h" - -#define NEXUS5x 0 -#define HWINFO 0 -#if NEXUS5x -#undef ISO_RST -#else -#define ISO_RST -#endif -#define DRAGON_NFC 1 -#define SIG_NFC 44 -#define MAX_BUFFER_SIZE 512 -#define MAX_SECURE_SESSIONS 1 -#define MSG_PROP_GID 0x4F -#define ESE_CLD_RST_OID 0x1E -#define ESE_CLD_RST_RSP_SIZE 0x04 - -/* VEN is kept ON all the time if you define the macro VEN_ALWAYS_ON. -Used for SN100 usecases */ -#define VEN_ALWAYS_ON -/* Macro added to disable SVDD power toggling */ -/* #define JCOP_4X_VALIDATION */ - -struct pn544_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct i2c_client *client; - struct miscdevice pn544_device; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int irq_gpio; - unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ -#ifdef ISO_RST - unsigned int iso_rst_gpio; /* ISO-RST pin gpio*/ -#endif - struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ - p61_access_state_t p61_current_state; /* stores the current P61 state */ - bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ - bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ - bool irq_enabled; - spinlock_t irq_enabled_lock; - long nfc_service_pid; /*used to signal the nfc the nfc service */ - chip_pwr_scheme_t chip_pwr_scheme; - unsigned int secure_timer_cnt; - struct workqueue_struct *pSecureTimerCbWq; - struct work_struct wq_task; - /* Bit value Status Remark - * b0 : 1 -> NFC_ON Driver Open should set the flag - * 0 NFC_OFF Driver release should reset this flag - * b1 : 1 -> FWDNLD If FWDNLD is going on. - * 0 Normal operation - * b2 : 1 -> ese_cold_reset sequence has been triggered from the SPI driver - * 0 -> ese_cold_reset cmd has been written by the NFC HAL - * bits b3 to b7 : Reserved for the future use. - * NOTE: Driver probe function should reset b0-b2 flags. - * The value of b3-b7 flags is undetermined. - * */ - volatile uint8_t state_flags; -}; -/* HiKey Compilation fix */ -#ifndef HiKey_620_COMPILATION_FIX -struct wake_lock nfc_wake_lock; -#if HWINFO -struct hw_type_info hw_info; -#endif -static bool sIsWakeLocked = false; -#endif -static struct pn544_dev *pn544_dev; -static struct semaphore ese_access_sema; -static struct semaphore svdd_sync_onoff_sema; -static struct completion dwp_onoff_sema; -static struct completion ese_cold_reset_sema; -static int8_t ese_cold_reset_rsp[ESE_CLD_RST_RSP_SIZE]; -static struct timer_list secure_timer; -static void release_ese_lock(p61_access_state_t p61_current_state); -int get_ese_lock(p61_access_state_t p61_current_state, int timeout); -static long set_jcop_download_state(unsigned long arg); -static long start_seccure_timer(unsigned long timer_value); -static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg); -#if HWINFO -static void check_hw_info(void); -#endif -#define SECURE_TIMER_WORK_QUEUE "SecTimerCbWq" - -static void pn544_disable_irq(struct pn544_dev *pn544_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); - if (pn544_dev->irq_enabled) { - disable_irq_nosync(pn544_dev->client->irq); - disable_irq_wake(pn544_dev->client->irq); - pn544_dev->irq_enabled = false; - } - spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); -} - -static int pn544_dev_release(struct inode *inode, struct file *filp) { - pn544_dev->state_flags = 0x00; - if (pn544_dev->firm_gpio) - gpio_set_value(pn544_dev->firm_gpio, 0); - pr_info(KERN_ALERT "Exit %s: NFC driver release nfc hal \n", __func__); - return 0; -} -static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) -{ - struct pn544_dev *pn544_dev = dev_id; - - pn544_disable_irq(pn544_dev); - /* HiKey Compilation fix */ - #ifndef HiKey_620_COMPILATION_FIX - if (sIsWakeLocked == false) - { - wake_lock(&nfc_wake_lock); - sIsWakeLocked = true; - } else { - pr_debug("%s already wake locked!\n", __func__); - } - #endif - /* Wake up waiting readers */ - wake_up(&pn544_dev->read_wq); - - - return IRQ_HANDLED; -} - -static void rcv_ese_cldrst_status(void) -{ - int ret = -1; - char tmp[MAX_BUFFER_SIZE]; - size_t rcount = (size_t)ese_cold_reset_rsp[2]; - /* Read data: No need to wait for the interrupt */ - ret = i2c_master_recv(pn544_dev->client, tmp, rcount); - if(ret == rcount){ - ese_cold_reset_rsp[3] = tmp[0]; - pr_info("%s NxpNciR : len = 4 > %02X%02X%02X%02X\n", __func__,ese_cold_reset_rsp[0], - ese_cold_reset_rsp[1],ese_cold_reset_rsp[2],ese_cold_reset_rsp[3]); - }else{ - pr_err("%s : Failed to receive payload of the cold_rst_cmd\n",__func__); - ese_cold_reset_rsp[3] = -EIO; - } - if(pn544_dev->state_flags &(P544_FLAG_NFC_ON)){ - complete(&ese_cold_reset_sema); - } -} - -static ssize_t pn544_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev = filp->private_data; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - //pr_debug("%s : reading %zu bytes.\n", __func__, count); - - mutex_lock(&pn544_dev->read_mutex); - - if (!gpio_get_value(pn544_dev->irq_gpio)) { - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto fail; - } - - while (1) { - pn544_dev->irq_enabled = true; - enable_irq(pn544_dev->client->irq); - enable_irq_wake(pn544_dev->client->irq); - ret = wait_event_interruptible( - pn544_dev->read_wq, - !pn544_dev->irq_enabled); - - pn544_disable_irq(pn544_dev); - - if (ret) - goto fail; - if(pn544_dev->state_flags & P544_FLAG_NFC_VEN_RESET) { - pr_warning("%s: releasing read \n", __func__); - pn544_dev->state_flags &= ~P544_FLAG_NFC_VEN_RESET; - ret = -EL3RST; - goto fail; - } - if (gpio_get_value(pn544_dev->irq_gpio)) - break; - - pr_warning("%s: spurious interrupt detected\n", __func__); - } - } - - /* Read data */ - ret = i2c_master_recv(pn544_dev->client, tmp, count); - #ifndef HiKey_620_COMPILATION_FIX - /* HiKey Compilation fix */ - if (sIsWakeLocked == true) { - wake_unlock(&nfc_wake_lock); - sIsWakeLocked = false; - } - #endif - - /* if the received response for COLD_RESET_COMMAND - * Consume it in driver*/ - if((pn544_dev->state_flags & P544_FLAG_ESE_COLD_RESET_FROM_DRIVER) && - MSG_PROP_GID == tmp[0] && ESE_CLD_RST_OID == tmp[1]){ - memset(&ese_cold_reset_rsp, 0, sizeof(ese_cold_reset_rsp)); - memcpy(ese_cold_reset_rsp, tmp, 3); - rcv_ese_cldrst_status(); - mutex_unlock(&pn544_dev->read_mutex); - return 0; - } - mutex_unlock(&pn544_dev->read_mutex); - - /* pn544 seems to be slow in handling I2C read requests - * so add 1ms delay after recv operation */ -#if !NEXUS5x - udelay(1000); -#endif - - if (ret < 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - return ret; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - return -EIO; - } - if (copy_to_user(buf, tmp, ret)) { - pr_warning("%s : failed to copy to user space\n", __func__); - return -EFAULT; - } - return ret; - - fail: - mutex_unlock(&pn544_dev->read_mutex); - return ret; -} - -static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - pn544_dev = filp->private_data; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - return -EFAULT; - } - - //pr_debug("%s : writing %zu bytes.\n", __func__, count); - /* Write data */ - ret = i2c_master_send(pn544_dev->client, tmp, count); - if (ret != count) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - ret = -EIO; - } - /* pn544 seems to be slow in handling I2C write requests - * so add 1ms delay after I2C send oparation */ - udelay(1000); - - return ret; -} - -static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) -{ - pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); - if (current_state) - { - if(set){ - if(pn544_dev->p61_current_state == P61_STATE_IDLE) - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->p61_current_state |= current_state; - } - else{ - pn544_dev->p61_current_state ^= current_state; - if(!pn544_dev->p61_current_state) - pn544_dev->p61_current_state = P61_STATE_IDLE; - } - } - pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); -} - -static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) -{ - - if (current_state == NULL) { - //*current_state = P61_STATE_INVALID; - pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); - } else { - *current_state = pn544_dev->p61_current_state; - } -} -static void p61_access_lock(struct pn544_dev *pn544_dev) -{ - mutex_lock(&pn544_dev->p61_state_mutex); -} -static void p61_access_unlock(struct pn544_dev *pn544_dev) -{ - mutex_unlock(&pn544_dev->p61_state_mutex); -} - -long p61_cold_reset(void) -{ - long ret = 0; - unsigned int loop=0x03; - struct file filp; - int timeout = 2000; /* 2s timeout :NCI cmd timeout*/ - unsigned long tempJ = msecs_to_jiffies(timeout); - uint8_t cmd_ese_cold_reset[] = {0x2F, 0x1E, 0x00}; - filp.private_data = pn544_dev; - pr_info("%s: Enter", __func__); - - if(pn544_dev->state_flags & P544_FLAG_FW_DNLD){ - /* If FW DNLD, Operation is not permitted */ - pr_err("%s : Operation is not permitted during fwdnld\n", __func__); - return -EPERM; - } - /* pn544_dev_read() should return the rsp if JNI has requested the cold reset*/ - pn544_dev->state_flags |= (P544_FLAG_ESE_COLD_RESET_FROM_DRIVER); - init_completion(&ese_cold_reset_sema); - /* write command to I2C line*/ - do{ - ret = i2c_master_send(pn544_dev->client, cmd_ese_cold_reset, sizeof(cmd_ese_cold_reset)); - if (ret == sizeof(cmd_ese_cold_reset)) { - break; - } - loop--; - usleep_range(5000, 6000); - }while(loop); - if(!loop && (ret != sizeof(cmd_ese_cold_reset)) ){ - pr_err("%s : i2c_master_send returned %ld\n", __func__, ret); - pn544_dev->state_flags &= ~(P544_FLAG_ESE_COLD_RESET_FROM_DRIVER); - return -EIO; - } - - pr_info("%s: NxpNciX: %ld > %02X%02X%02X \n", __func__, ret,cmd_ese_cold_reset[0], - cmd_ese_cold_reset[1],cmd_ese_cold_reset[2]); - ret = 0x00; - if(pn544_dev->state_flags & P544_FLAG_NFC_ON)/* NFC_ON */ - { - /* Read is pending from the NFC service which will complete the ese_cold_reset_sema */ - if(wait_for_completion_timeout(&ese_cold_reset_sema, tempJ) == 0){ - pr_err("%s: Timeout", __func__); - ese_cold_reset_rsp[3] = -EAGAIN; // Failure case - } - }else { /* NFC_OFF */ - /* call the pn544_dev_read() */ - filp.f_flags &= ~O_NONBLOCK; - ret = pn544_dev_read(&filp, NULL,3, 0); - } - if(0x00 == ret) /* success case */ - ret = ese_cold_reset_rsp[3]; - pn544_dev->state_flags &= ~(P544_FLAG_ESE_COLD_RESET_FROM_DRIVER); - /* Return the status to the SPI Driver */ - pr_info("%s: exit, Status:%ld", __func__,ret); - return ret; -} -EXPORT_SYMBOL(p61_cold_reset); - -static int signal_handler(p61_access_state_t state, long nfc_pid) -{ - struct siginfo sinfo; - pid_t pid; - struct task_struct *task; - int sigret = 0, ret = 0; - pr_info("%s: Enter\n", __func__); - - if(nfc_pid == 0) - { - pr_info("nfc_pid is clear don't call signal_handler.\n"); - } - else - { - memset(&sinfo, 0, sizeof(struct siginfo)); - sinfo.si_signo = SIG_NFC; - sinfo.si_code = SI_QUEUE; - sinfo.si_int = state; - pid = nfc_pid; - - task = pid_task(find_vpid(pid), PIDTYPE_PID); - if(task) - { - pr_info("%s.\n", task->comm); - sigret = force_sig_info(SIG_NFC, &sinfo, task); - if(sigret < 0){ - pr_info("send_sig_info failed..... sigret %d.\n", sigret); - ret = -1; - //msleep(60); - } - } - else{ - pr_info("finding task from PID failed\r\n"); - ret = -1; - } - } - pr_info("%s: Exit ret = %d\n", __func__, ret); - return ret; -} -static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) -{ - int timeout = 100; //100 ms timeout - unsigned long tempJ = msecs_to_jiffies(timeout); - pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); - if(nfc_service_pid) - { - if (0 == signal_handler(origin, nfc_service_pid)) - { - sema_init(&svdd_sync_onoff_sema, 0); - pr_info("Waiting for svdd protection response"); - if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) - { - pr_info("svdd wait protection: Timeout"); - } - pr_info("svdd wait protection : released"); - } - } -} -static int release_svdd_wait(void) -{ - pr_info("%s: Enter \n", __func__); - up(&svdd_sync_onoff_sema); - return 0; -} - -static void dwp_OnOff(long nfc_service_pid, p61_access_state_t origin) -{ - int timeout = 100; //100 ms timeout - unsigned long tempJ = msecs_to_jiffies(timeout); - if(nfc_service_pid) - { - if (0 == signal_handler(origin, nfc_service_pid)) - { - init_completion(&dwp_onoff_sema); - if(wait_for_completion_timeout(&dwp_onoff_sema, tempJ) != 0) - { - pr_info("Dwp On/off wait protection: Timeout"); - } - pr_info("Dwp On/Off wait protection : released"); - } - } -} -static int release_dwpOnOff_wait(void) -{ - pr_info("%s: Enter \n", __func__); - complete(&dwp_onoff_sema); - return 0; -} - -static int pn544_dev_open(struct inode *inode, struct file *filp) -{ - struct pn544_dev *pn544_dev = container_of(filp->private_data, - struct pn544_dev, - pn544_device); - - filp->private_data = pn544_dev; - pn544_dev->state_flags |= (P544_FLAG_NFC_ON); - pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); - - return 0; -} - -static int set_nfc_pid(unsigned long arg) -{ - pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); - pn544_dev->nfc_service_pid = arg; - return 0; -} - -long pn544_dev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - /* Free pass autobahn area, not protected. Use it carefullly. START */ - switch(cmd) - { - case P544_GET_ESE_ACCESS: - return get_ese_lock(P61_STATE_WIRED, arg); - break; - case P544_REL_SVDD_WAIT: - return release_svdd_wait(); - break; - case P544_SET_NFC_SERVICE_PID: - return set_nfc_pid(arg); - break; - case P544_REL_DWPONOFF_WAIT: - return release_dwpOnOff_wait(); - break; - default: - break; - } - /* Free pass autobahn area, not protected. Use it carefullly. END */ - - p61_access_lock(pn544_dev); - switch (cmd) { - case PN544_SET_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 2) { - if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) - { - /* NFCC fw/download should not be allowed if p61 is used - * by SPI - */ - pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - pn544_dev->nfc_ven_enabled = true; - if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) - || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) - { - /* power on with firmware download (requires hw reset) - */ - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - } - - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } else if (arg == 1) { - /* power on */ - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - if(current_state & P61_STATE_DWNLD){ - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, false); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = true; - #ifndef VEN_ALWAYS_ON - if (pn544_dev->spi_ven_enabled == false || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { - gpio_set_value(pn544_dev->ven_gpio, 1); - } - #endif - } else if (arg == 0) { - /* power off */ - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = false; - /* Don't change Ven state if spi made it high */ - #ifndef VEN_ALWAYS_ON - if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) - || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - } - #endif - /* HiKey Compilation fix */ - #ifndef HiKey_620_COMPILATION_FIX - if (sIsWakeLocked == true) { - wake_unlock(&nfc_wake_lock); - sIsWakeLocked = false; - } - #endif - } else if (arg == 3) { - /*NFC Service called ISO-RST*/ - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - if(current_state & P61_STATE_WIRED) { - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - } -#ifdef ISO_RST - gpio_set_value(pn544_dev->iso_rst_gpio, 0); - msleep(50); - gpio_set_value(pn544_dev->iso_rst_gpio, 1); - msleep(50); - pr_info("%s ISO RESET from DWP DONE\n", __func__); -#endif - } else if (arg == 4) { - pr_info("%s FW dwldioctl called from NFC \n", __func__); - /*NFC Service called FW dwnld*/ - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - pn544_dev->state_flags |= (P544_FLAG_FW_DNLD); - msleep(10); - } - } else if (arg == 5) { - pn544_dev->state_flags |= P544_FLAG_NFC_VEN_RESET; - pn544_disable_irq(pn544_dev); - wake_up(&pn544_dev->read_wq); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - pr_info("%s VEN reset DONE >>>>>>>\n", __func__); - } else if (arg == 6) { - if (pn544_dev->firm_gpio) { - gpio_set_value(pn544_dev->firm_gpio, 0); - pn544_dev->state_flags &= ~(P544_FLAG_FW_DNLD); - } - pr_info("%s FW GPIO set to 0x00 >>>>>>>\n", __func__); - }else { - pr_err("%s bad arg %lu\n", __func__, arg); - /* changed the p61 state to idle*/ - p61_access_unlock(pn544_dev); - return -EINVAL; - } - } - break; - case P61_SET_SPI_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) { - pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - /*To handle triple mode protection signal - NFC service when SPI session started*/ - if (!(current_state & P61_STATE_JCP_DWNLD)){ - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - /*signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid);*/ - dwp_OnOff(pn544_dev->nfc_service_pid, P61_STATE_SPI); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - - if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) - break; - #ifndef VEN_ALWAYS_ON - if (pn544_dev->nfc_ven_enabled == false) - { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - #endif - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - - /* Delay (10ms) after SVDD_PWR_ON to allow JCOP to bootup (5ms jcop boot time + 5ms guard time) */ - usleep_range(10000, 12000); - - } else { - pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); - if(current_state & P61_STATE_SPI_PRIO){ - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - if (!(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - if(!(current_state & P61_STATE_WIRED)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | - P61_STATE_SPI_PRIO_END); - }else { - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } else if (!(current_state & P61_STATE_WIRED)) { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - pn544_dev->spi_ven_enabled = false; - - if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) - break; - - /* if secure timer is running, Delay the SPI close by 25ms after sending End of Apdu to enable eSE go into DPD - gracefully (20ms after EOS + 5ms DPD settlement time) */ - if(pn544_dev->secure_timer_cnt) - usleep_range(25000, 30000); - - if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) - { -#ifndef JCOP_4X_VALIDATION - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ - usleep_range(2500, 3000); -#endif - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } -#ifndef JCOP_4X_VALIDATION - #ifndef VEN_ALWAYS_ON - if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - #endif -#endif - }else if(current_state & P61_STATE_SPI){ - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - if (!(current_state & P61_STATE_WIRED) && - (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) && - !(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - /* if secure timer is running, Delay the SPI close by 25ms after sending End of Apdu to enable eSE go into DPD - gracefully (20ms after EOS + 5ms DPD settlement time) */ - if(pn544_dev->secure_timer_cnt) - usleep_range(25000, 30000); - - if (!(pn544_dev->secure_timer_cnt)) { -#ifndef JCOP_4X_VALIDATION - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ - usleep_range(2500, 3000); -#endif - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } - /*If JCOP3.2 or 3.3 for handling triple mode - protection signal NFC service */ - else - { - if (!(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } else { - signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); - } - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } else if (pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { -#ifndef JCOP_4X_VALIDATION - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); -#endif - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); - } - } - pn544_dev->spi_ven_enabled = false; -#ifndef VEN_ALWAYS_ON - if (pn544_dev->nfc_ven_enabled == false && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) - && !(pn544_dev->secure_timer_cnt)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } -#endif - } else { - pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - }else if (arg == 2) { - pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); - if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - if (pn544_dev->spi_ven_enabled == false) - { - pn544_dev->spi_ven_enabled = true; - #ifndef VEN_ALWAYS_ON - if ((pn544_dev->nfc_ven_enabled == false) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - #endif - } - if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); -#ifndef JCOP_4X_VALIDATION - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); -#endif - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - msleep(10); - if(!gpio_get_value(pn544_dev->ese_pwr_gpio)) - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } - } else { - pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 3) { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); - if (current_state & P61_STATE_WIRED){ - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - /*signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid);*/ - dwp_OnOff(pn544_dev->nfc_service_pid, P61_STATE_SPI_PRIO); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) - { - #ifndef VEN_ALWAYS_ON - if (pn544_dev->nfc_ven_enabled == false) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - #endif - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - - /* Delay (10ms) after SVDD_PWR_ON to allow JCOP to bootup (5ms jcop boot time + 5ms guard time) */ - usleep_range(10000, 12000); - } - }else { - pr_info("%s : Prio Session Start power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 4) { - if (current_state & P61_STATE_SPI_PRIO) - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - /*after SPI prio timeout, the state is changing from SPI prio to SPI */ - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - if (current_state & P61_STATE_WIRED) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - } - else - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Device or resource busy */ - } - } else if(arg == 5){ - release_ese_lock(P61_STATE_SPI); - } else if (arg == 6) { - /*SPI Service called ISO-RST*/ - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if(current_state & P61_STATE_WIRED) { - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - if(current_state & P61_STATE_SPI) { - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - }else if(current_state & P61_STATE_SPI_PRIO) { - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - } -#ifdef ISO_RST - gpio_set_value(pn544_dev->iso_rst_gpio, 0); - msleep(50); - gpio_set_value(pn544_dev->iso_rst_gpio, 1); - msleep(50); - pr_info("%s ISO RESET from SPI DONE\n", __func__); -#endif - } - else { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - - case P61_GET_PWR_STATUS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); - put_user(current_state, (int __user *)arg); - } - break; - - case PN544_SET_DWNLD_STATUS: - { - long ret; - ret = set_jcop_download_state(arg); - if(ret < 0) - { - p61_access_unlock(pn544_dev); - return ret; - } - } - break; - - case P61_SET_WIRED_ACCESS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) - { - if (current_state) - { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); - if (current_state & P61_STATE_SPI_PRIO) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } else { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); - if (current_state & P61_STATE_WIRED){ - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } else { - pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - } - else if(arg == 2) - { - pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); - if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } - else if(arg == 3) - { - pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); - if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } - else if(arg == 4) - { - release_ese_lock(P61_STATE_WIRED); - } - else { - pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - case P544_SET_POWER_SCHEME: - { - if(arg == PN67T_PWR_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; - pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); - } - else if(arg == PN80T_LEGACY_PWR_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; - pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); - } - else if(arg == PN80T_EXT_PMU_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; - pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); - } - else - { - pr_info("%s : The power scheme is invalid,\n", __func__); - } - } - break; - case P544_SECURE_TIMER_SESSION: - { - secure_timer_operation(pn544_dev, arg); - } - break; - default: - pr_err("%s bad ioctl %u\n", __func__, cmd); - p61_access_unlock(pn544_dev); - return -EINVAL; - } - p61_access_unlock(pn544_dev); - return 0; -} -EXPORT_SYMBOL(pn544_dev_ioctl); - -static void secure_timer_workqueue(struct work_struct *Wq) -{ - p61_access_state_t current_state = P61_STATE_INVALID; - printk( KERN_INFO "secure_timer_callback: called (%lu).\n", jiffies); - /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: START */ - get_ese_lock(P61_STATE_WIRED, MAX_ESE_ACCESS_TIME_OUT_MS); - p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); - p61_get_access_state(pn544_dev, ¤t_state); - - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - printk( KERN_INFO "secure_timer_callback: make se_pwer_gpio low, state = %d", current_state); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ - usleep_range(2500, 3000); - #ifndef VEN_ALWAYS_ON - if(pn544_dev->nfc_service_pid == 0x00) - { - gpio_set_value(pn544_dev->ven_gpio, 0); - printk( KERN_INFO "secure_timer_callback :make ven_gpio low, state = %d", current_state); - } - #endif - } - pn544_dev->secure_timer_cnt = 0; - /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: END */ - release_ese_lock(P61_STATE_WIRED); - return; -} - -static void secure_timer_callback( unsigned long data ) -{ - /* Flush and push the timer callback event to the bottom half(work queue) - to be executed later, at a safer time */ - flush_workqueue(pn544_dev->pSecureTimerCbWq); - queue_work(pn544_dev->pSecureTimerCbWq, &pn544_dev->wq_task); - return; -} - -static long start_seccure_timer(unsigned long timer_value) -{ - long ret = -EINVAL; - pr_info("start_seccure_timer: enter\n"); - /* Delete the timer if timer pending */ - if(timer_pending(&secure_timer) == 1) - { - pr_info("start_seccure_timer: delete pending timer \n"); - /* delete timer if already pending */ - del_timer(&secure_timer); - } - /* Start the timer if timer value is non-zero */ - if(timer_value) - { - init_timer(&secure_timer); - setup_timer( &secure_timer, secure_timer_callback, 0 ); - - pr_info("start_seccure_timer: timeout %lums (%lu)\n",timer_value, jiffies ); - ret = mod_timer( &secure_timer, jiffies + msecs_to_jiffies(timer_value)); - if (ret) - pr_info("start_seccure_timer: Error in mod_timer\n"); - } - return ret; -} - -static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg) -{ - long ret = -EINVAL; - unsigned long timer_value = arg; - - printk( KERN_INFO "secure_timer_operation, %d\n",pn544_dev->chip_pwr_scheme); - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - ret = start_seccure_timer(timer_value); - if(!ret) - { - pn544_dev->secure_timer_cnt = 1; - p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, true); - } - else - { - pn544_dev->secure_timer_cnt = 0; - p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); - pr_info("%s :Secure timer reset \n", __func__); - } - } - else - { - pr_info("%s :Secure timer session not applicable \n", __func__); - } - return ret; -} - -static long set_jcop_download_state(unsigned long arg) -{ - p61_access_state_t current_state = P61_STATE_INVALID; - long ret = 0; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s:Enter PN544_SET_DWNLD_STATUS:JCOP Dwnld state arg = %ld",__func__, arg); - if(arg == JCP_DWNLD_INIT) - { - if(pn544_dev->nfc_service_pid) - { - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(JCP_DWNLD_INIT, pn544_dev->nfc_service_pid); - } - else - { - if (current_state & P61_STATE_JCP_DWNLD) - { - ret = -EINVAL; - } - else - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); - } - } - } - else if (arg == JCP_DWNLD_START) - { - if (current_state & P61_STATE_JCP_DWNLD) - { - ret = -EINVAL; - } - else - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); - } - } - else if (arg == JCP_SPI_DWNLD_COMPLETE) - { - if(pn544_dev->nfc_service_pid) - { - signal_handler(JCP_DWP_DWNLD_COMPLETE, pn544_dev->nfc_service_pid); - } - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); - } - else if (arg == JCP_DWP_DWNLD_COMPLETE) - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); - } - else - { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - pr_info("%s: PN544_SET_DWNLD_STATUS = %x",__func__, current_state); - - return ret; -} - -int get_ese_lock(p61_access_state_t p61_current_state, int timeout) -{ - unsigned long tempJ = msecs_to_jiffies(timeout); - if(down_timeout(&ese_access_sema, tempJ) != 0) - { - printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); - return -EBUSY; - } - return 0; -} -EXPORT_SYMBOL(get_ese_lock); - -static void release_ese_lock(p61_access_state_t p61_current_state) -{ - up(&ese_access_sema); -} - - -static const struct file_operations pn544_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = pn544_dev_read, - .write = pn544_dev_write, - .open = pn544_dev_open, - .release = pn544_dev_release, - .unlocked_ioctl = pn544_dev_ioctl, -}; -#if DRAGON_NFC -static int pn544_parse_dt(struct device *dev, - struct pn544_i2c_platform_data *data) -{ - struct device_node *np = dev->of_node; - int errorno = 0; - -#if !NEXUS5x - data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); - if ((!gpio_is_valid(data->irq_gpio))) - return -EINVAL; - - data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); - if ((!gpio_is_valid(data->ven_gpio))) - return -EINVAL; - - data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); - if ((!gpio_is_valid(data->firm_gpio))) - return -EINVAL; - - data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); - if ((!gpio_is_valid(data->ese_pwr_gpio))) - return -EINVAL; - data->iso_rst_gpio = of_get_named_gpio(np, "nxp,pn544-iso-pwr-rst", 0); - if ((!gpio_is_valid(data->iso_rst_gpio))) - return -EINVAL; -#else - data->ven_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_ven", 0, NULL); - data->firm_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_mode", 0, NULL); - data->irq_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_irq", 0, NULL); -#endif - pr_info("%s: %d, %d, %d, %d, %d error:%d\n", __func__, - data->irq_gpio, data->ven_gpio, data->firm_gpio, data->iso_rst_gpio, - data->ese_pwr_gpio, errorno); - - return errorno; -} -#endif - -static int pn544_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - struct pn544_i2c_platform_data *platform_data; - //struct pn544_dev *pn544_dev; - -#if !DRAGON_NFC - platform_data = client->dev.platform_data; -#else - struct device_node *node = client->dev.of_node; - - if (node) { - platform_data = devm_kzalloc(&client->dev, - sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); - if (!platform_data) { - dev_err(&client->dev, - "nfc-nci probe: Failed to allocate memory\n"); - return -ENOMEM; - } - ret = pn544_parse_dt(&client->dev, platform_data); - if (ret) - { - pr_info("%s pn544_parse_dt failed", __func__); - } - client->irq = gpio_to_irq(platform_data->irq_gpio); - if (client->irq < 0) - { - pr_info("%s gpio to irq failed", __func__); - } - } else { - platform_data = client->dev.platform_data; - } -#endif - if (platform_data == NULL) { - pr_err("%s : nfc probe fail\n", __func__); - return -ENODEV; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - return -ENODEV; - } -#if !DRAGON_NFC - ret = gpio_request(platform_data->irq_gpio, "nfc_int"); - if (ret) - return -ENODEV; - ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); - if (ret) - goto err_ven; - ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); - if (ret) - goto err_ese_pwr; - if (platform_data->firm_gpio) { - ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); - if (ret) - goto err_firm; - } -#ifdef ISO_RST - if(platform_data->iso_rst_gpio) { - ret = gpio_request(platform_data->iso_rst_gpio, "nfc_iso_rst"); - if (ret) - goto err_iso_rst; - } -#endif -#endif - pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); - if (pn544_dev == NULL) { - dev_err(&client->dev, - "failed to allocate memory for module data\n"); - ret = -ENOMEM; - goto err_exit; - } - - pn544_dev->irq_gpio = platform_data->irq_gpio; - pn544_dev->ven_gpio = platform_data->ven_gpio; - pn544_dev->firm_gpio = platform_data->firm_gpio; - pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; -#ifdef ISO_RST - pn544_dev->iso_rst_gpio = platform_data->iso_rst_gpio; -#endif - pn544_dev->p61_current_state = P61_STATE_IDLE; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; - pn544_dev->client = client; - pn544_dev->secure_timer_cnt = 0; - - pn544_dev->state_flags = 0x00; - ret = gpio_direction_input(pn544_dev->irq_gpio); - if (ret < 0) { - pr_err("%s :not able to set irq_gpio as input\n", __func__); - goto err_ven; - } - #ifndef VEN_ALWAYS_ON - ret = gpio_direction_output(pn544_dev->ven_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_firm; - } - #else - ret = gpio_direction_output(pn544_dev->ven_gpio, 1); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_firm; - } - #endif - ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); - goto err_ese_pwr; - } - if (platform_data->firm_gpio) { - ret = gpio_direction_output(pn544_dev->firm_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set firm_gpio as output\n", - __func__); - goto err_exit; - } - } -#ifdef ISO_RST - ret = gpio_direction_output(pn544_dev->iso_rst_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set iso rst gpio as output\n", __func__); - goto err_iso_rst; - } -#endif - /* init mutex and queues */ - init_waitqueue_head(&pn544_dev->read_wq); - mutex_init(&pn544_dev->read_mutex); - sema_init(&ese_access_sema, 1); - mutex_init(&pn544_dev->p61_state_mutex); - spin_lock_init(&pn544_dev->irq_enabled_lock); - pn544_dev->pSecureTimerCbWq = create_workqueue(SECURE_TIMER_WORK_QUEUE); - INIT_WORK(&pn544_dev->wq_task, secure_timer_workqueue); - pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; - pn544_dev->pn544_device.name = "pn553"; - pn544_dev->pn544_device.fops = &pn544_dev_fops; - - ret = misc_register(&pn544_dev->pn544_device); - if (ret) { - pr_err("%s : misc_register failed\n", __FILE__); - goto err_misc_register; - } - /* HiKey Compilation fix */ - #ifndef HiKey_620_COMPILATION_FIX - wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); - #endif -#ifdef ISO_RST - /* Setting ISO RESET pin high to power ESE during init */ - gpio_set_value(pn544_dev->iso_rst_gpio, 1); -#endif - /* request irq. the irq is set whenever the chip has data available - * for reading. it is cleared when all data has been read. - */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - pn544_dev->irq_enabled = true; - ret = request_irq(client->irq, pn544_dev_irq_handler, - IRQF_TRIGGER_HIGH, client->name, pn544_dev); - if (ret) { - dev_err(&client->dev, "request_irq failed\n"); - goto err_request_irq_failed; - } - enable_irq_wake(pn544_dev->client->irq); - pn544_disable_irq(pn544_dev); - i2c_set_clientdata(client, pn544_dev); -#ifdef VEN_ALWAYS_ON - msleep(5); /* VBAT--> VDDIO(HIGH) + Guardtime of min 5ms --> VEN(HIGH) */ - /* VEN toggle(reset) to proceed */ - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(5); - gpio_set_value(pn544_dev->ven_gpio, 1); -#endif - -#if HWINFO - /* - * This function is used only if - * hardware info is required during probe*/ - check_hw_info(); -#endif - - return 0; - - err_request_irq_failed: - misc_deregister(&pn544_dev->pn544_device); - err_misc_register: - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - kfree(pn544_dev); - err_exit: - if (pn544_dev->firm_gpio) - gpio_free(platform_data->firm_gpio); - err_firm: - gpio_free(platform_data->ese_pwr_gpio); - err_ese_pwr: - gpio_free(platform_data->ven_gpio); - err_ven: - gpio_free(platform_data->irq_gpio); -#ifdef ISO_RST - err_iso_rst: - gpio_free(platform_data->iso_rst_gpio); -#endif - return ret; -} - -static int pn544_remove(struct i2c_client *client) -{ - struct pn544_dev *pn544_dev; - - pn544_dev = i2c_get_clientdata(client); - free_irq(client->irq, pn544_dev); - misc_deregister(&pn544_dev->pn544_device); - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - gpio_free(pn544_dev->irq_gpio); - gpio_free(pn544_dev->ven_gpio); - gpio_free(pn544_dev->ese_pwr_gpio); - destroy_workqueue(pn544_dev->pSecureTimerCbWq); -#ifdef ISO_RST - gpio_free(pn544_dev->iso_rst_gpio); -#endif - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - - if (pn544_dev->firm_gpio) - gpio_free(pn544_dev->firm_gpio); - kfree(pn544_dev); - - return 0; -} - -static const struct i2c_device_id pn544_id[] = { -#if NEXUS5x - { "pn548", 0 }, -#else - { "pn544", 0 }, -#endif - { } -}; -#if DRAGON_NFC -static struct of_device_id pn544_i2c_dt_match[] = { - { -#if NEXUS5x - .compatible = "nxp,pn548", -#else - .compatible = "nxp,pn544", -#endif - }, - {} -}; -#endif -static struct i2c_driver pn544_driver = { - .id_table = pn544_id, - .probe = pn544_probe, - .remove = pn544_remove, - .driver = { - .owner = THIS_MODULE, -#if NEXUS5x - .name = "pn548", -#else - .name = "pn544", -#endif -#if DRAGON_NFC - .of_match_table = pn544_i2c_dt_match, -#endif - }, -}; -#if HWINFO -/****************************************************************************** - * Function check_hw_info - * - * Description This function is called during pn544_probe to retrieve - * HW info. - * Useful get HW information in case of previous FW download is - * interrupted and core reset is not allowed. - * This function checks if core reset is allowed, if not - * sets DWNLD_REQ(firm_gpio) , ven reset and sends firmware - * get version command. - * In response HW information will be received. - * - * Returns None - * - ******************************************************************************/ -static void check_hw_info() { - char read_data[20]; - int ret, get_version_len = 8, retry_count = 0; - static uint8_t cmd_reset_nci[] = {0x20, 0x00, 0x01, 0x00}; - char get_version_cmd[] = - {0x00, 0x04, 0xF1, 0x00, 0x00, 0x00, 0x6E, 0xEF}; - - pr_info("%s :Enter\n", __func__); - - /* - * Ven Reset before sending core Reset - * This is to check core reset is allowed or not. - * If not allowed then previous FW download is interrupted in between - * */ - pr_info("%s :Ven Reset \n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - ret = i2c_master_send(pn544_dev->client, cmd_reset_nci, 4); - - if (ret == 4) { - pr_info("%s : core reset write success\n", __func__); - } else { - - /* - * Core reset failed. - * set the DWNLD_REQ , do ven reset - * send firmware download info command - * */ - pr_err("%s : write failed\n", __func__); - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - } - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - ret = i2c_master_send(pn544_dev->client, get_version_cmd, get_version_len); - if (ret != get_version_len) { - ret = -EIO; - pr_err("%s : write_failed \n", __func__); - } - else { - pr_info("%s :data sent\n", __func__); - } - - ret = 0; - - while (retry_count < 10) { - - /* - * Wait for read interrupt - * If spurious interrupt is received retry again - * */ - pn544_dev->irq_enabled = true; - enable_irq(pn544_dev->client->irq); - enable_irq_wake(pn544_dev->client->irq); - ret = wait_event_interruptible( - pn544_dev->read_wq, - !pn544_dev->irq_enabled); - - pn544_disable_irq(pn544_dev); - - if (gpio_get_value(pn544_dev->irq_gpio)) - break; - - pr_warning("%s: spurious interrupt detected\n", __func__); - retry_count ++; - } - - if(ret) { - return; - } - - /* - * Read response data and copy into hw_type_info - * */ - ret = i2c_master_recv(pn544_dev->client, read_data, 14); - - if(ret) { - memcpy(hw_info.data, read_data, ret); - hw_info.len = ret; - pr_info("%s :data received len : %d\n", __func__,hw_info.len); - } - else { - pr_err("%s :Read Failed\n", __func__); - } - } -} -#endif -/* - * module load/unload record keeping - */ - -static int __init pn544_dev_init(void) -{ - pr_info("Loading pn544 driver\n"); - return i2c_add_driver(&pn544_driver); -} -module_init(pn544_dev_init); - -static void __exit pn544_dev_exit(void) -{ - pr_info("Unloading pn544 driver\n"); - i2c_del_driver(&pn544_driver); -} -module_exit(pn544_dev_exit); - -MODULE_AUTHOR("Sylvain Fonteneau"); -MODULE_DESCRIPTION("NFC PN544 driver"); -MODULE_LICENSE("GPL"); diff --git a/pn553-i2c/pn553.h b/pn553-i2c/pn553.h deleted file mode 100644 index ccc2830bc3..0000000000 --- a/pn553-i2c/pn553.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/****************************************************************************** - * - * The original Work has been changed by NXP Semiconductors. - * - * Copyright (C) 2013-2014 NXP Semiconductors - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#ifndef _PN553_H_ -#define _PN553_H_ -#define PN544_MAGIC 0xE9 - -/* - * PN544 power control via ioctl - * PN544_SET_PWR(0): power off - * PN544_SET_PWR(1): power on - * PN544_SET_PWR(2): reset and power on with firmware download enabled - */ -#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, long) - -/* - * SPI Request NFCC to enable p61 power, only in param - * Only for SPI - * level 1 = Enable power - * level 0 = Disable power - */ -#define P61_SET_SPI_PWR _IOW(PN544_MAGIC, 0x02, long) - -/* SPI or DWP can call this ioctl to get the current - * power state of P61 - * -*/ -#define P61_GET_PWR_STATUS _IOR(PN544_MAGIC, 0x03, long) - -/* DWP side this ioctl will be called - * level 1 = Wired access is enabled/ongoing - * level 0 = Wired access is disalbed/stopped -*/ -#define P61_SET_WIRED_ACCESS _IOW(PN544_MAGIC, 0x04, long) - -/* - NFC Init will call the ioctl to register the PID with the i2c driver -*/ -#define P544_SET_NFC_SERVICE_PID _IOW(PN544_MAGIC, 0x05, long) - -/* - NFC and SPI will call the ioctl to get the i2c/spi bus access -*/ -#define P544_GET_ESE_ACCESS _IOW(PN544_MAGIC, 0x06, long) -/* - NFC and SPI will call the ioctl to update the power scheme -*/ -#define P544_SET_POWER_SCHEME _IOW(PN544_MAGIC, 0x07, long) - -/* - NFC will call the ioctl to release the svdd protection -*/ -#define P544_REL_SVDD_WAIT _IOW(PN544_MAGIC, 0x08, long) - -/* SPI or DWP can call this ioctl to get the current - * power state of P61 - * -*/ -#define PN544_SET_DWNLD_STATUS _IOW(PN544_MAGIC, 0x09, long) -/* - NFC will call the ioctl to release the dwp on/off protection -*/ -#define P544_REL_DWPONOFF_WAIT _IOW(PN544_MAGIC, 0x0A, long) - -/* - NFC will call the ioctl to start Secure Timer -*/ - -#define P544_SECURE_TIMER_SESSION _IOW(PN544_MAGIC, 0x0B, long) - -#define MAX_ESE_ACCESS_TIME_OUT_MS 200 /*100 milliseconds*/ - -/* - NFC_ON: Driver is being used by the NFC service -*/ -#define P544_FLAG_NFC_ON 0x01 -/* - FW_DNLD: NFC_ON and FW download is going on -*/ -#define P544_FLAG_FW_DNLD 0x02 -/* - FW_DNLD: NFC_ON and FW download is going on -*/ -#define P544_FLAG_ESE_COLD_RESET_FROM_DRIVER 0x04 -/* - FW_DNLD: NFC_ON and FW download with VEN reset -*/ -#define P544_FLAG_NFC_VEN_RESET 0x08 - -typedef enum p61_access_state{ - P61_STATE_INVALID = 0x0000, - P61_STATE_IDLE = 0x0100, /* p61 is free to use */ - P61_STATE_WIRED = 0x0200, /* p61 is being accessed by DWP (NFCC)*/ - P61_STATE_SPI = 0x0400, /* P61 is being accessed by SPI */ - P61_STATE_DWNLD = 0x0800, /* NFCC fw download is in progress */ - P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ - P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ - P61_STATE_SPI_END = 0x4000, - P61_STATE_JCP_DWNLD = 0x8000,/* JCOP downlad in progress */ - P61_STATE_SECURE_MODE = 0x100000, /* secure mode state*/ - P61_STATE_SPI_SVDD_SYNC_START = 0x0001, /*ESE_VDD Low req by SPI*/ - P61_STATE_SPI_SVDD_SYNC_END = 0x0002, /*ESE_VDD is Low by SPI*/ - P61_STATE_DWP_SVDD_SYNC_START = 0x0004, /*ESE_VDD Low req by Nfc*/ - P61_STATE_DWP_SVDD_SYNC_END = 0x0008 /*ESE_VDD is Low by Nfc*/ -}p61_access_state_t; - -typedef enum chip_type_pwr_scheme{ - PN67T_PWR_SCHEME = 0x01, - PN80T_LEGACY_PWR_SCHEME, - PN80T_EXT_PMU_SCHEME, -}chip_pwr_scheme_t; - -typedef enum jcop_dwnld_state{ - JCP_DWNLD_IDLE = P61_STATE_JCP_DWNLD, /* jcop dwnld is ongoing*/ - JCP_DWNLD_INIT=0x8010, /* jcop dwonload init state*/ - JCP_DWNLD_START=0x8020, /* download started */ - JCP_SPI_DWNLD_COMPLETE=0x8040, /* jcop download complete in spi interface*/ - JCP_DWP_DWNLD_COMPLETE=0x8080, /* jcop download complete */ -} jcop_dwnld_state_t; - -struct pn544_i2c_platform_data { - unsigned int irq_gpio; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ - unsigned int iso_rst_gpio; /* gpio used for ISO hard reset P73*/ -}; - -struct hw_type_info { - /* - * Response of get_version_cmd will be stored in data - * byte structure : - * byte 0-1 : Header - * byte 2 : Status - * byte 3 : Hardware Version - * byte 4 : ROM code - * byte 5 : 0x00 constant - * byte 6-7 : Protected data version - * byte 8-9 : Trim data version - * byte 10-11 : FW version - * byte 12-13 : CRC - * */ - char data[20]; - int len; -}; -#endif From 25c57d3a9ed89449979b811ed02c8d2b6bdf7b76 Mon Sep 17 00:00:00 2001 From: Nanjesh Date: Fri, 24 Apr 2020 23:24:40 +0530 Subject: [PATCH 034/100] Updated corresponding to - NFC_AR_00_6000_11.02.00_OpnSrc --- nfc/Kconfig | 29 - nfc/Makefile | 11 - nfc/common.c | 667 ------------- nfc/common.h | 229 ----- nfc/i2c_drv.c | 465 --------- nfc/i2c_drv.h | 47 - nfc/i3c_drv.c | 766 --------------- nfc/i3c_drv.h | 109 --- nfc/sn110.c | 38 - nfc/sn110.h | 23 - pn553-i2c/Kconfig | 13 + pn553-i2c/Makefile | 9 + pn553-i2c/cold_reset.c | 343 +++++++ {nfc => pn553-i2c}/cold_reset.h | 23 +- pn553-i2c/pn553.c | 1611 +++++++++++++++++++++++++++++++ pn553-i2c/pn553.h | 266 +++++ 16 files changed, 2259 insertions(+), 2390 deletions(-) delete mode 100644 nfc/Kconfig delete mode 100644 nfc/Makefile delete mode 100644 nfc/common.c delete mode 100644 nfc/common.h delete mode 100644 nfc/i2c_drv.c delete mode 100644 nfc/i2c_drv.h delete mode 100644 nfc/i3c_drv.c delete mode 100644 nfc/i3c_drv.h delete mode 100644 nfc/sn110.c delete mode 100644 nfc/sn110.h create mode 100644 pn553-i2c/Kconfig create mode 100644 pn553-i2c/Makefile create mode 100644 pn553-i2c/cold_reset.c rename {nfc => pn553-i2c}/cold_reset.h (62%) create mode 100644 pn553-i2c/pn553.c create mode 100644 pn553-i2c/pn553.h diff --git a/nfc/Kconfig b/nfc/Kconfig deleted file mode 100644 index f87a2b7818..0000000000 --- a/nfc/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -# -# near field communication configuration -# - -config NXP_NFC_I2C - tristate "NFC on I2C Interface" - depends on I2C - ---help--- - This selects Near field controller on I2C Interface. - - If you want NFC support, you should say Y here and - also to your specific host controller driver. - -config NXP_NFC_I3C - tristate "NFC on I3C Interface" - depends on I3C - ---help--- - This selects Near field controller on I3C Interface. - - If you want NFC support, you should say Y here and - also to your specific host controller driver. - -config NXP_NFC_SN110 - bool "Nxp NFC sn110 Controller" - ---help--- - You'll have to say Y if your computer contains an sn110 i2C device that - you want to use under Linux. - - You can say N here if you don't have any sn110 I2C connected to your computer. diff --git a/nfc/Makefile b/nfc/Makefile deleted file mode 100644 index 8dc087ee68..0000000000 --- a/nfc/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for nfc devices -# -ifdef CONFIG_NXP_NFC_I2C -obj-y += common.o -else ifdef CONFIG_NXP_NFC_I3C -obj-y += common.o -endif -obj-$(CONFIG_NXP_NFC_I2C) += i2c_drv.o -obj-$(CONFIG_NXP_NFC_I3C) += i3c_drv.o -obj-$(CONFIG_NXP_NFC_SN110) += sn110.o diff --git a/nfc/common.c b/nfc/common.c deleted file mode 100644 index 6c3f5c2a80..0000000000 --- a/nfc/common.c +++ /dev/null @@ -1,667 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2019-2020 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#include -#include -#include -#include "../nfc/cold_reset.h" -#include "common.h" - -nfc_dev_t *nfc_dev_platform = NULL; - -int nfc_parse_dt(struct device *dev, platform_gpio_t *nfc_gpio, - uint8_t interface) -{ - struct device_node *np = dev->of_node; - - if (!np) { - pr_err("nfc of_node NULL\n"); - return -EINVAL; - } - //required for i2c based chips only - if (interface == PLATFORM_IF_I2C) { - nfc_gpio->irq = of_get_named_gpio(np, DTS_IRQ_GPIO_STR, 0); - if ((!gpio_is_valid(nfc_gpio->irq))) { - pr_err("nfc irq gpio invalid %d\n", nfc_gpio->irq); - return -EINVAL; - } - pr_info("%s: irq %d\n", __func__, nfc_gpio->irq); - } - nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); - if ((!gpio_is_valid(nfc_gpio->ven))) { - pr_err("nfc ven gpio invalid %d\n", nfc_gpio->ven); - return -EINVAL; - } - - nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); - if ((!gpio_is_valid(nfc_gpio->dwl_req))) { - pr_err("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req); - return -EINVAL; - } - //required for old platform only - nfc_gpio->ese_pwr = of_get_named_gpio(np, DTS_ESE_GPIO_STR, 0); - if ((!gpio_is_valid(nfc_gpio->ese_pwr))) { - pr_err("nfc ese_pwr gpio invalid %d\n", nfc_gpio->ese_pwr); - nfc_gpio->ese_pwr = -EINVAL; - } - - pr_info("%s: %d, %d, %d, %d\n", __func__, - nfc_gpio->irq, nfc_gpio->ven, nfc_gpio->dwl_req, - nfc_gpio->ese_pwr); - return 0; -} - -void gpio_set_ven(nfc_dev_t *nfc_dev, int value) -{ - if (nfc_dev->ven_policy == VEN_ALWAYS_ENABLED) { - value |= 1; - } - if (gpio_get_value(nfc_dev->gpio.ven) != value) { - gpio_set_value(nfc_dev->gpio.ven, value); - /* hardware dependent delay */ - usleep_range(10000, 10100); - } -} - -int configure_gpio(unsigned int gpio, int flag) -{ - int ret; - pr_debug("%s: nfc gpio [%d] flag [%01x]\n", __func__, gpio, flag); - if (gpio_is_valid(gpio)) { - ret = gpio_request(gpio, "nfc_gpio"); - if (ret) { - pr_err("%s: unable to request nfc gpio [%d]\n", - __func__, gpio); - return ret; - } - /*set direction and value for output pin */ - if (flag & GPIO_OUTPUT) - ret = gpio_direction_output(gpio, (GPIO_HIGH & flag)); - else - ret = gpio_direction_input(gpio); - - if (ret) { - pr_err - ("%s: unable to set direction for nfc gpio [%d]\n", - __func__, gpio); - gpio_free(gpio); - return ret; - } - /*Consider value as control for input IRQ pin */ - if (flag & GPIO_IRQ) { - ret = gpio_to_irq(gpio); - if (ret < 0) { - pr_err - ("%s: unable to set irq for nfc gpio [%d]\n", - __func__, gpio); - gpio_free(gpio); - return ret; - } - pr_debug - ("%s: gpio_to_irq successful [%d]\n", - __func__, gpio); - return ret; - } - } else { - pr_err("%s: invalid gpio\n", __func__); - ret = -EINVAL; - } - return ret; -} - -void gpio_free_all(nfc_dev_t *nfc_dev) -{ - if (gpio_is_valid(nfc_dev->gpio.ese_pwr)) { - gpio_free(nfc_dev->gpio.ese_pwr); - } - if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { - gpio_free(nfc_dev->gpio.dwl_req); - } - if (gpio_is_valid(nfc_dev->gpio.irq)) { - gpio_free(nfc_dev->gpio.irq); - } - if (gpio_is_valid(nfc_dev->gpio.ven)) { - gpio_free(nfc_dev->gpio.ven); - } -} - -void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count) -{ - pr_debug("%s: entry\n", __func__); - device_destroy(nfc_dev->nfc_class, nfc_dev->devno); - cdev_del(&nfc_dev->c_dev); - class_destroy(nfc_dev->nfc_class); - unregister_chrdev_region(nfc_dev->devno, count); -} - -int nfc_misc_register(nfc_dev_t *nfc_dev, - const struct file_operations *nfc_fops, - int count, char *devname, char *classname) -{ - int ret = 0; - ret = alloc_chrdev_region(&nfc_dev->devno, 0, count, devname); - if (ret < 0) { - pr_err("%s: failed to alloc chrdev region ret %d\n", - __func__, ret); - return ret; - } - nfc_dev->nfc_class = class_create(THIS_MODULE, classname); - if (IS_ERR(nfc_dev->nfc_class)) { - ret = PTR_ERR(nfc_dev->nfc_class); - pr_err("%s: failed to register device class ret %d\n", - __func__, ret); - unregister_chrdev_region(nfc_dev->devno, count); - return ret; - } - cdev_init(&nfc_dev->c_dev, nfc_fops); - ret = cdev_add(&nfc_dev->c_dev, nfc_dev->devno, count); - if (ret < 0) { - pr_err("%s: failed to add cdev ret %d\n", __func__, ret); - class_destroy(nfc_dev->nfc_class); - unregister_chrdev_region(nfc_dev->devno, count); - return ret; - } - nfc_dev->nfc_device = device_create(nfc_dev->nfc_class, NULL, - nfc_dev->devno, nfc_dev, devname); - if (IS_ERR(nfc_dev->nfc_device)) { - ret = PTR_ERR(nfc_dev->nfc_device); - pr_err("%s: failed to create the device ret %d\n", - __func__, ret); - cdev_del(&nfc_dev->c_dev); - class_destroy(nfc_dev->nfc_class); - unregister_chrdev_region(nfc_dev->devno, count); - return ret; - } - return 0; -} - -static void enable_interrupt(nfc_dev_t *nfc_dev) -{ - if (nfc_dev->interface == PLATFORM_IF_I2C) - i2c_enable_irq(&nfc_dev->i2c_dev); - else { -#ifdef CONFIG_NXP_NFC_I3C - i3c_enable_ibi(&nfc_dev->i3c_dev); -#endif //CONFIG_NXP_NFC_I3C - } -} - -static void disable_interrupt(nfc_dev_t *nfc_dev) -{ - if (nfc_dev->interface == PLATFORM_IF_I2C) - i2c_disable_irq(&nfc_dev->i2c_dev); - else { -#ifdef CONFIG_NXP_NFC_I3C - i3c_disable_ibi(&nfc_dev->i3c_dev); -#endif //CONFIG_NXP_NFC_I3C - } -} - -static int send_cold_reset_cmd(nfc_dev_t *nfc_dev) -{ - int ret = 0; - char cmd[COLD_RESET_CMD_LEN]; - - cmd[0] = COLD_RESET_CMD_GID; - cmd[1] = COLD_RESET_OID; - cmd[2] = COLD_RESET_CMD_PAYLOAD_LEN; - if (nfc_dev->interface == PLATFORM_IF_I2C) { - ret = i2c_write(&nfc_dev->i2c_dev, cmd, - COLD_RESET_CMD_LEN, MAX_RETRY_COUNT); - } else { - //TODO: Handling Cold reset for I3C - //ret = i3c_write(nfc_dev->i3c_dev, cmd, COLD_RESET_CMD_LEN); - } - if (ret != COLD_RESET_CMD_LEN) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - nfc_dev->cold_reset.timer_started = false; - return -EIO; - } - pr_info("%s: NxpNciX: %d > %02X%02X%02X \n", __func__, ret, cmd[0], - cmd[1], cmd[2]); - return ret; -} - -void read_cold_reset_rsp(nfc_dev_t *nfc_dev, char *buf) -{ - int ret = -1; - char rsp[COLD_RESET_RSP_LEN]; - i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; - cold_reset_t *cold_reset = &nfc_dev->cold_reset; - cold_reset->status = -EIO; - /* - * read header also if NFC is disabled - * for enable case, will be taken care by nfc read thread - */ - if (!cold_reset->nfc_enabled) { - if (nfc_dev->interface == PLATFORM_IF_I2C) { - ret = i2c_read(i2c_dev, rsp, NCI_HDR_LEN); - } else { - //TODO: Handling Cold reset for I3C - //ret = i3c_read(i3c_dev, rsp, NCI_HDR_LEN); - } - if (ret != NCI_HDR_LEN) { - pr_err("%s: failure to read cold reset rsp header\n", - __func__); - return; - } - } else { - memcpy(rsp, buf, NCI_HDR_LEN); - } - if ((NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_OFFSET]) != COLD_RESET_RSP_LEN) { - pr_err("%s: - invalid response for cold_reset\n", __func__); - return; - } - if (nfc_dev->interface == PLATFORM_IF_I2C) { - ret = i2c_read(i2c_dev, &rsp[NCI_PAYLOAD_IDX], rsp[2]); - } else { - //TODO:Handling Cold Reset for I3C - //ret = i3c_read(nfc_dev->i3c_dev, &rsp[NCI_PAYLOAD_IDX], rsp[2]); - } - if (ret != rsp[2]) { - pr_err("%s: failure to read cold reset rsp header\n", __func__); - return; - } - pr_info("%s NxpNciR : len = 4 > %02X%02X%02X%02X\n", __func__, rsp[0], - rsp[1], rsp[2], rsp[3]); - cold_reset->status = rsp[NCI_PAYLOAD_IDX]; -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) -static void ese_cold_reset_gaurd_timer_callback(unsigned long data) -{ - (void)data; -#else -static void ese_cold_reset_gaurd_timer_callback(struct timer_list *unused) -{ -#endif - pr_info("%s: Enter\n",__func__); - nfc_dev_platform->cold_reset.timer_started = false; - return; -} - -static long start_ese_cold_reset_guard_timer(void) -{ - long ret = -EINVAL; - if (timer_pending(&nfc_dev_platform->cold_reset.timer) == 1) { - pr_info("ese_cold_reset_guard_timer: delete pending timer \n"); - /* delete timer if already pending */ - del_timer(&nfc_dev_platform->cold_reset.timer); - } - nfc_dev_platform->cold_reset.timer_started = true; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) - init_timer(&nfc_dev_platform->cold_reset.timer); - setup_timer( &nfc_dev_platform->cold_reset.timer, ese_cold_reset_gaurd_timer_callback, 0); -#else - timer_setup(&nfc_dev_platform->cold_reset.timer, ese_cold_reset_gaurd_timer_callback, 0); -#endif - ret = mod_timer(&nfc_dev_platform->cold_reset.timer, - jiffies + msecs_to_jiffies(ESE_COLD_RESET_GUARD_TIME)); - return ret; -} - -static int perform_ese_cold_reset(nfc_dev_t *nfc_dev, - ese_cold_reset_origin_t origin) -{ - int ret = 0; - - if (gpio_get_value(nfc_dev->gpio.dwl_req)) { - pr_err("FW download in-progress\n"); - return -EBUSY; - } - if (!gpio_get_value(nfc_dev->gpio.ven)) { - pr_err("VEN LOW - NFCC powered off\n"); - return -ENODEV; - } - - mutex_lock(&nfc_dev->cold_reset.sync_mutex); - if (!nfc_dev->cold_reset.timer_started) { - ret = start_ese_cold_reset_guard_timer(); - if (ret) { - pr_err("%s: Error in mod_timer\n", __func__); - mutex_unlock(&nfc_dev->cold_reset.sync_mutex); - return ret; - } - /* set default value for status as failure */ - nfc_dev->cold_reset.status = -EIO; - ret = send_cold_reset_cmd(nfc_dev); - if (ret <= 0) { - pr_err("failed to send cold reset command\n"); - mutex_unlock(&nfc_dev->cold_reset.sync_mutex); - return ret; - } - ret = 0; - nfc_dev->cold_reset.rsp_pending = true; - /* check if NFC is enabled */ - if (nfc_dev->cold_reset.nfc_enabled) { - /* Pending read from NFC_HAL will read the cold reset rsp and signal read_wq */ - if (!wait_event_interruptible_timeout - (nfc_dev->cold_reset.read_wq, - nfc_dev->cold_reset.rsp_pending == false, - msecs_to_jiffies(ESE_COLD_RESET_CMD_RSP_TIMEOUT))) - { - pr_err("%s:Cold Reset Response Timeout\n", - __func__); - } - } else { - /* Read data as NFC thread is not active */ - enable_interrupt(nfc_dev); - read_cold_reset_rsp(nfc_dev, NULL); - nfc_dev->cold_reset.rsp_pending = false; - // TODO: Handling Cold reset for I3C - // ret = i3c_read(i3c_dev, rsp, NCI_HDR_LEN); - } - if (!ret) { /* wait for reboot guard timer */ - if (wait_event_interruptible_timeout - (nfc_dev->cold_reset.read_wq, true, - msecs_to_jiffies(ESE_COLD_RESET_REBOOT_GUARD_TIME)) - == 0) { - pr_err("%s: guard Timeout interrupted", - __func__); - } - } - } - mutex_unlock(&nfc_dev->cold_reset.sync_mutex); - if (ret == 0) /* success case */ - ret = nfc_dev->cold_reset.status; - return ret; -} - -/* - * Power management of the eSE - * eSE and NFCC both are powered using VEN gpio, - * VEN HIGH - eSE and NFCC both are powered on - * VEN LOW - eSE and NFCC both are power down - */ -int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg) -{ - int ret = 0; - if (arg == ESE_POWER_ON) { - /** - * Let's store the NFC VEN pin state - * will check stored value in case of eSE power off request, - * to find out if NFC MW also sent request to set VEN HIGH - * VEN state will remain HIGH if NFC is enabled otherwise - * it will be set as LOW - */ - nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_dev->gpio.ven); - if (!nfc_dev->nfc_ven_enabled) { - pr_debug("eSE HAL service setting ven HIGH\n"); - gpio_set_ven(nfc_dev, 1); - } else { - pr_debug("ven already HIGH\n"); - } - } else if (arg == ESE_POWER_OFF) { - if (!nfc_dev->nfc_ven_enabled) { - pr_debug("NFC not enabled, disabling ven\n"); - gpio_set_ven(nfc_dev, 0); - } else { - pr_debug("keep ven high as NFC is enabled\n"); - } - } else if (IS_COLD_RESET_REQ(arg) && - nfc_dev->interface == PLATFORM_IF_I2C) { - ret = perform_ese_cold_reset(nfc_dev, arg); - } else if (arg == ESE_POWER_STATE) { - // eSE power state - ret = gpio_get_value(nfc_dev->gpio.ven); - } else { - pr_err("%s bad arg %lu\n", __func__, arg); - ret = -ENOIOCTLCMD; - } - return ret; -} - -EXPORT_SYMBOL(nfc_ese_pwr); - -/* - * This function shall be called from SPI, UWB, NFC driver to perform eSE cold reset. - */ -int ese_cold_reset(ese_cold_reset_origin_t origin) -{ - int ret = 0; - unsigned long arg; - pr_info("%s: Enter origin:%d", __func__, origin); - - switch (origin) { - case ESE_COLD_RESET_SOURCE_SPI: - arg = ESE_COLD_RESET_SPI; - break; - case ESE_COLD_RESET_SOURCE_UWB: - arg = ESE_COLD_RESET_UWB; - break; - default: - pr_info("%s: Invalid argument", __func__); - return -EINVAL; - } - if (nfc_dev_platform == NULL) - return -ENODEV; - ret = nfc_ese_pwr(nfc_dev_platform, arg); - pr_info("%s:%d exit, Status:%d", __func__, origin, ret); - return ret; -} - -EXPORT_SYMBOL(ese_cold_reset); - -/* - * nfc_ioctl_power_states() - power control - * @filp: pointer to the file descriptor - * @arg: mode that we want to move to - * - * Device power control. Depending on the arg value, device moves to - * different states - * (arg = 0): NFC_ENABLE GPIO = 0, FW_DL GPIO = 0 - * (arg = 1): NFC_ENABLE GPIO = 1, FW_DL GPIO = 0 - * (arg = 2): FW_DL GPIO = 1 - * - * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case - */ -static int nfc_ioctl_power_states(nfc_dev_t *nfc_dev, unsigned long arg) -{ - int ret = 0; - if (arg == NFC_POWER_OFF) { - /* - * We are attempting a hardware reset so let us disable - * interrupts to avoid spurious notifications to upper - * layers. - */ - disable_interrupt(nfc_dev); - pr_debug("gpio firm disable\n"); - if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { - gpio_set_value(nfc_dev->gpio.dwl_req, 0); - usleep_range(10000, 10100); - } - if (gpio_is_valid(nfc_dev->gpio.ese_pwr)) { - if (!gpio_get_value(nfc_dev->gpio.ese_pwr)) { - pr_debug("disabling ven\n"); - gpio_set_ven(nfc_dev, 0); - } else { - pr_debug("keeping ven high\n"); - } - } else { - pr_debug("ese_pwr invalid, set ven to low\n"); - gpio_set_ven(nfc_dev, 0); - } - nfc_dev->nfc_ven_enabled = false; - } else if (arg == NFC_POWER_ON) { - enable_interrupt(nfc_dev); - pr_debug("gpio_set_value enable: %s:\n", __func__); - if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { - gpio_set_value(nfc_dev->gpio.dwl_req, 0); - usleep_range(10000, 10100); - } - gpio_set_ven(nfc_dev, 1); - nfc_dev->nfc_ven_enabled = true; -#ifdef CONFIG_NXP_NFC_I3C - if (nfc_dev->interface == PLATFORM_IF_I3C) - nfc_dev->i3c_dev.read_hdr = NCI_HDR_LEN; -#endif //CONFIG_NXP_NFC_I3C - } else if (arg == NFC_FW_DWL_VEN_TOGGLE) { - /* - * We are switching to Dowload Mode, toggle the enable pin - * in order to set the NFCC in the new mode - */ - if (gpio_is_valid(nfc_dev->gpio.ese_pwr)) { - if (gpio_get_value(nfc_dev->gpio.ese_pwr)) { - pr_err - ("FW download forbidden while ese is on\n"); - return -EBUSY; /* Device or resource busy */ - } - } - gpio_set_value(nfc_dev->gpio.ven, 1); - if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { - gpio_set_value(nfc_dev->gpio.dwl_req, 1); - usleep_range(10000, 10100); - } - if (nfc_dev->interface == PLATFORM_IF_I2C) { - gpio_set_value(nfc_dev->gpio.ven, 0); - usleep_range(10000, 10100); - } - gpio_set_value(nfc_dev->gpio.ven, 1); - usleep_range(10000, 10100); - } else if (arg == NFC_FW_DWL_HIGH) { - /* - * Setting firmware download gpio to HIGH - * before FW download start - */ - pr_debug("set fw gpio high\n"); - if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { - gpio_set_value(nfc_dev->gpio.dwl_req, 1); - usleep_range(10000, 10100); - } else - pr_debug("gpio.dwl_req is invalid\n"); - } else if (arg == NFC_VEN_FORCED_HARD_RESET - && nfc_dev->interface == PLATFORM_IF_I2C) { - /* - * TODO: Enable Ven reset for I3C, after hot join integration - */ - gpio_set_value(nfc_dev->gpio.ven, 0); - usleep_range(10000, 10100); - gpio_set_value(nfc_dev->gpio.ven, 1); - usleep_range(10000, 10100); - pr_info("%s VEN forced reset done\n", __func__); - } else if (arg == NFC_FW_DWL_LOW) { - /* - * Setting firmware download gpio to LOW - * FW download finished - */ - pr_debug("set fw gpio LOW\n"); - if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { - gpio_set_value(nfc_dev->gpio.dwl_req, 0); - usleep_range(10000, 10100); - } else { - pr_debug("gpio.dwl_req is invalid\n"); - } -#ifdef CONFIG_NXP_NFC_I3C - if (nfc_dev->interface == PLATFORM_IF_I3C) - nfc_dev->i3c_dev.read_hdr = NCI_HDR_LEN; -#endif //CONFIG_NXP_NFC_I3C -#ifdef CONFIG_NXP_NFC_I3C - } else if (arg == NFC_FW_HDR_LEN) { - if (nfc_dev->interface == PLATFORM_IF_I3C) - nfc_dev->i3c_dev.read_hdr = FW_HDR_LEN; -#endif //CONFIG_NXP_NFC_I3C - } else { - pr_err("%s bad arg %lu\n", __func__, arg); - ret = -ENOIOCTLCMD; - } - return ret; -} - -/** @brief IOCTL function to be used to set or get data from upper layer. - * - * @param pfile fil node for opened device. - * @cmd IOCTL type from upper layer. - * @arg IOCTL arg from upper layer. - * - * @return 0 on success, error code for failures. - */ -long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) -{ - int ret = 0; - struct nfc_dev *nfc_dev = pfile->private_data; - if (!nfc_dev) - return -ENODEV; - - pr_debug("%s cmd = %x arg = %zx\n", __func__, cmd, arg); - switch (cmd) { - case NFC_SET_PWR: - ret = nfc_ioctl_power_states(nfc_dev, arg); - break; - case ESE_SET_PWR: - ret = nfc_ese_pwr(nfc_dev, arg); - break; - case ESE_GET_PWR: - ret = nfc_ese_pwr(nfc_dev, 3); - break; - case NFC_GET_PLATFORM_TYPE: - ret = nfc_dev->interface; - break; - default: - pr_err("%s bad cmd %lu\n", __func__, arg); - ret = -ENOIOCTLCMD; - }; - return ret; -} - -int nfc_dev_open(struct inode *inode, struct file *filp) -{ - nfc_dev_t *nfc_dev = container_of(inode->i_cdev, nfc_dev_t, c_dev); - if (!nfc_dev) - return -ENODEV; - pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); - - mutex_lock(&nfc_dev->dev_ref_mutex); - - filp->private_data = nfc_dev; - - if (nfc_dev->dev_ref_count == 0) { - if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { - gpio_set_value(nfc_dev->gpio.dwl_req, 0); - usleep_range(10000, 10100); - } - nfc_dev->cold_reset.nfc_enabled = true; - enable_interrupt(nfc_dev); - } - nfc_dev->dev_ref_count = nfc_dev->dev_ref_count + 1; - mutex_unlock(&nfc_dev->dev_ref_mutex); - return 0; -} - -int nfc_dev_close(struct inode *inode, struct file *filp) -{ - nfc_dev_t *nfc_dev = container_of(inode->i_cdev, nfc_dev_t, c_dev); - if (!nfc_dev) - return -ENODEV; - pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); - mutex_lock(&nfc_dev->dev_ref_mutex); - if (nfc_dev->dev_ref_count == 1) { - disable_interrupt(nfc_dev); - if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { - gpio_set_value(nfc_dev->gpio.dwl_req, 0); - usleep_range(10000, 10100); - } - nfc_dev->cold_reset.nfc_enabled = false; - } - if (nfc_dev->dev_ref_count > 0) - nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; - - filp->private_data = NULL; - - mutex_unlock(&nfc_dev->dev_ref_mutex); - return 0; -} diff --git a/nfc/common.h b/nfc/common.h deleted file mode 100644 index 49f6e2b49b..0000000000 --- a/nfc/common.h +++ /dev/null @@ -1,229 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2019-2020 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#ifndef _COMMON_H_ -#define _COMMON_H_ -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_NXP_NFC_I2C -#include "i2c_drv.h" -#endif -#ifdef CONFIG_NXP_NFC_I3C -#include "i3c_drv.h" -#endif - -#define DEV_COUNT 1 /* Max device count for this driver */ -#define CLASS_NAME "nfc" /* i2c device class */ - -// NFC character device name, this will be in /dev/ -#define NFC_CHAR_DEV_NAME "pn553" -#define NCI_HDR_LEN 3 /* HDR length of NCI packet */ -#define NCI_PAYLOAD_LEN_OFFSET 2 -#define NCI_PAYLOAD_IDX 3 -#define MAX_NCI_PAYLOAD_LEN (255) -#define MAX_BUFFER_SIZE (NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN) -#define MAX_RETRY_COUNT (3) -#define NO_RETRY (1) -#define MAX_IRQ_WAIT_TIME (90) -#define WAKEUP_SRC_TIMEOUT (2000) - -/* ESE_COLD_RESET MACROS */ -#define COLD_RESET_CMD_LEN 3 -#define COLD_RESET_RSP_LEN 4 -#define COLD_RESET_CMD_GID 0x2F -#define COLD_RESET_CMD_PAYLOAD_LEN 0x00 -#define COLD_RESET_RSP_GID 0x4F -#define COLD_RESET_OID 0x1E -/* - * ESE_RESET: Bit mask to check if ese_reset_guard timer is started (bit b7) - * */ -#define ESE_COLD_RESET_GUARD_TIMER_MASK (0x80) -/* - * ESE_RESET: Guard time to allow eSE cold reset from the driver - * */ -#define ESE_COLD_RESET_GUARD_TIME (3000) //3s -/* - * ESE_RESET: NCI command response timeout -*/ -#define ESE_COLD_RESET_CMD_RSP_TIMEOUT (2000) //2s -/* - * ESE_RESET: Guard time to reboot the JCOP -*/ -#define ESE_COLD_RESET_REBOOT_GUARD_TIME (50) //50ms -/* - * ESE_RESET: Checks if eSE cold reset has been requested - */ -#define IS_COLD_RESET_REQ(arg) ((arg == ESE_COLD_RESET_NFC) || \ - (arg == ESE_COLD_RESET_SPI) || (arg == ESE_COLD_RESET_UWB)) -/* - * ESE_RESET: macro evaluates to 1 if eSE cold reset response is received - * */ -#define IS_COLD_RESET_RSP(buf) ((COLD_RESET_RSP_GID == buf[0]) && (COLD_RESET_OID == buf[1])) - -#define NFC_MAGIC 0xE9 - -/*Ioctls*/ -// The type should be aligned with MW HAL definitions -#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, long) -#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, long) -#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, long) -#define NFC_GET_PLATFORM_TYPE _IO(NFC_MAGIC, 0x0B) - -#define DTS_IRQ_GPIO_STR "nxp,pn544-irq" -#define DTS_VEN_GPIO_STR "nxp,pn544-ven" -#define DTS_FWDN_GPIO_STR "nxp,pn544-fw-dwnld" -#define DTS_ESE_GPIO_STR "nxp,pn544-ese-pwr" - -enum ese_ioctl_request { - /* eSE POWER ON */ - ESE_POWER_ON = 0, - /* eSE POWER OFF */ - ESE_POWER_OFF, - /* eSE POWER STATE */ - ESE_POWER_STATE, - /* eSE COLD RESET */ - ESE_COLD_RESET_NFC, - ESE_COLD_RESET_SPI, - ESE_COLD_RESET_UWB, -}; - -enum nfcc_ioctl_request { - /* NFC disable request with VEN LOW */ - NFC_POWER_OFF = 0, - /* NFC enable request with VEN Toggle */ - NFC_POWER_ON, - /* firmware download request with VEN Toggle */ - NFC_FW_DWL_VEN_TOGGLE, - /* ISO reset request */ - NFC_ISO_RESET, - /* request for firmware download gpio HIGH */ - NFC_FW_DWL_HIGH, - /* VEN hard reset request */ - NFC_VEN_FORCED_HARD_RESET, - /* request for firmware download gpio LOW */ - NFC_FW_DWL_LOW, - /*for HDR size change in FW mode */ - NFC_FW_HDR_LEN, - /* Cold reset request for eSE */ - NFC_ESE_COLD_RST, -}; - -/*nfc platform interface type*/ -enum interface_flags { - /*I2C physical IF for NFCC */ - PLATFORM_IF_I2C = 0, - /*I3C physical IF for NFCC */ - PLATFORM_IF_I3C, -}; -/*nfc platform interface type*/ -enum ven_policy_flags { - /*VEN usage in lagacy platform */ - VEN_LEGACY = 0, - /*VEN reset only to recover from failure usecases */ - VEN_ALWAYS_ENABLED, -}; -/* Power state for IBI handing, mainly needed to defer the IBI handling - for the IBI received in suspend state to do it later in resume call*/ -enum pm_state_flags { - PM_STATE_NORMAL = 0, - PM_STATE_SUSPEND, - PM_STATE_IBI_BEFORE_RESUME, -}; - -/* Enum for GPIO values*/ -enum gpio_values { - GPIO_INPUT = 0x0, - GPIO_OUTPUT = 0x1, - GPIO_HIGH = 0x2, - GPIO_OUTPUT_HIGH = 0x3, - GPIO_IRQ = 0x4, -}; - -// NFC GPIO variables -typedef struct platform_gpio { - unsigned int irq; - unsigned int ven; - unsigned int dwl_req; - unsigned int ese_pwr; -} platform_gpio_t; - -//Features specific Parameters -typedef struct cold_reset { - wait_queue_head_t read_wq; - bool rsp_pending; - unsigned int ntf; - uint8_t status; - /* NFC device opened by MW */ - bool nfc_enabled; - /* eSe cold reset guard timer is started */ - bool timer_started; - struct mutex sync_mutex; - struct timer_list timer; -} cold_reset_t; - -/* Device specific structure */ -typedef struct nfc_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct mutex ese_access_mutex; - struct mutex dev_ref_mutex; - unsigned int dev_ref_count; - struct class *nfc_class; - struct device *nfc_device; - struct cdev c_dev; - dev_t devno; - /* Interface flag */ - uint8_t interface; - - /*store the ven functioning */ - uint8_t ven_policy; - /* NFC VEN pin state */ - bool nfc_ven_enabled; - union { -#ifdef CONFIG_NXP_NFC_I2C - i2c_dev_t i2c_dev; -#endif -#ifdef CONFIG_NXP_NFC_I3C - i3c_dev_t i3c_dev; -#endif - }; - platform_gpio_t gpio; - cold_reset_t cold_reset; -} nfc_dev_t; - -int nfc_dev_open(struct inode *inode, struct file *filp); -int nfc_dev_close(struct inode *inode, struct file *filp); -long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); -int nfc_parse_dt(struct device *dev, platform_gpio_t *nfc_gpio, - uint8_t interface); -int nfc_misc_register(nfc_dev_t *nfc_dev, - const struct file_operations *nfc_fops, - int count, char *devname, char *classname); -void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count); -int configure_gpio(unsigned int gpio, int flag); -void read_cold_reset_rsp(nfc_dev_t *nfc_dev, char *buf); -void gpio_set_ven(nfc_dev_t *nfc_dev, int value); -void gpio_free_all(nfc_dev_t *nfc_dev); -#endif //_COMMON_H_ diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c deleted file mode 100644 index 5d1e1393c5..0000000000 --- a/nfc/i2c_drv.c +++ /dev/null @@ -1,465 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2013-2020 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "../nfc/cold_reset.h" -#include "common.h" -#include "sn110.h" - -extern nfc_dev_t *nfc_dev_platform; - -/** - * i2c_disable_irq() - * - * Check if interrupt is disabled or not - * and disable interrupt - * - * Return: void - */ -void i2c_disable_irq(i2c_dev_t *i2c_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&i2c_dev->irq_enabled_lock, flags); - if (i2c_dev->irq_enabled) { - disable_irq_nosync(i2c_dev->client->irq); - i2c_dev->irq_enabled = false; - } - spin_unlock_irqrestore(&i2c_dev->irq_enabled_lock, flags); -} - -/** - * i2c_enable_irq() - * - * Check if interrupt is enabled or not - * and enable interrupt - * - * Return: void - */ -void i2c_enable_irq(i2c_dev_t *i2c_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&i2c_dev->irq_enabled_lock, flags); - if (!i2c_dev->irq_enabled) { - i2c_dev->irq_enabled = true; - enable_irq(i2c_dev->client->irq); - } - spin_unlock_irqrestore(&i2c_dev->irq_enabled_lock, flags); -} - -static irqreturn_t i2c_irq_handler(int irq, void *dev_id) -{ - nfc_dev_t *nfc_dev = dev_id; - i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; - if (device_may_wakeup(&i2c_dev->client->dev)) - pm_wakeup_event(&i2c_dev->client->dev, WAKEUP_SRC_TIMEOUT); - - i2c_disable_irq(i2c_dev); - wake_up(&nfc_dev->read_wq); - - return IRQ_HANDLED; -} - -int i2c_read(i2c_dev_t *i2c_dev, char *buf, size_t count) -{ - int ret; - pr_debug("%s : reading %zu bytes.\n", __func__, count); - /* Read data */ - ret = i2c_master_recv(i2c_dev->client, buf, count); - if (ret <= 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - goto err; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - ret = -EIO; - } - /* delay for the slow nfc devices between susequent read operation */ - usleep_range(1000, 1100); -err: - return ret; -} - -int i2c_write(i2c_dev_t *i2c_dev, char *buf, size_t count, int max_retry_cnt) -{ - int ret = -EINVAL; - int retry_cnt; - - pr_debug("%s : writing %zu bytes.\n", __func__, count); - - for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) { - ret = i2c_master_send(i2c_dev->client, buf, count); - if (ret <= 0) { - pr_warn - ("%s: write failed, Maybe in Standby Mode - Retry(%d)\n", - __func__, retry_cnt); - usleep_range(1000, 1100); - } else if (ret == count) - break; - } - return ret; -} - -ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - int ret; - char tmp[MAX_BUFFER_SIZE]; - nfc_dev_t *nfc_dev = filp->private_data; - i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - pr_debug("%s : reading %zu bytes.\n", __func__, count); - mutex_lock(&nfc_dev->read_mutex); - if (!gpio_get_value(nfc_dev->gpio.irq)) { - if (filp->f_flags & O_NONBLOCK) { - pr_err(":f_falg has O_NONBLOCK. EAGAIN\n"); - ret = -EAGAIN; - goto err; - } - while (1) { - ret = 0; - if (!i2c_dev->irq_enabled) { - i2c_dev->irq_enabled = true; - enable_irq(i2c_dev->client->irq); - } - ret = wait_event_interruptible(nfc_dev->read_wq, - !i2c_dev->irq_enabled); - if (ret) { - pr_err("error wakeup of read wq\n"); - goto err; - } - - i2c_disable_irq(i2c_dev); - if (!gpio_get_value(nfc_dev->gpio.ven)) { - pr_info("%s: releasing read\n", __func__); - ret = -EIO; - goto err; - } - if (gpio_get_value(nfc_dev->gpio.irq)) - break; - pr_warn("%s: spurious interrupt detected\n", __func__); - } - } - - memset(tmp, 0x00, count); - /* Read data */ - ret = i2c_read(i2c_dev, tmp, count); - if (ret <= 0) { - pr_err("%s: i2c_read returned %d\n", __func__, ret); - goto err; - } - /* check if it's response of cold reset command - * NFC HAL process shouldn't receive this data as - * command was sent by driver - */ - if (nfc_dev->cold_reset.rsp_pending && IS_COLD_RESET_RSP(tmp)) { - read_cold_reset_rsp(nfc_dev, tmp); - nfc_dev->cold_reset.rsp_pending = false; - wake_up_interruptible(&nfc_dev->cold_reset.read_wq); - mutex_unlock(&nfc_dev->read_mutex); - /* - * NFC process doesn't know about cold reset command - * being sent as it was initiated by eSE process - * we shouldn't return any data to NFC process - */ - return 0; - } - if (copy_to_user(buf, tmp, ret)) { - pr_warn("%s : failed to copy to user space\n", __func__); - ret = -EFAULT; - } - -err: - mutex_unlock(&nfc_dev->read_mutex); - return ret; -} - -ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - int ret; - char tmp[MAX_BUFFER_SIZE]; - nfc_dev_t *nfc_dev = filp->private_data; - i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - return -EFAULT; - } - ret = i2c_write(i2c_dev, tmp, count, NO_RETRY); - if (ret != count) { - pr_err("%s: failed to write %d\n", __func__, ret); - ret = -EIO; - } - - return ret; -} - -static const struct file_operations nfc_i2c_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = nfc_i2c_dev_read, - .write = nfc_i2c_dev_write, - .open = nfc_dev_open, - .release = nfc_dev_close, - .unlocked_ioctl = nfc_dev_ioctl, -}; - -int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - int ret = 0; - nfc_dev_t *nfc_dev = NULL; - i2c_dev_t *i2c_dev = NULL; - platform_gpio_t nfc_gpio; - pr_debug("%s: enter\n", __func__); - /*retrive details of gpios from dt */ - ret = nfc_parse_dt(&client->dev, &nfc_gpio, PLATFORM_IF_I2C); - if (ret) { - pr_err("%s : failed to parse dt\n", __func__); - goto err; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - ret = -ENODEV; - goto err; - } - nfc_dev = kzalloc(sizeof(nfc_dev_t), GFP_KERNEL); - if (nfc_dev == NULL) { - ret = -ENOMEM; - goto err; - } - nfc_dev_platform = nfc_dev; - nfc_dev->interface = PLATFORM_IF_I2C; - nfc_dev->i2c_dev.client = client; - i2c_dev = &nfc_dev->i2c_dev; - - ret = configure_gpio(nfc_gpio.ven, GPIO_OUTPUT); - if (ret) { - pr_err("%s: unable to request nfc reset gpio [%d]\n", - __func__, nfc_gpio.ven); - goto err; - } - ret = configure_gpio(nfc_gpio.irq, GPIO_IRQ); - if (ret <= 0) { - pr_err("%s: unable to request nfc irq gpio [%d]\n", - __func__, nfc_gpio.irq); - goto err; - } - client->irq = ret; - ret = configure_gpio(nfc_gpio.dwl_req, GPIO_OUTPUT); - if (ret) { - pr_err("%s: unable to request nfc firm downl gpio [%d]\n", - __func__, nfc_gpio.dwl_req); - goto err; - } - ret = configure_gpio(nfc_gpio.ese_pwr, GPIO_OUTPUT); - if (ret) { - pr_err("%s: unable to request nfc ese pwr gpio [%d]\n", - __func__, nfc_gpio.ese_pwr); - } - nfc_dev->gpio.ven = nfc_gpio.ven; - nfc_dev->gpio.irq = nfc_gpio.irq; - nfc_dev->gpio.dwl_req = nfc_gpio.dwl_req; - nfc_dev->gpio.ese_pwr = nfc_gpio.ese_pwr; - - /* init mutex and queues */ - init_waitqueue_head(&nfc_dev->read_wq); - init_waitqueue_head(&nfc_dev->cold_reset.read_wq); - mutex_init(&nfc_dev->read_mutex); - mutex_init(&nfc_dev->dev_ref_mutex); - mutex_init(&nfc_dev->ese_access_mutex); - mutex_init(&nfc_dev->cold_reset.sync_mutex); - spin_lock_init(&i2c_dev->irq_enabled_lock); - - ret = nfc_misc_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT, - NFC_CHAR_DEV_NAME, CLASS_NAME); - if (ret) { - pr_err("%s: nfc_misc_register failed\n", __func__); - goto err_mutex_destroy; - } - /* interrupt initializations */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - i2c_dev->irq_enabled = true; - ret = request_irq(client->irq, i2c_irq_handler, - IRQF_TRIGGER_HIGH, client->name, nfc_dev); - if (ret) { - pr_err("%s: request_irq failed\n", __func__); - goto err_nfc_misc_unregister; - } - i2c_disable_irq(i2c_dev); - device_init_wakeup(&client->dev, true); - device_set_wakeup_capable(&client->dev, true); - i2c_set_clientdata(client, nfc_dev); - i2c_dev->irq_wake_up = false; - nfc_dev->cold_reset.rsp_pending = false; - nfc_dev->cold_reset.nfc_enabled = false; - - /*call to platform specific probe */ - ret = sn110_i2c_probe(nfc_dev); - if (ret != 0) { - pr_err("%s: probing platform failed\n", __func__); - goto err_request_free_irq; - }; - pr_info("%s probing nfc i2c successfully", __func__); - return 0; -err_request_free_irq: - free_irq(client->irq, nfc_dev); -err_nfc_misc_unregister: - nfc_misc_unregister(nfc_dev, DEV_COUNT); -err_mutex_destroy: - mutex_destroy(&nfc_dev->dev_ref_mutex); - mutex_destroy(&nfc_dev->read_mutex); - mutex_destroy(&nfc_dev->ese_access_mutex); - mutex_destroy(&nfc_dev->cold_reset.sync_mutex); -err: - gpio_free_all(nfc_dev); - if (nfc_dev) - kfree(nfc_dev); - pr_err("%s: probing not successful, check hardware\n", __func__); - return ret; -} - -int nfc_i2c_dev_remove(struct i2c_client *client) -{ - int ret = 0; - nfc_dev_t *nfc_dev = NULL; - pr_info("%s: remove device\n", __func__); - nfc_dev = i2c_get_clientdata(client); - if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); - ret = -ENODEV; - return ret; - } - free_irq(client->irq, nfc_dev); - nfc_misc_unregister(nfc_dev, DEV_COUNT); - mutex_destroy(&nfc_dev->read_mutex); - mutex_destroy(&nfc_dev->ese_access_mutex); - mutex_destroy(&nfc_dev->cold_reset.sync_mutex); - gpio_free_all(nfc_dev); - if (nfc_dev) - kfree(nfc_dev); - return ret; -} - -int nfc_i2c_dev_suspend(struct device *device) -{ - struct i2c_client *client = to_i2c_client(device); - nfc_dev_t *nfc_dev = i2c_get_clientdata(client); - i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; - - if (device_may_wakeup(&client->dev) && i2c_dev->irq_enabled) { - if (!enable_irq_wake(client->irq)) - i2c_dev->irq_wake_up = true; - } - return 0; -} - -int nfc_i2c_dev_resume(struct device *device) -{ - struct i2c_client *client = to_i2c_client(device); - nfc_dev_t *nfc_dev = i2c_get_clientdata(client); - i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; - - if (device_may_wakeup(&client->dev) && i2c_dev->irq_wake_up) { - if (!disable_irq_wake(client->irq)) - i2c_dev->irq_wake_up = false; - } - return 0; -} - -static const struct i2c_device_id nfc_i2c_dev_id[] = { - {NFC_I2C_DEV_ID, 0}, - {} -}; - -static const struct of_device_id nfc_i2c_dev_match_table[] = { - {.compatible = NFC_I2C_DRV_STR,}, - {} -}; - -static const struct dev_pm_ops nfc_i2c_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(nfc_i2c_dev_suspend, nfc_i2c_dev_resume) -}; - -static struct i2c_driver nfc_i2c_dev_driver = { - .id_table = nfc_i2c_dev_id, - .probe = nfc_i2c_dev_probe, - .remove = nfc_i2c_dev_remove, - .driver = { - .name = NFC_I2C_DRV_STR, - .pm = &nfc_i2c_dev_pm_ops, - .of_match_table = nfc_i2c_dev_match_table, - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - }, -}; - -MODULE_DEVICE_TABLE(of, nfc_i2c_dev_match_table); - -static int __init nfc_i2c_dev_init(void) -{ - int ret = 0; - pr_info("Loading NXP NFC I2C driver\n"); - ret = i2c_add_driver(&nfc_i2c_dev_driver); - return ret; -} - -module_init(nfc_i2c_dev_init); - -static void __exit nfc_i2c_dev_exit(void) -{ - pr_info("Unloading NXP NFC I2C driver\n"); - i2c_del_driver(&nfc_i2c_dev_driver); -} - -module_exit(nfc_i2c_dev_exit); - -MODULE_DESCRIPTION("NXP NFC I2C driver"); -MODULE_LICENSE("GPL"); diff --git a/nfc/i2c_drv.h b/nfc/i2c_drv.h deleted file mode 100644 index eef57dc8d3..0000000000 --- a/nfc/i2c_drv.h +++ /dev/null @@ -1,47 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2019-2020 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#ifndef _I2C_DRV_H_ -#define _I2C_DRV_H_ -#include - -/*kept same as dts */ -#define NFC_I2C_DRV_STR "nxp,pn544" -#define NFC_I2C_DEV_ID "pn553" - -//Interface specific parameters -typedef struct i2c_dev { - struct i2c_client *client; - /*IRQ parameters */ - bool irq_enabled; - spinlock_t irq_enabled_lock; - /* NFC_IRQ wake-up state */ - bool irq_wake_up; -} i2c_dev_t; - -long nfc_i2c_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); -int nfc_i2c_dev_probe(struct i2c_client *client, - const struct i2c_device_id *id); -int nfc_i2c_dev_remove(struct i2c_client *client); -int nfc_i2c_dev_suspend(struct device *device); -int nfc_i2c_dev_resume(struct device *device); -void i2c_disable_irq(i2c_dev_t *i2c_dev); -void i2c_enable_irq(i2c_dev_t *i2c_dev); -int i2c_write(i2c_dev_t *i2c_dev, char *buf, size_t count, int max_retry_cnt); -int i2c_read(i2c_dev_t *i2c_dev, char *buf, size_t count); -#endif //_I2C_DRV_H_ diff --git a/nfc/i3c_drv.c b/nfc/i3c_drv.c deleted file mode 100644 index 063308c268..0000000000 --- a/nfc/i3c_drv.c +++ /dev/null @@ -1,766 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2019-2020 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" -#include "sn110.h" - -/** @brief This API used to write I3C data to I3C device. - * - * @param dev the i3c_dev for the i3c device. - * @param buf the data to write - * @param count the number of bytes of data to be written. - * @return ret number of bytes written ,negative error core otherwise. - */ -ssize_t i3c_write(i3c_dev_t *i3c_dev, const char *buf, const size_t count, - int max_retry_cnt) -{ - int ret = -EIO; - int retry_count = 0; - struct i3c_priv_xfer write_buf = { - .rnw = NFC_I3C_WRITE, - .len = count, - .data.out = buf - }; - do { - ret = i3c_device_do_priv_xfers(i3c_dev->device, &write_buf, - (sizeof(write_buf) / - sizeof(struct i3c_priv_xfer))); - - pr_debug("%s exit ret = %x\n", __func__, ret); - if (!ret) { - ret = count; - break; - } - pr_err("%s errno = %x\n", __func__, write_buf.err); - retry_count++; - - usleep_range(1000, 1100); - } while (retry_count < max_retry_cnt); - return ret; -} - -/** @brief This API used to read data from I3C device. - * - * @param dev the i3c_dev for the slave. - * @param buf the buffer to copy the data. - * @param count the number of bytes to be read. - * - * @return number of bytes read ,negative error code otherwise. - */ -ssize_t i3c_read(i3c_dev_t *i3c_dev, char *buf, size_t count) -{ - int ret = -EIO; - struct i3c_priv_xfer read_buf = { - .rnw = NFC_I3C_READ, - .len = count, - .data.in = buf - }; - - ret = i3c_device_do_priv_xfers(i3c_dev->device, &read_buf, - (sizeof(read_buf) / - sizeof(struct i3c_priv_xfer))); - pr_debug("%s exit ret = %x\n", __func__, ret); - if (!ret) - ret = count; - else - pr_err("%s errno = %x\n", __func__, read_buf.err); - - return ret; -} - -/** @brief This API can be used to write data to nci buf. - * The API will overwrite the existing memory if - * it reaches the end of total allocated memory. - * @param dev the dev structure for driver. - * @param readbuf the buffer to be copied data from - * @param count the number of bytes to copy to nci_buffer. - * @return number of bytes copied to nci buffer , error code otherwise - */ -static ssize_t i3c_kbuf_store(i3c_dev_t *i3c_dev, const char *buf, - const size_t count) -{ - size_t buf_offset = 0; - size_t requested_size = count; - size_t available_size = 0; - - if (i3c_dev == NULL) - return -ENODEV; - else if (buf == NULL || count == 0) - return -EINVAL; - - pr_debug("%s enter\n", __func__); - if (count > i3c_dev->buf.total_size) { - pr_err("%s No memory to copy the data\n", __func__); - return -ENOMEM; - } - - pr_debug("%s:total_size %zx write_off = %x read_off = %x\n", - __func__, i3c_dev->buf.total_size, i3c_dev->buf.write_offset, - i3c_dev->buf.read_offset); - - mutex_lock(&i3c_dev->nci_buf_mutex); - - available_size = i3c_dev->buf.total_size - i3c_dev->buf.write_offset; - - /* - * When available buffer is less than requested count, - * copy the data upto available memory. - * The remaining data is copied to the start of memory. - * The write offset is incremented by the remaining copied bytes - * from the beginning. - */ - - if (requested_size > available_size) { - pr_warn - ("%s:out of mem req_size = %zx avail = %zx\n", - __func__, requested_size, available_size); - memcpy(i3c_dev->buf.kbuf + i3c_dev->buf.write_offset, - buf + buf_offset, available_size); - requested_size = requested_size - available_size; - i3c_dev->buf.write_offset = 0; - buf_offset = available_size; - pr_debug("%s: requested_size = %zx available_size = %zx\n", - __func__, requested_size, available_size); - } - if (requested_size) { - memcpy(i3c_dev->buf.kbuf + i3c_dev->buf.write_offset, - buf + buf_offset, requested_size); - i3c_dev->buf.write_offset += requested_size; - if (i3c_dev->buf.write_offset == i3c_dev->buf.total_size) - i3c_dev->buf.write_offset = 0; - } - complete(&i3c_dev->read_cplt); - mutex_unlock(&i3c_dev->nci_buf_mutex); - pr_debug("%s: total bytes req_size = %zx avail_size = %zx\n", - __func__, requested_size, available_size); - - return count; -} - -/** @brief This API can be used to retrieve data from driver buffer. - * - * When data is not available, it waits for required data to be present. - * When data is present it copies the data into buffer reuested by read. - * @param dev the dev structure for driver. - * @param buf the buffer to copy the data. - * @param count the number of bytes to be read. - * @return number of bytes copied , error code for failures . - */ -static ssize_t i3c_nci_kbuf_retrieve(i3c_dev_t *i3c_dev, char *buf, - size_t count) -{ - int ret = 0; - size_t requested_size = count; - size_t available_size = 0; - size_t copied_size = 0; - if (i3c_dev == NULL) - return -ENODEV; - else if (buf == NULL || count == 0) - return -EINVAL; - pr_debug("%s enter\n", __func__); - - /* - * When the requested data count is more than available data to read, - * wait on completion till the requested bytes are available. - * If write offset is more than read offset and available data is - * more than requested count, copy the requested bytes directly and - * increment the read_offset. - * If read offset is more than write offset, - * available size is total_size size - read_offset - * and upto write offset from the beginning of buffer. - */ - - do { - - pr_debug("%s: read_offset = %x write_offset = %x\n", __func__, - i3c_dev->buf.read_offset, i3c_dev->buf.write_offset); - - mutex_lock(&i3c_dev->nci_buf_mutex); - if (i3c_dev->buf.read_offset <= i3c_dev->buf.write_offset) - available_size = - i3c_dev->buf.write_offset - - i3c_dev->buf.read_offset; - else - available_size = - (i3c_dev->buf.total_size - - i3c_dev->buf.read_offset) + - i3c_dev->buf.write_offset; - mutex_unlock(&i3c_dev->nci_buf_mutex); - if (available_size >= requested_size) - break; - - reinit_completion(&i3c_dev->read_cplt); - ret = wait_for_completion_interruptible(&i3c_dev->read_cplt); - if (ret != 0) { - pr_err("didnt get completion, interrupted!! ret %d\n", - ret); - return -EINVAL; - } - } while (available_size < requested_size); - - mutex_lock(&i3c_dev->nci_buf_mutex); - - if (i3c_dev->buf.write_offset >= i3c_dev->buf.read_offset + - requested_size) { - /* - * Write offset is more than read offset + count , copy the data - * directly and increment the read offset - */ - memcpy(buf, i3c_dev->buf.kbuf + i3c_dev->buf.read_offset, - requested_size); - i3c_dev->buf.read_offset += requested_size; - } else { - copied_size = - i3c_dev->buf.total_size - i3c_dev->buf.read_offset; - if (copied_size > requested_size) - copied_size = requested_size; - /* - * Read offset is more than write offset. Copy requested data - * from read_offset to the total size and increment the read - * offset. If requested data is still greater than zero, - * copy the data from beginning of buffer. - */ - memcpy(buf, i3c_dev->buf.kbuf + i3c_dev->buf.read_offset, - copied_size); - requested_size = requested_size - copied_size; - i3c_dev->buf.read_offset += copied_size; - if (requested_size) { - pr_debug("%s remaining copied bytes\n", __func__); - memcpy(buf + copied_size, i3c_dev->buf.kbuf, - requested_size); - i3c_dev->buf.read_offset = requested_size; - } - } - mutex_unlock(&i3c_dev->nci_buf_mutex); - pr_debug("%s , count = %zx exit\n", __func__, count); - return count; -} - -/** @brief This API can be used to read data from I3C device from HAL layer. - * - * This read function is registered during probe. - * When data is not available, it waits for required data to be present. - * @param filp the device file handle opened by HAL. - * @param buf the buffer to read the data. - * @param count the number of bytes to be read. - * @param offset the offset in the buf. - * @return Number of bytes read from I3C device ,error code for failures. - */ -ssize_t nfc_i3c_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - int ret; - char tmp[MAX_BUFFER_SIZE]; - nfc_dev_t *nfc_dev = filp->private_data; - i3c_dev_t *i3c_dev = &nfc_dev->i3c_dev; - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - memset(tmp, 0x00, count); - pr_debug("%s : reading %zu bytes\n", __func__, count); - - mutex_lock(&nfc_dev->read_mutex); - ret = i3c_nci_kbuf_retrieve(i3c_dev, tmp, count); - if (ret != count) { - pr_err("%s: buf read from I3C device returned error (%d)\n", - __func__, ret); - ret = -EIO; - } else if (copy_to_user(buf, tmp, ret)) { - pr_warn("%s : failed to copy to user space\n", __func__); - ret = -EFAULT; - } - - mutex_unlock(&nfc_dev->read_mutex); - - return ret; -} - -/** @brief This API can be used to write data to I3C device. - * - * @param dev the i3c_dev for the slave. - * @param buf the buffer to copy the data. - * @param count the number of bytes to be read. - * @return ret count number of btes written, error code for failures. - */ -ssize_t nfc_i3c_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - int ret; - char tmp[MAX_BUFFER_SIZE]; - nfc_dev_t *nfc_dev = filp->private_data; - i3c_dev_t *i3c_dev = &nfc_dev->i3c_dev; - if (count > MAX_BUFFER_SIZE) { - pr_err("%s: requested writes size(%d) more then expected\n", - __func__, count); - return -ENOMEM; - } - - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - ret = PTR_ERR(tmp); - return ret; - } - - ret = i3c_write(i3c_dev, tmp, count, NO_RETRY); - if (ret != count) { - pr_err("%s: failed to write %d\n", __func__, ret); - ret = -EIO; - } - pr_debug("%s : i3c-%d: NfcNciTx %x %x %x\n", __func__, - iminor(file_inode(filp)), tmp[0], tmp[1], tmp[2]); - pr_debug("%s : ret = %x\n", __func__, ret); - return ret; -} - -/** @brief This API shall be called from workqueue queue from IBI handler. - * First it will read HDR byte from I3C chip.Based on the length byte - * it will read the next length bytes.Then it will write these bytes - * to nci write buf. - * @param work the work added into the workqueue. - * - * @return void - */ -static void i3c_workqueue_handler(struct work_struct *work) -{ - int ret = 0; - int length_byte = 0; - unsigned char *tmp = NULL; - unsigned char hdr_len = NCI_HDR_LEN; - i3c_dev_t *i3c_dev = container_of(work, i3c_dev_t, work); - - if (!i3c_dev) { - pr_err("%s: dev not found\n", __func__); - return; - } - hdr_len = i3c_dev->read_hdr; - tmp = i3c_dev->read_kbuf; - if (!tmp) { - pr_err("%s: No memory to copy read data\n", __func__); - return; - } - pr_info("%s: hdr_len = %d\n", __func__, hdr_len); - memset(tmp, 0x00, i3c_dev->read_kbuf_len); - - ret = i3c_read(i3c_dev, tmp, hdr_len); - if (ret < 0) { - pr_err("%s: i3c_read returned error %d\n", __func__, ret); - return; - } - if (hdr_len == FW_HDR_LEN) - length_byte = tmp[hdr_len - 1] + FW_CRC_LEN; - else - length_byte = tmp[hdr_len - 1]; - ret = i3c_read(i3c_dev, tmp + hdr_len, length_byte); - if (ret < 0) { - pr_err("%s: i3c_read returned error %d\n", __func__, ret); - i3c_kbuf_store(i3c_dev, tmp, hdr_len); - return; - } - i3c_kbuf_store(i3c_dev, tmp, hdr_len + length_byte); -} - -/** @brief This API is used to handle IBI coming from the I3C device. - * This will add work into the workqueue , which will call workqueue - * handler to read data from I3C device. - * @param device I3C device. - * @param payload payload shall be NULL for NFC device. - * @return void. - */ -static void i3c_ibi_handler(struct i3c_device *device, - const struct i3c_ibi_payload *payload) -{ - nfc_dev_t *nfc_dev = i3cdev_get_drvdata(device); - i3c_dev_t *i3c_dev = &nfc_dev->i3c_dev; - pr_debug("%s: Received read IBI request from slave", __func__); - if (device_may_wakeup(&device->dev)) - pm_wakeup_event(&device->dev, WAKEUP_SRC_TIMEOUT); - - if (atomic_read(&i3c_dev->pm_state) == PM_STATE_NORMAL) { - if (!queue_work(i3c_dev->wq, &i3c_dev->work)) - pr_debug("%s: queue work success\n", __func__); - } else { - /*assume suspend state and expect only 1 IBI in suspend state */ - atomic_set(&i3c_dev->pm_state, PM_STATE_IBI_BEFORE_RESUME); - } -} - -/** @brief This API can be used to enable IBI from the I3C device. - * @param i3c_dev the i3c_dev for the slave. - * @return 0 on success, error code for failures. - */ -int i3c_enable_ibi(i3c_dev_t *i3c_dev) -{ - int ret = 0; - int retry_count = 0; - - if (!i3c_dev->ibi_enabled) { - do { - ret = i3c_device_enable_ibi(i3c_dev->device); - if (!ret) { - i3c_dev->ibi_enabled = true; - break; - } - - pr_debug("en_ibi ret %d retrying..\n", ret); - retry_count++; - usleep_range(RETRY_WAIT_TIME_USEC, - (RETRY_WAIT_TIME_USEC + 100)); - } while (retry_count < RETRY_COUNT_IBI); - } else { - pr_debug("%s: already enabled\n", __func__); - } - return ret; -} - -/** @brief This API can be used to disable IBI from the I3C device. - * @param i3c_dev the i3c_dev for the slave. - * @return 0 on success, error code for failures. - */ -int i3c_disable_ibi(i3c_dev_t *i3c_dev) -{ - int ret = 0; - int retry_count = 0; - - if (i3c_dev->ibi_enabled) { - do { - ret = i3c_device_disable_ibi(i3c_dev->device); - if (!ret) { - i3c_dev->ibi_enabled = false; - break; - } - pr_debug("dis_ibi ret %d retrying..\n", ret); - retry_count++; - usleep_range(RETRY_WAIT_TIME_USEC, - (RETRY_WAIT_TIME_USEC + 100)); - } while (retry_count < RETRY_COUNT_IBI); - } else { - pr_debug("%s: already disabled\n", __func__); - } - return ret; -} - -/** @brief This API can be used to request IBI from the I3C device. - * This function will request IBI from master controller for the device - * and register ibi handler, enable IBI . - * @param i3c_dev the i3c_dev for the slave. - * @return 0 on success, error code for failures. - */ -static int i3c_request_ibi(i3c_dev_t *i3c_dev) -{ - int ret = 0; - struct i3c_ibi_setup ibireq = { - .handler = i3c_ibi_handler, - .max_payload_len = MAX_IBI_PAYLOAD_LEN, - .num_slots = NUM_NFC_IBI_SLOT, - }; - ret = i3c_device_request_ibi(i3c_dev->device, &ibireq); - pr_debug("%s Request IBI status = %d\n", __func__, ret); - return ret; -} - -/** @brief This API can be used to create a workqueue for - * handling IBI request from I3C device. - * - * @param dev the i3c_dev for the slave. - * @return 0 on success, error code for failures. - */ -static int i3c_init_workqueue(i3c_dev_t *i3c_dev) -{ - i3c_dev->wq = alloc_workqueue(I3C_WORKQUEUE_NAME, 0, 0); - if (!i3c_dev->wq) - return -ENOMEM; - - INIT_WORK(&i3c_dev->work, i3c_workqueue_handler); - pr_debug("%s ibi workqueue created successfully\n", __func__); - return 0; -} - -/** @brief This API can be used to set the NCI buf to zero. - * - * @param dev the dev for the driver. - * @return 0 on success, error code for failures. - */ -static int i3c_reset_nci_buf(i3c_dev_t *i3c_dev) -{ - i3c_dev->buf.write_offset = 0; - i3c_dev->buf.read_offset = 0; - memset(i3c_dev->buf.kbuf, 0, i3c_dev->buf.total_size); - return 0; -} - -static const struct file_operations nfc_i3c_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = nfc_i3c_dev_read, - .write = nfc_i3c_dev_write, - .open = nfc_dev_open, - .release = nfc_dev_close, - .unlocked_ioctl = nfc_dev_ioctl, -}; - -/** @brief This API can be used to probe I3c device. - * - * @param device the i3c_dev for the slave. - * @return 0 on success, error code for failures. - */ -int nfc_i3c_dev_probe(struct i3c_device *device) -{ - int ret = 0; - nfc_dev_t *nfc_dev = NULL; - platform_gpio_t nfc_gpio; - pr_debug("%s: enter\n", __func__); - /*retrive details of gpios from dt */ - ret = nfc_parse_dt(&device->dev, &nfc_gpio, PLATFORM_IF_I3C); - if (ret) { - pr_err("%s : failed to parse dt\n", __func__); - goto err; - } - nfc_dev = kzalloc(sizeof(nfc_dev_t), GFP_KERNEL); - if (nfc_dev == NULL) { - ret = -ENOMEM; - goto err; - } - - /* - * Memory allocation for the read from the I3C before - * storing it in Kbuf store - */ - nfc_dev->i3c_dev.read_hdr = NCI_HDR_LEN; - nfc_dev->i3c_dev.read_kbuf_len = MAX_BUFFER_SIZE; - nfc_dev->i3c_dev.read_kbuf = kzalloc(MAX_BUFFER_SIZE, - GFP_DMA | GFP_KERNEL); - if (!nfc_dev->i3c_dev.read_kbuf) { - ret = -ENOMEM; - goto err; - } - - /* - * Kbuf memory for storing NCI/Firmware Mode Buffers before - * actual read from the user - */ - nfc_dev->i3c_dev.buf.kbuf = (char *)__get_free_pages(GFP_KERNEL, 0); - if (!nfc_dev->i3c_dev.buf.kbuf) { - ret = -ENOMEM; - goto err; - } - nfc_dev->i3c_dev.buf.total_size = PAGE_SIZE; - i3c_reset_nci_buf(&nfc_dev->i3c_dev); - nfc_dev->interface = PLATFORM_IF_I3C; - nfc_dev->i3c_dev.device = device; - - ret = configure_gpio(nfc_gpio.ven, GPIO_OUTPUT_HIGH); - if (ret) { - pr_err("%s: unable to request nfc reset gpio [%d]\n", - __func__, nfc_gpio.ven); - goto err; - } - ret = configure_gpio(nfc_gpio.dwl_req, GPIO_OUTPUT); - if (ret) { - pr_err("%s: unable to request nfc firm downl gpio [%d]\n", - __func__, nfc_gpio.dwl_req); - goto err; - } - - nfc_dev->gpio.ven = nfc_gpio.ven; - nfc_dev->gpio.irq = nfc_gpio.irq; - nfc_dev->gpio.dwl_req = -EINVAL; - nfc_dev->gpio.ese_pwr = -EINVAL; - - /* init mutex and queues */ - init_completion(&nfc_dev->i3c_dev.read_cplt); - mutex_init(&nfc_dev->i3c_dev.nci_buf_mutex); - mutex_init(&nfc_dev->dev_ref_mutex); - mutex_init(&nfc_dev->read_mutex); - ret = i3c_init_workqueue(&nfc_dev->i3c_dev); - if (ret) { - pr_err("%s: alloc workqueue failed\n", __func__); - goto err_mutex_destroy; - } - ret = nfc_misc_register(nfc_dev, &nfc_i3c_dev_fops, DEV_COUNT, - NFC_CHAR_DEV_NAME, CLASS_NAME); - if (ret) { - pr_err("%s: nfc_misc_register failed\n", __func__); - goto err_mutex_destroy; - } - i3cdev_set_drvdata(device, nfc_dev); - - ret = i3c_request_ibi(&nfc_dev->i3c_dev); - if (ret) { - pr_err("%s: i3c_request_ibi failed\n", __func__); - goto err_nfc_misc_unregister; - } - atomic_set(&nfc_dev->i3c_dev.pm_state, PM_STATE_NORMAL); - - device_init_wakeup(&device->dev, true); - device_set_wakeup_capable(&device->dev, true); - /*call to platform specific probe */ - ret = sn110_i3c_probe(nfc_dev); - if (ret != 0) { - pr_err("%s: probing platform failed\n", __func__); - goto err_nfc_misc_unregister; - }; - pr_info("%s probing nfc i3c successfully", __func__); - return 0; -err_nfc_misc_unregister: - nfc_misc_unregister(nfc_dev, DEV_COUNT); -err_mutex_destroy: - mutex_destroy(&nfc_dev->read_mutex); - mutex_destroy(&nfc_dev->dev_ref_mutex); - mutex_destroy(&nfc_dev->i3c_dev.nci_buf_mutex); -err: - gpio_free_all(nfc_dev); - if (nfc_dev->i3c_dev.buf.kbuf) - free_pages((unsigned long)nfc_dev->i3c_dev.buf.kbuf, 0); - if (nfc_dev->i3c_dev.read_kbuf) - kfree(nfc_dev->i3c_dev.read_kbuf); - if (nfc_dev) - kfree(nfc_dev); - pr_err("%s: probing not successful, check hardware\n", __func__); - return ret; -} - -/** @brief This API is automatically called on shutdown or crash. - * - * @param device the i3c_dev for the slave. - * @return 0 on success, error code for failures. - */ -int nfc_i3c_dev_remove(struct i3c_device *device) -{ - nfc_dev_t *nfc_dev = i3cdev_get_drvdata(device); - i3c_dev_t *i3c_dev = NULL; - if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); - return -ENODEV; - } - i3c_dev = &nfc_dev->i3c_dev; - i3c_device_disable_ibi(device); - i3c_device_free_ibi(device); - if (i3c_dev->wq) - destroy_workqueue(i3c_dev->wq); - nfc_misc_unregister(nfc_dev, DEV_COUNT); - mutex_destroy(&nfc_dev->read_mutex); - mutex_destroy(&nfc_dev->dev_ref_mutex); - mutex_destroy(&i3c_dev->nci_buf_mutex); - gpio_free_all(nfc_dev); - kfree(i3c_dev->read_kbuf); - free_pages((unsigned long)i3c_dev->buf.kbuf, 0); - kfree(nfc_dev); - return 0; -} - -int nfc_i3c_dev_suspend(struct device *pdev) -{ - struct i3c_device *device = dev_to_i3cdev(pdev); - nfc_dev_t *nfc_dev = i3cdev_get_drvdata(device); - pr_debug("%s: enter\n", __func__); - if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); - return -ENODEV; - } - - if (device_may_wakeup(&device->dev) && nfc_dev->i3c_dev.ibi_enabled) - atomic_set(&nfc_dev->i3c_dev.pm_state, PM_STATE_SUSPEND); - - return 0; -} - -int nfc_i3c_dev_resume(struct device *pdev) -{ - struct i3c_device *device = dev_to_i3cdev(pdev); - nfc_dev_t *nfc_dev = i3cdev_get_drvdata(device); - i3c_dev_t *i3c_dev = NULL; - pr_debug("%s: enter\n", __func__); - if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); - return -ENODEV; - } - i3c_dev = &nfc_dev->i3c_dev; - if (device_may_wakeup(&device->dev)) { - - if (atomic_read(&i3c_dev->pm_state) == - PM_STATE_IBI_BEFORE_RESUME) { - /*queue the deferered work to work queue */ - if (!queue_work(i3c_dev->wq, &i3c_dev->work)) - pr_debug("%s: Added workqueue successfully\n", - __func__); - } - atomic_set(&i3c_dev->pm_state, PM_STATE_NORMAL); - } - - return 0; -} - -static const struct i3c_device_id nfc_i3c_dev_id[] = { - I3C_DEVICE(NFC_I3C_MANU_ID, NFC_I3C_PART_ID, 0), - {}, -}; - -static const struct of_device_id nfc_i3c_dev_match_table[] = { - { - .compatible = NFC_I3C_DRV_STR - }, - {} -}; - -static const struct dev_pm_ops nfc_i3c_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(nfc_i3c_dev_suspend, nfc_i3c_dev_resume) -}; - -static struct i3c_driver nfc_i3c_dev_driver = { - .id_table = nfc_i3c_dev_id, - .probe = nfc_i3c_dev_probe, - .remove = nfc_i3c_dev_remove, - .driver = { - .owner = THIS_MODULE, - .name = NFC_I3C_DRV_STR, - .pm = &nfc_i3c_dev_pm_ops, - .of_match_table = nfc_i3c_dev_match_table, - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - }, -}; - -MODULE_DEVICE_TABLE(of, nfc_i3c_dev_match_table); - -static int __init nfc_dev_i3c_init(void) -{ - int ret = 0; - pr_info("Loading NXP NFC I3C driver\n"); - ret = i3c_driver_register_with_owner(&nfc_i3c_dev_driver, THIS_MODULE); - pr_debug("NFC i3c driver register ret = %d\n", ret); - return ret; -} - -module_init(nfc_dev_i3c_init); - -static void __exit nfc_i3c_dev_exit(void) -{ - pr_info("Unloading NXP NFC I3C driver\n"); - i3c_driver_unregister(&nfc_i3c_dev_driver); -} - -module_exit(nfc_i3c_dev_exit); - -MODULE_DESCRIPTION("NXP NFC I3C driver"); -MODULE_LICENSE("GPL"); diff --git a/nfc/i3c_drv.h b/nfc/i3c_drv.h deleted file mode 100644 index 5ed2e77ca5..0000000000 --- a/nfc/i3c_drv.h +++ /dev/null @@ -1,109 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2019-2020 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#ifndef _I3C_DRV_H_ -#define _I3C_DRV_H_ - -#include -#include - -//to to kept same as dt -#define NFC_I3C_DRV_STR "nxp,pn544_i3c" -#define NFC_I3C_MANU_ID (0x011B) -#define NFC_I3C_PART_ID (0) - -//Byte indicating I3C Read -#define NFC_I3C_READ 1 - -//Byte indicating I3C Write -#define NFC_I3C_WRITE 0 - -// Maximum no of IBI slot -#define NUM_NFC_IBI_SLOT 1 - -// Maximum IBI payload length -#define MAX_IBI_PAYLOAD_LEN 0 - -// CRC len to be read -#define FW_CRC_LEN 2 - -// FW DNLD HDR length -#define FW_HDR_LEN 2 - -// Time to wait before retrying I3C writes, in micro seconds -#define RETRY_WAIT_TIME_USEC (2000) - -// Retry count for enable/disable IBI CCC -#define RETRY_COUNT_IBI (3) - -// I3C WorkQueue name -#define I3C_WORKQUEUE_NAME "i3c_workq" -/** - * struct nci_buf - NCI buffer used to store and retrieve read data from device. - * @read_offset: The offset pointing to data available to read in nci buf. - * @write_offset: The offset pointing to free buf available to write. - * @total_size: Size of nci buf. - * @kbuf: allocated nci buf. - */ -struct nci_buf { - unsigned int read_offset; - unsigned int write_offset; - size_t total_size; - char *kbuf; -}; - -/** - * struct i3c_dev Structure representing device and driver data. - * @i3c_device Structure to represent I3C device. - * @wq: NCI workqueue for handling IBI request. - * @work: Work added to workqueue to read data from IBI handler. - * @buf Driver buf store read data from device.Read call will - * fetch from this buffer. - * @nci_buf_mutex: mutex to protect NCI buf retrieve/store . - * @read_cplt: Completion to wait for read data to be available. - * @read_kbuf_len: Temp buf len to hold I3C data. - * @read_kbuf: Temp buf to hold I3C data. - * @read_hdr Header size for reads. - * @ibi_enabled: IBI enabled or not. - * @pm_state: PM state of NFC I3C device. - */ -typedef struct i3c_dev { - struct i3c_device *device; - struct workqueue_struct *wq; - struct work_struct work; - struct nci_buf buf; - struct mutex nci_buf_mutex; - struct completion read_cplt; - size_t read_kbuf_len; - char *read_kbuf; - unsigned char read_hdr; - bool ibi_enabled; - atomic_t pm_state; - -} i3c_dev_t; - -int nfc_i3c_dev_probe(struct i3c_device *device); -int nfc_i3c_dev_remove(struct i3c_device *device); -int nfc_i3c_dev_suspend(struct device *device); -int nfc_i3c_dev_resume(struct device *device); -int i3c_enable_ibi(i3c_dev_t *i3c_dev); -int i3c_disable_ibi(i3c_dev_t *i3c_dev); -ssize_t i3c_write(i3c_dev_t *i3c_dev, const char *buf, const size_t count, - int max_retry_cnt); -ssize_t i3c_read(i3c_dev_t *, char *buf, size_t count); -#endif //_I3C_DRV_H_ diff --git a/nfc/sn110.c b/nfc/sn110.c deleted file mode 100644 index 605ccf12a8..0000000000 --- a/nfc/sn110.c +++ /dev/null @@ -1,38 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2019-2020 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#include -#include "common.h" -#include "sn110.h" - -int sn110_i2c_probe(nfc_dev_t *nfc_dev) -{ - pr_debug("%s: enter\n", __func__); - usleep_range(5000, 5100); - gpio_set_value(nfc_dev->gpio.ven, 1); - usleep_range(5000, 5100); - nfc_dev->ven_policy = VEN_ALWAYS_ENABLED; - return 0; -} - -int sn110_i3c_probe(nfc_dev_t *nfc_dev) -{ - pr_debug("%s: enter\n", __func__); - nfc_dev->ven_policy = VEN_ALWAYS_ENABLED; - return 0; -} diff --git a/nfc/sn110.h b/nfc/sn110.h deleted file mode 100644 index 93de1bebfb..0000000000 --- a/nfc/sn110.h +++ /dev/null @@ -1,23 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2019-2020 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#ifndef _NFC_SN110_H_ -#define _NFC_SN110_H_ -int sn110_i2c_probe(nfc_dev_t *nfc_dev); -int sn110_i3c_probe(nfc_dev_t *nfc_dev); -#endif //_NFC_SN110_H_ diff --git a/pn553-i2c/Kconfig b/pn553-i2c/Kconfig new file mode 100644 index 0000000000..878e4a8169 --- /dev/null +++ b/pn553-i2c/Kconfig @@ -0,0 +1,13 @@ +# +# Nxp Nci protocol (I2C) devices +# + +config NFC_PN553_DEVICES + bool "Nxp pn553 NCI protocol driver (I2C) devices" + default y + ---help--- + You'll have to say Y if your computer contains an I2C device that + you want to use under Linux. + + You can say N here if you don't have any SPI connected to your computer. + diff --git a/pn553-i2c/Makefile b/pn553-i2c/Makefile new file mode 100644 index 0000000000..c5a3cd2a41 --- /dev/null +++ b/pn553-i2c/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for nfc devices +# + +obj-$(CONFIG_NFC_PN553_DEVICES) += pn553.o +obj-$(CONFIG_NFC_PN553_DEVICES) += cold_reset.o + +ccflags-$(CONFIG_NFC_PN553_DEVICES) := -DDEBUG + diff --git a/pn553-i2c/cold_reset.c b/pn553-i2c/cold_reset.c new file mode 100644 index 0000000000..bc0b176731 --- /dev/null +++ b/pn553-i2c/cold_reset.c @@ -0,0 +1,343 @@ +/****************************************************************************** + * Copyright (C) 2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cold_reset.h" +#include "pn553.h" + +/*ESE_COLD_RESET MACROS */ +#define MAX_BUFFER_SIZE 512 /* copied from pn553.c */ +#define MSG_NFCC_CMD 0x20 +#define NCI_PROP_RST_RSP_SIZE 0x04 + + +/* Evaluates to 1 If cold reset is in progress or the guard timer is still running */ +#define IS_COLD_RESET_REQ_IN_PROGRESS(flags) \ + (flags & (MASK_ESE_COLD_RESET | MASK_ESE_COLD_RESET_GUARD_TIMER)) + +#define IS_RESET_PROTECTION_ENABLED(flags) (flags & RST_PROTECTION_ENABLED) + +#define IS_COLD_RESET_ALLOWED(flags, src) (!IS_COLD_RESET_REQ_IN_PROGRESS(flags) \ + && (!IS_RESET_PROTECTION_ENABLED(flags) || src == ESE_COLD_RESET_SOURCE_SPI)) + +static struct pn544_dev *pn544_dev; +struct mutex ese_cold_reset_sync_mutex; +struct mutex nci_send_cmd_mutex; + +extern ssize_t pn544_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset); + +static int8_t prop_nci_rsp[NCI_PROP_RST_RSP_SIZE]; +static struct timer_list ese_cold_reset_timer; +static struct completion prop_cmd_resp_sema; +static struct completion ese_cold_reset_sema; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) +static void ese_cold_reset_gaurd_timer_callback(unsigned long data); +#else +static void ese_cold_reset_gaurd_timer_callback(struct timer_list *unused); +#endif +static long start_ese_cold_reset_guard_timer(void); + +extern struct pn544_dev * get_nfcc_dev_data(void); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) +static void ese_cold_reset_gaurd_timer_callback(unsigned long data) +{ + (void)data; +#else +static void ese_cold_reset_gaurd_timer_callback(struct timer_list *unused) +{ +#endif + pr_info("%s: Enter\n",__func__); + pn544_dev->state_flags &= ~MASK_ESE_COLD_RESET_GUARD_TIMER; + return; +} + +static long start_ese_cold_reset_guard_timer(void) +{ + long ret = -EINVAL; + printk( KERN_INFO "starting ese_cold_reset_timer \n"); + if(timer_pending(&ese_cold_reset_timer) == 1) + { + pr_info("ese_cold_reset_guard_timer: delete pending timer \n"); + /* delete timer if already pending */ + del_timer(&ese_cold_reset_timer); + } + pn544_dev->state_flags |= MASK_ESE_COLD_RESET_GUARD_TIMER; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) + init_timer(&ese_cold_reset_timer); + setup_timer( &ese_cold_reset_timer, ese_cold_reset_gaurd_timer_callback, 0 ); +#else + timer_setup(&ese_cold_reset_timer, ese_cold_reset_gaurd_timer_callback, 0); +#endif + ret = mod_timer(&ese_cold_reset_timer, jiffies + msecs_to_jiffies(ESE_COLD_RESET_GUARD_TIME)); + if (ret) + printk( KERN_INFO "%s: Error in mod_timer\n",__func__); + return ret; +} +void ese_reset_resource_init(void) { + mutex_init(&ese_cold_reset_sync_mutex); + mutex_init(&nci_send_cmd_mutex); +} +void ese_reset_resource_destroy(void) { + mutex_destroy(&ese_cold_reset_sync_mutex); + mutex_destroy(&nci_send_cmd_mutex); +} +void rcv_prop_resp_status(const char * const buf) +{ + int ret = -1; + char tmp[MAX_BUFFER_SIZE]; + size_t rcount = 0; + memset(&prop_nci_rsp, 0, sizeof(prop_nci_rsp)); + memcpy(prop_nci_rsp, buf, 3); + rcount = (size_t)prop_nci_rsp[2]; + + /* Read data: No need to wait for the interrupt */ + ret = i2c_master_recv(pn544_dev->client, tmp, rcount); + if(ret == rcount){ + prop_nci_rsp[3] = tmp[0]; + pr_info("%s NxpNciR : len = 4 > %02X%02X%02X%02X\n", __func__,prop_nci_rsp[0], + prop_nci_rsp[1],prop_nci_rsp[2],prop_nci_rsp[3]); + }else{ + pr_err("%s : Failed to receive payload of the cold_rst_cmd\n",__func__); + prop_nci_rsp[3] = -EIO; + } + if(pn544_dev->state_flags &(P544_FLAG_NFC_ON)){ + complete(&prop_cmd_resp_sema); + } +} + +/****************************************************************************** + * Function : send_nci_transceive + * + * Description : Common NCI command send utility function. + * + * Parameters : prop_cmd : Data to be sent to NFCC + * prop_cmd_size : Length of the data to be sent + * + * Returns : 0 (SUCCESS)/ (-1)otherwise + + *****************************************************************************/ +static int send_nci_transceive(uint8_t *prop_cmd, size_t prop_cmd_size) { + int ret = 0; + unsigned int loop=0x03; + struct file filp; + int retry = 1; + + pr_info("%s: Enter", __func__); + + filp.private_data = pn544_dev; + if(pn544_dev->state_flags & P544_FLAG_FW_DNLD) { + /* If FW DNLD, Operation is not permitted */ + pr_err("%s : Operation is not permitted during fwdnld\n", __func__); + return -ECANCELED; + } + mutex_lock(&nci_send_cmd_mutex); + init_completion(&prop_cmd_resp_sema); + /* write command to I2C line*/ + do { + ret = i2c_master_send(pn544_dev->client, prop_cmd, prop_cmd_size); + if (ret == prop_cmd_size) { + break; + } + usleep_range(5000, 6000); + } while(loop--); + if(!loop && (ret != prop_cmd_size)) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + mutex_unlock(&nci_send_cmd_mutex); + return -EREMOTEIO; + } + ret = 0x00; + + do { + if(pn544_dev->state_flags & P544_FLAG_NFC_ON)/* NFC_ON */ { + /* Read is pending from the NFC service which will complete the prop_cmd_resp_sema */ + if(wait_for_completion_timeout(&prop_cmd_resp_sema, + msecs_to_jiffies(NCI_CMD_RSP_TIMEOUT)) == 0){ + pr_err("%s: Timeout", __func__); + ret = prop_nci_rsp[3] = -EAGAIN; // Failure case + } + } else { /* NFC_OFF */ + /* call the pn544_dev_read() */ + filp.f_flags &= ~O_NONBLOCK; + ret = pn544_dev_read(&filp, NULL,3, 0); + if(!ret) + break; + usleep_range(2000, 3000); + } + } while((retry-- >= 0) && ret == -ERESTARTSYS); + + mutex_unlock(&nci_send_cmd_mutex); + if(0x00 == ret && prop_nci_rsp[3]) + ret = -1 * prop_nci_rsp[3]; + /* Return the status to the SPI/UWB Driver */ + pr_info("%s: exit, Status:%d", __func__, ret); + return ret; +} + +/****************************************************************************** + * Function : do_reset_protection + * + * Description : It shall be called by SPI driver to enable/disable reset + * protection + * + * Parameters : Enable(TRUE)/Disable(FALSE) + * + * Returns : + * 0 : OK < Success case > + * -EPERM(-1) : REJECTED < NFCC rejects the cold reset cmd> + * -3 : FAILED < NFCC responds to cold reset cmd> + * -EIO(-5) : SYNTAX_ERROR < NFCC cmd framing is wrong > + * -6 : SEMANTIC_ERROR < NFCC rsp to cold reset cmd > + * -9 : INAVLID_PARAM < NFCC rsp to cold reset cmd > + * -EAGAIN(-11) : < 1. mod_timer(): temp error during kernel alloc > + * < 2. No rsp received from NFCC for cold reset cmd > + * -ENOMEM(-12) : < mod_timer(): failed to allocate memory > + * -EINVAL(-22) : < 1. cold rst req is received from unknown source > + * < 2. mod_timer(): invalid arg is passed> + * -EREMOTEIO(-121): < Reset cmd write failure over I2C > + * -ECANCELED(-125): < FW DWNLD is going on so driver canceled operation > + * -ERESTARTSYS(-512): < Userspace process is restarted during read operation > + *****************************************************************************/ +int do_reset_protection(bool type) { + int ret = 0; + uint8_t prop_cmd[] = {0x2F, 0x1F, 0x01, 0x00}; + pn544_dev = get_nfcc_dev_data(); + + pr_info("%s: Enter cmd type: %d", __func__, type); + + prop_cmd[RST_PROTECTION_CMD_INDEX] = (type) ? 1 : 0; + + if(type ) { + pn544_dev->state_flags |= RST_PROTECTION_ENABLED; + } else { + if(!(pn544_dev->state_flags & RST_PROTECTION_ENABLED)) { + return ret; + } + } + pr_info("%s: NxpNciX: %d > %02X%02X%02X%02X \n", __func__, ret,prop_cmd[0], + prop_cmd[1],prop_cmd[2],prop_cmd[3]); + + ret = send_nci_transceive(prop_cmd, sizeof(prop_cmd)); + if(ret) { + pr_err("%s : send_nci_command returned %d\n", __func__, ret); + } + if(!type) { + pn544_dev->state_flags &= ~RST_PROTECTION_ENABLED; + } + pr_info("%s: exit, Status:%d state_flag : %x ", __func__, ret, + pn544_dev->state_flags); + return ret; +} +EXPORT_SYMBOL(do_reset_protection); + +/****************************************************************************** + * Function : ese_cold_reset + * + * Description : It shall be called by NFC/SPI/UWB driver to perform driver to + * to driver eSE cold reset. + * + * Parameters : src Source of the cold reset request + * + * Returns : + * 0 : OK < Success case > + * -EPERM(-1) : REJECTED < Guard timer running> + * -3 : FAILED < NFCC responds to cold reset cmd> + * -EIO(-5) : SYNTAX_ERROR < NFCC cmd framing is wrong > + * -6 : SEMANTIC_ERROR < NFCC rsp to cold reset cmd > + * -9 : INAVLID_PARAM < NFCC rsp to cold reset cmd > + * -EAGAIN(-11) : < 1. mod_timer(): temp error during kernel alloc > + * < 2. No rsp received from NFCC for cold reset cmd > + * -ENOMEM(-12) : < mod_timer(): failed to allocate memory > + * -EBUSY(-16) : < eSE busy, in updater mode> + * -EINVAL(-22) : < 1. cold rst req is received from unknown source > + * < 2. mod_timer(): invalid arg is passed> + * -EREMOTEIO(-121): < Reset cmd write failure over I2C > + * -ECANCELED(-125): < FW DWNLD is going on so driver canceled operation > + * -ERESTARTSYS(-512): < Userspace process is restarted during read operation > + *****************************************************************************/ +int ese_cold_reset(ese_cold_reset_origin_t src) +{ + int ret = 0; + uint8_t ese_cld_reset[] = {0x2F, 0x1E, 0x00}; + + pr_info("%s: Enter origin:%d", __func__, src); + + switch(src) { + case ESE_COLD_RESET_SOURCE_NFC: + case ESE_COLD_RESET_SOURCE_SPI: + case ESE_COLD_RESET_SOURCE_UWB: + break; + default: + pr_info("%s: Invalid argument", __func__); + return -EINVAL; + } + pn544_dev = get_nfcc_dev_data(); + mutex_lock(&ese_cold_reset_sync_mutex); + if(IS_COLD_RESET_ALLOWED(pn544_dev->state_flags, src)) { + ret = start_ese_cold_reset_guard_timer(); + if(ret) { + mutex_unlock(&ese_cold_reset_sync_mutex); + return ret; /* EAGAIN/EINVAL/ENOMEM*/ + } + pn544_dev->state_flags |= src << ESE_COLD_RESET_ORIGIN_FLAGS_POS; + init_completion(&ese_cold_reset_sema); + pr_info("%s: NxpNciX: %d > %02X%02X%02X \n", __func__, ret,ese_cld_reset[0], + ese_cld_reset[1],ese_cld_reset[2]); + ret = send_nci_transceive(ese_cld_reset, sizeof(ese_cld_reset)); + if(ret) { + pn544_dev->state_flags &= ~(MASK_ESE_COLD_RESET | MASK_ESE_COLD_RESET_GUARD_TIMER); + mutex_unlock(&ese_cold_reset_sync_mutex); + return ret; + } + /* wait for reboot guard timer*/ + if(!ret && wait_for_completion_timeout(&ese_cold_reset_sema, + msecs_to_jiffies(ESE_COLD_RESET_REBOOT_GUARD_TIME)) == 0){ + pr_info("%s: guard Timeout", __func__); + } + } else { + if(IS_RESET_PROTECTION_ENABLED(pn544_dev->state_flags)) { + pr_err("%s : Not allowed resource busy \n", __func__); + ret = -EBUSY; + } + else if(IS_COLD_RESET_REQ_IN_PROGRESS(pn544_dev->state_flags)) { + pr_err("%s : Operation not permitted \n", __func__); + ret = -EPERM; + } + else { + /*No Action required*/ + } + } + pn544_dev->state_flags &= ~(src << ESE_COLD_RESET_ORIGIN_FLAGS_POS); + mutex_unlock(&ese_cold_reset_sync_mutex); + + /* Return the status to the SPI/UWB Driver */ + pr_info("%s:%d exit, Status:%d", __func__, src, ret); + return ret; +} + +EXPORT_SYMBOL(ese_cold_reset); diff --git a/nfc/cold_reset.h b/pn553-i2c/cold_reset.h similarity index 62% rename from nfc/cold_reset.h rename to pn553-i2c/cold_reset.h index 35afe748dc..59ceb374e3 100644 --- a/nfc/cold_reset.h +++ b/pn553-i2c/cold_reset.h @@ -16,13 +16,24 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ +#ifndef _NFC_COMMON_H_ +#define _NFC_COMMON_H_ -#ifndef _NFC_COLD_RESET_H_ -#define _NFC_COLD_RESET_H_ +#define MSG_NFCC_RSP 0x40 +#define MSG_PROP_GID 0x0F +#define ESE_CLD_RST_OID 0x1E +#define RST_PROTECTION_CMD_INDEX 0x03 + +#define RST_PROTECTION_OID 0x1F +#define RST_PROTECTION_ENABLED 0x08 typedef enum ese_cold_reset_origin { - ESE_COLD_RESET_SOURCE_SPI, - ESE_COLD_RESET_SOURCE_UWB, -} ese_cold_reset_origin_t; + ESE_COLD_RESET_NOT_REQUESTED = 0x00, + ESE_COLD_RESET_SOURCE_NFC = 0x01, + ESE_COLD_RESET_SOURCE_SPI = 0x02, + ESE_COLD_RESET_SOURCE_UWB = 0x04, +}ese_cold_reset_origin_t; -#endif /* NFC_COLD_RESET_H_ */ +void ese_reset_resource_init(void); +void ese_reset_resource_destroy(void); +#endif /* _NFC_COMMON_H_ */ diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c new file mode 100644 index 0000000000..0579655aab --- /dev/null +++ b/pn553-i2c/pn553.c @@ -0,0 +1,1611 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2020 NXP Semiconductors + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* HiKey Compilation fix */ +#define HiKey_620_COMPILATION_FIX 1 +#ifndef HiKey_620_COMPILATION_FIX +#include +#endif + +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include +#include +#endif + +#include +#include "pn553.h" +#include "cold_reset.h" + +#define DRAGON_NFC 1 +#define SIG_NFC 44 +#define MAX_BUFFER_SIZE 512 +#define MAX_SECURE_SESSIONS 1 + +/* This macro evaluates to 1 if the cold reset is requested by driver(SPI/UWB). */ +#define IS_PROP_CMD_REQUESTED(flags) (flags & (MASK_ESE_COLD_RESET | RST_PROTECTION_ENABLED)) +/* This macro evaluates to 1 if eSE cold reset response is received */ +#define IS_PROP_RSP(buf) \ + (((MSG_NFCC_RSP | MSG_PROP_GID) == buf[0]) && ((ESE_CLD_RST_OID == buf[1]) || \ + (RST_PROTECTION_OID == buf[1]) )) + +/* VEN is kept ON all the time if you define the macro VEN_ALWAYS_ON. +Used for SN100 usecases */ +#define VEN_ALWAYS_ON +/* Macro added to disable SVDD power toggling */ +/* #define JCOP_4X_VALIDATION */ + + +/* HiKey Compilation fix */ +#ifndef HiKey_620_COMPILATION_FIX +struct wake_lock nfc_wake_lock; +#if HWINFO +struct hw_type_info hw_info; +#endif +static bool sIsWakeLocked = false; +#endif +static struct pn544_dev *pn544_dev; +static struct semaphore ese_access_sema; +static struct semaphore svdd_sync_onoff_sema; +static struct completion dwp_onoff_sema; +static struct timer_list secure_timer; +static void release_ese_lock(p61_access_state_t p61_current_state); +int get_ese_lock(p61_access_state_t p61_current_state, int timeout); +static long set_jcop_download_state(unsigned long arg); +static long start_seccure_timer(unsigned long timer_value); +static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg); +extern void rcv_prop_resp_status(const char * const buf); +extern long ese_cold_reset(ese_cold_reset_origin_t src); +extern void ese_reset_resource_init(void); +extern void ese_reset_resource_destroy(void); +#if HWINFO +static void check_hw_info(void); +#endif +#define SECURE_TIMER_WORK_QUEUE "SecTimerCbWq" + +struct pn544_dev * get_nfcc_dev_data(void) { + return pn544_dev; +} +static void pn544_disable_irq(struct pn544_dev *pn544_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + if (pn544_dev->irq_enabled) { + disable_irq_nosync(pn544_dev->client->irq); + disable_irq_wake(pn544_dev->client->irq); + pn544_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); +} + +static int pn544_dev_release(struct inode *inode, struct file *filp) { + pn544_dev->state_flags &= ~(P544_FLAG_NFC_VEN_RESET|P544_FLAG_NFC_ON|P544_FLAG_FW_DNLD); + if (pn544_dev->firm_gpio) + gpio_set_value(pn544_dev->firm_gpio, 0); + pr_info(KERN_ALERT "Exit %s: NFC driver release nfc hal \n", __func__); + return 0; +} +static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) +{ + struct pn544_dev *pn544_dev = dev_id; + + pn544_disable_irq(pn544_dev); + /* HiKey Compilation fix */ + #ifndef HiKey_620_COMPILATION_FIX + if (sIsWakeLocked == false) + { + wake_lock(&nfc_wake_lock); + sIsWakeLocked = true; + } else { + pr_debug("%s already wake locked!\n", __func__); + } + #endif + /* Wake up waiting readers */ + wake_up(&pn544_dev->read_wq); + + + return IRQ_HANDLED; +} + +ssize_t pn544_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + //pr_debug("%s : reading %zu bytes.\n", __func__, count); + + mutex_lock(&pn544_dev->read_mutex); + + if (!gpio_get_value(pn544_dev->irq_gpio)) { + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } + + while (1) { + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + enable_irq_wake(pn544_dev->client->irq); + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + pn544_disable_irq(pn544_dev); + + if (ret) + goto fail; + if(pn544_dev->state_flags & P544_FLAG_NFC_VEN_RESET) { + pr_warning("%s: releasing read \n", __func__); + pn544_dev->state_flags &= ~P544_FLAG_NFC_VEN_RESET; + ret = -EL3RST; + goto fail; + } + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + + /* Read data */ + ret = i2c_master_recv(pn544_dev->client, tmp, count); + #ifndef HiKey_620_COMPILATION_FIX + /* HiKey Compilation fix */ + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } + #endif + + + /* If ese cold reset has been requested then read the response */ + if(IS_PROP_CMD_REQUESTED(pn544_dev->state_flags) && IS_PROP_RSP(tmp)) { + rcv_prop_resp_status(tmp); + /* Request is from driver, consume the response */ + mutex_unlock(&pn544_dev->read_mutex); + return 0; + } + mutex_unlock(&pn544_dev->read_mutex); + + /* pn544 seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ +#if !NEXUS5x + udelay(1000); +#endif + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return ret; + + fail: + mutex_unlock(&pn544_dev->read_mutex); + return ret; +} + +static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + pn544_dev = filp->private_data; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + + //pr_debug("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn544_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + /* pn544 seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); + + return ret; +} + +static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) +{ + pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); + if (current_state) + { + if(set){ + if(pn544_dev->p61_current_state == P61_STATE_IDLE) + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->p61_current_state |= current_state; + } + else{ + pn544_dev->p61_current_state ^= current_state; + if(!pn544_dev->p61_current_state) + pn544_dev->p61_current_state = P61_STATE_IDLE; + } + } + pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); +} + +static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) +{ + + if (current_state == NULL) { + //*current_state = P61_STATE_INVALID; + pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); + } else { + *current_state = pn544_dev->p61_current_state; + } +} +static void p61_access_lock(struct pn544_dev *pn544_dev) +{ + mutex_lock(&pn544_dev->p61_state_mutex); +} +static void p61_access_unlock(struct pn544_dev *pn544_dev) +{ + mutex_unlock(&pn544_dev->p61_state_mutex); +} + +static int signal_handler(p61_access_state_t state, long nfc_pid) +{ + struct siginfo sinfo; + pid_t pid; + struct task_struct *task; + int sigret = 0, ret = 0; + pr_info("%s: Enter\n", __func__); + + if(nfc_pid == 0) + { + pr_info("nfc_pid is clear don't call signal_handler.\n"); + } + else + { + memset(&sinfo, 0, sizeof(struct siginfo)); + sinfo.si_signo = SIG_NFC; + sinfo.si_code = SI_QUEUE; + sinfo.si_int = state; + pid = nfc_pid; + + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if(task) + { + pr_info("%s.\n", task->comm); + sigret = force_sig_info(SIG_NFC, &sinfo, task); + if(sigret < 0){ + pr_info("send_sig_info failed..... sigret %d.\n", sigret); + ret = -1; + //msleep(60); + } + } + else{ + pr_info("finding task from PID failed\r\n"); + ret = -1; + } + } + pr_info("%s: Exit ret = %d\n", __func__, ret); + return ret; +} +static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 100; //100 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); + if(nfc_service_pid) + { + if (0 == signal_handler(origin, nfc_service_pid)) + { + sema_init(&svdd_sync_onoff_sema, 0); + pr_info("Waiting for svdd protection response"); + if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) + { + pr_info("svdd wait protection: Timeout"); + } + pr_info("svdd wait protection : released"); + } + } +} +static int release_svdd_wait(void) +{ + pr_info("%s: Enter \n", __func__); + up(&svdd_sync_onoff_sema); + return 0; +} + +static void dwp_OnOff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 100; //100 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + if(nfc_service_pid) + { + if (0 == signal_handler(origin, nfc_service_pid)) + { + init_completion(&dwp_onoff_sema); + if(wait_for_completion_timeout(&dwp_onoff_sema, tempJ) != 0) + { + pr_info("Dwp On/off wait protection: Timeout"); + } + pr_info("Dwp On/Off wait protection : released"); + } + } +} +static int release_dwpOnOff_wait(void) +{ + pr_info("%s: Enter \n", __func__); + complete(&dwp_onoff_sema); + return 0; +} + +static int pn544_dev_open(struct inode *inode, struct file *filp) +{ + struct pn544_dev *pn544_dev = container_of(filp->private_data, + struct pn544_dev, + pn544_device); + + filp->private_data = pn544_dev; + pn544_dev->state_flags |= (P544_FLAG_NFC_ON); + pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + + return 0; +} + +static int set_nfc_pid(unsigned long arg) +{ + pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); + pn544_dev->nfc_service_pid = arg; + return 0; +} + +long pn544_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + /* Free pass autobahn area, not protected. Use it carefullly. START */ + switch(cmd) + { + case P544_GET_ESE_ACCESS: + return get_ese_lock(P61_STATE_WIRED, arg); + break; + case P544_REL_SVDD_WAIT: + return release_svdd_wait(); + break; + case P544_SET_NFC_SERVICE_PID: + return set_nfc_pid(arg); + break; + case P544_REL_DWPONOFF_WAIT: + return release_dwpOnOff_wait(); + break; + default: + break; + } + /* Free pass autobahn area, not protected. Use it carefullly. END */ + + p61_access_lock(pn544_dev); + switch (cmd) { + case PN544_SET_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 2) { + if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) + { + /* NFCC fw/download should not be allowed if p61 is used + * by SPI + */ + pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + pn544_dev->nfc_ven_enabled = true; + if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) + || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) + { + /* power on with firmware download (requires hw reset) + */ + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + pn544_dev->state_flags |= (P544_FLAG_FW_DNLD); + } + + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } else if (arg == 1) { + /* power on */ + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + if(current_state & P61_STATE_DWNLD){ + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, false); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + pn544_dev->state_flags &= ~(P544_FLAG_FW_DNLD); + } + + pn544_dev->nfc_ven_enabled = true; + #ifndef VEN_ALWAYS_ON + if (pn544_dev->spi_ven_enabled == false || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { + gpio_set_value(pn544_dev->ven_gpio, 1); + } + #endif + } else if (arg == 0) { + /* power off */ + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = false; + /* Don't change Ven state if spi made it high */ + #ifndef VEN_ALWAYS_ON + if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) + || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + } + #endif + /* HiKey Compilation fix */ + #ifndef HiKey_620_COMPILATION_FIX + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } + #endif + } else if (arg == 3) { + /*NFC Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_WIRED) { + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + } +#ifdef ISO_RST + gpio_set_value(pn544_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn544_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from DWP DONE\n", __func__); +#endif + } else if (arg == 4) { + pr_info("%s FW dwldioctl called from NFC \n", __func__); + /*NFC Service called FW dwnld*/ + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + pn544_dev->state_flags |= (P544_FLAG_FW_DNLD); + msleep(10); + } + } else if (arg == 5) { + pn544_dev->state_flags |= P544_FLAG_NFC_VEN_RESET; + pn544_disable_irq(pn544_dev); + wake_up(&pn544_dev->read_wq); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + pr_info("%s VEN reset DONE >>>>>>>\n", __func__); + } else if (arg == 6) { + if (pn544_dev->firm_gpio) { + gpio_set_value(pn544_dev->firm_gpio, 0); + pn544_dev->state_flags &= ~(P544_FLAG_FW_DNLD); + } + pr_info("%s FW GPIO set to 0x00 >>>>>>>\n", __func__); + }else { + pr_err("%s bad arg %lu\n", __func__, arg); + /* changed the p61 state to idle*/ + p61_access_unlock(pn544_dev); + return -EINVAL; + } + } + break; + case P61_SET_SPI_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) { + pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if (!(current_state & P61_STATE_JCP_DWNLD)){ + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + /*signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid);*/ + dwp_OnOff(pn544_dev->nfc_service_pid, P61_STATE_SPI); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + + if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + #ifndef VEN_ALWAYS_ON + if (pn544_dev->nfc_ven_enabled == false) + { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + #endif + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + + /* Delay (10ms) after SVDD_PWR_ON to allow JCOP to bootup (5ms jcop boot time + 5ms guard time) */ + usleep_range(10000, 12000); + + } else { + pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); + if(current_state & P61_STATE_SPI_PRIO){ + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + if (!(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + if(!(current_state & P61_STATE_WIRED)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | + P61_STATE_SPI_PRIO_END); + }else { + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } else if (!(current_state & P61_STATE_WIRED)) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + pn544_dev->spi_ven_enabled = false; + + if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + + /* if secure timer is running, Delay the SPI close by 25ms after sending End of Apdu to enable eSE go into DPD + gracefully (20ms after EOS + 5ms DPD settlement time) */ + if(pn544_dev->secure_timer_cnt) + usleep_range(25000, 30000); + + if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) + { +#ifndef JCOP_4X_VALIDATION + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); +#endif + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } +#ifndef JCOP_4X_VALIDATION + #ifndef VEN_ALWAYS_ON + if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + #endif +#endif + }else if(current_state & P61_STATE_SPI){ + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + if (!(current_state & P61_STATE_WIRED) && + (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) && + !(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + /* if secure timer is running, Delay the SPI close by 25ms after sending End of Apdu to enable eSE go into DPD + gracefully (20ms after EOS + 5ms DPD settlement time) */ + if(pn544_dev->secure_timer_cnt) + usleep_range(25000, 30000); + + if (!(pn544_dev->secure_timer_cnt)) { +#ifndef JCOP_4X_VALIDATION + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); +#endif + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } + /*If JCOP3.2 or 3.3 for handling triple mode + protection signal NFC service */ + else + { + if (!(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + } else { + signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } else if (pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { +#ifndef JCOP_4X_VALIDATION + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); +#endif + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); + } + } + pn544_dev->spi_ven_enabled = false; +#ifndef VEN_ALWAYS_ON + if (pn544_dev->nfc_ven_enabled == false && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) + && !(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } +#endif + } else { + pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + }else if (arg == 2) { + pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); + if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + #ifndef VEN_ALWAYS_ON + if ((pn544_dev->nfc_ven_enabled == false) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + #endif + } + if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); +#ifndef JCOP_4X_VALIDATION + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); +#endif + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + msleep(10); + if(!gpio_get_value(pn544_dev->ese_pwr_gpio)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + } else { + pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 3) { + int ret = ese_cold_reset(ESE_COLD_RESET_SOURCE_NFC); + p61_access_unlock(pn544_dev); + return ret; + }else if (arg == 4) { + if (current_state & P61_STATE_SPI_PRIO) + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + /*after SPI prio timeout, the state is changing from SPI prio to SPI */ + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + else + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Device or resource busy */ + } + } else if(arg == 5){ + release_ese_lock(P61_STATE_SPI); + } else if (arg == 6) { + /*SPI Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if(current_state & P61_STATE_WIRED) { + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_SPI) { + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + }else if(current_state & P61_STATE_SPI_PRIO) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + } +#ifdef ISO_RST + gpio_set_value(pn544_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn544_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from SPI DONE\n", __func__); +#endif + } + else { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + + case P61_GET_PWR_STATUS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); + put_user(current_state, (int __user *)arg); + } + break; + + case PN544_SET_DWNLD_STATUS: + { + long ret; + ret = set_jcop_download_state(arg); + if(ret < 0) + { + p61_access_unlock(pn544_dev); + return ret; + } + } + break; + + case P61_SET_WIRED_ACCESS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) + { + if (current_state) + { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); + if (current_state & P61_STATE_SPI_PRIO) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } else { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); + p61_access_unlock(pn544_dev); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); + if (current_state & P61_STATE_WIRED){ + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } else { + pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + p61_access_unlock(pn544_dev); + return -EPERM; /* Operation not permitted */ + } + } + else if(arg == 2) + { + pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); + if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } + else if(arg == 3) + { + pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); + if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + else if(arg == 4) + { + release_ese_lock(P61_STATE_WIRED); + } + else { + pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + } + break; + case P544_SET_POWER_SCHEME: + { + if(arg == PN67T_PWR_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); + } + else if(arg == PN80T_LEGACY_PWR_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; + pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); + } + else if(arg == PN80T_EXT_PMU_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; + pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); + } + else + { + pr_info("%s : The power scheme is invalid,\n", __func__); + } + } + break; + case P544_SECURE_TIMER_SESSION: + { + secure_timer_operation(pn544_dev, arg); + } + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + p61_access_unlock(pn544_dev); + return -EINVAL; + } + p61_access_unlock(pn544_dev); + return 0; +} +EXPORT_SYMBOL(pn544_dev_ioctl); + +static void secure_timer_workqueue(struct work_struct *Wq) +{ + p61_access_state_t current_state = P61_STATE_INVALID; + printk( KERN_INFO "secure_timer_callback: called (%lu).\n", jiffies); + /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: START */ + get_ese_lock(P61_STATE_WIRED, MAX_ESE_ACCESS_TIME_OUT_MS); + p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); + p61_get_access_state(pn544_dev, ¤t_state); + + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + printk( KERN_INFO "secure_timer_callback: make se_pwer_gpio low, state = %d", current_state); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); + #ifndef VEN_ALWAYS_ON + if(pn544_dev->nfc_service_pid == 0x00) + { + gpio_set_value(pn544_dev->ven_gpio, 0); + printk( KERN_INFO "secure_timer_callback :make ven_gpio low, state = %d", current_state); + } + #endif + } + pn544_dev->secure_timer_cnt = 0; + /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: END */ + release_ese_lock(P61_STATE_WIRED); + return; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) +static void secure_timer_callback( unsigned long data ) +{ +(void)data; +#else +static void secure_timer_callback(struct timer_list *unused) +{ +#endif + /* Flush and push the timer callback event to the bottom half(work queue) + to be executed later, at a safer time */ + flush_workqueue(pn544_dev->pSecureTimerCbWq); + queue_work(pn544_dev->pSecureTimerCbWq, &pn544_dev->wq_task); + return; +} + +static long start_seccure_timer(unsigned long timer_value) +{ + long ret = -EINVAL; + pr_info("start_seccure_timer: enter\n"); + /* Delete the timer if timer pending */ + if(timer_pending(&secure_timer) == 1) + { + pr_info("start_seccure_timer: delete pending timer \n"); + /* delete timer if already pending */ + del_timer(&secure_timer); + } + /* Start the timer if timer value is non-zero */ + if(timer_value) + { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) + init_timer(&secure_timer); + setup_timer( &secure_timer, secure_timer_callback, 0 ); +#else + timer_setup(&secure_timer, secure_timer_callback, 0); +#endif + pr_info("start_seccure_timer: timeout %lums (%lu)\n",timer_value, jiffies ); + ret = mod_timer( &secure_timer, jiffies + msecs_to_jiffies(timer_value)); + if (ret) + pr_info("start_seccure_timer: Error in mod_timer\n"); + } + return ret; +} + +static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg) +{ + long ret = -EINVAL; + unsigned long timer_value = arg; + + printk( KERN_INFO "secure_timer_operation, %d\n",pn544_dev->chip_pwr_scheme); + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + ret = start_seccure_timer(timer_value); + if(!ret) + { + pn544_dev->secure_timer_cnt = 1; + p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, true); + } + else + { + pn544_dev->secure_timer_cnt = 0; + p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); + pr_info("%s :Secure timer reset \n", __func__); + } + } + else + { + pr_info("%s :Secure timer session not applicable \n", __func__); + } + return ret; +} + +static long set_jcop_download_state(unsigned long arg) +{ + p61_access_state_t current_state = P61_STATE_INVALID; + long ret = 0; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s:Enter PN544_SET_DWNLD_STATUS:JCOP Dwnld state arg = %ld",__func__, arg); + if(arg == JCP_DWNLD_INIT) + { + if(pn544_dev->nfc_service_pid) + { + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(JCP_DWNLD_INIT, pn544_dev->nfc_service_pid); + } + else + { + if (current_state & P61_STATE_JCP_DWNLD) + { + ret = -EINVAL; + } + else + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); + } + } + } + else if (arg == JCP_DWNLD_START) + { + if (current_state & P61_STATE_JCP_DWNLD) + { + ret = -EINVAL; + } + else + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); + } + } + else if (arg == JCP_SPI_DWNLD_COMPLETE) + { + if(pn544_dev->nfc_service_pid) + { + signal_handler(JCP_DWP_DWNLD_COMPLETE, pn544_dev->nfc_service_pid); + } + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); + } + else if (arg == JCP_DWP_DWNLD_COMPLETE) + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); + } + else + { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + p61_access_unlock(pn544_dev); + return -EBADRQC; /* Invalid request code */ + } + pr_info("%s: PN544_SET_DWNLD_STATUS = %x",__func__, current_state); + + return ret; +} + +int get_ese_lock(p61_access_state_t p61_current_state, int timeout) +{ + unsigned long tempJ = msecs_to_jiffies(timeout); + if(down_timeout(&ese_access_sema, tempJ) != 0) + { + printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); + return -EBUSY; + } + return 0; +} +EXPORT_SYMBOL(get_ese_lock); + +static void release_ese_lock(p61_access_state_t p61_current_state) +{ + up(&ese_access_sema); +} + + +static const struct file_operations pn544_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_dev_read, + .write = pn544_dev_write, + .open = pn544_dev_open, + .release = pn544_dev_release, + .unlocked_ioctl = pn544_dev_ioctl, +}; +#if DRAGON_NFC +static int pn544_parse_dt(struct device *dev, + struct pn544_i2c_platform_data *data) +{ + struct device_node *np = dev->of_node; + int errorno = 0; + +#if !NEXUS5x + data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); + if ((!gpio_is_valid(data->irq_gpio))) + return -EINVAL; + + data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); + if ((!gpio_is_valid(data->ven_gpio))) + return -EINVAL; + + data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); + if ((!gpio_is_valid(data->firm_gpio))) + return -EINVAL; + + data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); + if ((!gpio_is_valid(data->ese_pwr_gpio))) + return -EINVAL; + data->iso_rst_gpio = of_get_named_gpio(np, "nxp,pn544-iso-pwr-rst", 0); + if ((!gpio_is_valid(data->iso_rst_gpio))) + return -EINVAL; +#else + data->ven_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_ven", 0, NULL); + data->firm_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_mode", 0, NULL); + data->irq_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_irq", 0, NULL); +#endif + pr_info("%s: %d, %d, %d, %d, %d error:%d\n", __func__, + data->irq_gpio, data->ven_gpio, data->firm_gpio, data->iso_rst_gpio, + data->ese_pwr_gpio, errorno); + + return errorno; +} +#endif + +static int pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct pn544_i2c_platform_data *platform_data; + //struct pn544_dev *pn544_dev; + +#if !DRAGON_NFC + platform_data = client->dev.platform_data; +#else + struct device_node *node = client->dev.of_node; + + if (node) { + platform_data = devm_kzalloc(&client->dev, + sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); + if (!platform_data) { + dev_err(&client->dev, + "nfc-nci probe: Failed to allocate memory\n"); + return -ENOMEM; + } + ret = pn544_parse_dt(&client->dev, platform_data); + if (ret) + { + pr_info("%s pn544_parse_dt failed", __func__); + } + client->irq = gpio_to_irq(platform_data->irq_gpio); + if (client->irq < 0) + { + pr_info("%s gpio to irq failed", __func__); + } + } else { + platform_data = client->dev.platform_data; + } +#endif + if (platform_data == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } +#if !DRAGON_NFC + ret = gpio_request(platform_data->irq_gpio, "nfc_int"); + if (ret) + return -ENODEV; + ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); + if (ret) + goto err_ven; + ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); + if (ret) + goto err_ese_pwr; + if (platform_data->firm_gpio) { + ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); + if (ret) + goto err_firm; + } +#ifdef ISO_RST + if(platform_data->iso_rst_gpio) { + ret = gpio_request(platform_data->iso_rst_gpio, "nfc_iso_rst"); + if (ret) + goto err_iso_rst; + } +#endif +#endif + pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); + if (pn544_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + pn544_dev->irq_gpio = platform_data->irq_gpio; + pn544_dev->ven_gpio = platform_data->ven_gpio; + pn544_dev->firm_gpio = platform_data->firm_gpio; + pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; +#ifdef ISO_RST + pn544_dev->iso_rst_gpio = platform_data->iso_rst_gpio; +#endif + pn544_dev->p61_current_state = P61_STATE_IDLE; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + pn544_dev->client = client; + pn544_dev->secure_timer_cnt = 0; + + pn544_dev->state_flags = 0x00; + ret = gpio_direction_input(pn544_dev->irq_gpio); + if (ret < 0) { + pr_err("%s :not able to set irq_gpio as input\n", __func__); + goto err_ven; + } + #ifndef VEN_ALWAYS_ON + ret = gpio_direction_output(pn544_dev->ven_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_firm; + } + #else + ret = gpio_direction_output(pn544_dev->ven_gpio, 1); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_firm; + } + #endif + ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); + goto err_ese_pwr; + } + if (platform_data->firm_gpio) { + ret = gpio_direction_output(pn544_dev->firm_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set firm_gpio as output\n", + __func__); + goto err_exit; + } + } +#ifdef ISO_RST + ret = gpio_direction_output(pn544_dev->iso_rst_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set iso rst gpio as output\n", __func__); + goto err_iso_rst; + } +#endif + /* init mutex and queues */ + ese_reset_resource_init(); + init_waitqueue_head(&pn544_dev->read_wq); + mutex_init(&pn544_dev->read_mutex); + sema_init(&ese_access_sema, 1); + mutex_init(&pn544_dev->p61_state_mutex); + spin_lock_init(&pn544_dev->irq_enabled_lock); + pn544_dev->pSecureTimerCbWq = create_workqueue(SECURE_TIMER_WORK_QUEUE); + INIT_WORK(&pn544_dev->wq_task, secure_timer_workqueue); + pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; + pn544_dev->pn544_device.name = "pn553"; + pn544_dev->pn544_device.fops = &pn544_dev_fops; + + ret = misc_register(&pn544_dev->pn544_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } + /* HiKey Compilation fix */ + #ifndef HiKey_620_COMPILATION_FIX + wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); + #endif +#ifdef ISO_RST + /* Setting ISO RESET pin high to power ESE during init */ + gpio_set_value(pn544_dev->iso_rst_gpio, 1); +#endif + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pn544_dev->irq_enabled = true; + ret = request_irq(client->irq, pn544_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, pn544_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + enable_irq_wake(pn544_dev->client->irq); + pn544_disable_irq(pn544_dev); + i2c_set_clientdata(client, pn544_dev); +#ifdef VEN_ALWAYS_ON + msleep(5); /* VBAT--> VDDIO(HIGH) + Guardtime of min 5ms --> VEN(HIGH) */ + /* VEN toggle(reset) to proceed */ + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(5); + gpio_set_value(pn544_dev->ven_gpio, 1); +#endif + +#if HWINFO + /* + * This function is used only if + * hardware info is required during probe*/ + check_hw_info(); +#endif + + return 0; + + err_request_irq_failed: + misc_deregister(&pn544_dev->pn544_device); + err_misc_register: + ese_reset_resource_destroy(); + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + kfree(pn544_dev); + err_exit: + if (pn544_dev->firm_gpio) + gpio_free(platform_data->firm_gpio); + err_firm: + gpio_free(platform_data->ese_pwr_gpio); + err_ese_pwr: + gpio_free(platform_data->ven_gpio); + err_ven: + gpio_free(platform_data->irq_gpio); +#ifdef ISO_RST + err_iso_rst: + gpio_free(platform_data->iso_rst_gpio); +#endif + return ret; +} + +static int pn544_remove(struct i2c_client *client) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn544_dev); + misc_deregister(&pn544_dev->pn544_device); + mutex_destroy(&pn544_dev->read_mutex); + mutex_destroy(&pn544_dev->p61_state_mutex); + gpio_free(pn544_dev->irq_gpio); + gpio_free(pn544_dev->ven_gpio); + gpio_free(pn544_dev->ese_pwr_gpio); + destroy_workqueue(pn544_dev->pSecureTimerCbWq); +#ifdef ISO_RST + gpio_free(pn544_dev->iso_rst_gpio); +#endif + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + ese_reset_resource_destroy(); + + if (pn544_dev->firm_gpio) + gpio_free(pn544_dev->firm_gpio); + kfree(pn544_dev); + + return 0; +} + +static const struct i2c_device_id pn544_id[] = { +#if NEXUS5x + { "pn548", 0 }, +#else + { "pn544", 0 }, +#endif + { } +}; +#if DRAGON_NFC +static struct of_device_id pn544_i2c_dt_match[] = { + { +#if NEXUS5x + .compatible = "nxp,pn548", +#else + .compatible = "nxp,pn544", +#endif + }, + {} +}; +#endif +static struct i2c_driver pn544_driver = { + .id_table = pn544_id, + .probe = pn544_probe, + .remove = pn544_remove, + .driver = { + .owner = THIS_MODULE, +#if NEXUS5x + .name = "pn548", +#else + .name = "pn544", +#endif +#if DRAGON_NFC + .of_match_table = pn544_i2c_dt_match, +#endif + }, +}; +#if HWINFO +/****************************************************************************** + * Function check_hw_info + * + * Description This function is called during pn544_probe to retrieve + * HW info. + * Useful get HW information in case of previous FW download is + * interrupted and core reset is not allowed. + * This function checks if core reset is allowed, if not + * sets DWNLD_REQ(firm_gpio) , ven reset and sends firmware + * get version command. + * In response HW information will be received. + * + * Returns None + * + ******************************************************************************/ +static void check_hw_info() { + char read_data[20]; + int ret, get_version_len = 8, retry_count = 0; + static uint8_t cmd_reset_nci[] = {0x20, 0x00, 0x01, 0x00}; + char get_version_cmd[] = + {0x00, 0x04, 0xF1, 0x00, 0x00, 0x00, 0x6E, 0xEF}; + + pr_info("%s :Enter\n", __func__); + + /* + * Ven Reset before sending core Reset + * This is to check core reset is allowed or not. + * If not allowed then previous FW download is interrupted in between + * */ + pr_info("%s :Ven Reset \n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + ret = i2c_master_send(pn544_dev->client, cmd_reset_nci, 4); + + if (ret == 4) { + pr_info("%s : core reset write success\n", __func__); + } else { + + /* + * Core reset failed. + * set the DWNLD_REQ , do ven reset + * send firmware download info command + * */ + pr_err("%s : write failed\n", __func__); + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + ret = i2c_master_send(pn544_dev->client, get_version_cmd, get_version_len); + if (ret != get_version_len) { + ret = -EIO; + pr_err("%s : write_failed \n", __func__); + } + else { + pr_info("%s :data sent\n", __func__); + } + + ret = 0; + + while (retry_count < 10) { + + /* + * Wait for read interrupt + * If spurious interrupt is received retry again + * */ + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + enable_irq_wake(pn544_dev->client->irq); + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + pn544_disable_irq(pn544_dev); + + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + retry_count ++; + } + + if(ret) { + return; + } + + /* + * Read response data and copy into hw_type_info + * */ + ret = i2c_master_recv(pn544_dev->client, read_data, 14); + + if(ret) { + memcpy(hw_info.data, read_data, ret); + hw_info.len = ret; + pr_info("%s :data received len : %d\n", __func__,hw_info.len); + } + else { + pr_err("%s :Read Failed\n", __func__); + } + } +} +#endif +/* + * module load/unload record keeping + */ + +static int __init pn544_dev_init(void) +{ + pr_info("Loading pn544 driver\n"); + return i2c_add_driver(&pn544_driver); +} +module_init(pn544_dev_init); + +static void __exit pn544_dev_exit(void) +{ + pr_info("Unloading pn544 driver\n"); + i2c_del_driver(&pn544_driver); +} +module_exit(pn544_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION("NFC PN544 driver"); +MODULE_LICENSE("GPL"); diff --git a/pn553-i2c/pn553.h b/pn553-i2c/pn553.h new file mode 100644 index 0000000000..d196474f3e --- /dev/null +++ b/pn553-i2c/pn553.h @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2020 NXP Semiconductors + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#ifndef _PN553_H_ +#define _PN553_H_ + +#include + +#define PN544_MAGIC 0xE9 + +/* + * PN544 power control via ioctl + * PN544_SET_PWR(0): power off + * PN544_SET_PWR(1): power on + * PN544_SET_PWR(2): reset and power on with firmware download enabled + */ +#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, long) + +/* + * SPI Request NFCC to enable p61 power, only in param + * Only for SPI + * level 1 = Enable power + * level 0 = Disable power + * This also be used to perform eSE cold reset when + * argument value is 0x03 + */ +#define P61_SET_SPI_PWR _IOW(PN544_MAGIC, 0x02, long) + +/* SPI or DWP can call this ioctl to get the current + * power state of P61 + * +*/ +#define P61_GET_PWR_STATUS _IOR(PN544_MAGIC, 0x03, long) + +/* DWP side this ioctl will be called + * level 1 = Wired access is enabled/ongoing + * level 0 = Wired access is disalbed/stopped +*/ +#define P61_SET_WIRED_ACCESS _IOW(PN544_MAGIC, 0x04, long) + +/* + NFC Init will call the ioctl to register the PID with the i2c driver +*/ +#define P544_SET_NFC_SERVICE_PID _IOW(PN544_MAGIC, 0x05, long) + +/* + NFC and SPI will call the ioctl to get the i2c/spi bus access +*/ +#define P544_GET_ESE_ACCESS _IOW(PN544_MAGIC, 0x06, long) +/* + NFC and SPI will call the ioctl to update the power scheme +*/ +#define P544_SET_POWER_SCHEME _IOW(PN544_MAGIC, 0x07, long) + +/* + NFC will call the ioctl to release the svdd protection +*/ +#define P544_REL_SVDD_WAIT _IOW(PN544_MAGIC, 0x08, long) + +/* SPI or DWP can call this ioctl to get the current + * power state of P61 + * +*/ +#define PN544_SET_DWNLD_STATUS _IOW(PN544_MAGIC, 0x09, long) +/* + NFC will call the ioctl to release the dwp on/off protection +*/ +#define P544_REL_DWPONOFF_WAIT _IOW(PN544_MAGIC, 0x0A, long) + +/* + NFC will call the ioctl to start Secure Timer +*/ + +#define P544_SECURE_TIMER_SESSION _IOW(PN544_MAGIC, 0x0B, long) + +#define MAX_ESE_ACCESS_TIME_OUT_MS 200 /*100 milliseconds*/ + +/* + NFC_ON: Driver is being used by the NFC service (bit b0) +*/ +#define P544_FLAG_NFC_ON 0x01 +/* + FW_DNLD: NFC_ON and FW download is going on (bit b1) +*/ +#define P544_FLAG_FW_DNLD 0x02 +/* + * VEN_RESET: NFC_ON and FW download with VEN reset (bit b2) +*/ +#define P544_FLAG_NFC_VEN_RESET 0x04 +/* + * ESE_RESET: Starting of flag positions for eSE cold reset origin +*/ +#define ESE_COLD_RESET_ORIGIN_FLAGS_POS (4) //(bit b4) +#define ESE_COLD_RESET_ORIGIN_NFC_FLAG_POS (4) //(bit b4) +/* + * ESE_RESET: Mask for the flags used for Driver to driver cold reset + * b6, b5, b4 : + * 0 0 0 -> no request for ese_cold_reset + * 0 0 1 -> ese_cold_reset requested from NFC driver + * 0 1 0 -> ese_cold_reset requested from eSE driver + * 1 0 0 -> ese_cold_reset requested from UWB driver +*/ +#define MASK_ESE_COLD_RESET (0x70) +/* + * ESE_RESET: Bit mask to check if ese_reset_guard timer is started (bit b7) +*/ +#define MASK_ESE_COLD_RESET_GUARD_TIMER (0x80) +/* + * ESE_RESET: Guard time to allow eSE cold reset from the driver +*/ +#define ESE_COLD_RESET_GUARD_TIME (3000) //3s +/* + * ESE_RESET: NCI command response timeout +*/ +#define NCI_CMD_RSP_TIMEOUT (2000) //2s +/* + * ESE_RESET: Guard time to reboot the JCOP +*/ +#define ESE_COLD_RESET_REBOOT_GUARD_TIME (50) //50ms + +typedef enum p61_access_state{ + P61_STATE_INVALID = 0x0000, + P61_STATE_IDLE = 0x0100, /* p61 is free to use */ + P61_STATE_WIRED = 0x0200, /* p61 is being accessed by DWP (NFCC)*/ + P61_STATE_SPI = 0x0400, /* P61 is being accessed by SPI */ + P61_STATE_DWNLD = 0x0800, /* NFCC fw download is in progress */ + P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ + P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ + P61_STATE_SPI_END = 0x4000, + P61_STATE_JCP_DWNLD = 0x8000,/* JCOP downlad in progress */ + P61_STATE_SECURE_MODE = 0x100000, /* secure mode state*/ + P61_STATE_SPI_SVDD_SYNC_START = 0x0001, /*ESE_VDD Low req by SPI*/ + P61_STATE_SPI_SVDD_SYNC_END = 0x0002, /*ESE_VDD is Low by SPI*/ + P61_STATE_DWP_SVDD_SYNC_START = 0x0004, /*ESE_VDD Low req by Nfc*/ + P61_STATE_DWP_SVDD_SYNC_END = 0x0008 /*ESE_VDD is Low by Nfc*/ +}p61_access_state_t; + +typedef enum chip_type_pwr_scheme{ + PN67T_PWR_SCHEME = 0x01, + PN80T_LEGACY_PWR_SCHEME, + PN80T_EXT_PMU_SCHEME, +}chip_pwr_scheme_t; + +typedef enum jcop_dwnld_state{ + JCP_DWNLD_IDLE = P61_STATE_JCP_DWNLD, /* jcop dwnld is ongoing*/ + JCP_DWNLD_INIT=0x8010, /* jcop dwonload init state*/ + JCP_DWNLD_START=0x8020, /* download started */ + JCP_SPI_DWNLD_COMPLETE=0x8040, /* jcop download complete in spi interface*/ + JCP_DWP_DWNLD_COMPLETE=0x8080, /* jcop download complete */ +} jcop_dwnld_state_t; + +struct pn544_i2c_platform_data { + unsigned int irq_gpio; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ + unsigned int iso_rst_gpio; /* gpio used for ISO hard reset P73*/ +}; + +struct hw_type_info { + /* + * Response of get_version_cmd will be stored in data + * byte structure : + * byte 0-1 : Header + * byte 2 : Status + * byte 3 : Hardware Version + * byte 4 : ROM code + * byte 5 : 0x00 constant + * byte 6-7 : Protected data version + * byte 8-9 : Trim data version + * byte 10-11 : FW version + * byte 12-13 : CRC + * */ + char data[20]; + int len; +}; + +#define NEXUS5x 0 +#define HWINFO 0 +#if NEXUS5x +#undef ISO_RST +#else +#define ISO_RST +#endif + +struct pn544_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn544_device; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int irq_gpio; + unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ +#ifdef ISO_RST + unsigned int iso_rst_gpio; /* ISO-RST pin gpio*/ +#endif + struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ + p61_access_state_t p61_current_state; /* stores the current P61 state */ + bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ + bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + long nfc_service_pid; /*used to signal the nfc the nfc service */ + chip_pwr_scheme_t chip_pwr_scheme; + unsigned int secure_timer_cnt; + struct workqueue_struct *pSecureTimerCbWq; + struct work_struct wq_task; + /* This byte represents different flags used during eSE cold reset request from + * Driver to driver + * Bit value Status Remark + * b0 : 1 -> NFC_ON Driver Open should set the flag + * 0 NFC_OFF Driver release should reset this flag + * b1 : 1 -> FWDNLD If FWDNLD is going on. + * 0 Normal operation + * b2 : 1 --> Ven reset has been requested + * b3 : reserved bit + * b6, b5, b4 : + * 0 0 0 -> no request for ese_cold_reset + * 0 0 1 -> ese_cold_reset requested from NFC driver + * 0 1 0 -> ese_cold_reset requested from eSE driver + * 0 1 1 -> ese_cold_reset requested from UWB driver + * Remaining combinations: Reserved for future use. + * These bits will be cleared once cold reset rsp is received. + * b7 : 1 --> The ese_cold reset guard time has is running + * It will be cleared by the Guard Timer Callback + * */ + volatile uint8_t state_flags; +}; + +#endif From 8c5402967f65222a901c2d6130240019f32be8e9 Mon Sep 17 00:00:00 2001 From: nxf24591 Date: Fri, 7 Aug 2020 13:58:19 +0530 Subject: [PATCH 035/100] Updated corresponding to - NFC_AR_00_6000_11.04.00_OpnSrc --- pn553-i2c/cold_reset.c | 4 ++-- pn553-i2c/pn553.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pn553-i2c/cold_reset.c b/pn553-i2c/cold_reset.c index bc0b176731..9f1cc91981 100644 --- a/pn553-i2c/cold_reset.c +++ b/pn553-i2c/cold_reset.c @@ -145,7 +145,7 @@ void rcv_prop_resp_status(const char * const buf) static int send_nci_transceive(uint8_t *prop_cmd, size_t prop_cmd_size) { int ret = 0; unsigned int loop=0x03; - struct file filp; + struct file filp = {NULL}; int retry = 1; pr_info("%s: Enter", __func__); @@ -187,7 +187,7 @@ static int send_nci_transceive(uint8_t *prop_cmd, size_t prop_cmd_size) { ret = pn544_dev_read(&filp, NULL,3, 0); if(!ret) break; - usleep_range(2000, 3000); + usleep_range(3500, 4000); } } while((retry-- >= 0) && ret == -ERESTARTSYS); diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c index 0579655aab..af30db6b3e 100644 --- a/pn553-i2c/pn553.c +++ b/pn553-i2c/pn553.c @@ -79,7 +79,7 @@ #define DRAGON_NFC 1 #define SIG_NFC 44 -#define MAX_BUFFER_SIZE 512 +#define MAX_BUFFER_SIZE 554 #define MAX_SECURE_SESSIONS 1 /* This macro evaluates to 1 if the cold reset is requested by driver(SPI/UWB). */ From bedce836293caeba73093a007f2830a696e7bde8 Mon Sep 17 00:00:00 2001 From: nxf24591 Date: Fri, 20 Nov 2020 18:32:04 +0530 Subject: [PATCH 036/100] Updated corresponding to - NFC_AR_00_6000_11.06.00 --- nfc/Makefile | 6 + nfc/common.c | 447 +++++++ nfc/common.h | 211 +++ nfc/common_ese.c | 347 +++++ nfc/common_ese.h | 97 ++ nfc/i2c_drv.c | 467 +++++++ pn553-i2c/cold_reset.h => nfc/i2c_drv.h | 44 +- pn553-i2c/Kconfig | 13 - pn553-i2c/Makefile | 9 - pn553-i2c/cold_reset.c | 343 ----- pn553-i2c/pn553.c | 1611 ----------------------- pn553-i2c/pn553.h | 266 ---- 12 files changed, 1600 insertions(+), 2261 deletions(-) create mode 100644 nfc/Makefile create mode 100644 nfc/common.c create mode 100644 nfc/common.h create mode 100644 nfc/common_ese.c create mode 100644 nfc/common_ese.h create mode 100644 nfc/i2c_drv.c rename pn553-i2c/cold_reset.h => nfc/i2c_drv.h (51%) delete mode 100644 pn553-i2c/Kconfig delete mode 100644 pn553-i2c/Makefile delete mode 100644 pn553-i2c/cold_reset.c delete mode 100644 pn553-i2c/pn553.c delete mode 100644 pn553-i2c/pn553.h diff --git a/nfc/Makefile b/nfc/Makefile new file mode 100644 index 0000000000..52c28951e7 --- /dev/null +++ b/nfc/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for nfc devices +# +obj-$(CONFIG_NXP_NFC_I2C) += pn553_i2c.o +pn553_i2c-objs := common.o common_ese.o i2c_drv.o +#ccflags-y := -DDEBUG diff --git a/nfc/common.c b/nfc/common.c new file mode 100644 index 0000000000..ee6f64a39a --- /dev/null +++ b/nfc/common.c @@ -0,0 +1,447 @@ +/****************************************************************************** + * Copyright (C) 2019-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#include +#include +#include +#include +#include "common.h" +#include "common_ese.h" + +int nfc_parse_dt(struct device *dev, platform_gpio_t * nfc_gpio, + uint8_t interface) +{ + struct device_node *np = dev->of_node; + + if (!np) { + pr_err("nfc of_node NULL\n"); + return -EINVAL; + } + + nfc_gpio->irq = -EINVAL; + nfc_gpio->dwl_req = -EINVAL; + nfc_gpio->ven = -EINVAL; + + //required for i2c based chips only + if (interface == PLATFORM_IF_I2C) { + nfc_gpio->irq = of_get_named_gpio(np, DTS_IRQ_GPIO_STR, 0); + if ((!gpio_is_valid(nfc_gpio->irq))) { + pr_err("nfc irq gpio invalid %d\n", nfc_gpio->irq); + return -EINVAL; + } + pr_info("%s: irq %d\n", __func__, nfc_gpio->irq); + + nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); + if ((!gpio_is_valid(nfc_gpio->dwl_req))) { + pr_err("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req); + } + } + nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); + if ((!gpio_is_valid(nfc_gpio->ven))) { + pr_err("nfc ven gpio invalid %d\n", nfc_gpio->ven); + return -EINVAL; + } + + pr_info("%s: %d, %d, %d, %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven, + nfc_gpio->dwl_req); + return 0; +} + +void set_valid_gpio(int gpio, int value) +{ + if (gpio_is_valid(gpio)) { + pr_debug("%s gpio %d value %d\n", __func__, gpio, value); + gpio_set_value(gpio, value); + // hardware dependent delay + usleep_range(10000, 10100); + } +} + +int get_valid_gpio(int gpio) +{ + int value = -1; + if (gpio_is_valid(gpio)) { + value = gpio_get_value(gpio); + pr_debug("%s gpio %d value %d\n", __func__, gpio, value); + } + return value; +} + +void gpio_set_ven(struct nfc_dev *nfc_dev, int value) +{ + if (gpio_get_value(nfc_dev->gpio.ven) != value) { + pr_debug("%s: gpio_set_ven %d\n", __func__, value); + /*reset on change in level from high to low */ + if (value) { + common_ese_on_hard_reset(nfc_dev); + } + gpio_set_value(nfc_dev->gpio.ven, value); + // hardware dependent delay + usleep_range(10000, 10100); + } +} + +int configure_gpio(unsigned int gpio, int flag) +{ + int ret; + pr_debug("%s: nfc gpio [%d] flag [%01x]\n", __func__, gpio, flag); + if (gpio_is_valid(gpio)) { + ret = gpio_request(gpio, "nfc_gpio"); + if (ret) { + pr_err("%s: unable to request nfc gpio [%d]\n", __func__, gpio); + return ret; + } + /*set direction and value for output pin */ + if (flag & GPIO_OUTPUT) { + ret = gpio_direction_output(gpio, (GPIO_HIGH & flag)); + pr_debug("nfc o/p gpio %d level %d\n", gpio, gpio_get_value(gpio)); + } else { + ret = gpio_direction_input(gpio); + pr_debug("nfc i/p gpio %d\n", gpio); + } + + if (ret) { + pr_err("%s: unable to set direction for nfc gpio [%d]\n", __func__, gpio); + gpio_free(gpio); + return ret; + } + /*Consider value as control for input IRQ pin */ + if (flag & GPIO_IRQ) { + ret = gpio_to_irq(gpio); + if (ret < 0) { + pr_err("%s: unable to set irq for nfc gpio [%d]\n", __func__, gpio); + gpio_free(gpio); + return ret; + } + pr_debug("%s: gpio_to_irq successful [%d]\n", __func__, gpio); + return ret; + } + } else { + pr_err("%s: invalid gpio\n", __func__); + ret = -EINVAL; + } + return ret; +} + +void gpio_free_all(nfc_dev_t *nfc_dev) +{ + if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { + gpio_free(nfc_dev->gpio.dwl_req); + } + if (gpio_is_valid(nfc_dev->gpio.irq)) { + gpio_free(nfc_dev->gpio.irq); + } + if (gpio_is_valid(nfc_dev->gpio.ven)) { + gpio_free(nfc_dev->gpio.ven); + } +} + +void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count) +{ + pr_debug("%s: entry\n", __func__); + device_destroy(nfc_dev->nfc_class, nfc_dev->devno); + cdev_del(&nfc_dev->c_dev); + class_destroy(nfc_dev->nfc_class); + unregister_chrdev_region(nfc_dev->devno, count); +} + +int nfc_misc_register(nfc_dev_t *nfc_dev, + const struct file_operations *nfc_fops, + int count, char *devname, char *classname) +{ + int ret = 0; + ret = alloc_chrdev_region(&nfc_dev->devno, 0, count, devname); + if (ret < 0) { + pr_err("%s: failed to alloc chrdev region ret %d\n", __func__, ret); + return ret; + } + nfc_dev->nfc_class = class_create(THIS_MODULE, classname); + if (IS_ERR(nfc_dev->nfc_class)) { + ret = PTR_ERR(nfc_dev->nfc_class); + pr_err("%s: failed to register device class ret %d\n", __func__, ret); + unregister_chrdev_region(nfc_dev->devno, count); + return ret; + } + cdev_init(&nfc_dev->c_dev, nfc_fops); + ret = cdev_add(&nfc_dev->c_dev, nfc_dev->devno, count); + if (ret < 0) { + pr_err("%s: failed to add cdev ret %d\n", __func__, ret); + class_destroy(nfc_dev->nfc_class); + unregister_chrdev_region(nfc_dev->devno, count); + return ret; + } + nfc_dev->nfc_device = device_create(nfc_dev->nfc_class, NULL, + nfc_dev->devno, nfc_dev, devname); + if (IS_ERR(nfc_dev->nfc_device)) { + ret = PTR_ERR(nfc_dev->nfc_device); + pr_err("%s: failed to create the device ret %d\n", __func__, ret); + cdev_del(&nfc_dev->c_dev); + class_destroy(nfc_dev->nfc_class); + unregister_chrdev_region(nfc_dev->devno, count); + return ret; + } + return 0; +} + +/* + * nfc_ioctl_power_states() - power control + * @nfc_dev: nfc device data structure + * @arg: mode that we want to move to + * + * Device power control. Depending on the arg value, device moves to + * different states, refer common.h for args + * + * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case + */ +static int nfc_ioctl_power_states(nfc_dev_t *nfc_dev, unsigned long arg) +{ + int ret = 0; + if (arg == NFC_POWER_OFF) { + /* + * We are attempting a hardware reset so let us disable + * interrupts to avoid spurious notifications to upper + * layers. + */ + nfc_dev->nfc_disable_intr(nfc_dev); + set_valid_gpio(nfc_dev->gpio.dwl_req, 0); + gpio_set_ven(nfc_dev, 0); + nfc_dev->nfc_ven_enabled = false; + } else if (arg == NFC_POWER_ON) { + nfc_dev->nfc_enable_intr(nfc_dev); + set_valid_gpio(nfc_dev->gpio.dwl_req, 0); + + gpio_set_ven(nfc_dev, 1); + nfc_dev->nfc_ven_enabled = true; + } else if (arg == NFC_FW_DWL_VEN_TOGGLE) { + /* + * We are switching to download Mode, toggle the enable pin + * in order to set the NFCC in the new mode + */ + nfc_dev->nfc_disable_intr(nfc_dev); + set_valid_gpio(nfc_dev->gpio.dwl_req, 1); + if (nfc_dev->interface == PLATFORM_IF_I2C) { + nfc_dev->nfc_state = NFC_STATE_FW_DWL; + } + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + nfc_dev->nfc_enable_intr(nfc_dev); + } else if (arg == NFC_FW_DWL_HIGH) { + /* + * Setting firmware download gpio to HIGH + * before FW download start + */ + set_valid_gpio(nfc_dev->gpio.dwl_req, 1); + if (nfc_dev->interface == PLATFORM_IF_I2C) { + nfc_dev->nfc_state = NFC_STATE_FW_DWL; + } + + } else if (arg == NFC_VEN_FORCED_HARD_RESET) { + nfc_dev->nfc_disable_intr(nfc_dev); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + nfc_dev->nfc_enable_intr(nfc_dev); + } else if (arg == NFC_FW_DWL_LOW) { + /* + * Setting firmware download gpio to LOW + * FW download finished + */ + set_valid_gpio(nfc_dev->gpio.dwl_req, 0); + if (nfc_dev->interface == PLATFORM_IF_I2C) { + nfc_dev->nfc_state = NFC_STATE_NCI; + } + } else { + pr_err("%s bad arg %lu\n", __func__, arg); + ret = -ENOIOCTLCMD; + } + return ret; +} + +/** @brief IOCTL function to be used to set or get data from upper layer. + * + * @param pfile fil node for opened device. + * @cmd IOCTL type from upper layer. + * @arg IOCTL arg from upper layer. + * + * @return 0 on success, error code for failures. + */ +long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct nfc_dev *nfc_dev = pfile->private_data; + if (!nfc_dev) + return -ENODEV; + + pr_debug("%s cmd = %x arg = %zx\n", __func__, cmd, arg); + switch (cmd) { + case NFC_SET_PWR: + ret = nfc_ioctl_power_states(nfc_dev, arg); + break; + case ESE_SET_PWR: + ret = nfc_ese_pwr(nfc_dev, arg); + break; + case ESE_GET_PWR: + ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE); + break; + case NFC_GET_PLATFORM_TYPE: + ret = nfc_dev->interface; + break; + case NFC_GET_NFC_STATE: + ret = nfc_dev->nfc_state; + pr_debug("nfc get state %d\n", ret); + break; + case NFC_GET_IRQ_STATE: + ret = 0; + ret = gpio_get_value(nfc_dev->gpio.irq); + break; + default: + pr_err("%s bad cmd %lu\n", __func__, arg); + ret = -ENOIOCTLCMD; + }; + return ret; +} + +int nfc_dev_open(struct inode *inode, struct file *filp) +{ + nfc_dev_t *nfc_dev = container_of(inode->i_cdev, nfc_dev_t, c_dev); + pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); + + mutex_lock(&nfc_dev->dev_ref_mutex); + + filp->private_data = nfc_dev; + + if (nfc_dev->dev_ref_count == 0) { + set_valid_gpio(nfc_dev->gpio.dwl_req, 0); + + nfc_dev->nfc_enable_intr(nfc_dev); + } + nfc_dev->dev_ref_count = nfc_dev->dev_ref_count + 1; + mutex_unlock(&nfc_dev->dev_ref_mutex); + return 0; +} + +int nfc_dev_close(struct inode *inode, struct file *filp) +{ + nfc_dev_t *nfc_dev = container_of(inode->i_cdev, nfc_dev_t, c_dev); + pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); + mutex_lock(&nfc_dev->dev_ref_mutex); + if (nfc_dev->dev_ref_count == 1) { + nfc_dev->nfc_disable_intr(nfc_dev); + set_valid_gpio(nfc_dev->gpio.dwl_req, 0); + } + if (nfc_dev->dev_ref_count > 0) + nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; + else { + nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS_NFC); + /* Uncomment below line incase of eSE calls flow is via NFC driver + * i.e. direct calls from SPI HAL to NFC driver*/ + //nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS); + } + filp->private_data = NULL; + + mutex_unlock(&nfc_dev->dev_ref_mutex); + return 0; +} + +static int get_nfcc_boot_state(struct nfc_dev *nfc_dev) +{ + int ret = 0; + char get_version_cmd[] = { 0x00, 0x04, 0xF1, 0x00, 0x00, 0x00, 0x6E, 0xEF }; + char get_session_state_cmd[] = { 0x00, 0x04, 0xF2, 0x00, 0x00, 0x00, 0xF5, 0x33 }; + char rsp_buf[MAX_BUFFER_SIZE]; + /*clearing any data in the kbuf store */ + do { + ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, MAX_BUFFER_SIZE); + if (ret < 0) { + pr_err("%s: - nfc read ret %d\n", __func__, ret); + } + pr_info("%s: - nfc read ret %d\n", __func__, ret); + } while (ret > 0); + + pr_debug("%s:Sending GET_VERSION cmd\n", __func__); + ret = nfc_dev->nfc_write(nfc_dev, get_version_cmd, + sizeof(get_version_cmd), MAX_RETRY_COUNT); + if (ret <= 0) { + pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret); + goto err; + } + memset(rsp_buf, 0x00, MAX_BUFFER_SIZE); + pr_debug("%s:Reading response of GET_VERSION cmd\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, MAX_BUFFER_SIZE); + if (ret <= 0) { + pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret); + goto err; + } else if (rsp_buf[0] == 0x0 + && ret == (FW_HDR_LEN + rsp_buf[FW_PAYLOAD_LEN_IDX] + FW_CRC_LEN) + && (ret == DL_GET_VERSION_RSP_LEN_1 || ret == DL_GET_VERSION_RSP_LEN_2)) { + + pr_info("%s:NFC chip_type 0x%02x rom_version 0x%02x fw_minor 0x%02x fw_major 0x%02x\n", + __func__, rsp_buf[3], rsp_buf[4], rsp_buf[6], rsp_buf[7]); + } else if (rsp_buf[0] != 0x0 + && ret == (NCI_HDR_LEN + rsp_buf[NCI_PAYLOAD_LEN_IDX])) { + pr_info("%s:NFC response bytes 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, + rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[3]); + pr_debug("%s NFCC booted in NCI mode %d\n", __func__, __LINE__); + return NFC_STATE_NCI; + } + + pr_debug("%s:Sending GET_SESSION_STATE cmd \n", __func__); + ret = nfc_dev->nfc_write(nfc_dev, get_session_state_cmd, + sizeof(get_session_state_cmd), + MAX_RETRY_COUNT); + if (ret <= 0) { + pr_err("%s: - nfc get session state cmd err ret %d\n", __func__, ret); + goto err; + } + memset(rsp_buf, 0x00, DL_GET_SESSION_STATE_RSP_LEN); + pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_SESSION_STATE_RSP_LEN); + if (ret <= 0) { + pr_err("%s: - nfc get session state rsp err %d\n", __func__, ret); + goto err; + } + pr_debug("Response bytes are %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x", + rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5], + rsp_buf[6], rsp_buf[7]); + /*verify fw in non-teared state */ + if (rsp_buf[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) { + pr_debug("%s NFCC booted in teared fw state %d\n", __func__, __LINE__); + return NFC_STATE_FW_TEARED; + } + pr_debug("%s NFCC booted in FW DN mode %d\n", __func__, __LINE__); + return NFC_STATE_FW_DWL; +err: + pr_err("%s Unlikely NFCC not booted in FW DN mode %d\n", __func__, __LINE__); + return NFC_STATE_UNKNOWN; +} + +int validate_nfc_state_nci(nfc_dev_t *nfc_dev) +{ + if (!gpio_get_value(nfc_dev->gpio.ven)) { + pr_err("VEN LOW - NFCC powered off\n"); + return -ENODEV; + } else { + if (get_valid_gpio(nfc_dev->gpio.dwl_req) == 1) { + pr_err("FW download in-progress\n"); + return -EBUSY; + } else if (nfc_dev->nfc_state == NFC_STATE_FW_DWL) { + pr_err("FW download state \n"); + return -EBUSY; + } + } + return 0; +} diff --git a/nfc/common.h b/nfc/common.h new file mode 100644 index 0000000000..30bb468e1d --- /dev/null +++ b/nfc/common.h @@ -0,0 +1,211 @@ +/****************************************************************************** + * Copyright (C) 2019-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#ifndef _COMMON_H_ +#define _COMMON_H_ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c_drv.h" + +#define DEV_COUNT 1 /* Max device count for this driver */ +#define CLASS_NAME "nfc" /* i2c device class */ + +// NFC character device name, this will be in /dev/ +#define NFC_CHAR_DEV_NAME "pn553" + +// NCI packet details +#define NCI_MSG_CMD 0x20 +#define NCI_MSG_RSP 0x40 +#define NCI_HDR_LEN 3 +#define NCI_PAYLOAD_IDX 3 +#define NCI_PAYLOAD_LEN_IDX 2 + +// FW DNLD packet details +#define FW_HDR_LEN 2 +#define FW_PAYLOAD_LEN_IDX 1 +#define FW_CRC_LEN 2 +#define MIN_NFC_DL_FRAME_SIZE 3 + +#define NCI_RESET_CMD_LEN (4) +#define NCI_RESET_RSP_LEN (4) +#define NCI_RESET_NTF_LEN (13) + +#define DL_GET_VERSION_CMD_LEN (8) +#define DL_GET_VERSION_RSP_LEN_1 (12) +#define DL_GET_VERSION_RSP_LEN_2 (20) + +#define DL_RESET_CMD_LEN (8) +#define DL_GET_SESSION_STATE_CMD_LEN (8) +#define DL_GET_SESSION_STATE_RSP_LEN (8) +#define GET_SESSION_STS_OFF (3) +#define NFCC_SESSION_STS_CLOSED (0x0) +#define MAX_NCI_PAYLOAD_LEN (255) +#define MAX_BUFFER_SIZE (NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN) +#define MAX_DL_PAYLOAD_LEN (550) +#define MAX_DL_BUFFER_SIZE (FW_HDR_LEN + FW_CRC_LEN + MAX_DL_PAYLOAD_LEN) +// Maximum retry count for standby writes +#define MAX_RETRY_COUNT (3) +// Retry count for normal write +#define NO_RETRY (1) +#define MAX_IRQ_WAIT_TIME (90) +#define WAKEUP_SRC_TIMEOUT (2000) + +/*command response timeout*/ +#define NCI_CMD_RSP_TIMEOUT (2000) //2s + +#define NFC_MAGIC 0xE9 + +/*Ioctls*/ +// The type should be aligned with MW HAL definitions +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, long) +#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, long) +#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, long) +#define NFC_GET_PLATFORM_TYPE _IO(NFC_MAGIC, 0x04) +#define NFC_GET_NFC_STATE _IO(NFC_MAGIC, 0x05) +/* NFC HAL can call this ioctl to get the current IRQ state */ +#define NFC_GET_IRQ_STATE _IOW(NFC_MAGIC, 0x06, long) + +#define DTS_IRQ_GPIO_STR "nxp,pn544-irq" +#define DTS_VEN_GPIO_STR "nxp,pn544-ven" +#define DTS_FWDN_GPIO_STR "nxp,pn544-fw-dwnld" + +enum nfcc_ioctl_request { + /* NFC disable request with VEN LOW */ + NFC_POWER_OFF = 0, + /* NFC enable request with VEN Toggle */ + NFC_POWER_ON, + /* firmware download request with VEN Toggle */ + NFC_FW_DWL_VEN_TOGGLE, + /* ISO reset request */ + NFC_ISO_RESET, + /* request for firmware download gpio HIGH */ + NFC_FW_DWL_HIGH, + /* VEN hard reset request */ + NFC_VEN_FORCED_HARD_RESET, + /* request for firmware download gpio LOW */ + NFC_FW_DWL_LOW, +}; + +/*nfc platform interface type*/ +enum interface_flags { + /*I2C physical IF for NFCC */ + PLATFORM_IF_I2C = 0, +}; + +/*nfc state flags*/ +enum nfc_state_flags { + /*nfc in unknown state */ + NFC_STATE_UNKNOWN = 0, + /*nfc in download mode */ + NFC_STATE_FW_DWL = 0x1, + /*nfc booted in NCI mode */ + NFC_STATE_NCI = 0x2, + /*nfc booted in Fw teared mode */ + NFC_STATE_FW_TEARED = 0x4, +}; +/* + * Power state for IBI handing, mainly needed to defer the IBI handling + * for the IBI received in suspend state to do it later in resume call + */ +enum pm_state_flags { + PM_STATE_NORMAL = 0, + PM_STATE_SUSPEND, + PM_STATE_IBI_BEFORE_RESUME, +}; + +/* Enum for GPIO values*/ +enum gpio_values { + GPIO_INPUT = 0x0, + GPIO_OUTPUT = 0x1, + GPIO_HIGH = 0x2, + GPIO_OUTPUT_HIGH = 0x3, + GPIO_IRQ = 0x4, +}; + +// NFC GPIO variables +typedef struct platform_gpio { + unsigned int irq; + unsigned int ven; + unsigned int dwl_req; +} platform_gpio_t; + +//cold reset Features specific Parameters +typedef struct cold_reset { + bool rsp_pending; /*cmd rsp pending status */ + bool in_progress; /*for cold reset when gurad timer in progress */ + bool reset_protection; /*reset protection enabled/disabled */ + uint8_t status; /*status from response buffer */ + uint8_t rst_prot_src; /*reset protection source (SPI, NFC) */ + struct mutex sync_mutex; + struct timer_list timer; + wait_queue_head_t read_wq; +} cold_reset_t; + +/* Device specific structure */ +typedef struct nfc_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct mutex ese_access_mutex; + struct mutex dev_ref_mutex; + unsigned int dev_ref_count; + struct class *nfc_class; + struct device *nfc_device; + struct cdev c_dev; + dev_t devno; + /* Interface flag */ + uint8_t interface; + /* nfc state flags */ + uint8_t nfc_state; + /* NFC VEN pin state */ + bool nfc_ven_enabled; + union { + i2c_dev_t i2c_dev; + }; + platform_gpio_t gpio; + cold_reset_t cold_reset; + + /*funtion pointers for the common i2c functionality */ + int (*nfc_read) (struct nfc_dev *dev, char *buf, size_t count); + int (*nfc_write) (struct nfc_dev *dev, const char *buf, const size_t count, + int max_retry_cnt); + int (*nfc_enable_intr) (struct nfc_dev *dev); + int (*nfc_disable_intr) (struct nfc_dev *dev); + int (*nfc_flush_readq) (struct nfc_dev *dev); +} nfc_dev_t; + +int nfc_dev_open(struct inode *inode, struct file *filp); +int nfc_dev_close(struct inode *inode, struct file *filp); +long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); +int nfc_parse_dt(struct device *dev, platform_gpio_t *nfc_gpio, + uint8_t interface); +int nfc_misc_register(nfc_dev_t *nfc_dev, + const struct file_operations *nfc_fops, int count, char *devname, + char *classname); +void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count); +int configure_gpio(unsigned int gpio, int flag); +void gpio_set_ven(nfc_dev_t *nfc_dev, int value); +void gpio_free_all(nfc_dev_t *nfc_dev); +int validate_nfc_state_nci(nfc_dev_t *nfc_dev); +#endif //_COMMON_H_ diff --git a/nfc/common_ese.c b/nfc/common_ese.c new file mode 100644 index 0000000000..10ff475969 --- /dev/null +++ b/nfc/common_ese.c @@ -0,0 +1,347 @@ +/****************************************************************************** + * Copyright (C) 2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "common_ese.h" + +static void cold_reset_gaurd_timer_callback(struct timer_list *t) +{ + cold_reset_t *cold_reset = from_timer(cold_reset, t, timer); + pr_debug("%s: Enter\n", __func__); + cold_reset->in_progress = false; + return; +} + +static long start_cold_reset_guard_timer(cold_reset_t *cold_reset) +{ + long ret = -EINVAL; + if (timer_pending(&cold_reset->timer) == 1) { + pr_debug("ese_cold_reset_guard_timer: delete pending timer \n"); + /* delete timer if already pending */ + del_timer(&cold_reset->timer); + } + cold_reset->in_progress = true; + timer_setup(&cold_reset->timer, cold_reset_gaurd_timer_callback, 0); + ret = mod_timer(&cold_reset->timer, + jiffies + msecs_to_jiffies(ESE_CLD_RST_GUARD_TIME)); + return ret; +} + +static int send_cold_reset_protection_cmd(nfc_dev_t *nfc_dev, bool requestType) +{ + int ret = 0; + int length = 0; + uint8_t *cmd = NULL; + uint8_t cld_rst_cmd[] = { NCI_PROP_MSG_CMD, CLD_RST_OID, + CLD_RST_PAYLOAD_SIZE + }; + uint8_t rst_prot_cmd[] = { NCI_PROP_MSG_CMD, RST_PROT_OID, + RST_PROT_PAYLOAD_SIZE, 0x00 + }; + + cold_reset_t *cold_reset = &nfc_dev->cold_reset; + if (requestType) { + length = sizeof(rst_prot_cmd); + rst_prot_cmd[NCI_PAYLOAD_IDX] = (!cold_reset->reset_protection) ? 1 : 0; + cmd = rst_prot_cmd; + } else { + length = sizeof(cld_rst_cmd); + cmd = cld_rst_cmd; + } + + ret = nfc_dev->nfc_write(nfc_dev, cmd, length, MAX_RETRY_COUNT); + if (ret != length) { + pr_err("%s : nfc_write returned %d\n", __func__, ret); + return -EIO; + } + + if (requestType) { + pr_debug("%s: NxpNciX: %d > %02X%02X%02X%02X\n", __func__, ret, cmd[0], cmd[1], + cmd[2], cmd[3]); + } else { + pr_debug("%s: NxpNciX: %d > %02X%02X%02X\n", __func__, ret, cmd[0], cmd[1], + cmd[2]); + } + return ret; +} + +void wakeup_on_prop_rsp(nfc_dev_t *nfc_dev, uint8_t *buf) +{ + cold_reset_t *cold_reset = &nfc_dev->cold_reset; + cold_reset->status = -EIO; + + if ((NCI_HDR_LEN + buf[NCI_PAYLOAD_LEN_IDX]) != NCI_PROP_MSG_RSP_LEN) { + pr_err("%s: - invalid response for cold_reset/protection \n", __func__); + } else { + cold_reset->status = buf[NCI_PAYLOAD_IDX]; + } + pr_debug("%s NxpNciR : len = 4 > %02X%02X%02X%02X\n", __func__, buf[0], buf[1], + buf[2], buf[3]); + + cold_reset->rsp_pending = false; + wake_up_interruptible(&cold_reset->read_wq); +} + +static int validate_cold_reset_protection_request(cold_reset_t *cold_reset, + unsigned long arg) +{ + if (!cold_reset->reset_protection) { + if (IS_RST_PROT_EN_REQ(arg) && IS_SRC_VALID_PROT(arg)) { + pr_debug("%s:req - reset protection enable\n", __func__); + } else if (IS_CLD_RST_REQ(arg) && IS_SRC_VALID(arg)) { + pr_debug("%s:req - cold reset\n", __func__); + } else if (IS_RST_PROT_DIS_REQ(arg) && IS_SRC_VALID_PROT(arg)) { + pr_debug("%s:req - reset protection already disable\n", __func__); + return -EINVAL; + } else { + pr_err("%s:Operation not permitted \n", __func__); + return -EPERM; + } + } else { + if (IS_RST_PROT_DIS_REQ(arg) + && IS_SRC(arg, cold_reset->rst_prot_src)) { + pr_debug("%s:req - disable reset protection from same src\n", __func__); + } else if (IS_CLD_RST_REQ(arg) + && IS_SRC(arg, cold_reset->rst_prot_src)) { + pr_debug("%s:req - cold reset from same source\n", __func__); + } else if (IS_RST_PROT_EN_REQ(arg) + && IS_SRC(arg, cold_reset->rst_prot_src)) { + pr_debug("%s:request - enable reset protection from same source\n", __func__); + } else { + pr_err("%s: Operation not permitted \n", __func__); + return -EPERM; + } + } + return 0; +} + +static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg) +{ + int ret = 0; + struct file filp; + cold_reset_t *cold_reset = &nfc_dev->cold_reset; + bool nfc_dev_opened = false; + + /*check if NFCC not in the FW download or hard reset state */ + ret = validate_nfc_state_nci(nfc_dev); + if (ret < 0) { + pr_err("%s: invalid cmd", __func__); + return ret; + } + + /* check if NFC is enabled */ + mutex_lock(&nfc_dev->dev_ref_mutex); + nfc_dev_opened = (nfc_dev->dev_ref_count > 0) ? true : false; + mutex_unlock(&nfc_dev->dev_ref_mutex); + + mutex_lock(&cold_reset->sync_mutex); + /*check if NFCC not in the FW download or hard reset state */ + ret = validate_cold_reset_protection_request(cold_reset, arg); + if (ret < 0) { + pr_err("%s: invalid cmd", __func__); + goto err; + } + + /*check if cold reset already in progress */ + if (IS_CLD_RST_REQ(arg) && cold_reset->in_progress) { + pr_err("%s: cold reset already in progress", __func__); + ret = -EBUSY; + goto err; + } + /* set default value for status as failure */ + cold_reset->status = -EIO; + cold_reset->rsp_pending = true; + + /*enable interrupt before sending cmd, when devnode not opened by HAL */ + if (!nfc_dev_opened) + nfc_dev->nfc_enable_intr(nfc_dev); + + ret = send_cold_reset_protection_cmd(nfc_dev, IS_RST_PROT_REQ(arg)); + if (ret < 0) { + pr_err("failed to send cold reset/protection command\n"); + cold_reset->rsp_pending = false; + goto err; + } + ret = 0; + /*start the cold reset guard timer */ + if (IS_CLD_RST_REQ(arg)) { + /*Guard timer not needed when OSU over NFC*/ + if(!(cold_reset->reset_protection && IS_SRC_NFC(arg))) { + ret = start_cold_reset_guard_timer(cold_reset); + if (ret) { + pr_err("%s: Error in mod_timer\n", __func__); + goto err; + } + } + } + + do { + /* Read is pending from the HAL service which will complete the response */ + if (nfc_dev_opened) { + if (!wait_event_interruptible_timeout + (cold_reset->read_wq, + cold_reset->rsp_pending == false, + msecs_to_jiffies(NCI_CMD_RSP_TIMEOUT))) { + pr_err("%s:cold reset/protection response timeout\n", __func__); + ret = -EAGAIN; + } + } else { + /* Read data as NFC thread is not active */ + filp.private_data = nfc_dev; +#if IS_ENABLED(CONFIG_NXP_NFC_I2C) + if (nfc_dev->interface == PLATFORM_IF_I2C) { + filp.f_flags &= ~O_NONBLOCK; + ret = nfc_i2c_dev_read(&filp, NULL, 3, 0); + usleep_range(3500, 4000); + } +#endif //IS_ENABLED(CONFIG_NXP_NFC_I2C) + } + } while (ret == -ERESTARTSYS || ret == -EFAULT); + + if (ret == 0) { /* success case */ + ret = cold_reset->status; + if (IS_RST_PROT_REQ(arg)) { + cold_reset->reset_protection = IS_RST_PROT_EN_REQ(arg); + cold_reset->rst_prot_src = + IS_RST_PROT_EN_REQ(arg) ? GET_SRC(arg) : SRC_NONE; + /* wait for reboot guard timer */ + } else if (wait_event_interruptible_timeout + (cold_reset->read_wq, true, + msecs_to_jiffies(ESE_CLD_RST_REBOOT_GUARD_TIME)) == + 0) { + pr_info("%s: reboot guard timer timeout", __func__); + } + } +err: + mutex_unlock(&cold_reset->sync_mutex); + return ret; +} + +/* + * Power management of the eSE + * eSE and NFCC both are powered using VEN gpio, + * VEN HIGH - eSE and NFCC both are powered on + * VEN LOW - eSE and NFCC both are power down + */ +int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg) +{ + int ret = 0; + if (arg == ESE_POWER_ON) { + /** + * Let's store the NFC VEN pin state + * will check stored value in case of eSE power off request, + * to find out if NFC MW also sent request to set VEN HIGH + * VEN state will remain HIGH if NFC is enabled otherwise + * it will be set as LOW + */ + nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_dev->gpio.ven); + if (!nfc_dev->nfc_ven_enabled) { + pr_debug("eSE HAL service setting ven HIGH\n"); + gpio_set_ven(nfc_dev, 1); + } else { + pr_debug("ven already HIGH\n"); + } + } else if (arg == ESE_POWER_OFF) { + if (!nfc_dev->nfc_ven_enabled) { + pr_debug("NFC not enabled, disabling ven\n"); + gpio_set_ven(nfc_dev, 0); + } else { + pr_debug("keep ven high as NFC is enabled\n"); + } + } else if (arg == ESE_POWER_STATE) { + // eSE get power state + ret = gpio_get_value(nfc_dev->gpio.ven); + } else if (IS_CLD_RST_REQ(arg) || IS_RST_PROT_REQ(arg)) { + ret = perform_cold_reset_protection(nfc_dev, arg); + } else { + pr_err("%s bad arg %lu\n", __func__, arg); + ret = -ENOIOCTLCMD; + } + return ret; +} + +EXPORT_SYMBOL(nfc_ese_pwr); + +#define ESE_LEGACY_INTERFACE +#ifdef ESE_LEGACY_INTERFACE +static nfc_dev_t *nfc_dev_legacy = NULL; + +/****************************************************************************** + * perform_ese_cold_reset() - It shall be called by others driver(not nfc/ese) + * to perform cold reset only + * @arg: request of cold reset from other drivers should be ESE_CLD_RST_OTHER + * + * Returns:- 0 in case of sucess and negative values in case of failure + *****************************************************************************/ +int perform_ese_cold_reset(unsigned long arg) +{ + int ret = 0; + if (nfc_dev_legacy) { + if (IS_CLD_RST_REQ(arg) && IS_SRC_OTHER(arg)) { + ret = nfc_ese_pwr(nfc_dev_legacy, arg); + } else { + pr_err("%s : Operation not permitted \n", __func__); + return -EPERM; + } + } + pr_debug("%s:%d exit, status:%lu", __func__, arg, ret); + return ret; +} + +EXPORT_SYMBOL(perform_ese_cold_reset); +#endif //ESE_LEGACY_INTERFACE + +void common_ese_on_hard_reset(nfc_dev_t *nfc_dev) +{ + cold_reset_t *cold_reset = &nfc_dev->cold_reset; + cold_reset->rsp_pending = false; + cold_reset->in_progress = false; + if (timer_pending(&cold_reset->timer) == 1) { + del_timer(&cold_reset->timer); + } +} + +void common_ese_init(nfc_dev_t *nfc_dev) +{ + cold_reset_t *cold_reset = &nfc_dev->cold_reset; + cold_reset->reset_protection = false; + cold_reset->rst_prot_src = SRC_NONE; + init_waitqueue_head(&cold_reset->read_wq); + mutex_init(&cold_reset->sync_mutex); + common_ese_on_hard_reset(nfc_dev); +#ifdef ESE_LEGACY_INTERFACE + nfc_dev_legacy = nfc_dev; +#endif //ESE_LEGACY_INTERFACE +} + +void common_ese_exit(nfc_dev_t *nfc_dev) +{ + mutex_destroy(&nfc_dev->cold_reset.sync_mutex); +#ifdef ESE_LEGACY_INTERFACE + nfc_dev_legacy = NULL; +#endif //ESE_LEGACY_INTERFACE +} diff --git a/nfc/common_ese.h b/nfc/common_ese.h new file mode 100644 index 0000000000..61f6fe4e91 --- /dev/null +++ b/nfc/common_ese.h @@ -0,0 +1,97 @@ +/****************************************************************************** + * Copyright (C) 2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#ifndef _COMMON_ESE_H_ +#define _COMMON_ESE_H_ + +#include "common.h" + +/*nci prop msg 1st byte*/ +#define NCI_PROP_MSG_GID 0x0F +#define NCI_PROP_MSG_CMD (NCI_MSG_CMD | NCI_PROP_MSG_GID) +#define NCI_PROP_MSG_RSP (NCI_MSG_RSP | NCI_PROP_MSG_GID) + +/*nci prop msg 2nd byte*/ +#define CLD_RST_OID 0x1E +#define RST_PROT_OID 0x1F + +/*nci prop msg 3rd byte*/ +#define CLD_RST_PAYLOAD_SIZE 0x00 +#define RST_PROT_PAYLOAD_SIZE 0x01 + +/*nci prop msg response length*/ +#define NCI_PROP_MSG_RSP_LEN 0x04 + +/*cold reset guard time to allow back to back cold reset after some time*/ +#define ESE_CLD_RST_GUARD_TIME (3000) //3s +/*guard time to reboot after reset*/ +#define ESE_CLD_RST_REBOOT_GUARD_TIME (50) //50ms +/*sources of reset protection and cold reset*/ +typedef enum reset_source { + SRC_SPI = 0, + SRC_NFC = 0x10, + SRC_OTHER = 0x20, + SRC_NONE = 0x80, +} reset_source_t; + +enum ese_ioctl_request { + ESE_POWER_ON = 0, /* eSE POWER ON */ + ESE_POWER_OFF, /* eSE POWER OFF */ + ESE_POWER_STATE, /* eSE GET POWER STATE */ + + /*ese reset requests from eSE service/hal/driver */ + ESE_CLD_RST, /* eSE COLD RESET */ + ESE_RST_PROT_EN, /* eSE RESET PROTECTION ENABLE */ + ESE_RST_PROT_DIS, /* eSE RESET PROTECTION DISABLE */ + + /*similar ese reset requests from nfc service/hal/driver */ + ESE_CLD_RST_NFC = ESE_CLD_RST | SRC_NFC, + ESE_RST_PROT_EN_NFC = ESE_RST_PROT_EN | SRC_NFC, + ESE_RST_PROT_DIS_NFC = ESE_RST_PROT_DIS | SRC_NFC, + + /*similar ese reset requests from other service/hal/driver */ + ESE_CLD_RST_OTHER = ESE_CLD_RST | SRC_OTHER, +}; + +#define GET_SRC(arg) (arg & 0xF0) +#define IS_SRC(arg, src) (GET_SRC(arg) == src) +#define IS_SRC_SPI(arg) IS_SRC(arg, SRC_SPI) +#define IS_SRC_NFC(arg) IS_SRC(arg, SRC_NFC) +#define IS_SRC_OTHER(arg) IS_SRC(arg, SRC_OTHER) +#define IS_SRC_VALID(arg) (IS_SRC_SPI(arg) || IS_SRC_NFC(arg) || \ + IS_SRC_OTHER(arg)) +#define IS_SRC_VALID_PROT(arg) (IS_SRC_SPI(arg) || IS_SRC_NFC(arg)) + +#define IS_RST(arg, type) ((arg & 0xF) == type) +#define IS_CLD_RST_REQ(arg) IS_RST(arg, ESE_CLD_RST) +#define IS_RST_PROT_EN_REQ(arg) IS_RST(arg, ESE_RST_PROT_EN) +#define IS_RST_PROT_DIS_REQ(arg) IS_RST(arg, ESE_RST_PROT_DIS) +#define IS_RST_PROT_REQ(arg) (IS_RST_PROT_EN_REQ(arg) || IS_RST_PROT_DIS_REQ(arg)) +/* This macro evaluates to 1 if prop cmd response is received */ +#define IS_PROP_CMD_RSP(buf) \ + ((NCI_PROP_MSG_RSP == buf[0]) && ((CLD_RST_OID == buf[1]) || \ + (RST_PROT_OID == buf[1]))) + +void wakeup_on_prop_rsp(nfc_dev_t *nfc_dev, uint8_t *buf); +int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg); +void common_ese_on_hard_reset(nfc_dev_t *nfc_dev); +void common_ese_init(nfc_dev_t *nfc_dev); +void common_ese_exit(nfc_dev_t *nfc_dev); + +#endif /* _COMMON_ESE_H_ */ diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c new file mode 100644 index 0000000000..5f69aaabbd --- /dev/null +++ b/nfc/i2c_drv.c @@ -0,0 +1,467 @@ +/****************************************************************************** + * Copyright (C) 2013-2020 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "common_ese.h" +/** + * i2c_disable_irq() + * + * Check if interrupt is disabled or not + * and disable interrupt + * + * Return: int + */ +int i2c_disable_irq(struct nfc_dev *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->i2c_dev.irq_enabled_lock, flags); + if (dev->i2c_dev.irq_enabled) { + disable_irq_nosync(dev->i2c_dev.client->irq); + dev->i2c_dev.irq_enabled = false; + } + spin_unlock_irqrestore(&dev->i2c_dev.irq_enabled_lock, flags); + + return 0; +} + +/** + * i2c_enable_irq() + * + * Check if interrupt is enabled or not + * and enable interrupt + * + * Return: int + */ +int i2c_enable_irq(struct nfc_dev *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->i2c_dev.irq_enabled_lock, flags); + if (!dev->i2c_dev.irq_enabled) { + dev->i2c_dev.irq_enabled = true; + enable_irq(dev->i2c_dev.client->irq); + } + spin_unlock_irqrestore(&dev->i2c_dev.irq_enabled_lock, flags); + + return 0; +} + +static irqreturn_t i2c_irq_handler(int irq, void *dev_id) +{ + nfc_dev_t *nfc_dev = dev_id; + i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + if (device_may_wakeup(&i2c_dev->client->dev)) + pm_wakeup_event(&i2c_dev->client->dev, WAKEUP_SRC_TIMEOUT); + + i2c_disable_irq(nfc_dev); + wake_up(&nfc_dev->read_wq); + + return IRQ_HANDLED; +} + +int i2c_read(struct nfc_dev *dev, char *buf, size_t count) +{ + int ret; + pr_debug("%s : reading %zu bytes.\n", __func__, count); + /* Read data */ + ret = i2c_master_recv(dev->i2c_dev.client, buf, count); + if (ret <= 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + goto err; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + ret = -EIO; + } +err: + return ret; +} + +int i2c_write(struct nfc_dev *dev, const char *buf, size_t count, + int max_retry_cnt) +{ + int ret = -EINVAL; + int retry_cnt; + + pr_debug("%s : writing %zu bytes.\n", __func__, count); + + for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) { + ret = i2c_master_send(dev->i2c_dev.client, buf, count); + if (ret <= 0) { + pr_warn("%s: write failed, Maybe in Standby Mode - Retry(%d)\n", __func__, + retry_cnt); + usleep_range(1000, 1100); + } else if (ret == count) + break; + } + return ret; +} + +ssize_t nfc_i2c_dev_read(struct file * filp, char __user *buf, + size_t count, loff_t * offset) +{ + int ret; + char tmp[MAX_BUFFER_SIZE]; + nfc_dev_t *nfc_dev = filp->private_data; + i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + mutex_lock(&nfc_dev->read_mutex); + if (!gpio_get_value(nfc_dev->gpio.irq)) { + if (filp->f_flags & O_NONBLOCK) { + pr_err(":f_falg has O_NONBLOCK. EAGAIN\n"); + ret = -EAGAIN; + goto err; + } + while (1) { + ret = 0; + if (!i2c_dev->irq_enabled) { + i2c_dev->irq_enabled = true; + enable_irq(i2c_dev->client->irq); + } + if (!gpio_get_value(nfc_dev->gpio.irq)) { + ret = wait_event_interruptible(nfc_dev->read_wq, + !i2c_dev-> + irq_enabled); + + if (ret) { + pr_err("error wakeup of read wq\n"); + goto err; + } + } + i2c_disable_irq(nfc_dev); + + if (gpio_get_value(nfc_dev->gpio.irq)) + break; + if (!gpio_get_value(nfc_dev->gpio.ven)) { + pr_info("%s: releasing read\n", __func__); + ret = -EIO; + goto err; + } + pr_warn("%s: spurious interrupt detected\n", __func__); + } + } + + memset(tmp, 0x00, count); + /* Read data */ + ret = i2c_read(nfc_dev, tmp, count); + if (ret <= 0) { + pr_err("%s: i2c_read returned %d\n", __func__, ret); + goto err; + } + /* check if it's response of cold reset command + * NFC HAL process shouldn't receive this data as + * command was sent by driver + */ + if (nfc_dev->cold_reset.rsp_pending) { + if (IS_PROP_CMD_RSP(tmp)) { + /* Read data */ + ret = + i2c_read(nfc_dev, &tmp[NCI_PAYLOAD_IDX], + tmp[NCI_PAYLOAD_LEN_IDX]); + if (ret <= 0) { + pr_err("%s: failure to read prop cold reset/protection rsp header\n", __func__); + goto err; + } + wakeup_on_prop_rsp(nfc_dev, tmp); + mutex_unlock(&nfc_dev->read_mutex); + /* + * NFC process doesn't know about cold reset command + * being sent as it was initiated by eSE process + * we shouldn't return any data to NFC process + */ + return 0; + } + } + if (copy_to_user(buf, tmp, ret)) { + pr_warn("%s : failed to copy to user space\n", __func__); + ret = -EFAULT; + } + +err: + mutex_unlock(&nfc_dev->read_mutex); + return ret; +} + +ssize_t nfc_i2c_dev_write(struct file * filp, const char __user *buf, + size_t count, loff_t * offset) +{ + int ret; + char tmp[MAX_DL_BUFFER_SIZE]; + nfc_dev_t *nfc_dev = filp->private_data; + + if (count > MAX_DL_BUFFER_SIZE) + count = MAX_DL_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + ret = i2c_write(nfc_dev, tmp, count, NO_RETRY); + if (ret != count) { + pr_err("%s: failed to write %d\n", __func__, ret); + ret = -EIO; + } + + return ret; +} + +static const struct file_operations nfc_i2c_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = nfc_i2c_dev_read, + .write = nfc_i2c_dev_write, + .open = nfc_dev_open, + .release = nfc_dev_close, + .unlocked_ioctl = nfc_dev_ioctl, +}; + +int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + nfc_dev_t *nfc_dev = NULL; + i2c_dev_t *i2c_dev = NULL; + platform_gpio_t nfc_gpio; + pr_debug("%s: enter\n", __func__); + /*retrive details of gpios from dt */ + ret = nfc_parse_dt(&client->dev, &nfc_gpio, PLATFORM_IF_I2C); + if (ret) { + pr_err("%s : failed to parse dt\n", __func__); + goto err; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + ret = -ENODEV; + goto err; + } + nfc_dev = kzalloc(sizeof(nfc_dev_t), GFP_KERNEL); + if (nfc_dev == NULL) { + ret = -ENOMEM; + goto err; + } + nfc_dev->interface = PLATFORM_IF_I2C; + nfc_dev->nfc_state = NFC_STATE_NCI; + nfc_dev->i2c_dev.client = client; + i2c_dev = &nfc_dev->i2c_dev; + nfc_dev->nfc_read = i2c_read; + nfc_dev->nfc_write = i2c_write; + nfc_dev->nfc_enable_intr = i2c_enable_irq; + nfc_dev->nfc_disable_intr = i2c_disable_irq; + + ret = configure_gpio(nfc_gpio.ven, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc reset gpio [%d]\n", __func__, nfc_gpio.ven); + goto err; + } + ret = configure_gpio(nfc_gpio.irq, GPIO_IRQ); + if (ret <= 0) { + pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__, nfc_gpio.irq); + goto err; + } + client->irq = ret; + ret = configure_gpio(nfc_gpio.dwl_req, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc firm downl gpio [%d]\n", __func__, + nfc_gpio.dwl_req); + } + + /*copy the retrived gpio details from DT */ + memcpy(&nfc_dev->gpio, &nfc_gpio, sizeof(struct platform_gpio)); + + /* init mutex and queues */ + init_waitqueue_head(&nfc_dev->read_wq); + mutex_init(&nfc_dev->read_mutex); + mutex_init(&nfc_dev->dev_ref_mutex); + mutex_init(&nfc_dev->ese_access_mutex); + spin_lock_init(&i2c_dev->irq_enabled_lock); + common_ese_init(nfc_dev); + ret = nfc_misc_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT, + NFC_CHAR_DEV_NAME, CLASS_NAME); + if (ret) { + pr_err("%s: nfc_misc_register failed\n", __func__); + goto err_mutex_destroy; + } + /* interrupt initializations */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + i2c_dev->irq_enabled = true; + ret = request_irq(client->irq, i2c_irq_handler, + IRQF_TRIGGER_HIGH, client->name, nfc_dev); + if (ret) { + pr_err("%s: request_irq failed\n", __func__); + goto err_nfc_misc_unregister; + } + i2c_disable_irq(nfc_dev); + device_init_wakeup(&client->dev, true); + device_set_wakeup_capable(&client->dev, true); + i2c_set_clientdata(client, nfc_dev); + i2c_dev->irq_wake_up = false; + + //reset nfc + usleep_range(10000, 10100); + gpio_set_value(nfc_dev->gpio.ven, 1); + usleep_range(10000, 10100); + + pr_info("%s probing nfc i2c successfully", __func__); + return 0; +err_nfc_misc_unregister: + nfc_misc_unregister(nfc_dev, DEV_COUNT); +err_mutex_destroy: + mutex_destroy(&nfc_dev->dev_ref_mutex); + mutex_destroy(&nfc_dev->read_mutex); + mutex_destroy(&nfc_dev->ese_access_mutex); + mutex_destroy(&nfc_dev->cold_reset.sync_mutex); +err: + gpio_free_all(nfc_dev); + kfree(nfc_dev); + pr_err("%s: probing not successful, check hardware\n", __func__); + return ret; +} + +int nfc_i2c_dev_remove(struct i2c_client *client) +{ + int ret = 0; + nfc_dev_t *nfc_dev = NULL; + pr_info("%s: remove device\n", __func__); + nfc_dev = i2c_get_clientdata(client); + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + ret = -ENODEV; + return ret; + } + if (nfc_dev->dev_ref_count > 0) { + pr_err("%s: device already in use\n", __func__); + return -EBUSY; + } + device_init_wakeup(&client->dev, false); + free_irq(client->irq, nfc_dev); + nfc_misc_unregister(nfc_dev, DEV_COUNT); + mutex_destroy(&nfc_dev->read_mutex); + mutex_destroy(&nfc_dev->ese_access_mutex); + mutex_destroy(&nfc_dev->cold_reset.sync_mutex); + gpio_free_all(nfc_dev); + kfree(nfc_dev); + return ret; +} + +int nfc_i2c_dev_suspend(struct device *device) +{ + struct i2c_client *client = to_i2c_client(device); + nfc_dev_t *nfc_dev = i2c_get_clientdata(client); + i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + + if (device_may_wakeup(&client->dev) && i2c_dev->irq_enabled) { + if (!enable_irq_wake(client->irq)) + i2c_dev->irq_wake_up = true; + } + return 0; +} + +int nfc_i2c_dev_resume(struct device *device) +{ + struct i2c_client *client = to_i2c_client(device); + nfc_dev_t *nfc_dev = i2c_get_clientdata(client); + i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + + if (device_may_wakeup(&client->dev) && i2c_dev->irq_wake_up) { + if (!disable_irq_wake(client->irq)) + i2c_dev->irq_wake_up = false; + } + return 0; +} + +static const struct i2c_device_id nfc_i2c_dev_id[] = { + {NFC_I2C_DEV_ID, 0}, + {} +}; + +static const struct of_device_id nfc_i2c_dev_match_table[] = { + {.compatible = NFC_I2C_DRV_STR,}, + {} +}; + +static const struct dev_pm_ops nfc_i2c_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(nfc_i2c_dev_suspend, nfc_i2c_dev_resume) +}; + +static struct i2c_driver nfc_i2c_dev_driver = { + .id_table = nfc_i2c_dev_id, + .probe = nfc_i2c_dev_probe, + .remove = nfc_i2c_dev_remove, + .driver = { + .name = NFC_I2C_DRV_STR, + .pm = &nfc_i2c_dev_pm_ops, + .of_match_table = nfc_i2c_dev_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; + +MODULE_DEVICE_TABLE(of, nfc_i2c_dev_match_table); + +static int __init nfc_i2c_dev_init(void) +{ + int ret = 0; + pr_info("Loading NXP NFC I2C driver\n"); + ret = i2c_add_driver(&nfc_i2c_dev_driver); + if (ret != 0) + pr_err("NFC I2C add driver error ret %d\n", ret); + return ret; +} + +module_init(nfc_i2c_dev_init); + +static void __exit nfc_i2c_dev_exit(void) +{ + pr_info("Unloading NXP NFC I2C driver\n"); + i2c_del_driver(&nfc_i2c_dev_driver); +} + +module_exit(nfc_i2c_dev_exit); + +MODULE_DESCRIPTION("NXP NFC I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/pn553-i2c/cold_reset.h b/nfc/i2c_drv.h similarity index 51% rename from pn553-i2c/cold_reset.h rename to nfc/i2c_drv.h index 59ceb374e3..8b41d41dd2 100644 --- a/pn553-i2c/cold_reset.h +++ b/nfc/i2c_drv.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) 2020 NXP + * Copyright (C) 2019-2020 NXP * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,24 +16,30 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ -#ifndef _NFC_COMMON_H_ -#define _NFC_COMMON_H_ +#ifndef _I2C_DRV_H_ +#define _I2C_DRV_H_ +#include -#define MSG_NFCC_RSP 0x40 -#define MSG_PROP_GID 0x0F -#define ESE_CLD_RST_OID 0x1E -#define RST_PROTECTION_CMD_INDEX 0x03 +/*kept same as dts */ +#define NFC_I2C_DRV_STR "nxp,pn544" +#define NFC_I2C_DEV_ID "pn553" -#define RST_PROTECTION_OID 0x1F -#define RST_PROTECTION_ENABLED 0x08 +//Interface specific parameters +typedef struct i2c_dev { + struct i2c_client *client; + /*IRQ parameters */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + /* NFC_IRQ wake-up state */ + bool irq_wake_up; +} i2c_dev_t; -typedef enum ese_cold_reset_origin { - ESE_COLD_RESET_NOT_REQUESTED = 0x00, - ESE_COLD_RESET_SOURCE_NFC = 0x01, - ESE_COLD_RESET_SOURCE_SPI = 0x02, - ESE_COLD_RESET_SOURCE_UWB = 0x04, -}ese_cold_reset_origin_t; - -void ese_reset_resource_init(void); -void ese_reset_resource_destroy(void); -#endif /* _NFC_COMMON_H_ */ +long nfc_i2c_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); +int nfc_i2c_dev_probe(struct i2c_client *client, + const struct i2c_device_id *id); +int nfc_i2c_dev_remove(struct i2c_client *client); +int nfc_i2c_dev_suspend(struct device *device); +int nfc_i2c_dev_resume(struct device *device); +ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, size_t count, + loff_t * offset); +#endif //_I2C_DRV_H_ diff --git a/pn553-i2c/Kconfig b/pn553-i2c/Kconfig deleted file mode 100644 index 878e4a8169..0000000000 --- a/pn553-i2c/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# Nxp Nci protocol (I2C) devices -# - -config NFC_PN553_DEVICES - bool "Nxp pn553 NCI protocol driver (I2C) devices" - default y - ---help--- - You'll have to say Y if your computer contains an I2C device that - you want to use under Linux. - - You can say N here if you don't have any SPI connected to your computer. - diff --git a/pn553-i2c/Makefile b/pn553-i2c/Makefile deleted file mode 100644 index c5a3cd2a41..0000000000 --- a/pn553-i2c/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for nfc devices -# - -obj-$(CONFIG_NFC_PN553_DEVICES) += pn553.o -obj-$(CONFIG_NFC_PN553_DEVICES) += cold_reset.o - -ccflags-$(CONFIG_NFC_PN553_DEVICES) := -DDEBUG - diff --git a/pn553-i2c/cold_reset.c b/pn553-i2c/cold_reset.c deleted file mode 100644 index 9f1cc91981..0000000000 --- a/pn553-i2c/cold_reset.c +++ /dev/null @@ -1,343 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2020 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "cold_reset.h" -#include "pn553.h" - -/*ESE_COLD_RESET MACROS */ -#define MAX_BUFFER_SIZE 512 /* copied from pn553.c */ -#define MSG_NFCC_CMD 0x20 -#define NCI_PROP_RST_RSP_SIZE 0x04 - - -/* Evaluates to 1 If cold reset is in progress or the guard timer is still running */ -#define IS_COLD_RESET_REQ_IN_PROGRESS(flags) \ - (flags & (MASK_ESE_COLD_RESET | MASK_ESE_COLD_RESET_GUARD_TIMER)) - -#define IS_RESET_PROTECTION_ENABLED(flags) (flags & RST_PROTECTION_ENABLED) - -#define IS_COLD_RESET_ALLOWED(flags, src) (!IS_COLD_RESET_REQ_IN_PROGRESS(flags) \ - && (!IS_RESET_PROTECTION_ENABLED(flags) || src == ESE_COLD_RESET_SOURCE_SPI)) - -static struct pn544_dev *pn544_dev; -struct mutex ese_cold_reset_sync_mutex; -struct mutex nci_send_cmd_mutex; - -extern ssize_t pn544_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset); - -static int8_t prop_nci_rsp[NCI_PROP_RST_RSP_SIZE]; -static struct timer_list ese_cold_reset_timer; -static struct completion prop_cmd_resp_sema; -static struct completion ese_cold_reset_sema; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) -static void ese_cold_reset_gaurd_timer_callback(unsigned long data); -#else -static void ese_cold_reset_gaurd_timer_callback(struct timer_list *unused); -#endif -static long start_ese_cold_reset_guard_timer(void); - -extern struct pn544_dev * get_nfcc_dev_data(void); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) -static void ese_cold_reset_gaurd_timer_callback(unsigned long data) -{ - (void)data; -#else -static void ese_cold_reset_gaurd_timer_callback(struct timer_list *unused) -{ -#endif - pr_info("%s: Enter\n",__func__); - pn544_dev->state_flags &= ~MASK_ESE_COLD_RESET_GUARD_TIMER; - return; -} - -static long start_ese_cold_reset_guard_timer(void) -{ - long ret = -EINVAL; - printk( KERN_INFO "starting ese_cold_reset_timer \n"); - if(timer_pending(&ese_cold_reset_timer) == 1) - { - pr_info("ese_cold_reset_guard_timer: delete pending timer \n"); - /* delete timer if already pending */ - del_timer(&ese_cold_reset_timer); - } - pn544_dev->state_flags |= MASK_ESE_COLD_RESET_GUARD_TIMER; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) - init_timer(&ese_cold_reset_timer); - setup_timer( &ese_cold_reset_timer, ese_cold_reset_gaurd_timer_callback, 0 ); -#else - timer_setup(&ese_cold_reset_timer, ese_cold_reset_gaurd_timer_callback, 0); -#endif - ret = mod_timer(&ese_cold_reset_timer, jiffies + msecs_to_jiffies(ESE_COLD_RESET_GUARD_TIME)); - if (ret) - printk( KERN_INFO "%s: Error in mod_timer\n",__func__); - return ret; -} -void ese_reset_resource_init(void) { - mutex_init(&ese_cold_reset_sync_mutex); - mutex_init(&nci_send_cmd_mutex); -} -void ese_reset_resource_destroy(void) { - mutex_destroy(&ese_cold_reset_sync_mutex); - mutex_destroy(&nci_send_cmd_mutex); -} -void rcv_prop_resp_status(const char * const buf) -{ - int ret = -1; - char tmp[MAX_BUFFER_SIZE]; - size_t rcount = 0; - memset(&prop_nci_rsp, 0, sizeof(prop_nci_rsp)); - memcpy(prop_nci_rsp, buf, 3); - rcount = (size_t)prop_nci_rsp[2]; - - /* Read data: No need to wait for the interrupt */ - ret = i2c_master_recv(pn544_dev->client, tmp, rcount); - if(ret == rcount){ - prop_nci_rsp[3] = tmp[0]; - pr_info("%s NxpNciR : len = 4 > %02X%02X%02X%02X\n", __func__,prop_nci_rsp[0], - prop_nci_rsp[1],prop_nci_rsp[2],prop_nci_rsp[3]); - }else{ - pr_err("%s : Failed to receive payload of the cold_rst_cmd\n",__func__); - prop_nci_rsp[3] = -EIO; - } - if(pn544_dev->state_flags &(P544_FLAG_NFC_ON)){ - complete(&prop_cmd_resp_sema); - } -} - -/****************************************************************************** - * Function : send_nci_transceive - * - * Description : Common NCI command send utility function. - * - * Parameters : prop_cmd : Data to be sent to NFCC - * prop_cmd_size : Length of the data to be sent - * - * Returns : 0 (SUCCESS)/ (-1)otherwise - - *****************************************************************************/ -static int send_nci_transceive(uint8_t *prop_cmd, size_t prop_cmd_size) { - int ret = 0; - unsigned int loop=0x03; - struct file filp = {NULL}; - int retry = 1; - - pr_info("%s: Enter", __func__); - - filp.private_data = pn544_dev; - if(pn544_dev->state_flags & P544_FLAG_FW_DNLD) { - /* If FW DNLD, Operation is not permitted */ - pr_err("%s : Operation is not permitted during fwdnld\n", __func__); - return -ECANCELED; - } - mutex_lock(&nci_send_cmd_mutex); - init_completion(&prop_cmd_resp_sema); - /* write command to I2C line*/ - do { - ret = i2c_master_send(pn544_dev->client, prop_cmd, prop_cmd_size); - if (ret == prop_cmd_size) { - break; - } - usleep_range(5000, 6000); - } while(loop--); - if(!loop && (ret != prop_cmd_size)) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - mutex_unlock(&nci_send_cmd_mutex); - return -EREMOTEIO; - } - ret = 0x00; - - do { - if(pn544_dev->state_flags & P544_FLAG_NFC_ON)/* NFC_ON */ { - /* Read is pending from the NFC service which will complete the prop_cmd_resp_sema */ - if(wait_for_completion_timeout(&prop_cmd_resp_sema, - msecs_to_jiffies(NCI_CMD_RSP_TIMEOUT)) == 0){ - pr_err("%s: Timeout", __func__); - ret = prop_nci_rsp[3] = -EAGAIN; // Failure case - } - } else { /* NFC_OFF */ - /* call the pn544_dev_read() */ - filp.f_flags &= ~O_NONBLOCK; - ret = pn544_dev_read(&filp, NULL,3, 0); - if(!ret) - break; - usleep_range(3500, 4000); - } - } while((retry-- >= 0) && ret == -ERESTARTSYS); - - mutex_unlock(&nci_send_cmd_mutex); - if(0x00 == ret && prop_nci_rsp[3]) - ret = -1 * prop_nci_rsp[3]; - /* Return the status to the SPI/UWB Driver */ - pr_info("%s: exit, Status:%d", __func__, ret); - return ret; -} - -/****************************************************************************** - * Function : do_reset_protection - * - * Description : It shall be called by SPI driver to enable/disable reset - * protection - * - * Parameters : Enable(TRUE)/Disable(FALSE) - * - * Returns : - * 0 : OK < Success case > - * -EPERM(-1) : REJECTED < NFCC rejects the cold reset cmd> - * -3 : FAILED < NFCC responds to cold reset cmd> - * -EIO(-5) : SYNTAX_ERROR < NFCC cmd framing is wrong > - * -6 : SEMANTIC_ERROR < NFCC rsp to cold reset cmd > - * -9 : INAVLID_PARAM < NFCC rsp to cold reset cmd > - * -EAGAIN(-11) : < 1. mod_timer(): temp error during kernel alloc > - * < 2. No rsp received from NFCC for cold reset cmd > - * -ENOMEM(-12) : < mod_timer(): failed to allocate memory > - * -EINVAL(-22) : < 1. cold rst req is received from unknown source > - * < 2. mod_timer(): invalid arg is passed> - * -EREMOTEIO(-121): < Reset cmd write failure over I2C > - * -ECANCELED(-125): < FW DWNLD is going on so driver canceled operation > - * -ERESTARTSYS(-512): < Userspace process is restarted during read operation > - *****************************************************************************/ -int do_reset_protection(bool type) { - int ret = 0; - uint8_t prop_cmd[] = {0x2F, 0x1F, 0x01, 0x00}; - pn544_dev = get_nfcc_dev_data(); - - pr_info("%s: Enter cmd type: %d", __func__, type); - - prop_cmd[RST_PROTECTION_CMD_INDEX] = (type) ? 1 : 0; - - if(type ) { - pn544_dev->state_flags |= RST_PROTECTION_ENABLED; - } else { - if(!(pn544_dev->state_flags & RST_PROTECTION_ENABLED)) { - return ret; - } - } - pr_info("%s: NxpNciX: %d > %02X%02X%02X%02X \n", __func__, ret,prop_cmd[0], - prop_cmd[1],prop_cmd[2],prop_cmd[3]); - - ret = send_nci_transceive(prop_cmd, sizeof(prop_cmd)); - if(ret) { - pr_err("%s : send_nci_command returned %d\n", __func__, ret); - } - if(!type) { - pn544_dev->state_flags &= ~RST_PROTECTION_ENABLED; - } - pr_info("%s: exit, Status:%d state_flag : %x ", __func__, ret, - pn544_dev->state_flags); - return ret; -} -EXPORT_SYMBOL(do_reset_protection); - -/****************************************************************************** - * Function : ese_cold_reset - * - * Description : It shall be called by NFC/SPI/UWB driver to perform driver to - * to driver eSE cold reset. - * - * Parameters : src Source of the cold reset request - * - * Returns : - * 0 : OK < Success case > - * -EPERM(-1) : REJECTED < Guard timer running> - * -3 : FAILED < NFCC responds to cold reset cmd> - * -EIO(-5) : SYNTAX_ERROR < NFCC cmd framing is wrong > - * -6 : SEMANTIC_ERROR < NFCC rsp to cold reset cmd > - * -9 : INAVLID_PARAM < NFCC rsp to cold reset cmd > - * -EAGAIN(-11) : < 1. mod_timer(): temp error during kernel alloc > - * < 2. No rsp received from NFCC for cold reset cmd > - * -ENOMEM(-12) : < mod_timer(): failed to allocate memory > - * -EBUSY(-16) : < eSE busy, in updater mode> - * -EINVAL(-22) : < 1. cold rst req is received from unknown source > - * < 2. mod_timer(): invalid arg is passed> - * -EREMOTEIO(-121): < Reset cmd write failure over I2C > - * -ECANCELED(-125): < FW DWNLD is going on so driver canceled operation > - * -ERESTARTSYS(-512): < Userspace process is restarted during read operation > - *****************************************************************************/ -int ese_cold_reset(ese_cold_reset_origin_t src) -{ - int ret = 0; - uint8_t ese_cld_reset[] = {0x2F, 0x1E, 0x00}; - - pr_info("%s: Enter origin:%d", __func__, src); - - switch(src) { - case ESE_COLD_RESET_SOURCE_NFC: - case ESE_COLD_RESET_SOURCE_SPI: - case ESE_COLD_RESET_SOURCE_UWB: - break; - default: - pr_info("%s: Invalid argument", __func__); - return -EINVAL; - } - pn544_dev = get_nfcc_dev_data(); - mutex_lock(&ese_cold_reset_sync_mutex); - if(IS_COLD_RESET_ALLOWED(pn544_dev->state_flags, src)) { - ret = start_ese_cold_reset_guard_timer(); - if(ret) { - mutex_unlock(&ese_cold_reset_sync_mutex); - return ret; /* EAGAIN/EINVAL/ENOMEM*/ - } - pn544_dev->state_flags |= src << ESE_COLD_RESET_ORIGIN_FLAGS_POS; - init_completion(&ese_cold_reset_sema); - pr_info("%s: NxpNciX: %d > %02X%02X%02X \n", __func__, ret,ese_cld_reset[0], - ese_cld_reset[1],ese_cld_reset[2]); - ret = send_nci_transceive(ese_cld_reset, sizeof(ese_cld_reset)); - if(ret) { - pn544_dev->state_flags &= ~(MASK_ESE_COLD_RESET | MASK_ESE_COLD_RESET_GUARD_TIMER); - mutex_unlock(&ese_cold_reset_sync_mutex); - return ret; - } - /* wait for reboot guard timer*/ - if(!ret && wait_for_completion_timeout(&ese_cold_reset_sema, - msecs_to_jiffies(ESE_COLD_RESET_REBOOT_GUARD_TIME)) == 0){ - pr_info("%s: guard Timeout", __func__); - } - } else { - if(IS_RESET_PROTECTION_ENABLED(pn544_dev->state_flags)) { - pr_err("%s : Not allowed resource busy \n", __func__); - ret = -EBUSY; - } - else if(IS_COLD_RESET_REQ_IN_PROGRESS(pn544_dev->state_flags)) { - pr_err("%s : Operation not permitted \n", __func__); - ret = -EPERM; - } - else { - /*No Action required*/ - } - } - pn544_dev->state_flags &= ~(src << ESE_COLD_RESET_ORIGIN_FLAGS_POS); - mutex_unlock(&ese_cold_reset_sync_mutex); - - /* Return the status to the SPI/UWB Driver */ - pr_info("%s:%d exit, Status:%d", __func__, src, ret); - return ret; -} - -EXPORT_SYMBOL(ese_cold_reset); diff --git a/pn553-i2c/pn553.c b/pn553-i2c/pn553.c deleted file mode 100644 index af30db6b3e..0000000000 --- a/pn553-i2c/pn553.c +++ /dev/null @@ -1,1611 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -/****************************************************************************** - * - * The original Work has been changed by NXP Semiconductors. - * - * Copyright (C) 2013-2020 NXP Semiconductors - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* HiKey Compilation fix */ -#define HiKey_620_COMPILATION_FIX 1 -#ifndef HiKey_620_COMPILATION_FIX -#include -#endif - -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) -#include -#include -#endif - -#include -#include "pn553.h" -#include "cold_reset.h" - -#define DRAGON_NFC 1 -#define SIG_NFC 44 -#define MAX_BUFFER_SIZE 554 -#define MAX_SECURE_SESSIONS 1 - -/* This macro evaluates to 1 if the cold reset is requested by driver(SPI/UWB). */ -#define IS_PROP_CMD_REQUESTED(flags) (flags & (MASK_ESE_COLD_RESET | RST_PROTECTION_ENABLED)) -/* This macro evaluates to 1 if eSE cold reset response is received */ -#define IS_PROP_RSP(buf) \ - (((MSG_NFCC_RSP | MSG_PROP_GID) == buf[0]) && ((ESE_CLD_RST_OID == buf[1]) || \ - (RST_PROTECTION_OID == buf[1]) )) - -/* VEN is kept ON all the time if you define the macro VEN_ALWAYS_ON. -Used for SN100 usecases */ -#define VEN_ALWAYS_ON -/* Macro added to disable SVDD power toggling */ -/* #define JCOP_4X_VALIDATION */ - - -/* HiKey Compilation fix */ -#ifndef HiKey_620_COMPILATION_FIX -struct wake_lock nfc_wake_lock; -#if HWINFO -struct hw_type_info hw_info; -#endif -static bool sIsWakeLocked = false; -#endif -static struct pn544_dev *pn544_dev; -static struct semaphore ese_access_sema; -static struct semaphore svdd_sync_onoff_sema; -static struct completion dwp_onoff_sema; -static struct timer_list secure_timer; -static void release_ese_lock(p61_access_state_t p61_current_state); -int get_ese_lock(p61_access_state_t p61_current_state, int timeout); -static long set_jcop_download_state(unsigned long arg); -static long start_seccure_timer(unsigned long timer_value); -static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg); -extern void rcv_prop_resp_status(const char * const buf); -extern long ese_cold_reset(ese_cold_reset_origin_t src); -extern void ese_reset_resource_init(void); -extern void ese_reset_resource_destroy(void); -#if HWINFO -static void check_hw_info(void); -#endif -#define SECURE_TIMER_WORK_QUEUE "SecTimerCbWq" - -struct pn544_dev * get_nfcc_dev_data(void) { - return pn544_dev; -} -static void pn544_disable_irq(struct pn544_dev *pn544_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); - if (pn544_dev->irq_enabled) { - disable_irq_nosync(pn544_dev->client->irq); - disable_irq_wake(pn544_dev->client->irq); - pn544_dev->irq_enabled = false; - } - spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); -} - -static int pn544_dev_release(struct inode *inode, struct file *filp) { - pn544_dev->state_flags &= ~(P544_FLAG_NFC_VEN_RESET|P544_FLAG_NFC_ON|P544_FLAG_FW_DNLD); - if (pn544_dev->firm_gpio) - gpio_set_value(pn544_dev->firm_gpio, 0); - pr_info(KERN_ALERT "Exit %s: NFC driver release nfc hal \n", __func__); - return 0; -} -static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) -{ - struct pn544_dev *pn544_dev = dev_id; - - pn544_disable_irq(pn544_dev); - /* HiKey Compilation fix */ - #ifndef HiKey_620_COMPILATION_FIX - if (sIsWakeLocked == false) - { - wake_lock(&nfc_wake_lock); - sIsWakeLocked = true; - } else { - pr_debug("%s already wake locked!\n", __func__); - } - #endif - /* Wake up waiting readers */ - wake_up(&pn544_dev->read_wq); - - - return IRQ_HANDLED; -} - -ssize_t pn544_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev = filp->private_data; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - //pr_debug("%s : reading %zu bytes.\n", __func__, count); - - mutex_lock(&pn544_dev->read_mutex); - - if (!gpio_get_value(pn544_dev->irq_gpio)) { - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto fail; - } - - while (1) { - pn544_dev->irq_enabled = true; - enable_irq(pn544_dev->client->irq); - enable_irq_wake(pn544_dev->client->irq); - ret = wait_event_interruptible( - pn544_dev->read_wq, - !pn544_dev->irq_enabled); - - pn544_disable_irq(pn544_dev); - - if (ret) - goto fail; - if(pn544_dev->state_flags & P544_FLAG_NFC_VEN_RESET) { - pr_warning("%s: releasing read \n", __func__); - pn544_dev->state_flags &= ~P544_FLAG_NFC_VEN_RESET; - ret = -EL3RST; - goto fail; - } - if (gpio_get_value(pn544_dev->irq_gpio)) - break; - - pr_warning("%s: spurious interrupt detected\n", __func__); - } - } - - /* Read data */ - ret = i2c_master_recv(pn544_dev->client, tmp, count); - #ifndef HiKey_620_COMPILATION_FIX - /* HiKey Compilation fix */ - if (sIsWakeLocked == true) { - wake_unlock(&nfc_wake_lock); - sIsWakeLocked = false; - } - #endif - - - /* If ese cold reset has been requested then read the response */ - if(IS_PROP_CMD_REQUESTED(pn544_dev->state_flags) && IS_PROP_RSP(tmp)) { - rcv_prop_resp_status(tmp); - /* Request is from driver, consume the response */ - mutex_unlock(&pn544_dev->read_mutex); - return 0; - } - mutex_unlock(&pn544_dev->read_mutex); - - /* pn544 seems to be slow in handling I2C read requests - * so add 1ms delay after recv operation */ -#if !NEXUS5x - udelay(1000); -#endif - - if (ret < 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - return ret; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - return -EIO; - } - if (copy_to_user(buf, tmp, ret)) { - pr_warning("%s : failed to copy to user space\n", __func__); - return -EFAULT; - } - return ret; - - fail: - mutex_unlock(&pn544_dev->read_mutex); - return ret; -} - -static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_dev *pn544_dev; - char tmp[MAX_BUFFER_SIZE]; - int ret; - - pn544_dev = filp->private_data; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - if (copy_from_user(tmp, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - return -EFAULT; - } - - //pr_debug("%s : writing %zu bytes.\n", __func__, count); - /* Write data */ - ret = i2c_master_send(pn544_dev->client, tmp, count); - if (ret != count) { - pr_err("%s : i2c_master_send returned %d\n", __func__, ret); - ret = -EIO; - } - /* pn544 seems to be slow in handling I2C write requests - * so add 1ms delay after I2C send oparation */ - udelay(1000); - - return ret; -} - -static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) -{ - pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); - if (current_state) - { - if(set){ - if(pn544_dev->p61_current_state == P61_STATE_IDLE) - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->p61_current_state |= current_state; - } - else{ - pn544_dev->p61_current_state ^= current_state; - if(!pn544_dev->p61_current_state) - pn544_dev->p61_current_state = P61_STATE_IDLE; - } - } - pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); -} - -static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) -{ - - if (current_state == NULL) { - //*current_state = P61_STATE_INVALID; - pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); - } else { - *current_state = pn544_dev->p61_current_state; - } -} -static void p61_access_lock(struct pn544_dev *pn544_dev) -{ - mutex_lock(&pn544_dev->p61_state_mutex); -} -static void p61_access_unlock(struct pn544_dev *pn544_dev) -{ - mutex_unlock(&pn544_dev->p61_state_mutex); -} - -static int signal_handler(p61_access_state_t state, long nfc_pid) -{ - struct siginfo sinfo; - pid_t pid; - struct task_struct *task; - int sigret = 0, ret = 0; - pr_info("%s: Enter\n", __func__); - - if(nfc_pid == 0) - { - pr_info("nfc_pid is clear don't call signal_handler.\n"); - } - else - { - memset(&sinfo, 0, sizeof(struct siginfo)); - sinfo.si_signo = SIG_NFC; - sinfo.si_code = SI_QUEUE; - sinfo.si_int = state; - pid = nfc_pid; - - task = pid_task(find_vpid(pid), PIDTYPE_PID); - if(task) - { - pr_info("%s.\n", task->comm); - sigret = force_sig_info(SIG_NFC, &sinfo, task); - if(sigret < 0){ - pr_info("send_sig_info failed..... sigret %d.\n", sigret); - ret = -1; - //msleep(60); - } - } - else{ - pr_info("finding task from PID failed\r\n"); - ret = -1; - } - } - pr_info("%s: Exit ret = %d\n", __func__, ret); - return ret; -} -static void svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) -{ - int timeout = 100; //100 ms timeout - unsigned long tempJ = msecs_to_jiffies(timeout); - pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); - if(nfc_service_pid) - { - if (0 == signal_handler(origin, nfc_service_pid)) - { - sema_init(&svdd_sync_onoff_sema, 0); - pr_info("Waiting for svdd protection response"); - if(down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) - { - pr_info("svdd wait protection: Timeout"); - } - pr_info("svdd wait protection : released"); - } - } -} -static int release_svdd_wait(void) -{ - pr_info("%s: Enter \n", __func__); - up(&svdd_sync_onoff_sema); - return 0; -} - -static void dwp_OnOff(long nfc_service_pid, p61_access_state_t origin) -{ - int timeout = 100; //100 ms timeout - unsigned long tempJ = msecs_to_jiffies(timeout); - if(nfc_service_pid) - { - if (0 == signal_handler(origin, nfc_service_pid)) - { - init_completion(&dwp_onoff_sema); - if(wait_for_completion_timeout(&dwp_onoff_sema, tempJ) != 0) - { - pr_info("Dwp On/off wait protection: Timeout"); - } - pr_info("Dwp On/Off wait protection : released"); - } - } -} -static int release_dwpOnOff_wait(void) -{ - pr_info("%s: Enter \n", __func__); - complete(&dwp_onoff_sema); - return 0; -} - -static int pn544_dev_open(struct inode *inode, struct file *filp) -{ - struct pn544_dev *pn544_dev = container_of(filp->private_data, - struct pn544_dev, - pn544_device); - - filp->private_data = pn544_dev; - pn544_dev->state_flags |= (P544_FLAG_NFC_ON); - pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); - - return 0; -} - -static int set_nfc_pid(unsigned long arg) -{ - pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); - pn544_dev->nfc_service_pid = arg; - return 0; -} - -long pn544_dev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - /* Free pass autobahn area, not protected. Use it carefullly. START */ - switch(cmd) - { - case P544_GET_ESE_ACCESS: - return get_ese_lock(P61_STATE_WIRED, arg); - break; - case P544_REL_SVDD_WAIT: - return release_svdd_wait(); - break; - case P544_SET_NFC_SERVICE_PID: - return set_nfc_pid(arg); - break; - case P544_REL_DWPONOFF_WAIT: - return release_dwpOnOff_wait(); - break; - default: - break; - } - /* Free pass autobahn area, not protected. Use it carefullly. END */ - - p61_access_lock(pn544_dev); - switch (cmd) { - case PN544_SET_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 2) { - if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) - { - /* NFCC fw/download should not be allowed if p61 is used - * by SPI - */ - pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - pn544_dev->nfc_ven_enabled = true; - if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) - || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) - { - /* power on with firmware download (requires hw reset) - */ - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - pn544_dev->state_flags |= (P544_FLAG_FW_DNLD); - } - - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - } else if (arg == 1) { - /* power on */ - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - if(current_state & P61_STATE_DWNLD){ - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, false); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - pn544_dev->state_flags &= ~(P544_FLAG_FW_DNLD); - } - - pn544_dev->nfc_ven_enabled = true; - #ifndef VEN_ALWAYS_ON - if (pn544_dev->spi_ven_enabled == false || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { - gpio_set_value(pn544_dev->ven_gpio, 1); - } - #endif - } else if (arg == 0) { - /* power off */ - if (pn544_dev->firm_gpio) { - if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ - p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); - } - gpio_set_value(pn544_dev->firm_gpio, 0); - } - - pn544_dev->nfc_ven_enabled = false; - /* Don't change Ven state if spi made it high */ - #ifndef VEN_ALWAYS_ON - if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) - || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - } - #endif - /* HiKey Compilation fix */ - #ifndef HiKey_620_COMPILATION_FIX - if (sIsWakeLocked == true) { - wake_unlock(&nfc_wake_lock); - sIsWakeLocked = false; - } - #endif - } else if (arg == 3) { - /*NFC Service called ISO-RST*/ - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - if(current_state & P61_STATE_WIRED) { - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - } -#ifdef ISO_RST - gpio_set_value(pn544_dev->iso_rst_gpio, 0); - msleep(50); - gpio_set_value(pn544_dev->iso_rst_gpio, 1); - msleep(50); - pr_info("%s ISO RESET from DWP DONE\n", __func__); -#endif - } else if (arg == 4) { - pr_info("%s FW dwldioctl called from NFC \n", __func__); - /*NFC Service called FW dwnld*/ - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - pn544_dev->state_flags |= (P544_FLAG_FW_DNLD); - msleep(10); - } - } else if (arg == 5) { - pn544_dev->state_flags |= P544_FLAG_NFC_VEN_RESET; - pn544_disable_irq(pn544_dev); - wake_up(&pn544_dev->read_wq); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - pr_info("%s VEN reset DONE >>>>>>>\n", __func__); - } else if (arg == 6) { - if (pn544_dev->firm_gpio) { - gpio_set_value(pn544_dev->firm_gpio, 0); - pn544_dev->state_flags &= ~(P544_FLAG_FW_DNLD); - } - pr_info("%s FW GPIO set to 0x00 >>>>>>>\n", __func__); - }else { - pr_err("%s bad arg %lu\n", __func__, arg); - /* changed the p61 state to idle*/ - p61_access_unlock(pn544_dev); - return -EINVAL; - } - } - break; - case P61_SET_SPI_PWR: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) { - pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); - if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - /*To handle triple mode protection signal - NFC service when SPI session started*/ - if (!(current_state & P61_STATE_JCP_DWNLD)){ - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - /*signal_handler(P61_STATE_SPI, pn544_dev->nfc_service_pid);*/ - dwp_OnOff(pn544_dev->nfc_service_pid, P61_STATE_SPI); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - pn544_dev->spi_ven_enabled = true; - - if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) - break; - #ifndef VEN_ALWAYS_ON - if (pn544_dev->nfc_ven_enabled == false) - { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - #endif - /* pull the gpio to high once NFCC is power on*/ - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - - /* Delay (10ms) after SVDD_PWR_ON to allow JCOP to bootup (5ms jcop boot time + 5ms guard time) */ - usleep_range(10000, 12000); - - } else { - pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); - if(current_state & P61_STATE_SPI_PRIO){ - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - if (!(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - if(!(current_state & P61_STATE_WIRED)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | - P61_STATE_SPI_PRIO_END); - }else { - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } else if (!(current_state & P61_STATE_WIRED)) { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - pn544_dev->spi_ven_enabled = false; - - if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) - break; - - /* if secure timer is running, Delay the SPI close by 25ms after sending End of Apdu to enable eSE go into DPD - gracefully (20ms after EOS + 5ms DPD settlement time) */ - if(pn544_dev->secure_timer_cnt) - usleep_range(25000, 30000); - - if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) - { -#ifndef JCOP_4X_VALIDATION - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ - usleep_range(2500, 3000); -#endif - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } -#ifndef JCOP_4X_VALIDATION - #ifndef VEN_ALWAYS_ON - if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } - #endif -#endif - }else if(current_state & P61_STATE_SPI){ - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - if (!(current_state & P61_STATE_WIRED) && - (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) && - !(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - /* if secure timer is running, Delay the SPI close by 25ms after sending End of Apdu to enable eSE go into DPD - gracefully (20ms after EOS + 5ms DPD settlement time) */ - if(pn544_dev->secure_timer_cnt) - usleep_range(25000, 30000); - - if (!(pn544_dev->secure_timer_cnt)) { -#ifndef JCOP_4X_VALIDATION - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ - usleep_range(2500, 3000); -#endif - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } - /*If JCOP3.2 or 3.3 for handling triple mode - protection signal NFC service */ - else - { - if (!(current_state & P61_STATE_JCP_DWNLD)) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); - } else { - signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); - } - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } else if (pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - } - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { -#ifndef JCOP_4X_VALIDATION - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); -#endif - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); - } - } - pn544_dev->spi_ven_enabled = false; -#ifndef VEN_ALWAYS_ON - if (pn544_dev->nfc_ven_enabled == false && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) - && !(pn544_dev->secure_timer_cnt)) { - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - } -#endif - } else { - pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - }else if (arg == 2) { - pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); - if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { - if (pn544_dev->spi_ven_enabled == false) - { - pn544_dev->spi_ven_enabled = true; - #ifndef VEN_ALWAYS_ON - if ((pn544_dev->nfc_ven_enabled == false) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) { - /* provide power to NFCC if, NFC service not provided */ - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - } - #endif - } - if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); -#ifndef JCOP_4X_VALIDATION - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); -#endif - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - msleep(10); - if(!gpio_get_value(pn544_dev->ese_pwr_gpio)) - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - msleep(10); - } - } else { - pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - }else if (arg == 3) { - int ret = ese_cold_reset(ESE_COLD_RESET_SOURCE_NFC); - p61_access_unlock(pn544_dev); - return ret; - }else if (arg == 4) { - if (current_state & P61_STATE_SPI_PRIO) - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - /*after SPI prio timeout, the state is changing from SPI prio to SPI */ - p61_update_access_state(pn544_dev, P61_STATE_SPI, true); - if (current_state & P61_STATE_WIRED) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - } - else - { - pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Device or resource busy */ - } - } else if(arg == 5){ - release_ese_lock(P61_STATE_SPI); - } else if (arg == 6) { - /*SPI Service called ISO-RST*/ - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if(current_state & P61_STATE_WIRED) { - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - if(current_state & P61_STATE_SPI) { - p61_update_access_state(pn544_dev, P61_STATE_SPI, false); - }else if(current_state & P61_STATE_SPI_PRIO) { - p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); - } -#ifdef ISO_RST - gpio_set_value(pn544_dev->iso_rst_gpio, 0); - msleep(50); - gpio_set_value(pn544_dev->iso_rst_gpio, 1); - msleep(50); - pr_info("%s ISO RESET from SPI DONE\n", __func__); -#endif - } - else { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - - case P61_GET_PWR_STATUS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); - put_user(current_state, (int __user *)arg); - } - break; - - case PN544_SET_DWNLD_STATUS: - { - long ret; - ret = set_jcop_download_state(arg); - if(ret < 0) - { - p61_access_unlock(pn544_dev); - return ret; - } - } - break; - - case P61_SET_WIRED_ACCESS: - { - p61_access_state_t current_state = P61_STATE_INVALID; - p61_get_access_state(pn544_dev, ¤t_state); - if (arg == 1) - { - if (current_state) - { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); - p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); - if (current_state & P61_STATE_SPI_PRIO) - { - if(pn544_dev->nfc_service_pid){ - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); - } - else{ - pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); - } - } - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } else { - pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); - p61_access_unlock(pn544_dev); - return -EBUSY; /* Device or resource busy */ - } - } else if (arg == 0) { - pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); - if (current_state & P61_STATE_WIRED){ - p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } else { - pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", - __func__, pn544_dev->p61_current_state); - p61_access_unlock(pn544_dev); - return -EPERM; /* Operation not permitted */ - } - } - else if(arg == 2) - { - pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); - if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) - { - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); - } - } - else if(arg == 3) - { - pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); - if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) - gpio_set_value(pn544_dev->ese_pwr_gpio, 1); - } - else if(arg == 4) - { - release_ese_lock(P61_STATE_WIRED); - } - else { - pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - } - break; - case P544_SET_POWER_SCHEME: - { - if(arg == PN67T_PWR_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; - pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); - } - else if(arg == PN80T_LEGACY_PWR_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; - pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); - } - else if(arg == PN80T_EXT_PMU_SCHEME) - { - pn544_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; - pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); - } - else - { - pr_info("%s : The power scheme is invalid,\n", __func__); - } - } - break; - case P544_SECURE_TIMER_SESSION: - { - secure_timer_operation(pn544_dev, arg); - } - break; - default: - pr_err("%s bad ioctl %u\n", __func__, cmd); - p61_access_unlock(pn544_dev); - return -EINVAL; - } - p61_access_unlock(pn544_dev); - return 0; -} -EXPORT_SYMBOL(pn544_dev_ioctl); - -static void secure_timer_workqueue(struct work_struct *Wq) -{ - p61_access_state_t current_state = P61_STATE_INVALID; - printk( KERN_INFO "secure_timer_callback: called (%lu).\n", jiffies); - /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: START */ - get_ese_lock(P61_STATE_WIRED, MAX_ESE_ACCESS_TIME_OUT_MS); - p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); - p61_get_access_state(pn544_dev, ¤t_state); - - if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) - { - printk( KERN_INFO "secure_timer_callback: make se_pwer_gpio low, state = %d", current_state); - gpio_set_value(pn544_dev->ese_pwr_gpio, 0); - /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ - usleep_range(2500, 3000); - #ifndef VEN_ALWAYS_ON - if(pn544_dev->nfc_service_pid == 0x00) - { - gpio_set_value(pn544_dev->ven_gpio, 0); - printk( KERN_INFO "secure_timer_callback :make ven_gpio low, state = %d", current_state); - } - #endif - } - pn544_dev->secure_timer_cnt = 0; - /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: END */ - release_ese_lock(P61_STATE_WIRED); - return; -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) -static void secure_timer_callback( unsigned long data ) -{ -(void)data; -#else -static void secure_timer_callback(struct timer_list *unused) -{ -#endif - /* Flush and push the timer callback event to the bottom half(work queue) - to be executed later, at a safer time */ - flush_workqueue(pn544_dev->pSecureTimerCbWq); - queue_work(pn544_dev->pSecureTimerCbWq, &pn544_dev->wq_task); - return; -} - -static long start_seccure_timer(unsigned long timer_value) -{ - long ret = -EINVAL; - pr_info("start_seccure_timer: enter\n"); - /* Delete the timer if timer pending */ - if(timer_pending(&secure_timer) == 1) - { - pr_info("start_seccure_timer: delete pending timer \n"); - /* delete timer if already pending */ - del_timer(&secure_timer); - } - /* Start the timer if timer value is non-zero */ - if(timer_value) - { -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) - init_timer(&secure_timer); - setup_timer( &secure_timer, secure_timer_callback, 0 ); -#else - timer_setup(&secure_timer, secure_timer_callback, 0); -#endif - pr_info("start_seccure_timer: timeout %lums (%lu)\n",timer_value, jiffies ); - ret = mod_timer( &secure_timer, jiffies + msecs_to_jiffies(timer_value)); - if (ret) - pr_info("start_seccure_timer: Error in mod_timer\n"); - } - return ret; -} - -static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg) -{ - long ret = -EINVAL; - unsigned long timer_value = arg; - - printk( KERN_INFO "secure_timer_operation, %d\n",pn544_dev->chip_pwr_scheme); - if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) - { - ret = start_seccure_timer(timer_value); - if(!ret) - { - pn544_dev->secure_timer_cnt = 1; - p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, true); - } - else - { - pn544_dev->secure_timer_cnt = 0; - p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); - pr_info("%s :Secure timer reset \n", __func__); - } - } - else - { - pr_info("%s :Secure timer session not applicable \n", __func__); - } - return ret; -} - -static long set_jcop_download_state(unsigned long arg) -{ - p61_access_state_t current_state = P61_STATE_INVALID; - long ret = 0; - p61_get_access_state(pn544_dev, ¤t_state); - pr_info("%s:Enter PN544_SET_DWNLD_STATUS:JCOP Dwnld state arg = %ld",__func__, arg); - if(arg == JCP_DWNLD_INIT) - { - if(pn544_dev->nfc_service_pid) - { - pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); - signal_handler(JCP_DWNLD_INIT, pn544_dev->nfc_service_pid); - } - else - { - if (current_state & P61_STATE_JCP_DWNLD) - { - ret = -EINVAL; - } - else - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); - } - } - } - else if (arg == JCP_DWNLD_START) - { - if (current_state & P61_STATE_JCP_DWNLD) - { - ret = -EINVAL; - } - else - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); - } - } - else if (arg == JCP_SPI_DWNLD_COMPLETE) - { - if(pn544_dev->nfc_service_pid) - { - signal_handler(JCP_DWP_DWNLD_COMPLETE, pn544_dev->nfc_service_pid); - } - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); - } - else if (arg == JCP_DWP_DWNLD_COMPLETE) - { - p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); - } - else - { - pr_info("%s bad ese pwr arg %lu\n", __func__, arg); - p61_access_unlock(pn544_dev); - return -EBADRQC; /* Invalid request code */ - } - pr_info("%s: PN544_SET_DWNLD_STATUS = %x",__func__, current_state); - - return ret; -} - -int get_ese_lock(p61_access_state_t p61_current_state, int timeout) -{ - unsigned long tempJ = msecs_to_jiffies(timeout); - if(down_timeout(&ese_access_sema, tempJ) != 0) - { - printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); - return -EBUSY; - } - return 0; -} -EXPORT_SYMBOL(get_ese_lock); - -static void release_ese_lock(p61_access_state_t p61_current_state) -{ - up(&ese_access_sema); -} - - -static const struct file_operations pn544_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = pn544_dev_read, - .write = pn544_dev_write, - .open = pn544_dev_open, - .release = pn544_dev_release, - .unlocked_ioctl = pn544_dev_ioctl, -}; -#if DRAGON_NFC -static int pn544_parse_dt(struct device *dev, - struct pn544_i2c_platform_data *data) -{ - struct device_node *np = dev->of_node; - int errorno = 0; - -#if !NEXUS5x - data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); - if ((!gpio_is_valid(data->irq_gpio))) - return -EINVAL; - - data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); - if ((!gpio_is_valid(data->ven_gpio))) - return -EINVAL; - - data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); - if ((!gpio_is_valid(data->firm_gpio))) - return -EINVAL; - - data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); - if ((!gpio_is_valid(data->ese_pwr_gpio))) - return -EINVAL; - data->iso_rst_gpio = of_get_named_gpio(np, "nxp,pn544-iso-pwr-rst", 0); - if ((!gpio_is_valid(data->iso_rst_gpio))) - return -EINVAL; -#else - data->ven_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_ven", 0, NULL); - data->firm_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_mode", 0, NULL); - data->irq_gpio = of_get_named_gpio_flags(np, - "nxp,gpio_irq", 0, NULL); -#endif - pr_info("%s: %d, %d, %d, %d, %d error:%d\n", __func__, - data->irq_gpio, data->ven_gpio, data->firm_gpio, data->iso_rst_gpio, - data->ese_pwr_gpio, errorno); - - return errorno; -} -#endif - -static int pn544_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - struct pn544_i2c_platform_data *platform_data; - //struct pn544_dev *pn544_dev; - -#if !DRAGON_NFC - platform_data = client->dev.platform_data; -#else - struct device_node *node = client->dev.of_node; - - if (node) { - platform_data = devm_kzalloc(&client->dev, - sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); - if (!platform_data) { - dev_err(&client->dev, - "nfc-nci probe: Failed to allocate memory\n"); - return -ENOMEM; - } - ret = pn544_parse_dt(&client->dev, platform_data); - if (ret) - { - pr_info("%s pn544_parse_dt failed", __func__); - } - client->irq = gpio_to_irq(platform_data->irq_gpio); - if (client->irq < 0) - { - pr_info("%s gpio to irq failed", __func__); - } - } else { - platform_data = client->dev.platform_data; - } -#endif - if (platform_data == NULL) { - pr_err("%s : nfc probe fail\n", __func__); - return -ENODEV; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - return -ENODEV; - } -#if !DRAGON_NFC - ret = gpio_request(platform_data->irq_gpio, "nfc_int"); - if (ret) - return -ENODEV; - ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); - if (ret) - goto err_ven; - ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); - if (ret) - goto err_ese_pwr; - if (platform_data->firm_gpio) { - ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); - if (ret) - goto err_firm; - } -#ifdef ISO_RST - if(platform_data->iso_rst_gpio) { - ret = gpio_request(platform_data->iso_rst_gpio, "nfc_iso_rst"); - if (ret) - goto err_iso_rst; - } -#endif -#endif - pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); - if (pn544_dev == NULL) { - dev_err(&client->dev, - "failed to allocate memory for module data\n"); - ret = -ENOMEM; - goto err_exit; - } - - pn544_dev->irq_gpio = platform_data->irq_gpio; - pn544_dev->ven_gpio = platform_data->ven_gpio; - pn544_dev->firm_gpio = platform_data->firm_gpio; - pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; -#ifdef ISO_RST - pn544_dev->iso_rst_gpio = platform_data->iso_rst_gpio; -#endif - pn544_dev->p61_current_state = P61_STATE_IDLE; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; - pn544_dev->client = client; - pn544_dev->secure_timer_cnt = 0; - - pn544_dev->state_flags = 0x00; - ret = gpio_direction_input(pn544_dev->irq_gpio); - if (ret < 0) { - pr_err("%s :not able to set irq_gpio as input\n", __func__); - goto err_ven; - } - #ifndef VEN_ALWAYS_ON - ret = gpio_direction_output(pn544_dev->ven_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_firm; - } - #else - ret = gpio_direction_output(pn544_dev->ven_gpio, 1); - if (ret < 0) { - pr_err("%s : not able to set ven_gpio as output\n", __func__); - goto err_firm; - } - #endif - ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); - goto err_ese_pwr; - } - if (platform_data->firm_gpio) { - ret = gpio_direction_output(pn544_dev->firm_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set firm_gpio as output\n", - __func__); - goto err_exit; - } - } -#ifdef ISO_RST - ret = gpio_direction_output(pn544_dev->iso_rst_gpio, 0); - if (ret < 0) { - pr_err("%s : not able to set iso rst gpio as output\n", __func__); - goto err_iso_rst; - } -#endif - /* init mutex and queues */ - ese_reset_resource_init(); - init_waitqueue_head(&pn544_dev->read_wq); - mutex_init(&pn544_dev->read_mutex); - sema_init(&ese_access_sema, 1); - mutex_init(&pn544_dev->p61_state_mutex); - spin_lock_init(&pn544_dev->irq_enabled_lock); - pn544_dev->pSecureTimerCbWq = create_workqueue(SECURE_TIMER_WORK_QUEUE); - INIT_WORK(&pn544_dev->wq_task, secure_timer_workqueue); - pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; - pn544_dev->pn544_device.name = "pn553"; - pn544_dev->pn544_device.fops = &pn544_dev_fops; - - ret = misc_register(&pn544_dev->pn544_device); - if (ret) { - pr_err("%s : misc_register failed\n", __FILE__); - goto err_misc_register; - } - /* HiKey Compilation fix */ - #ifndef HiKey_620_COMPILATION_FIX - wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); - #endif -#ifdef ISO_RST - /* Setting ISO RESET pin high to power ESE during init */ - gpio_set_value(pn544_dev->iso_rst_gpio, 1); -#endif - /* request irq. the irq is set whenever the chip has data available - * for reading. it is cleared when all data has been read. - */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - pn544_dev->irq_enabled = true; - ret = request_irq(client->irq, pn544_dev_irq_handler, - IRQF_TRIGGER_HIGH, client->name, pn544_dev); - if (ret) { - dev_err(&client->dev, "request_irq failed\n"); - goto err_request_irq_failed; - } - enable_irq_wake(pn544_dev->client->irq); - pn544_disable_irq(pn544_dev); - i2c_set_clientdata(client, pn544_dev); -#ifdef VEN_ALWAYS_ON - msleep(5); /* VBAT--> VDDIO(HIGH) + Guardtime of min 5ms --> VEN(HIGH) */ - /* VEN toggle(reset) to proceed */ - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(5); - gpio_set_value(pn544_dev->ven_gpio, 1); -#endif - -#if HWINFO - /* - * This function is used only if - * hardware info is required during probe*/ - check_hw_info(); -#endif - - return 0; - - err_request_irq_failed: - misc_deregister(&pn544_dev->pn544_device); - err_misc_register: - ese_reset_resource_destroy(); - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - kfree(pn544_dev); - err_exit: - if (pn544_dev->firm_gpio) - gpio_free(platform_data->firm_gpio); - err_firm: - gpio_free(platform_data->ese_pwr_gpio); - err_ese_pwr: - gpio_free(platform_data->ven_gpio); - err_ven: - gpio_free(platform_data->irq_gpio); -#ifdef ISO_RST - err_iso_rst: - gpio_free(platform_data->iso_rst_gpio); -#endif - return ret; -} - -static int pn544_remove(struct i2c_client *client) -{ - struct pn544_dev *pn544_dev; - - pn544_dev = i2c_get_clientdata(client); - free_irq(client->irq, pn544_dev); - misc_deregister(&pn544_dev->pn544_device); - mutex_destroy(&pn544_dev->read_mutex); - mutex_destroy(&pn544_dev->p61_state_mutex); - gpio_free(pn544_dev->irq_gpio); - gpio_free(pn544_dev->ven_gpio); - gpio_free(pn544_dev->ese_pwr_gpio); - destroy_workqueue(pn544_dev->pSecureTimerCbWq); -#ifdef ISO_RST - gpio_free(pn544_dev->iso_rst_gpio); -#endif - pn544_dev->p61_current_state = P61_STATE_INVALID; - pn544_dev->nfc_ven_enabled = false; - pn544_dev->spi_ven_enabled = false; - ese_reset_resource_destroy(); - - if (pn544_dev->firm_gpio) - gpio_free(pn544_dev->firm_gpio); - kfree(pn544_dev); - - return 0; -} - -static const struct i2c_device_id pn544_id[] = { -#if NEXUS5x - { "pn548", 0 }, -#else - { "pn544", 0 }, -#endif - { } -}; -#if DRAGON_NFC -static struct of_device_id pn544_i2c_dt_match[] = { - { -#if NEXUS5x - .compatible = "nxp,pn548", -#else - .compatible = "nxp,pn544", -#endif - }, - {} -}; -#endif -static struct i2c_driver pn544_driver = { - .id_table = pn544_id, - .probe = pn544_probe, - .remove = pn544_remove, - .driver = { - .owner = THIS_MODULE, -#if NEXUS5x - .name = "pn548", -#else - .name = "pn544", -#endif -#if DRAGON_NFC - .of_match_table = pn544_i2c_dt_match, -#endif - }, -}; -#if HWINFO -/****************************************************************************** - * Function check_hw_info - * - * Description This function is called during pn544_probe to retrieve - * HW info. - * Useful get HW information in case of previous FW download is - * interrupted and core reset is not allowed. - * This function checks if core reset is allowed, if not - * sets DWNLD_REQ(firm_gpio) , ven reset and sends firmware - * get version command. - * In response HW information will be received. - * - * Returns None - * - ******************************************************************************/ -static void check_hw_info() { - char read_data[20]; - int ret, get_version_len = 8, retry_count = 0; - static uint8_t cmd_reset_nci[] = {0x20, 0x00, 0x01, 0x00}; - char get_version_cmd[] = - {0x00, 0x04, 0xF1, 0x00, 0x00, 0x00, 0x6E, 0xEF}; - - pr_info("%s :Enter\n", __func__); - - /* - * Ven Reset before sending core Reset - * This is to check core reset is allowed or not. - * If not allowed then previous FW download is interrupted in between - * */ - pr_info("%s :Ven Reset \n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - ret = i2c_master_send(pn544_dev->client, cmd_reset_nci, 4); - - if (ret == 4) { - pr_info("%s : core reset write success\n", __func__); - } else { - - /* - * Core reset failed. - * set the DWNLD_REQ , do ven reset - * send firmware download info command - * */ - pr_err("%s : write failed\n", __func__); - pr_info("%s power on with firmware\n", __func__); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - if (pn544_dev->firm_gpio) { - p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); - gpio_set_value(pn544_dev->firm_gpio, 1); - } - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 0); - msleep(10); - gpio_set_value(pn544_dev->ven_gpio, 1); - msleep(10); - ret = i2c_master_send(pn544_dev->client, get_version_cmd, get_version_len); - if (ret != get_version_len) { - ret = -EIO; - pr_err("%s : write_failed \n", __func__); - } - else { - pr_info("%s :data sent\n", __func__); - } - - ret = 0; - - while (retry_count < 10) { - - /* - * Wait for read interrupt - * If spurious interrupt is received retry again - * */ - pn544_dev->irq_enabled = true; - enable_irq(pn544_dev->client->irq); - enable_irq_wake(pn544_dev->client->irq); - ret = wait_event_interruptible( - pn544_dev->read_wq, - !pn544_dev->irq_enabled); - - pn544_disable_irq(pn544_dev); - - if (gpio_get_value(pn544_dev->irq_gpio)) - break; - - pr_warning("%s: spurious interrupt detected\n", __func__); - retry_count ++; - } - - if(ret) { - return; - } - - /* - * Read response data and copy into hw_type_info - * */ - ret = i2c_master_recv(pn544_dev->client, read_data, 14); - - if(ret) { - memcpy(hw_info.data, read_data, ret); - hw_info.len = ret; - pr_info("%s :data received len : %d\n", __func__,hw_info.len); - } - else { - pr_err("%s :Read Failed\n", __func__); - } - } -} -#endif -/* - * module load/unload record keeping - */ - -static int __init pn544_dev_init(void) -{ - pr_info("Loading pn544 driver\n"); - return i2c_add_driver(&pn544_driver); -} -module_init(pn544_dev_init); - -static void __exit pn544_dev_exit(void) -{ - pr_info("Unloading pn544 driver\n"); - i2c_del_driver(&pn544_driver); -} -module_exit(pn544_dev_exit); - -MODULE_AUTHOR("Sylvain Fonteneau"); -MODULE_DESCRIPTION("NFC PN544 driver"); -MODULE_LICENSE("GPL"); diff --git a/pn553-i2c/pn553.h b/pn553-i2c/pn553.h deleted file mode 100644 index d196474f3e..0000000000 --- a/pn553-i2c/pn553.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/****************************************************************************** - * - * The original Work has been changed by NXP Semiconductors. - * - * Copyright (C) 2013-2020 NXP Semiconductors - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#ifndef _PN553_H_ -#define _PN553_H_ - -#include - -#define PN544_MAGIC 0xE9 - -/* - * PN544 power control via ioctl - * PN544_SET_PWR(0): power off - * PN544_SET_PWR(1): power on - * PN544_SET_PWR(2): reset and power on with firmware download enabled - */ -#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, long) - -/* - * SPI Request NFCC to enable p61 power, only in param - * Only for SPI - * level 1 = Enable power - * level 0 = Disable power - * This also be used to perform eSE cold reset when - * argument value is 0x03 - */ -#define P61_SET_SPI_PWR _IOW(PN544_MAGIC, 0x02, long) - -/* SPI or DWP can call this ioctl to get the current - * power state of P61 - * -*/ -#define P61_GET_PWR_STATUS _IOR(PN544_MAGIC, 0x03, long) - -/* DWP side this ioctl will be called - * level 1 = Wired access is enabled/ongoing - * level 0 = Wired access is disalbed/stopped -*/ -#define P61_SET_WIRED_ACCESS _IOW(PN544_MAGIC, 0x04, long) - -/* - NFC Init will call the ioctl to register the PID with the i2c driver -*/ -#define P544_SET_NFC_SERVICE_PID _IOW(PN544_MAGIC, 0x05, long) - -/* - NFC and SPI will call the ioctl to get the i2c/spi bus access -*/ -#define P544_GET_ESE_ACCESS _IOW(PN544_MAGIC, 0x06, long) -/* - NFC and SPI will call the ioctl to update the power scheme -*/ -#define P544_SET_POWER_SCHEME _IOW(PN544_MAGIC, 0x07, long) - -/* - NFC will call the ioctl to release the svdd protection -*/ -#define P544_REL_SVDD_WAIT _IOW(PN544_MAGIC, 0x08, long) - -/* SPI or DWP can call this ioctl to get the current - * power state of P61 - * -*/ -#define PN544_SET_DWNLD_STATUS _IOW(PN544_MAGIC, 0x09, long) -/* - NFC will call the ioctl to release the dwp on/off protection -*/ -#define P544_REL_DWPONOFF_WAIT _IOW(PN544_MAGIC, 0x0A, long) - -/* - NFC will call the ioctl to start Secure Timer -*/ - -#define P544_SECURE_TIMER_SESSION _IOW(PN544_MAGIC, 0x0B, long) - -#define MAX_ESE_ACCESS_TIME_OUT_MS 200 /*100 milliseconds*/ - -/* - NFC_ON: Driver is being used by the NFC service (bit b0) -*/ -#define P544_FLAG_NFC_ON 0x01 -/* - FW_DNLD: NFC_ON and FW download is going on (bit b1) -*/ -#define P544_FLAG_FW_DNLD 0x02 -/* - * VEN_RESET: NFC_ON and FW download with VEN reset (bit b2) -*/ -#define P544_FLAG_NFC_VEN_RESET 0x04 -/* - * ESE_RESET: Starting of flag positions for eSE cold reset origin -*/ -#define ESE_COLD_RESET_ORIGIN_FLAGS_POS (4) //(bit b4) -#define ESE_COLD_RESET_ORIGIN_NFC_FLAG_POS (4) //(bit b4) -/* - * ESE_RESET: Mask for the flags used for Driver to driver cold reset - * b6, b5, b4 : - * 0 0 0 -> no request for ese_cold_reset - * 0 0 1 -> ese_cold_reset requested from NFC driver - * 0 1 0 -> ese_cold_reset requested from eSE driver - * 1 0 0 -> ese_cold_reset requested from UWB driver -*/ -#define MASK_ESE_COLD_RESET (0x70) -/* - * ESE_RESET: Bit mask to check if ese_reset_guard timer is started (bit b7) -*/ -#define MASK_ESE_COLD_RESET_GUARD_TIMER (0x80) -/* - * ESE_RESET: Guard time to allow eSE cold reset from the driver -*/ -#define ESE_COLD_RESET_GUARD_TIME (3000) //3s -/* - * ESE_RESET: NCI command response timeout -*/ -#define NCI_CMD_RSP_TIMEOUT (2000) //2s -/* - * ESE_RESET: Guard time to reboot the JCOP -*/ -#define ESE_COLD_RESET_REBOOT_GUARD_TIME (50) //50ms - -typedef enum p61_access_state{ - P61_STATE_INVALID = 0x0000, - P61_STATE_IDLE = 0x0100, /* p61 is free to use */ - P61_STATE_WIRED = 0x0200, /* p61 is being accessed by DWP (NFCC)*/ - P61_STATE_SPI = 0x0400, /* P61 is being accessed by SPI */ - P61_STATE_DWNLD = 0x0800, /* NFCC fw download is in progress */ - P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ - P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ - P61_STATE_SPI_END = 0x4000, - P61_STATE_JCP_DWNLD = 0x8000,/* JCOP downlad in progress */ - P61_STATE_SECURE_MODE = 0x100000, /* secure mode state*/ - P61_STATE_SPI_SVDD_SYNC_START = 0x0001, /*ESE_VDD Low req by SPI*/ - P61_STATE_SPI_SVDD_SYNC_END = 0x0002, /*ESE_VDD is Low by SPI*/ - P61_STATE_DWP_SVDD_SYNC_START = 0x0004, /*ESE_VDD Low req by Nfc*/ - P61_STATE_DWP_SVDD_SYNC_END = 0x0008 /*ESE_VDD is Low by Nfc*/ -}p61_access_state_t; - -typedef enum chip_type_pwr_scheme{ - PN67T_PWR_SCHEME = 0x01, - PN80T_LEGACY_PWR_SCHEME, - PN80T_EXT_PMU_SCHEME, -}chip_pwr_scheme_t; - -typedef enum jcop_dwnld_state{ - JCP_DWNLD_IDLE = P61_STATE_JCP_DWNLD, /* jcop dwnld is ongoing*/ - JCP_DWNLD_INIT=0x8010, /* jcop dwonload init state*/ - JCP_DWNLD_START=0x8020, /* download started */ - JCP_SPI_DWNLD_COMPLETE=0x8040, /* jcop download complete in spi interface*/ - JCP_DWP_DWNLD_COMPLETE=0x8080, /* jcop download complete */ -} jcop_dwnld_state_t; - -struct pn544_i2c_platform_data { - unsigned int irq_gpio; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ - unsigned int iso_rst_gpio; /* gpio used for ISO hard reset P73*/ -}; - -struct hw_type_info { - /* - * Response of get_version_cmd will be stored in data - * byte structure : - * byte 0-1 : Header - * byte 2 : Status - * byte 3 : Hardware Version - * byte 4 : ROM code - * byte 5 : 0x00 constant - * byte 6-7 : Protected data version - * byte 8-9 : Trim data version - * byte 10-11 : FW version - * byte 12-13 : CRC - * */ - char data[20]; - int len; -}; - -#define NEXUS5x 0 -#define HWINFO 0 -#if NEXUS5x -#undef ISO_RST -#else -#define ISO_RST -#endif - -struct pn544_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct i2c_client *client; - struct miscdevice pn544_device; - unsigned int ven_gpio; - unsigned int firm_gpio; - unsigned int irq_gpio; - unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ -#ifdef ISO_RST - unsigned int iso_rst_gpio; /* ISO-RST pin gpio*/ -#endif - struct mutex p61_state_mutex; /* used to make p61_current_state flag secure */ - p61_access_state_t p61_current_state; /* stores the current P61 state */ - bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ - bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ - bool irq_enabled; - spinlock_t irq_enabled_lock; - long nfc_service_pid; /*used to signal the nfc the nfc service */ - chip_pwr_scheme_t chip_pwr_scheme; - unsigned int secure_timer_cnt; - struct workqueue_struct *pSecureTimerCbWq; - struct work_struct wq_task; - /* This byte represents different flags used during eSE cold reset request from - * Driver to driver - * Bit value Status Remark - * b0 : 1 -> NFC_ON Driver Open should set the flag - * 0 NFC_OFF Driver release should reset this flag - * b1 : 1 -> FWDNLD If FWDNLD is going on. - * 0 Normal operation - * b2 : 1 --> Ven reset has been requested - * b3 : reserved bit - * b6, b5, b4 : - * 0 0 0 -> no request for ese_cold_reset - * 0 0 1 -> ese_cold_reset requested from NFC driver - * 0 1 0 -> ese_cold_reset requested from eSE driver - * 0 1 1 -> ese_cold_reset requested from UWB driver - * Remaining combinations: Reserved for future use. - * These bits will be cleared once cold reset rsp is received. - * b7 : 1 --> The ese_cold reset guard time has is running - * It will be cleared by the Guard Timer Callback - * */ - volatile uint8_t state_flags; -}; - -#endif From 2ec82a2bfde5cce454c93f2519e0895ee32a7069 Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Fri, 12 Feb 2021 22:49:38 +0530 Subject: [PATCH 037/100] Updated corresponding to - NFC_AR_00_02.00_6000_12.51.00_OpnSrc --- nfc/Makefile | 4 +- nfc/common.c | 266 +++++++-- nfc/common.h | 40 +- nfc/common_ese.c | 21 +- nfc/common_ese.h | 2 +- nfc/i2c_drv.c | 132 +++-- nfc/i2c_drv.h | 5 +- nfc/recovery_fw.c | 1325 ++++++++++++++++++++++++++++++++++++++++++++ nfc/recovery_seq.c | 281 ++++++++++ nfc/recovery_seq.h | 80 +++ 10 files changed, 2023 insertions(+), 133 deletions(-) create mode 100644 nfc/recovery_fw.c create mode 100644 nfc/recovery_seq.c create mode 100644 nfc/recovery_seq.h diff --git a/nfc/Makefile b/nfc/Makefile index 52c28951e7..debebf6b79 100644 --- a/nfc/Makefile +++ b/nfc/Makefile @@ -2,5 +2,5 @@ # Makefile for nfc devices # obj-$(CONFIG_NXP_NFC_I2C) += pn553_i2c.o -pn553_i2c-objs := common.o common_ese.o i2c_drv.o -#ccflags-y := -DDEBUG +pn553_i2c-objs := common.o common_ese.o i2c_drv.o recovery_seq.o recovery_fw.o +ccflags-y += -DRECOVERY_ENABLE -UDEBUG diff --git a/nfc/common.c b/nfc/common.c index ee6f64a39a..4f0264d9fb 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) 2019-2020 NXP + * Copyright (C) 2019-2021 NXP * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,10 +23,15 @@ #include "common.h" #include "common_ese.h" -int nfc_parse_dt(struct device *dev, platform_gpio_t * nfc_gpio, +#if defined(RECOVERY_ENABLE) +#include "recovery_seq.h" +#endif + +int nfc_parse_dt(struct device *dev, platform_configs_t *nfc_configs, uint8_t interface) { struct device_node *np = dev->of_node; + platform_gpio_t *nfc_gpio = &nfc_configs->gpio; if (!np) { pr_err("nfc of_node NULL\n"); @@ -45,11 +50,6 @@ int nfc_parse_dt(struct device *dev, platform_gpio_t * nfc_gpio, return -EINVAL; } pr_info("%s: irq %d\n", __func__, nfc_gpio->irq); - - nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); - if ((!gpio_is_valid(nfc_gpio->dwl_req))) { - pr_err("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req); - } } nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->ven))) { @@ -57,6 +57,11 @@ int nfc_parse_dt(struct device *dev, platform_gpio_t * nfc_gpio, return -EINVAL; } + nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); + if ((!gpio_is_valid(nfc_gpio->dwl_req))) { + pr_warn("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req); + } + pr_info("%s: %d, %d, %d, %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven, nfc_gpio->dwl_req); return 0; @@ -68,7 +73,8 @@ void set_valid_gpio(int gpio, int value) pr_debug("%s gpio %d value %d\n", __func__, gpio, value); gpio_set_value(gpio, value); // hardware dependent delay - usleep_range(10000, 10100); + usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, + NFC_GPIO_SET_WAIT_TIME_USEC + 100); } } @@ -84,15 +90,17 @@ int get_valid_gpio(int gpio) void gpio_set_ven(struct nfc_dev *nfc_dev, int value) { - if (gpio_get_value(nfc_dev->gpio.ven) != value) { + platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; + if (gpio_get_value(nfc_gpio->ven) != value) { pr_debug("%s: gpio_set_ven %d\n", __func__, value); /*reset on change in level from high to low */ if (value) { common_ese_on_hard_reset(nfc_dev); } - gpio_set_value(nfc_dev->gpio.ven, value); + gpio_set_value(nfc_gpio->ven, value); // hardware dependent delay - usleep_range(10000, 10100); + usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, + NFC_GPIO_SET_WAIT_TIME_USEC + 100); } } @@ -140,14 +148,15 @@ int configure_gpio(unsigned int gpio, int flag) void gpio_free_all(nfc_dev_t *nfc_dev) { - if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { - gpio_free(nfc_dev->gpio.dwl_req); + platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; + if (gpio_is_valid(nfc_gpio->dwl_req)) { + gpio_free(nfc_gpio->dwl_req); } - if (gpio_is_valid(nfc_dev->gpio.irq)) { - gpio_free(nfc_dev->gpio.irq); + if (gpio_is_valid(nfc_gpio->irq)) { + gpio_free(nfc_gpio->irq); } - if (gpio_is_valid(nfc_dev->gpio.ven)) { - gpio_free(nfc_dev->gpio.ven); + if (gpio_is_valid(nfc_gpio->ven)) { + gpio_free(nfc_gpio->ven); } } @@ -211,6 +220,7 @@ int nfc_misc_register(nfc_dev_t *nfc_dev, static int nfc_ioctl_power_states(nfc_dev_t *nfc_dev, unsigned long arg) { int ret = 0; + platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; if (arg == NFC_POWER_OFF) { /* * We are attempting a hardware reset so let us disable @@ -218,12 +228,12 @@ static int nfc_ioctl_power_states(nfc_dev_t *nfc_dev, unsigned long arg) * layers. */ nfc_dev->nfc_disable_intr(nfc_dev); - set_valid_gpio(nfc_dev->gpio.dwl_req, 0); + set_valid_gpio(nfc_gpio->dwl_req, 0); gpio_set_ven(nfc_dev, 0); nfc_dev->nfc_ven_enabled = false; } else if (arg == NFC_POWER_ON) { nfc_dev->nfc_enable_intr(nfc_dev); - set_valid_gpio(nfc_dev->gpio.dwl_req, 0); + set_valid_gpio(nfc_gpio->dwl_req, 0); gpio_set_ven(nfc_dev, 1); nfc_dev->nfc_ven_enabled = true; @@ -233,10 +243,8 @@ static int nfc_ioctl_power_states(nfc_dev_t *nfc_dev, unsigned long arg) * in order to set the NFCC in the new mode */ nfc_dev->nfc_disable_intr(nfc_dev); - set_valid_gpio(nfc_dev->gpio.dwl_req, 1); - if (nfc_dev->interface == PLATFORM_IF_I2C) { - nfc_dev->nfc_state = NFC_STATE_FW_DWL; - } + set_valid_gpio(nfc_gpio->dwl_req, 1); + nfc_dev->nfc_state = NFC_STATE_FW_DWL; gpio_set_ven(nfc_dev, 0); gpio_set_ven(nfc_dev, 1); nfc_dev->nfc_enable_intr(nfc_dev); @@ -245,10 +253,8 @@ static int nfc_ioctl_power_states(nfc_dev_t *nfc_dev, unsigned long arg) * Setting firmware download gpio to HIGH * before FW download start */ - set_valid_gpio(nfc_dev->gpio.dwl_req, 1); - if (nfc_dev->interface == PLATFORM_IF_I2C) { - nfc_dev->nfc_state = NFC_STATE_FW_DWL; - } + set_valid_gpio(nfc_gpio->dwl_req, 1); + nfc_dev->nfc_state = NFC_STATE_FW_DWL; } else if (arg == NFC_VEN_FORCED_HARD_RESET) { nfc_dev->nfc_disable_intr(nfc_dev); @@ -260,10 +266,8 @@ static int nfc_ioctl_power_states(nfc_dev_t *nfc_dev, unsigned long arg) * Setting firmware download gpio to LOW * FW download finished */ - set_valid_gpio(nfc_dev->gpio.dwl_req, 0); - if (nfc_dev->interface == PLATFORM_IF_I2C) { - nfc_dev->nfc_state = NFC_STATE_NCI; - } + set_valid_gpio(nfc_gpio->dwl_req, 0); + nfc_dev->nfc_state = NFC_STATE_NCI; } else { pr_err("%s bad arg %lu\n", __func__, arg); ret = -ENOIOCTLCMD; @@ -305,8 +309,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) pr_debug("nfc get state %d\n", ret); break; case NFC_GET_IRQ_STATE: - ret = 0; - ret = gpio_get_value(nfc_dev->gpio.irq); + ret = gpio_get_value(nfc_dev->configs.gpio.irq); break; default: pr_err("%s bad cmd %lu\n", __func__, arg); @@ -325,7 +328,7 @@ int nfc_dev_open(struct inode *inode, struct file *filp) filp->private_data = nfc_dev; if (nfc_dev->dev_ref_count == 0) { - set_valid_gpio(nfc_dev->gpio.dwl_req, 0); + set_valid_gpio(nfc_dev->configs.gpio.dwl_req, 0); nfc_dev->nfc_enable_intr(nfc_dev); } @@ -341,7 +344,7 @@ int nfc_dev_close(struct inode *inode, struct file *filp) mutex_lock(&nfc_dev->dev_ref_mutex); if (nfc_dev->dev_ref_count == 1) { nfc_dev->nfc_disable_intr(nfc_dev); - set_valid_gpio(nfc_dev->gpio.dwl_req, 0); + set_valid_gpio(nfc_dev->configs.gpio.dwl_req, 0); } if (nfc_dev->dev_ref_count > 0) nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; @@ -363,14 +366,6 @@ static int get_nfcc_boot_state(struct nfc_dev *nfc_dev) char get_version_cmd[] = { 0x00, 0x04, 0xF1, 0x00, 0x00, 0x00, 0x6E, 0xEF }; char get_session_state_cmd[] = { 0x00, 0x04, 0xF2, 0x00, 0x00, 0x00, 0xF5, 0x33 }; char rsp_buf[MAX_BUFFER_SIZE]; - /*clearing any data in the kbuf store */ - do { - ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, MAX_BUFFER_SIZE); - if (ret < 0) { - pr_err("%s: - nfc read ret %d\n", __func__, ret); - } - pr_info("%s: - nfc read ret %d\n", __func__, ret); - } while (ret > 0); pr_debug("%s:Sending GET_VERSION cmd\n", __func__); ret = nfc_dev->nfc_write(nfc_dev, get_version_cmd, @@ -381,18 +376,23 @@ static int get_nfcc_boot_state(struct nfc_dev *nfc_dev) } memset(rsp_buf, 0x00, MAX_BUFFER_SIZE); pr_debug("%s:Reading response of GET_VERSION cmd\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, MAX_BUFFER_SIZE); + ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_VERSION_RSP_LEN_2, NCI_CMD_RSP_TIMEOUT); if (ret <= 0) { pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret); goto err; - } else if (rsp_buf[0] == 0x0 - && ret == (FW_HDR_LEN + rsp_buf[FW_PAYLOAD_LEN_IDX] + FW_CRC_LEN) - && (ret == DL_GET_VERSION_RSP_LEN_1 || ret == DL_GET_VERSION_RSP_LEN_2)) { - + } else if (rsp_buf[0] == FW_MSG_CMD_RSP + && ret >= DL_GET_VERSION_RSP_LEN_2) { +#if defined(RECOVERY_ENABLE) + nfc_dev->fw_major_version = rsp_buf[FW_MAJOR_VER_OFFSET]; + /* recvoery neeeded only for SN1xx */ + if(rsp_buf[FW_ROM_CODE_VER_OFFSET] == RECOVERY_FW_SUPPORTED_ROM_VER && + nfc_dev->fw_major_version == RECOVERY_FW_SUPPORTED_MAJOR_VER) + nfc_dev->recovery_required = true; +#endif pr_info("%s:NFC chip_type 0x%02x rom_version 0x%02x fw_minor 0x%02x fw_major 0x%02x\n", __func__, rsp_buf[3], rsp_buf[4], rsp_buf[6], rsp_buf[7]); - } else if (rsp_buf[0] != 0x0 - && ret == (NCI_HDR_LEN + rsp_buf[NCI_PAYLOAD_LEN_IDX])) { + } else if (rsp_buf[0] != FW_MSG_CMD_RSP + && ret >= (NCI_HDR_LEN + rsp_buf[NCI_PAYLOAD_LEN_IDX])) { pr_info("%s:NFC response bytes 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[3]); pr_debug("%s NFCC booted in NCI mode %d\n", __func__, __LINE__); @@ -409,7 +409,7 @@ static int get_nfcc_boot_state(struct nfc_dev *nfc_dev) } memset(rsp_buf, 0x00, DL_GET_SESSION_STATE_RSP_LEN); pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_SESSION_STATE_RSP_LEN); + ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT); if (ret <= 0) { pr_err("%s: - nfc get session state rsp err %d\n", __func__, ret); goto err; @@ -431,11 +431,12 @@ err: int validate_nfc_state_nci(nfc_dev_t *nfc_dev) { - if (!gpio_get_value(nfc_dev->gpio.ven)) { + platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; + if (!gpio_get_value(nfc_gpio->ven)) { pr_err("VEN LOW - NFCC powered off\n"); return -ENODEV; } else { - if (get_valid_gpio(nfc_dev->gpio.dwl_req) == 1) { + if (get_valid_gpio(nfc_gpio->dwl_req) == 1) { pr_err("FW download in-progress\n"); return -EBUSY; } else if (nfc_dev->nfc_state == NFC_STATE_FW_DWL) { @@ -445,3 +446,162 @@ int validate_nfc_state_nci(nfc_dev_t *nfc_dev) } return 0; } + +static int set_nfcc_nci_state(struct nfc_dev *nfc_dev) +{ + int ret = 0; + char dl_reset_cmd[] = { 0x00, 0x04, 0xF0, 0x00, 0x00, 0x00, 0x18, 0x5B }; + + pr_debug("%s:Sending DL_RESET to boot in NCI mode\n", __func__); + ret = nfc_dev->nfc_write(nfc_dev, dl_reset_cmd, + sizeof(dl_reset_cmd), MAX_RETRY_COUNT); + if (ret <= 0) { + pr_err("%s: nfc dl reset cmd err ret %d\n", __func__, ret); + goto err; + } + usleep_range(NFC_SOFT_RESET_WAIT_TIME_USEC, + NFC_SOFT_RESET_WAIT_TIME_USEC + 100); + pr_debug("%s NFCC booted in NCI mode %d\n", __func__, __LINE__); + return 0; + +err: + pr_err("%s Unlikely NFCC not booted in NCI mode %d\n", __func__, __LINE__); + return -1; +} + +static bool do_nci_reset(nfc_dev_t *nfc_dev) { + const uint8_t cmd_reset_nci[] = {0x20, 0x00, 0x01, 0x00}; + char rsp_buf[MAX_BUFFER_SIZE]; + int status = 0; + + if (NULL == nfc_dev) { + pr_err("%s invalid params ", __func__); + return false; + } + pr_debug("%s Entry \n", __func__); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + pr_debug(" %s send core reset cmd \n", __func__); + status = nfc_dev->nfc_write(nfc_dev, cmd_reset_nci, + sizeof(cmd_reset_nci), NO_RETRY); + if (status <= 0) { + pr_err(" %s: nfc nci core reset cmd err status %d\n", __func__, status); + return false; + } + usleep_range(NCI_RESET_RESP_READ_DELAY, NCI_RESET_RESP_READ_DELAY + 100); + nfc_dev->nfc_enable_intr(nfc_dev); + pr_debug(" %s Reading response of NCI reset \n", __func__); + memset(rsp_buf, 0x00, MAX_BUFFER_SIZE); + status = nfc_dev->nfc_read(nfc_dev, rsp_buf, MAX_BUFFER_SIZE, NCI_RESET_RESP_TIMEOUT); + if (status <= 0) { + pr_err(" %s - nfc nci rest rsp error status %d\n", __func__, status); + nfc_dev->nfc_disable_intr(nfc_dev); + return false; + } + pr_debug(" %s: nci core reset response 0x%02x 0x%02x 0x%02x 0x%02x \n", + __func__, rsp_buf[0], rsp_buf[1],rsp_buf[2], rsp_buf[3]); + if(rsp_buf[0] != NCI_MSG_RSP) { + /* reset response failed response*/ + pr_err("%s invalid nci core reset response"); + nfc_dev->nfc_disable_intr(nfc_dev); + return false; + } + memset(rsp_buf, 0x00, MAX_BUFFER_SIZE); + /* read nci rest response ntf */ + status = nfc_dev->nfc_read(nfc_dev, rsp_buf, MAX_BUFFER_SIZE, NCI_CMD_RSP_TIMEOUT); + if (status <= 0) { + pr_err("%s - nfc nci rest rsp ntf error status %d\n" + , __func__, status); + } + pr_debug(" %s:NFC NCI Reset Response ntf 0x%02x 0x%02x 0x%02x 0x%02x \n", + __func__, rsp_buf[0], rsp_buf[1],rsp_buf[2], rsp_buf[3]); + nfc_dev->nfc_disable_intr(nfc_dev); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + return true; +} + +/* Check for availability of NFC controller hardware */ +int nfcc_hw_check(struct nfc_dev *nfc_dev) +{ + int ret = 0; + uint8_t nfc_state = NFC_STATE_UNKNOWN; + if(do_nci_reset(nfc_dev)) { + pr_info("%s recovery not required", __func__); + return ret; + } + nfc_dev->nfc_enable_intr(nfc_dev); + + /*set download mode for i2c products with dwl pin */ + enable_dwnld_mode(nfc_dev, true); + + nfc_state = get_nfcc_boot_state(nfc_dev); + switch (nfc_state) { + case NFC_STATE_FW_DWL: + usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, + NFC_GPIO_SET_WAIT_TIME_USEC + 100); + if (set_nfcc_nci_state(nfc_dev)) { + pr_debug("%s: - NFCC DL Reset Fails\n", __func__); + } else { + nfc_state = NFC_STATE_NCI; + /*set NCI mode for i2c products with dwl pin */ + enable_dwnld_mode(nfc_dev, false); + } + /* fall-through */ + case NFC_STATE_NCI: + nfc_dev->nfc_ven_enabled = true; + pr_debug("%s: - NFCC HW detected\n", __func__); + break; + case NFC_STATE_FW_TEARED: + pr_warn("%s: - NFCC FW Teared State\n", __func__); +#if defined(RECOVERY_ENABLE) + if(nfc_dev->recovery_required && + (do_recovery(nfc_dev) == STATUS_SUCCESS)) { + pr_debug("%s: - NFCC HW detected\n", __func__); + } +#endif + nfc_dev->nfc_ven_enabled = true; + break; + case NFC_STATE_UNKNOWN: + default: + ret = -ENXIO; + pr_debug("%s: - NFCC HW not available\n", __func__); + }; + + nfc_dev->nfc_disable_intr(nfc_dev); + if (nfc_state == NFC_STATE_FW_TEARED) { + nfc_state = NFC_STATE_FW_DWL; + } + nfc_dev->nfc_state = nfc_state; + return ret; +} + +void enable_dwnld_mode(nfc_dev_t* nfc_dev, bool value) { + if(nfc_dev != NULL) { + platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; + if (get_valid_gpio(nfc_gpio->dwl_req) != -1) { + set_valid_gpio(nfc_gpio->dwl_req, value); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + } + } +} + +void set_nfcc_state_from_rsp(struct nfc_dev *dev, const char *buf, + const int count) +{ + int packet_size = 0; + if (buf[0] == FW_MSG_CMD_RSP && buf[1] >= FW_MIN_PAYLOAD_LEN) { + packet_size = FW_HDR_LEN + buf[FW_PAYLOAD_LEN_IDX] + FW_CRC_LEN; + if (packet_size == count && dev->nfc_state == NFC_STATE_NCI) + dev->nfc_state = NFC_STATE_FW_DWL; + } else { + packet_size = NCI_HDR_LEN + buf[NCI_PAYLOAD_LEN_IDX]; + if (packet_size == count && dev->nfc_state == NFC_STATE_FW_DWL) + dev->nfc_state = NFC_STATE_NCI; + } + if (count != packet_size) { + pr_err("%s: Unlikely mismatch in packet size received (%d/%d)/\n", __func__, + packet_size, count); + } +} diff --git a/nfc/common.h b/nfc/common.h index 30bb468e1d..65dabf2858 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) 2019-2020 NXP + * Copyright (C) 2019-2021 NXP * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,11 +41,16 @@ #define NCI_HDR_LEN 3 #define NCI_PAYLOAD_IDX 3 #define NCI_PAYLOAD_LEN_IDX 2 +/*Time to wait for first NCI rest response*/ +#define NCI_RESET_RESP_READ_DELAY (10000) // 10ms +#define NCI_RESET_RESP_TIMEOUT (500) // 500ms // FW DNLD packet details +#define FW_MSG_CMD_RSP 0x00 #define FW_HDR_LEN 2 #define FW_PAYLOAD_LEN_IDX 1 #define FW_CRC_LEN 2 +#define FW_MIN_PAYLOAD_LEN 4 #define MIN_NFC_DL_FRAME_SIZE 3 #define NCI_RESET_CMD_LEN (4) @@ -72,9 +77,17 @@ #define MAX_IRQ_WAIT_TIME (90) #define WAKEUP_SRC_TIMEOUT (2000) +#define NCI_MAX_CMD_RSP_TIMEOUT (5000) //5s /*command response timeout*/ #define NCI_CMD_RSP_TIMEOUT (2000) //2s - +/*Time to wait for NFCC to be ready again after any change in the GPIO*/ +#define NFC_GPIO_SET_WAIT_TIME_USEC (10000) +/*Time to wait after soft reset via any NCI/DL cmd*/ +#define NFC_SOFT_RESET_WAIT_TIME_USEC (5000) +/*Time to wait before retrying i2c writes*/ +#define WRITE_RETRY_WAIT_TIME_USEC (1000) +/*Time to wait before retrying read for some specific usecases*/ +#define READ_RETRY_WAIT_TIME_USEC (3500) #define NFC_MAGIC 0xE9 /*Ioctls*/ @@ -85,7 +98,7 @@ #define NFC_GET_PLATFORM_TYPE _IO(NFC_MAGIC, 0x04) #define NFC_GET_NFC_STATE _IO(NFC_MAGIC, 0x05) /* NFC HAL can call this ioctl to get the current IRQ state */ -#define NFC_GET_IRQ_STATE _IOW(NFC_MAGIC, 0x06, long) +#define NFC_GET_IRQ_STATE _IO(NFC_MAGIC, 0x06) #define DTS_IRQ_GPIO_STR "nxp,pn544-irq" #define DTS_VEN_GPIO_STR "nxp,pn544-ven" @@ -151,6 +164,11 @@ typedef struct platform_gpio { unsigned int dwl_req; } platform_gpio_t; +// NFC Struct to get all the required configs from DTS*/ +typedef struct platform_configs { + platform_gpio_t gpio; +} platform_configs_t; + //cold reset Features specific Parameters typedef struct cold_reset { bool rsp_pending; /*cmd rsp pending status */ @@ -180,14 +198,20 @@ typedef struct nfc_dev { uint8_t nfc_state; /* NFC VEN pin state */ bool nfc_ven_enabled; +#if defined(RECOVERY_ENABLE) + /* current firmware major version */ + uint8_t fw_major_version; + /* NFC recovery Required */ + bool recovery_required; +#endif union { i2c_dev_t i2c_dev; }; - platform_gpio_t gpio; + platform_configs_t configs; cold_reset_t cold_reset; /*funtion pointers for the common i2c functionality */ - int (*nfc_read) (struct nfc_dev *dev, char *buf, size_t count); + int (*nfc_read) (struct nfc_dev *dev, char *buf, size_t count, int timeout); int (*nfc_write) (struct nfc_dev *dev, const char *buf, const size_t count, int max_retry_cnt); int (*nfc_enable_intr) (struct nfc_dev *dev); @@ -198,7 +222,7 @@ typedef struct nfc_dev { int nfc_dev_open(struct inode *inode, struct file *filp); int nfc_dev_close(struct inode *inode, struct file *filp); long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); -int nfc_parse_dt(struct device *dev, platform_gpio_t *nfc_gpio, +int nfc_parse_dt(struct device *dev, platform_configs_t *nfc_configs, uint8_t interface); int nfc_misc_register(nfc_dev_t *nfc_dev, const struct file_operations *nfc_fops, int count, char *devname, @@ -208,4 +232,8 @@ int configure_gpio(unsigned int gpio, int flag); void gpio_set_ven(nfc_dev_t *nfc_dev, int value); void gpio_free_all(nfc_dev_t *nfc_dev); int validate_nfc_state_nci(nfc_dev_t *nfc_dev); +int nfcc_hw_check(nfc_dev_t *nfc_dev); +void set_nfcc_state_from_rsp(nfc_dev_t *dev, const char *buf, + const int count); +void enable_dwnld_mode(nfc_dev_t* nfc_dev, bool value); #endif //_COMMON_H_ diff --git a/nfc/common_ese.c b/nfc/common_ese.c index 10ff475969..9c418036f3 100644 --- a/nfc/common_ese.c +++ b/nfc/common_ese.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) 2020 NXP + * Copyright (C) 2020-2021 NXP * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -143,6 +143,7 @@ static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg) { int ret = 0; struct file filp; + uint8_t cld_rst_rsp[MAX_BUFFER_SIZE]; cold_reset_t *cold_reset = &nfc_dev->cold_reset; bool nfc_dev_opened = false; @@ -212,13 +213,12 @@ static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg) } else { /* Read data as NFC thread is not active */ filp.private_data = nfc_dev; -#if IS_ENABLED(CONFIG_NXP_NFC_I2C) - if (nfc_dev->interface == PLATFORM_IF_I2C) { - filp.f_flags &= ~O_NONBLOCK; - ret = nfc_i2c_dev_read(&filp, NULL, 3, 0); - usleep_range(3500, 4000); - } -#endif //IS_ENABLED(CONFIG_NXP_NFC_I2C) + filp.f_flags &= ~O_NONBLOCK; + ret = nfc_dev->nfc_read(nfc_dev, cld_rst_rsp, 3, NCI_CMD_RSP_TIMEOUT); + if (!ret) + break; + usleep_range(READ_RETRY_WAIT_TIME_USEC, + READ_RETRY_WAIT_TIME_USEC + 500); } } while (ret == -ERESTARTSYS || ret == -EFAULT); @@ -250,6 +250,7 @@ err: int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg) { int ret = 0; + platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; if (arg == ESE_POWER_ON) { /** * Let's store the NFC VEN pin state @@ -258,7 +259,7 @@ int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg) * VEN state will remain HIGH if NFC is enabled otherwise * it will be set as LOW */ - nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_dev->gpio.ven); + nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_gpio->ven); if (!nfc_dev->nfc_ven_enabled) { pr_debug("eSE HAL service setting ven HIGH\n"); gpio_set_ven(nfc_dev, 1); @@ -274,7 +275,7 @@ int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg) } } else if (arg == ESE_POWER_STATE) { // eSE get power state - ret = gpio_get_value(nfc_dev->gpio.ven); + ret = gpio_get_value(nfc_gpio->ven); } else if (IS_CLD_RST_REQ(arg) || IS_RST_PROT_REQ(arg)) { ret = perform_cold_reset_protection(nfc_dev, arg); } else { diff --git a/nfc/common_ese.h b/nfc/common_ese.h index 61f6fe4e91..f4ebb5d57a 100644 --- a/nfc/common_ese.h +++ b/nfc/common_ese.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) 2020 NXP + * Copyright (C) 2020-2021 NXP * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 5f69aaabbd..2a0954e1d0 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) 2013-2020 NXP + * Copyright (C) 2013-2021 NXP * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,6 +43,8 @@ #include #include "common.h" #include "common_ese.h" + +static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, int timeout); /** * i2c_disable_irq() * @@ -100,23 +102,14 @@ static irqreturn_t i2c_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -int i2c_read(struct nfc_dev *dev, char *buf, size_t count) -{ - int ret; - pr_debug("%s : reading %zu bytes.\n", __func__, count); - /* Read data */ - ret = i2c_master_recv(dev->i2c_dev.client, buf, count); - if (ret <= 0) { - pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); - goto err; - } - if (ret > count) { - pr_err("%s: received too many bytes from i2c (%d)\n", - __func__, ret); - ret = -EIO; - } -err: - return ret; +int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout){ + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + + if(timeout > NCI_MAX_CMD_RSP_TIMEOUT) + timeout = NCI_MAX_CMD_RSP_TIMEOUT; + + return i2c_read_internal(dev, buf, count, timeout); } int i2c_write(struct nfc_dev *dev, const char *buf, size_t count, @@ -132,53 +125,58 @@ int i2c_write(struct nfc_dev *dev, const char *buf, size_t count, if (ret <= 0) { pr_warn("%s: write failed, Maybe in Standby Mode - Retry(%d)\n", __func__, retry_cnt); - usleep_range(1000, 1100); + usleep_range(WRITE_RETRY_WAIT_TIME_USEC, + WRITE_RETRY_WAIT_TIME_USEC + 100); } else if (ret == count) break; } return ret; } -ssize_t nfc_i2c_dev_read(struct file * filp, char __user *buf, - size_t count, loff_t * offset) +static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, int timeout) { int ret; char tmp[MAX_BUFFER_SIZE]; - nfc_dev_t *nfc_dev = filp->private_data; + nfc_dev_t *nfc_dev = dev; i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; if (count > MAX_BUFFER_SIZE) count = MAX_BUFFER_SIZE; pr_debug("%s : reading %zu bytes.\n", __func__, count); mutex_lock(&nfc_dev->read_mutex); - if (!gpio_get_value(nfc_dev->gpio.irq)) { - if (filp->f_flags & O_NONBLOCK) { - pr_err(":f_falg has O_NONBLOCK. EAGAIN\n"); - ret = -EAGAIN; - goto err; - } + if (!gpio_get_value(nfc_gpio->irq)) { + while (1) { ret = 0; if (!i2c_dev->irq_enabled) { i2c_dev->irq_enabled = true; enable_irq(i2c_dev->client->irq); } - if (!gpio_get_value(nfc_dev->gpio.irq)) { - ret = wait_event_interruptible(nfc_dev->read_wq, - !i2c_dev-> - irq_enabled); + if (!gpio_get_value(nfc_gpio->irq)) { + if(timeout) { + ret = wait_event_interruptible_timeout(nfc_dev->read_wq, + !i2c_dev-> irq_enabled, msecs_to_jiffies(timeout)); - if (ret) { - pr_err("error wakeup of read wq\n"); - goto err; + if (ret <= 0) { + pr_err("%s timeout/error in read\n", __func__); + goto err; + } + } else { + ret = wait_event_interruptible(nfc_dev->read_wq, + !i2c_dev->irq_enabled); + if (ret) { + pr_err("%s error wakeup of read wq\n", __func__); + goto err; + } } } i2c_disable_irq(nfc_dev); - if (gpio_get_value(nfc_dev->gpio.irq)) + if (gpio_get_value(nfc_gpio->irq)) break; - if (!gpio_get_value(nfc_dev->gpio.ven)) { + if (!gpio_get_value(nfc_gpio->ven)) { pr_info("%s: releasing read\n", __func__); ret = -EIO; goto err; @@ -189,7 +187,7 @@ ssize_t nfc_i2c_dev_read(struct file * filp, char __user *buf, memset(tmp, 0x00, count); /* Read data */ - ret = i2c_read(nfc_dev, tmp, count); + ret = i2c_master_recv(nfc_dev->i2c_dev.client, tmp, count); if (ret <= 0) { pr_err("%s: i2c_read returned %d\n", __func__, ret); goto err; @@ -201,8 +199,7 @@ ssize_t nfc_i2c_dev_read(struct file * filp, char __user *buf, if (nfc_dev->cold_reset.rsp_pending) { if (IS_PROP_CMD_RSP(tmp)) { /* Read data */ - ret = - i2c_read(nfc_dev, &tmp[NCI_PAYLOAD_IDX], + ret = i2c_master_recv(nfc_dev->i2c_dev.client, &tmp[NCI_PAYLOAD_IDX], tmp[NCI_PAYLOAD_LEN_IDX]); if (ret <= 0) { pr_err("%s: failure to read prop cold reset/protection rsp header\n", __func__); @@ -228,6 +225,17 @@ err: return ret; } +ssize_t nfc_i2c_dev_read(struct file * filp, char __user *buf, + size_t count, loff_t * offset) +{ + pr_debug("%s : reading %zu bytes.\n", __func__, count); + if (filp->f_flags & O_NONBLOCK) { + pr_err(":f_falg has O_NONBLOCK. EAGAIN\n"); + return -EAGAIN; + } + return i2c_read_internal((nfc_dev_t *)filp->private_data, buf, count, 0); +} + ssize_t nfc_i2c_dev_write(struct file * filp, const char __user *buf, size_t count, loff_t * offset) { @@ -266,10 +274,11 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) int ret = 0; nfc_dev_t *nfc_dev = NULL; i2c_dev_t *i2c_dev = NULL; - platform_gpio_t nfc_gpio; + platform_configs_t nfc_configs; + platform_gpio_t *nfc_gpio = &nfc_configs.gpio; pr_debug("%s: enter\n", __func__); /*retrive details of gpios from dt */ - ret = nfc_parse_dt(&client->dev, &nfc_gpio, PLATFORM_IF_I2C); + ret = nfc_parse_dt(&client->dev, &nfc_configs, PLATFORM_IF_I2C); if (ret) { pr_err("%s : failed to parse dt\n", __func__); goto err; @@ -293,26 +302,30 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) nfc_dev->nfc_write = i2c_write; nfc_dev->nfc_enable_intr = i2c_enable_irq; nfc_dev->nfc_disable_intr = i2c_disable_irq; +#if defined(RECOVERY_ENABLE) + nfc_dev->recovery_required = false; + nfc_dev->fw_major_version = 0; +#endif - ret = configure_gpio(nfc_gpio.ven, GPIO_OUTPUT); + ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT); if (ret) { - pr_err("%s: unable to request nfc reset gpio [%d]\n", __func__, nfc_gpio.ven); + pr_err("%s: unable to request nfc reset gpio [%d]\n", __func__, nfc_gpio->ven); goto err; } - ret = configure_gpio(nfc_gpio.irq, GPIO_IRQ); + ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ); if (ret <= 0) { - pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__, nfc_gpio.irq); + pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__, nfc_gpio->irq); goto err; } client->irq = ret; - ret = configure_gpio(nfc_gpio.dwl_req, GPIO_OUTPUT); + ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT); if (ret) { pr_err("%s: unable to request nfc firm downl gpio [%d]\n", __func__, - nfc_gpio.dwl_req); + nfc_gpio->dwl_req); } /*copy the retrived gpio details from DT */ - memcpy(&nfc_dev->gpio, &nfc_gpio, sizeof(struct platform_gpio)); + memcpy(&nfc_dev->configs, &nfc_configs, sizeof(struct platform_configs)); /* init mutex and queues */ init_waitqueue_head(&nfc_dev->read_wq); @@ -337,16 +350,17 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_nfc_misc_unregister; } i2c_disable_irq(nfc_dev); + + ret = nfcc_hw_check(nfc_dev); + if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { + pr_err("nfc hw check failed ret %d\n", ret); + } + device_init_wakeup(&client->dev, true); device_set_wakeup_capable(&client->dev, true); i2c_set_clientdata(client, nfc_dev); i2c_dev->irq_wake_up = false; - //reset nfc - usleep_range(10000, 10100); - gpio_set_value(nfc_dev->gpio.ven, 1); - usleep_range(10000, 10100); - pr_info("%s probing nfc i2c successfully", __func__); return 0; err_nfc_misc_unregister: @@ -357,10 +371,12 @@ err_mutex_destroy: mutex_destroy(&nfc_dev->ese_access_mutex); mutex_destroy(&nfc_dev->cold_reset.sync_mutex); err: - gpio_free_all(nfc_dev); - kfree(nfc_dev); - pr_err("%s: probing not successful, check hardware\n", __func__); - return ret; + if (nfc_dev) { + gpio_free_all(nfc_dev); + kfree(nfc_dev); + } + pr_err("%s: probing not successful, check hardware\n", __func__); + return ret; } int nfc_i2c_dev_remove(struct i2c_client *client) diff --git a/nfc/i2c_drv.h b/nfc/i2c_drv.h index 8b41d41dd2..745c211d72 100644 --- a/nfc/i2c_drv.h +++ b/nfc/i2c_drv.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) 2019-2020 NXP + * Copyright (C) 2019-2021 NXP * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,6 +40,5 @@ int nfc_i2c_dev_probe(struct i2c_client *client, int nfc_i2c_dev_remove(struct i2c_client *client); int nfc_i2c_dev_suspend(struct device *device); int nfc_i2c_dev_resume(struct device *device); -ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, size_t count, - loff_t * offset); + #endif //_I2C_DRV_H_ diff --git a/nfc/recovery_fw.c b/nfc/recovery_fw.c new file mode 100644 index 0000000000..c210337bd4 --- /dev/null +++ b/nfc/recovery_fw.c @@ -0,0 +1,1325 @@ +/******************************************************************************************** + * + * Copyright 2021 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"),to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + ********************************************************************************************/ +#include +const uint8_t gphDnldNfc_DlSequence[] = { + 0x01, 0x34, 0xC0, 0x00, 0xDE, 0x10, 0xAD, 0x69, 0xE0, 0x28, + 0xAC, 0xFA, 0xF2, 0x4A, 0x0F, 0x49, 0x7E, 0x6A, 0x61, 0xD1, + 0x00, 0xFD, 0x4A, 0x66, 0xDD, 0x42, 0x4D, 0xFF, 0x90, 0xA5, + 0x6C, 0x54, 0xF0, 0x53, 0x5E, 0x17, 0x1E, 0x28, 0x8B, 0xF2, + 0x56, 0x6D, 0x74, 0x7B, 0x4E, 0xBA, 0xEB, 0x8D, 0x22, 0x43, + 0x01, 0xE9, 0xC4, 0x85, 0x2B, 0xFB, 0xA7, 0xD9, 0x3C, 0x64, + 0x63, 0x2D, 0xBB, 0x63, 0x5C, 0xDB, 0x14, 0x4D, 0x86, 0xA0, + 0x73, 0xC1, 0x32, 0xA4, 0x12, 0xD0, 0xED, 0x12, 0x90, 0xCF, + 0xAF, 0x56, 0x35, 0x3D, 0x97, 0x6B, 0xAC, 0x81, 0x1B, 0xD6, + 0x77, 0x9A, 0x4F, 0x9C, 0x90, 0x7D, 0x16, 0x6E, 0xC4, 0xCD, + 0x2D, 0xD2, 0x57, 0x49, 0x99, 0x24, 0xBC, 0x06, 0x71, 0x04, + 0xA8, 0x14, 0xEF, 0x21, 0x55, 0x0D, 0xAD, 0x82, 0x88, 0x5C, + 0xEF, 0xDF, 0x03, 0x93, 0xB5, 0xE8, 0x21, 0x18, 0xE0, 0x54, + 0xB8, 0xE1, 0x7E, 0x88, 0xE9, 0xF7, 0xEE, 0x86, 0xD2, 0x36, + 0xD7, 0x4B, 0x99, 0x6C, 0x35, 0x8B, 0xE0, 0xA2, 0xA2, 0xFB, + 0xED, 0xB5, 0x9A, 0xA0, 0xEE, 0x19, 0x67, 0x66, 0x14, 0x14, + 0xEC, 0xEF, 0x3F, 0xC0, 0x25, 0x7C, 0xA8, 0x9F, 0x58, 0x11, + 0xCD, 0x99, 0x00, 0xBF, 0xB8, 0x6D, 0xD5, 0x06, 0x8A, 0x5D, + 0x40, 0xB0, 0x2C, 0x9A, 0x20, 0xA2, 0x30, 0xDA, 0xFD, 0xB0, + 0xE3, 0x05, 0x5F, 0xB7, 0x3B, 0x9C, 0xD6, 0xB8, 0x92, 0xAE, + 0x4B, 0xDC, 0xF2, 0x1D, 0xA4, 0x11, 0xCE, 0x0C, 0xFD, 0x37, + 0x6E, 0xBA, 0x8B, 0x6C, 0x84, 0x3E, 0x3A, 0x3D, 0x20, 0xBE, + 0x64, 0xA6, 0x56, 0x7F, 0x06, 0x66, 0x04, 0x38, 0x1D, 0x97, + 0xD9, 0x96, 0xE6, 0x07, 0x29, 0xE2, 0x1A, 0xC4, 0x5F, 0x0A, + 0xAC, 0x62, 0x50, 0xF8, 0xD2, 0x33, 0x3F, 0x7A, 0x50, 0x89, + 0x98, 0x44, 0xCB, 0xFD, 0x75, 0x79, 0x25, 0xB1, 0x3A, 0xDE, + 0x53, 0x86, 0x13, 0x54, 0x46, 0x0B, 0x5F, 0x94, 0xEC, 0x1B, + 0x72, 0x24, 0x35, 0x84, 0x67, 0xC8, 0xBE, 0xDB, 0xAC, 0xB2, + 0x0C, 0x94, 0x88, 0xE1, 0xC4, 0x36, 0xD1, 0x6B, 0xB9, 0x4C, + 0xAE, 0xB0, 0x55, 0xF8, 0xBE, 0xD4, 0x7D, 0x16, 0x76, 0x84, + 0x2E, 0x46, 0x0B, 0xF6, 0x0D, 0x43, 0xB6, 0xBB, 0x5F, 0x98, + 0x02, 0x26, 0xC0, 0x00, 0x02, 0x35, 0x79, 0x26, 0x91, 0x8C, + 0x34, 0x8D, 0x69, 0x6E, 0x7F, 0x6B, 0xBF, 0xBD, 0x81, 0x3F, + 0x9C, 0x94, 0x0C, 0x65, 0x47, 0xC5, 0x08, 0xA7, 0x14, 0x6F, + 0x5A, 0xAC, 0x7C, 0xAC, 0x0C, 0x15, 0xD5, 0x6F, 0xBF, 0xDC, + 0xCE, 0x97, 0xD0, 0xD5, 0xEB, 0x1D, 0x3C, 0x7A, 0xEB, 0x2A, + 0x4E, 0x76, 0x08, 0xF2, 0xEA, 0x3A, 0xA0, 0xB8, 0xFC, 0xA0, + 0x74, 0x92, 0x8F, 0x86, 0xB1, 0x15, 0x0D, 0x7D, 0x92, 0x0F, + 0x64, 0xCE, 0xCA, 0xC1, 0xC4, 0x20, 0xA2, 0x48, 0x2D, 0xB0, + 0x47, 0x24, 0xF1, 0x20, 0x77, 0xDF, 0x87, 0x0D, 0xFA, 0xC6, + 0x89, 0xEE, 0xBD, 0x5E, 0xD5, 0x85, 0x64, 0xBC, 0x40, 0x6E, + 0x86, 0x01, 0x3D, 0xB6, 0x83, 0x8C, 0xAA, 0xF3, 0x2D, 0x3A, + 0xBB, 0x0D, 0xE6, 0xA5, 0xC0, 0x64, 0x07, 0xCB, 0x57, 0x81, + 0x7E, 0xD8, 0x3C, 0x3D, 0x4A, 0x9F, 0x8E, 0xF0, 0x57, 0x2E, + 0x5E, 0x41, 0x42, 0x00, 0xB0, 0xC7, 0x4E, 0x17, 0xED, 0xC6, + 0xAB, 0x73, 0x71, 0x65, 0x1D, 0x60, 0x34, 0x2A, 0x2B, 0xAF, + 0x59, 0x82, 0x5E, 0x16, 0x48, 0x48, 0x0F, 0x86, 0x62, 0x0C, + 0x84, 0x56, 0x00, 0x03, 0x2A, 0xA6, 0x2C, 0x21, 0xD0, 0x70, + 0xF9, 0xE5, 0x37, 0x0E, 0x81, 0x20, 0x36, 0x4E, 0x86, 0x8D, + 0xCF, 0xED, 0xBD, 0x0D, 0x49, 0x75, 0x0E, 0x5B, 0x80, 0xF7, + 0xAF, 0x40, 0x56, 0x8B, 0xD8, 0xFC, 0xC6, 0xE4, 0x6D, 0xD6, + 0x2E, 0x0D, 0xD0, 0x76, 0x75, 0x39, 0x3E, 0xF0, 0xEA, 0xC5, + 0x23, 0x12, 0x06, 0x45, 0xEA, 0x04, 0x6D, 0xC1, 0xA2, 0x95, + 0x95, 0x40, 0xD6, 0x6B, 0x65, 0xD6, 0x7D, 0x62, 0xA5, 0xB4, + 0x6B, 0x6C, 0x24, 0x3E, 0xFB, 0xAB, 0x71, 0x4D, 0xFC, 0x24, + 0x9F, 0x71, 0x8C, 0x04, 0x9A, 0xEE, 0x6D, 0x72, 0x3A, 0x01, + 0x11, 0xC1, 0x01, 0xB2, 0xC2, 0xC8, 0xBA, 0x7D, 0x53, 0x56, + 0x0D, 0x3F, 0x35, 0xF6, 0x86, 0x46, 0x7C, 0x67, 0xBF, 0x83, + 0x04, 0x01, 0x98, 0xBC, 0x06, 0x08, 0xF3, 0x89, 0x88, 0x8E, + 0x93, 0xB3, 0xA9, 0x21, 0x18, 0x71, 0xFF, 0xFC, 0x4E, 0xF7, + 0xFE, 0x1A, 0x5D, 0xC9, 0x21, 0xF6, 0x3B, 0x27, 0x2C, 0x26, + 0x37, 0xE2, 0x4F, 0x8C, 0x94, 0x77, 0xC7, 0x0D, 0xB9, 0x74, + 0xCD, 0x9F, 0xE1, 0x70, 0xFD, 0x35, 0x11, 0xA2, 0xB6, 0xAC, + 0x39, 0x3D, 0xC9, 0x57, 0x94, 0x3F, 0x10, 0x89, 0x9F, 0x0F, + 0x7D, 0x49, 0x0E, 0xFE, 0x84, 0x34, 0x87, 0x5B, 0xA5, 0xA0, + 0x5E, 0x0D, 0xE4, 0x05, 0x5A, 0x45, 0x8B, 0x31, 0x28, 0xF0, + 0x80, 0x7A, 0xF9, 0x56, 0xE7, 0x60, 0xB0, 0x31, 0xBB, 0x75, + 0x7E, 0x30, 0x74, 0x53, 0x14, 0xF6, 0xDE, 0x24, 0x9E, 0xE0, + 0xB9, 0x9F, 0xE6, 0xB0, 0x5D, 0x5B, 0x7A, 0xF3, 0xFD, 0x0D, + 0x4C, 0xCA, 0xAD, 0x01, 0xE4, 0x3F, 0xFE, 0x1D, 0x03, 0xE7, + 0xD4, 0xC6, 0xC1, 0xE9, 0xF5, 0x9E, 0x72, 0x9C, 0x4A, 0x09, + 0x85, 0x2C, 0xBE, 0x46, 0x49, 0xE1, 0x0F, 0xBF, 0x27, 0xF2, + 0x81, 0xC3, 0x33, 0x95, 0xEC, 0xBE, 0x37, 0x2B, 0x65, 0xA5, + 0xEC, 0xF7, 0x69, 0x23, 0x3B, 0xA6, 0xA6, 0xC3, 0xC7, 0x9F, + 0x9B, 0x79, 0xE6, 0x37, 0xB4, 0xDB, 0x33, 0x3B, 0xC5, 0x19, + 0x50, 0x7B, 0xBB, 0x7B, 0x4B, 0xFF, 0x0A, 0x3A, 0x0F, 0xDE, + 0x9D, 0x1F, 0x70, 0xE0, 0x9C, 0x37, 0x9B, 0x61, 0x01, 0xD9, + 0xCB, 0x9F, 0xC7, 0x1F, 0x9B, 0x25, 0x7D, 0x18, 0xF0, 0x6F, + 0x12, 0x54, 0xC2, 0x17, 0x8F, 0xB2, 0x1F, 0x5D, 0x0F, 0x73, + 0xB2, 0xEE, 0xE9, 0x0E, 0xC4, 0xA1, 0x70, 0x48, 0xDF, 0x0B, + 0xB4, 0xDD, 0xFF, 0xC7, 0x01, 0xA6, 0xBC, 0x08, 0xCE, 0x0E, + 0xB4, 0x4A, 0xAE, 0xFF, 0x88, 0xA6, 0x4D, 0x60, 0xC7, 0x55, + 0x38, 0x74, 0x3C, 0x1D, 0x8F, 0x82, 0xD3, 0xD3, 0x31, 0x60, + 0xE4, 0xB2, 0x24, 0x76, 0xE7, 0xD8, 0x53, 0x05, 0x20, 0x3E, + 0x5C, 0xEF, 0x17, 0x4C, 0x20, 0x6F, 0x6A, 0x6D, 0x10, 0xA3, + 0xA4, 0xE9, 0xFB, 0x76, 0x66, 0x99, 0x5D, 0xD1, 0x34, 0x52, + 0x42, 0xBF, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x9E, 0xED, 0xAE, + 0xE5, 0x23, 0x85, 0x5C, 0xFF, 0xAD, 0x6E, 0x89, 0x02, 0x33, + 0x97, 0x74, 0x05, 0x59, 0x1E, 0x73, 0x4E, 0xD3, 0x9A, 0x97, + 0xD3, 0x85, 0x2B, 0x12, 0xFB, 0xA2, 0xF0, 0xA4, 0x4C, 0x2A, + 0x58, 0xFB, 0x56, 0x6C, 0xE9, 0xA6, 0x04, 0x07, 0x9F, 0xBC, + 0x76, 0x66, 0x01, 0x80, 0xB8, 0x1E, 0x4A, 0x8A, 0x0C, 0x76, + 0x8A, 0x3C, 0x5F, 0x25, 0xAD, 0x83, 0xF3, 0x10, 0x02, 0xE1, + 0x38, 0x4B, 0xFA, 0x81, 0xD2, 0xC5, 0x6D, 0x18, 0xA7, 0xD8, + 0x0A, 0x4E, 0xC9, 0xC7, 0xA3, 0x19, 0x52, 0x0D, 0xBB, 0xA9, + 0xDE, 0x9C, 0x90, 0x57, 0x71, 0x1A, 0x37, 0xA8, 0x70, 0x4D, + 0x75, 0x7E, 0x34, 0x90, 0x74, 0x0E, 0x02, 0xC8, 0x8A, 0x80, + 0x3D, 0x06, 0x67, 0xF4, 0xF2, 0xD4, 0x15, 0x66, 0x0D, 0x23, + 0xAE, 0x46, 0x0A, 0x23, 0x7B, 0x36, 0x96, 0x48, 0x7D, 0x99, + 0xF4, 0x09, 0xE3, 0xA9, 0x53, 0xAC, 0x94, 0xB7, 0x23, 0x7E, + 0x57, 0xCF, 0x90, 0xCD, 0x13, 0x0D, 0x50, 0xBD, 0xC9, 0xE4, + 0xC2, 0x22, 0x5F, 0x28, 0x11, 0xF8, 0x1F, 0x42, 0x33, 0xEE, + 0xF3, 0xB4, 0xED, 0x8F, 0xF4, 0xA0, 0xAE, 0xF5, 0xAE, 0x56, + 0x59, 0xC3, 0x65, 0xDB, 0xF2, 0x51, 0x6D, 0x15, 0xA3, 0xAF, + 0xA5, 0xC7, 0x9F, 0x7A, 0xE8, 0xCC, 0xB4, 0xD8, 0xCA, 0x39, + 0x3F, 0x79, 0xB3, 0x86, 0xDB, 0x37, 0x52, 0xDA, 0x5E, 0xDB, + 0x7F, 0x53, 0x60, 0x43, 0x75, 0x53, 0x93, 0xD4, 0xA2, 0xE2, + 0xE7, 0xB7, 0x42, 0xF0, 0x97, 0xA5, 0xB5, 0x52, 0xD3, 0xCF, + 0xE7, 0x70, 0x6F, 0x10, 0xD4, 0x85, 0xC4, 0x4B, 0x3D, 0x09, + 0xE1, 0x02, 0xB8, 0xED, 0xA5, 0xCC, 0x7B, 0x2D, 0x68, 0xEF, + 0xEF, 0x9E, 0x87, 0x8C, 0xB7, 0xC9, 0x85, 0xA8, 0x01, 0xC2, + 0xCF, 0x43, 0xB5, 0x6D, 0x30, 0x2A, 0x9F, 0x06, 0x96, 0xE0, + 0x43, 0xEC, 0x3F, 0xC1, 0x2F, 0x7D, 0x4D, 0x85, 0x76, 0xD3, + 0xF7, 0xFA, 0xC8, 0x84, 0x20, 0xA8, 0x3C, 0xD9, 0x3E, 0x4A, + 0xB4, 0x87, 0x05, 0xCF, 0x9B, 0x51, 0x68, 0xF9, 0x49, 0xBA, + 0x4D, 0x68, 0x97, 0x6E, 0x79, 0xDB, 0x04, 0x51, 0x66, 0x6F, + 0xF9, 0x59, 0x2D, 0x55, 0x96, 0x13, 0x59, 0x52, 0x30, 0xB8, + 0x73, 0xD1, 0x12, 0x33, 0x31, 0xEC, 0x4C, 0x0C, 0x8E, 0xD4, + 0x47, 0xE7, 0x30, 0xC6, 0x98, 0xB5, 0x5B, 0x35, 0x1B, 0xAC, + 0x51, 0xBB, 0xFA, 0xC3, 0x8D, 0x3E, 0x89, 0x83, 0x1C, 0xED, + 0xB1, 0x03, 0x9C, 0xC7, 0x5C, 0x89, 0xF9, 0xC2, 0xE3, 0x45, + 0x91, 0xDB, 0x41, 0x0A, 0x22, 0xD1, 0x90, 0x39, 0xD6, 0x9D, + 0x0A, 0xD8, 0x36, 0xDC, 0xDB, 0xDD, 0x63, 0x22, 0xF8, 0x7B, + 0x4D, 0x90, 0x4C, 0x27, 0x0F, 0xCC, 0x16, 0x0E, 0x32, 0x46, + 0xD7, 0x20, 0x5A, 0x43, 0xC4, 0xC5, 0x37, 0x2E, 0xEB, 0x3F, + 0x42, 0x2C, 0xFA, 0x99, 0xE2, 0xF9, 0x70, 0xB3, 0xC3, 0xCF, + 0x4C, 0x67, 0xEB, 0x7C, 0x9D, 0xAF, 0x96, 0x15, 0x97, 0xD2, + 0x07, 0x3B, 0xF6, 0xEF, 0x2F, 0x98, 0xAA, 0x1D, 0x45, 0xDC, + 0x11, 0xBA, 0xF6, 0x0C, 0x18, 0x64, 0x80, 0xF2, 0x6B, 0xBD, + 0x3C, 0x85, 0xC1, 0xCD, 0x78, 0xD0, 0x62, 0x79, 0x0F, 0xCD, + 0xCA, 0x3D, 0x94, 0x0A, 0x11, 0xEF, 0x11, 0x86, 0xFA, 0x3F, + 0x31, 0xB2, 0xF1, 0x2C, 0x74, 0x1B, 0x57, 0x05, 0xD4, 0x4F, + 0xAF, 0xE7, 0xCB, 0x60, 0x9E, 0x78, 0x82, 0xAD, 0xF3, 0x34, + 0x6A, 0x2F, 0xDC, 0xA1, 0xC9, 0xEA, 0x3E, 0x6E, 0x01, 0x80, + 0x17, 0x5B, 0xCC, 0xBB, 0xED, 0xD0, 0x30, 0x11, 0xBE, 0xEE, + 0x2E, 0x9F, 0xCE, 0xE1, 0xFF, 0x32, 0xB8, 0x7D, 0x40, 0xC8, + 0x46, 0x0F, 0x41, 0x16, 0xE1, 0xB3, 0x98, 0x47, 0xCE, 0xE1, + 0x41, 0xDE, 0x80, 0xA7, 0x56, 0x83, 0xA8, 0xDA, 0xC3, 0x49, + 0x33, 0x6F, 0x93, 0x68, 0xA0, 0xC6, 0x1A, 0x0B, 0x82, 0x38, + 0x56, 0xEE, 0xBB, 0x97, 0x5D, 0xBD, 0x8A, 0x32, 0x2D, 0xFE, + 0x40, 0xC7, 0x0D, 0xCA, 0x32, 0x08, 0xCC, 0xE2, 0x18, 0x57, + 0xBB, 0xC1, 0x60, 0x43, 0x02, 0x26, 0xC0, 0x00, 0x02, 0xAD, + 0x9E, 0x61, 0x0D, 0x67, 0x25, 0xE4, 0x6E, 0x8F, 0x6D, 0xEA, + 0x16, 0x98, 0xFA, 0x76, 0x6D, 0x6D, 0x3C, 0xED, 0x4B, 0x25, + 0x60, 0xC6, 0xAB, 0x59, 0x91, 0x43, 0xAA, 0xAA, 0xEC, 0x8F, + 0xA1, 0x3E, 0xB1, 0x78, 0x72, 0xEE, 0xD1, 0x91, 0xBA, 0xD9, + 0x9B, 0xE3, 0x55, 0x61, 0x98, 0x46, 0x4B, 0xC5, 0x41, 0x3B, + 0x9C, 0x88, 0x1D, 0x82, 0xD5, 0xD5, 0x99, 0x13, 0x64, 0x44, + 0x00, 0xBD, 0xBE, 0xC4, 0xF6, 0x6A, 0x2D, 0xE3, 0xD0, 0xE7, + 0x88, 0xD3, 0xA1, 0x48, 0x88, 0x84, 0x8A, 0x25, 0xAB, 0x90, + 0x43, 0xFB, 0x3D, 0x1B, 0x06, 0xB2, 0xFD, 0x24, 0x58, 0x0C, + 0xFA, 0x0A, 0xD3, 0x23, 0x73, 0xA7, 0xF8, 0x50, 0xC5, 0x1B, + 0x3A, 0x75, 0xF4, 0x24, 0xA8, 0x52, 0xFB, 0x1B, 0x61, 0xAB, + 0x79, 0x06, 0x54, 0xD9, 0x1D, 0x3A, 0x72, 0x4F, 0x8F, 0xD3, + 0xC7, 0x71, 0xA8, 0x66, 0x80, 0x49, 0x8D, 0x50, 0xD1, 0xBF, + 0xC8, 0x70, 0xAE, 0x4F, 0x64, 0x53, 0x26, 0x37, 0xDA, 0x6B, + 0x62, 0xFE, 0xF9, 0x60, 0xAD, 0xAD, 0x49, 0x51, 0x37, 0x2E, + 0x61, 0xA9, 0xAA, 0x72, 0xFD, 0x02, 0x20, 0x0B, 0xB0, 0xB0, + 0x07, 0x95, 0x0C, 0x38, 0x13, 0xB6, 0xA4, 0x33, 0xFA, 0xFA, + 0x12, 0xE1, 0x62, 0x00, 0x92, 0x46, 0x23, 0xAA, 0xD7, 0x9D, + 0xBD, 0xAF, 0x15, 0xCA, 0x8C, 0x88, 0x2A, 0x4B, 0x1B, 0xA8, + 0x06, 0xA0, 0xC2, 0x80, 0x8E, 0x98, 0x46, 0xA1, 0x84, 0x2C, + 0x4A, 0x0F, 0xEA, 0x70, 0xE6, 0xDD, 0x17, 0x30, 0x8A, 0x41, + 0x69, 0x8A, 0x1B, 0xC2, 0xC7, 0x18, 0xD5, 0xB3, 0x94, 0x4F, + 0x51, 0x15, 0xCC, 0x37, 0x9A, 0x9E, 0xFD, 0x12, 0x40, 0xC1, + 0xA3, 0x06, 0x0F, 0x36, 0xFC, 0x04, 0x18, 0x35, 0x40, 0x9C, + 0x9E, 0x46, 0x5E, 0x14, 0xB6, 0xF7, 0xBF, 0xE5, 0x21, 0x12, + 0xF2, 0xE2, 0x17, 0xB3, 0x63, 0x8C, 0xD1, 0xE3, 0xA9, 0x0A, + 0x80, 0x1B, 0x74, 0x7A, 0x58, 0x91, 0x88, 0x9D, 0xAE, 0xE6, + 0x05, 0x1D, 0x3C, 0x1E, 0xE9, 0x95, 0x08, 0x75, 0xEE, 0x20, + 0xA8, 0x4B, 0x3D, 0x36, 0xAF, 0xB0, 0xFA, 0x94, 0x62, 0x5D, + 0x9F, 0xD5, 0x50, 0x2A, 0x24, 0xFC, 0x1D, 0xDC, 0x39, 0xCB, + 0x0D, 0x5A, 0xA1, 0xDA, 0xEF, 0xC9, 0xB3, 0x62, 0xF8, 0x7D, + 0x0C, 0xE4, 0x6B, 0xEC, 0xF0, 0xF7, 0x96, 0x63, 0x58, 0x80, + 0x55, 0x22, 0x6D, 0x42, 0x38, 0xE9, 0x1D, 0x69, 0xD5, 0x2F, + 0x03, 0x3C, 0xCD, 0x27, 0x34, 0x99, 0x39, 0xF0, 0x5C, 0xE0, + 0x23, 0x70, 0x85, 0x4B, 0x30, 0xBD, 0x21, 0x01, 0xF6, 0x06, + 0x0B, 0xED, 0xBA, 0xA1, 0x6F, 0xE0, 0x6E, 0xD3, 0x78, 0xA8, + 0x56, 0x94, 0x92, 0x84, 0xA8, 0x60, 0x35, 0xA8, 0x86, 0x56, + 0x41, 0xEA, 0x12, 0x34, 0x86, 0x52, 0x18, 0x75, 0x43, 0x01, + 0x0A, 0xCE, 0xBA, 0x04, 0xF7, 0x32, 0x09, 0x2D, 0xB1, 0xAC, + 0x04, 0xB0, 0x4E, 0xEA, 0xBE, 0xDE, 0xDE, 0x95, 0x37, 0xDA, + 0x86, 0x72, 0xFE, 0x10, 0x16, 0xBB, 0xA7, 0xE9, 0x67, 0xC9, + 0x3C, 0x85, 0x18, 0xFF, 0xD7, 0x74, 0x25, 0x3A, 0x95, 0x04, + 0xD5, 0x7F, 0x99, 0x41, 0x6A, 0x6A, 0x2C, 0xF6, 0x3E, 0x3C, + 0x4B, 0xA7, 0xB9, 0xDA, 0x13, 0xFC, 0xF6, 0x46, 0xEF, 0x7E, + 0xB4, 0xA6, 0x1B, 0x36, 0x93, 0x5B, 0xDA, 0xDB, 0x6A, 0xC7, + 0x37, 0x58, 0x3C, 0x4F, 0x52, 0x7E, 0x39, 0xD7, 0xE2, 0xBA, + 0x79, 0xA7, 0x9A, 0x05, 0x8A, 0xF5, 0x65, 0x86, 0xF4, 0x52, + 0xBC, 0x79, 0x6D, 0xA9, 0xFE, 0xEE, 0xE6, 0xC5, 0x2B, 0x28, + 0x62, 0x8E, 0xF6, 0x6E, 0xD5, 0x08, 0x90, 0x96, 0x72, 0x7A, + 0x6B, 0x61, 0x8B, 0x6A, 0xE6, 0xCD, 0x05, 0x63, 0x12, 0x9A, + 0xF7, 0x01, 0xAC, 0xF7, 0x8F, 0x1F, 0xE0, 0xCA, 0x1E, 0xF9, + 0x86, 0xC1, 0xF6, 0x0D, 0x2D, 0x9F, 0x8A, 0x2C, 0x8B, 0x3C, + 0xE4, 0x89, 0xDF, 0x72, 0x86, 0x17, 0xA8, 0x7F, 0x9D, 0x8B, + 0x0D, 0x87, 0xCB, 0xC5, 0xAE, 0xE3, 0x90, 0xB1, 0xD9, 0x8B, + 0x5E, 0x04, 0x97, 0xAA, 0x19, 0x85, 0x02, 0x26, 0xC0, 0x00, + 0x02, 0x26, 0xDA, 0x00, 0x7E, 0x08, 0xC0, 0x08, 0x12, 0x9A, + 0x78, 0x4E, 0x9D, 0xA7, 0xB0, 0x5E, 0x0D, 0x76, 0x6D, 0x4D, + 0xC7, 0x89, 0x35, 0xDD, 0xB5, 0x58, 0x9F, 0x20, 0x3C, 0x41, + 0x77, 0x9B, 0x85, 0x06, 0x21, 0xA4, 0x99, 0x56, 0xF9, 0x5B, + 0x07, 0x01, 0x06, 0x1A, 0xE1, 0x1B, 0xC7, 0x9F, 0x46, 0x5D, + 0x1F, 0xB8, 0xB2, 0x91, 0xA5, 0xC2, 0x01, 0x94, 0xFA, 0x53, + 0x74, 0xFA, 0x6A, 0x5B, 0x63, 0x08, 0x2E, 0x24, 0xB0, 0xCF, + 0x03, 0x40, 0x9C, 0xA1, 0xF2, 0xDB, 0xA2, 0x35, 0xD7, 0xCA, + 0x78, 0x4E, 0x9D, 0x8B, 0x92, 0x4A, 0xD1, 0xEA, 0xF8, 0x14, + 0xCA, 0xA0, 0x32, 0x55, 0x95, 0xA0, 0x1F, 0xB7, 0x1D, 0x8B, + 0x8E, 0x8E, 0xA6, 0xF0, 0x2A, 0x30, 0x76, 0xB4, 0x9B, 0x6F, + 0xAB, 0xBC, 0xC7, 0xA8, 0xF6, 0x2B, 0x9D, 0x1D, 0xC2, 0x24, + 0x06, 0x10, 0x06, 0xE7, 0x59, 0x34, 0xE9, 0x30, 0xA8, 0xF5, + 0x61, 0x55, 0xEC, 0xFB, 0xA1, 0x43, 0x17, 0x10, 0x08, 0xFF, + 0x3C, 0x93, 0x03, 0xFF, 0x83, 0x35, 0x81, 0x77, 0x7E, 0x97, + 0xC2, 0xA0, 0x53, 0x2A, 0x26, 0xD4, 0xDF, 0xC0, 0xA3, 0x21, + 0x07, 0x14, 0x41, 0xD3, 0x7C, 0xE5, 0x40, 0x00, 0xDE, 0x32, + 0xF5, 0xB9, 0xBB, 0x61, 0x44, 0xBC, 0xA4, 0xFD, 0x67, 0xAA, + 0x69, 0xF4, 0x96, 0x93, 0xD2, 0xAF, 0xEA, 0xC5, 0x72, 0xDB, + 0xEA, 0x88, 0x2A, 0x5F, 0xC5, 0xAB, 0x00, 0xFA, 0xA9, 0x32, + 0x61, 0x58, 0xBE, 0xC0, 0x42, 0xA9, 0xFA, 0xB6, 0x44, 0xD6, + 0x59, 0xF8, 0x26, 0x8B, 0xB9, 0x0A, 0xD9, 0xE2, 0x5B, 0x1B, + 0x20, 0xD1, 0x34, 0x91, 0x81, 0xF3, 0xFF, 0xED, 0x6D, 0x81, + 0xF9, 0x7D, 0xE3, 0x73, 0x37, 0xC1, 0x01, 0x12, 0x28, 0x9B, + 0xEA, 0xDA, 0x0E, 0x3D, 0x68, 0x16, 0x23, 0xE1, 0x68, 0xFF, + 0x1A, 0x59, 0xCC, 0x89, 0xF8, 0x44, 0x70, 0x13, 0xB2, 0x98, + 0xB1, 0x31, 0xEA, 0xEC, 0x65, 0x21, 0x36, 0xEF, 0xCC, 0x85, + 0x62, 0xC3, 0xEC, 0x62, 0xE9, 0x06, 0xEC, 0xB3, 0x47, 0x94, + 0xE5, 0xF2, 0x6F, 0xFD, 0x80, 0xEE, 0x70, 0xB0, 0x06, 0x56, + 0x8B, 0xF2, 0xDC, 0x7A, 0x52, 0x90, 0xC2, 0xE4, 0x77, 0xDD, + 0xF7, 0xC2, 0x0C, 0x9C, 0xBE, 0x5A, 0x0F, 0xC6, 0x45, 0xB1, + 0x3A, 0x63, 0x38, 0x2C, 0xD9, 0xC4, 0x45, 0x08, 0x44, 0x90, + 0xE2, 0xBC, 0xA2, 0x5A, 0xE6, 0x2E, 0xFD, 0xCB, 0x36, 0x7F, + 0xA9, 0xAC, 0x8C, 0x34, 0x1A, 0x3C, 0xE2, 0x9B, 0x24, 0x45, + 0xE3, 0x9C, 0xCF, 0xF9, 0x96, 0xFE, 0x58, 0xB5, 0x29, 0x20, + 0x0B, 0xC9, 0x5C, 0xAF, 0xCF, 0x7F, 0xCB, 0x8A, 0x14, 0xE1, + 0xCD, 0xF7, 0x5B, 0x93, 0xBC, 0x7D, 0x7A, 0x3B, 0xD2, 0xF2, + 0xFA, 0x2B, 0x57, 0x02, 0x9C, 0xAC, 0xA2, 0x16, 0x11, 0x2D, + 0xDB, 0x3D, 0x42, 0x26, 0x87, 0xBE, 0x9F, 0x8B, 0x7B, 0x00, + 0x20, 0x09, 0x41, 0x05, 0xB0, 0x42, 0x98, 0x44, 0xD6, 0xCC, + 0x08, 0xA2, 0x20, 0x1F, 0x2A, 0x59, 0xB3, 0x05, 0x4F, 0xB4, + 0xA6, 0xF8, 0xF8, 0xFD, 0x27, 0xBB, 0xC5, 0xC3, 0x52, 0x4D, + 0x63, 0x37, 0xCF, 0xAE, 0x4C, 0x60, 0x1E, 0x98, 0x26, 0x12, + 0x3D, 0xB9, 0xE6, 0x87, 0x09, 0x17, 0xB1, 0xE4, 0x81, 0x2C, + 0x8E, 0x73, 0xA1, 0x40, 0x53, 0x96, 0xD8, 0x17, 0x7F, 0x39, + 0xA8, 0x4F, 0xE9, 0xEF, 0x30, 0xE2, 0x5E, 0xEF, 0x9C, 0x13, + 0x70, 0x21, 0x14, 0xA3, 0x5D, 0xEA, 0x43, 0xFB, 0xA6, 0x80, + 0x70, 0xB9, 0x4B, 0x68, 0x9C, 0x5A, 0x82, 0x59, 0x00, 0xFA, + 0x5E, 0x4C, 0x4F, 0x76, 0xB1, 0xF4, 0x45, 0xCD, 0xE6, 0x18, + 0x09, 0xE2, 0x36, 0x8A, 0x60, 0x4B, 0xF4, 0x61, 0x55, 0xC4, + 0xE9, 0x69, 0xC1, 0x03, 0x9E, 0x9C, 0xAF, 0x1C, 0xE5, 0xD1, + 0xFF, 0x45, 0x16, 0x43, 0xD7, 0xE5, 0x4B, 0xCC, 0xEA, 0x24, + 0x2E, 0xCE, 0xE3, 0x90, 0x17, 0xDB, 0xC4, 0x57, 0x4D, 0xF9, + 0xCB, 0xEC, 0x09, 0x62, 0xBD, 0xD8, 0x7A, 0x89, 0x55, 0x92, + 0x90, 0x7B, 0x22, 0x20, 0xD9, 0x9A, 0xC9, 0x19, 0x02, 0x26, + 0xC0, 0x00, 0x02, 0x2E, 0xA2, 0xCF, 0xDE, 0xE3, 0xDE, 0xA9, + 0x10, 0x3D, 0xEB, 0xD9, 0x4B, 0x51, 0x68, 0x41, 0x57, 0xCD, + 0x7C, 0xF4, 0x28, 0x84, 0x22, 0x1C, 0xA7, 0xA6, 0x8A, 0xDD, + 0x97, 0x5B, 0x8A, 0x07, 0x01, 0x97, 0x13, 0x20, 0x06, 0x12, + 0xC9, 0xBB, 0x6D, 0x12, 0x25, 0x6D, 0x08, 0x13, 0x3C, 0x32, + 0x48, 0xFE, 0x49, 0xD9, 0xC1, 0x3E, 0x00, 0x1C, 0xD9, 0xF0, + 0xE2, 0xB3, 0xE0, 0x07, 0xE1, 0x8F, 0xDF, 0x75, 0xE0, 0xB9, + 0x61, 0x1A, 0xBF, 0xAF, 0x66, 0xE0, 0xAB, 0x8A, 0x4B, 0x71, + 0xCB, 0x4F, 0xB7, 0x4C, 0x30, 0xC8, 0xB0, 0xC4, 0xC0, 0x38, + 0x73, 0xDD, 0x3C, 0xDC, 0x5D, 0x81, 0x40, 0x14, 0x23, 0x9C, + 0xD2, 0x48, 0xF9, 0xCB, 0xC4, 0x1B, 0xD5, 0xC7, 0x85, 0xB0, + 0x57, 0xC1, 0xF5, 0x41, 0x7A, 0x2E, 0xC6, 0x03, 0x86, 0x8C, + 0x4E, 0xAF, 0x24, 0x21, 0xB9, 0x0B, 0xE9, 0x24, 0x12, 0x02, + 0x3E, 0x35, 0x7C, 0x1D, 0x9A, 0x2D, 0x5E, 0xB7, 0xEE, 0x08, + 0x34, 0x2C, 0x2B, 0xAD, 0x8D, 0x02, 0xF6, 0xFE, 0x06, 0x88, + 0xD0, 0xA5, 0xA2, 0x1E, 0x5B, 0xD2, 0x88, 0x09, 0x9F, 0x43, + 0xDF, 0xC4, 0x85, 0x59, 0x50, 0x7B, 0x94, 0xD9, 0xBB, 0xBE, + 0xF5, 0x1D, 0x60, 0xD0, 0x90, 0x6F, 0xD5, 0x1E, 0x49, 0xF1, + 0x76, 0x04, 0x96, 0xCA, 0x3F, 0x44, 0x64, 0xBE, 0x41, 0xE7, + 0x4A, 0x6E, 0xA8, 0x11, 0x14, 0x21, 0xEA, 0x9E, 0x43, 0x6D, + 0x2E, 0xF6, 0x49, 0x7A, 0x8C, 0xD6, 0xF1, 0x4A, 0xC3, 0x17, + 0x16, 0x23, 0x3B, 0x02, 0x6A, 0xA7, 0x90, 0x1D, 0x8C, 0xBF, + 0xB4, 0x25, 0xDA, 0xB6, 0x0F, 0x2A, 0x60, 0xF5, 0xC1, 0x7F, + 0xFA, 0x1D, 0x0B, 0xAF, 0x28, 0x8A, 0x00, 0x8A, 0xBE, 0xA8, + 0x72, 0x20, 0x5F, 0xEC, 0x3F, 0x16, 0x6E, 0xAB, 0xC4, 0xFC, + 0x6B, 0x75, 0xD7, 0xFB, 0x73, 0x60, 0x7E, 0x25, 0xE5, 0xA3, + 0x91, 0x6A, 0x33, 0xD3, 0x9E, 0xAC, 0xFB, 0x8C, 0xD1, 0xC6, + 0x63, 0xF4, 0x3F, 0xB7, 0xD1, 0xD3, 0x88, 0x90, 0x4C, 0xA2, + 0x7E, 0x6B, 0x19, 0x61, 0xCC, 0xAB, 0x48, 0xDD, 0x8D, 0xE2, + 0x1B, 0xB7, 0x9E, 0x2F, 0x58, 0x10, 0x78, 0xAC, 0x94, 0xF6, + 0xD6, 0x62, 0x4D, 0x66, 0x78, 0x67, 0x9F, 0x1B, 0x3A, 0x78, + 0x4E, 0xA0, 0xDB, 0x47, 0x92, 0xC4, 0x43, 0x1A, 0x22, 0xFC, + 0x26, 0x38, 0xA4, 0xF2, 0x7A, 0x52, 0x31, 0x71, 0x63, 0x16, + 0x58, 0xF5, 0xA4, 0x4A, 0xCA, 0x73, 0xD5, 0x90, 0x39, 0x55, + 0x8F, 0xB2, 0xC0, 0x3F, 0x3A, 0xEC, 0x69, 0xC4, 0x42, 0xCE, + 0xB9, 0x1B, 0xA4, 0x32, 0x52, 0x14, 0x7C, 0xBB, 0xF6, 0xB3, + 0x5A, 0x7C, 0xF1, 0x75, 0x1E, 0x4B, 0xB8, 0xB0, 0xB3, 0x8E, + 0x13, 0x63, 0x7B, 0xF5, 0xB9, 0x93, 0x22, 0x98, 0xDF, 0x6C, + 0xEC, 0x51, 0x4F, 0xC8, 0x0B, 0xA0, 0x14, 0x57, 0x75, 0x1B, + 0xF6, 0xE9, 0x5D, 0xC2, 0x47, 0x65, 0xDF, 0x79, 0x0D, 0x48, + 0xBE, 0x4F, 0x46, 0xF0, 0x37, 0xA5, 0x7C, 0xA3, 0x6B, 0x3E, + 0xE6, 0xA2, 0x0E, 0x69, 0xAF, 0x3C, 0x46, 0x8A, 0x77, 0xD2, + 0xBF, 0x2A, 0x16, 0x00, 0x17, 0x2F, 0x9C, 0x4E, 0xD8, 0xA8, + 0x48, 0xD4, 0xCC, 0x0C, 0x29, 0xD1, 0x7A, 0xAE, 0x81, 0x4F, + 0x04, 0x76, 0x53, 0xCF, 0x22, 0x76, 0x39, 0x61, 0xB6, 0x76, + 0x42, 0xE6, 0x4E, 0x71, 0xB3, 0x06, 0xB9, 0x31, 0x04, 0x60, + 0x88, 0x04, 0x02, 0x89, 0x72, 0x13, 0xD8, 0x8E, 0xD7, 0xE7, + 0x88, 0xCC, 0x3B, 0x88, 0x4A, 0xC7, 0x96, 0x58, 0x12, 0xDA, + 0x75, 0x15, 0xE2, 0x9A, 0xFA, 0x9E, 0x7C, 0x0E, 0xD6, 0x86, + 0x64, 0x7F, 0x31, 0xE3, 0x5C, 0xD8, 0xCF, 0xC0, 0x6D, 0x9B, + 0x1A, 0x1D, 0x8E, 0x90, 0xED, 0x8E, 0x7B, 0xFD, 0xAF, 0xE0, + 0x85, 0xE2, 0x51, 0x49, 0xAE, 0xE6, 0x03, 0x78, 0x41, 0xB9, + 0x05, 0xA0, 0xB8, 0x25, 0x03, 0x51, 0xD1, 0x93, 0x05, 0xE1, + 0xAA, 0x19, 0x0F, 0x1A, 0xF0, 0xD6, 0x18, 0xB6, 0x23, 0xFD, + 0xBC, 0x6E, 0x10, 0xA5, 0x18, 0xE9, 0x3B, 0xE5, 0xA4, 0x22, + 0x02, 0x26, 0xC0, 0x00, 0x02, 0x55, 0x43, 0x38, 0x66, 0x6B, + 0x96, 0x00, 0x6F, 0x33, 0xEE, 0x72, 0x7A, 0x9E, 0xD2, 0x5C, + 0x1F, 0x87, 0x4C, 0xFC, 0xE9, 0x3C, 0xAB, 0xC7, 0x5E, 0x55, + 0xD6, 0xEF, 0x78, 0xB1, 0x4D, 0xA7, 0x92, 0x3F, 0x57, 0x3B, + 0xF5, 0x7F, 0xE0, 0xD6, 0xE0, 0xD0, 0x8D, 0xE5, 0xE1, 0xAE, + 0x48, 0xC1, 0xF7, 0xF3, 0xC3, 0xA4, 0xF7, 0x8F, 0xE7, 0x6F, + 0xB2, 0xB1, 0xA5, 0x6F, 0x6A, 0xCF, 0x5F, 0x3C, 0xF2, 0x50, + 0x31, 0x19, 0x89, 0xF1, 0x74, 0x55, 0xA2, 0xFF, 0x7A, 0x5D, + 0xCB, 0x96, 0xED, 0xE4, 0xEA, 0x28, 0x4B, 0xF7, 0xE4, 0x45, + 0x7D, 0x99, 0xAF, 0xC5, 0xDB, 0xC1, 0x2D, 0xE8, 0xE9, 0xEA, + 0x2B, 0xAD, 0x7E, 0x8E, 0x96, 0x25, 0xA0, 0x9E, 0xDA, 0x31, + 0xE4, 0xCD, 0xC6, 0x8D, 0x69, 0x39, 0x04, 0x53, 0x1B, 0xCA, + 0xEF, 0x96, 0x8E, 0xEF, 0xFB, 0x4E, 0xC8, 0x11, 0x8E, 0x42, + 0x03, 0xC2, 0x96, 0x1A, 0x2C, 0xD8, 0xCF, 0x17, 0x05, 0x36, + 0xF7, 0x02, 0xAB, 0xBD, 0x1A, 0xF3, 0x51, 0xC0, 0xE2, 0x1E, + 0x0D, 0x8D, 0xE9, 0x81, 0x57, 0xD1, 0xA1, 0x9A, 0x2C, 0x7D, + 0x43, 0xBD, 0x23, 0x50, 0xA9, 0x3D, 0x77, 0xC1, 0x5F, 0x2D, + 0x3A, 0x61, 0x56, 0xE1, 0x47, 0xB4, 0x6C, 0xB1, 0xDF, 0xD7, + 0x1E, 0x95, 0x00, 0x02, 0x5B, 0xDA, 0xBD, 0x39, 0x2A, 0x06, + 0x98, 0x2B, 0x54, 0x63, 0xC9, 0xDB, 0x30, 0xF2, 0xB6, 0xB6, + 0xC8, 0x22, 0xAB, 0xB5, 0x68, 0xA3, 0xB7, 0x94, 0x6C, 0x97, + 0x5B, 0xC0, 0x6F, 0xA5, 0x11, 0xFD, 0x9A, 0x52, 0x5A, 0xB5, + 0x3D, 0xEA, 0xC3, 0x23, 0xD1, 0xA7, 0x31, 0xA1, 0xCE, 0xA8, + 0x4A, 0x7C, 0x5D, 0xF6, 0x21, 0xC1, 0x38, 0x73, 0xA3, 0x83, + 0x00, 0x28, 0x9D, 0x76, 0x5A, 0xC5, 0x63, 0xDB, 0x47, 0x25, + 0xAB, 0xD7, 0x25, 0xAE, 0x7D, 0x87, 0xF1, 0xA1, 0xE6, 0x9C, + 0x83, 0x33, 0x30, 0xE1, 0xAD, 0x65, 0xFD, 0x0F, 0xBB, 0xD0, + 0xEF, 0xF5, 0xC3, 0x19, 0x9B, 0x9D, 0x13, 0xBA, 0xEF, 0x9F, + 0x13, 0x2F, 0x76, 0x55, 0x2C, 0x2A, 0xC3, 0x8B, 0x40, 0x79, + 0x49, 0x02, 0x88, 0xE7, 0x4B, 0x57, 0xF5, 0xC5, 0x56, 0x30, + 0xF2, 0xB8, 0x2D, 0x83, 0x6F, 0xB6, 0xBF, 0xE2, 0x7E, 0xFF, + 0x18, 0x61, 0x11, 0x6B, 0x77, 0xCC, 0x04, 0x8B, 0xE4, 0x7C, + 0xF9, 0x48, 0x9C, 0xE0, 0x10, 0x7F, 0x68, 0xFE, 0x40, 0xF0, + 0x23, 0x5C, 0x13, 0x56, 0xD7, 0xCC, 0xDA, 0x83, 0xD6, 0x5C, + 0xB2, 0xED, 0x3F, 0x4C, 0x1E, 0x0A, 0x2F, 0x9D, 0xA2, 0x08, + 0x95, 0xB1, 0x80, 0xFB, 0x04, 0xAC, 0xED, 0x88, 0x01, 0xDC, + 0x69, 0xC7, 0x2D, 0xE8, 0xEB, 0xD1, 0xCE, 0x8E, 0x32, 0x04, + 0x0B, 0xA5, 0x1E, 0xFA, 0x47, 0xA2, 0x8F, 0xB6, 0xF4, 0xC8, + 0xFE, 0x81, 0xFC, 0x68, 0xFF, 0x82, 0x9A, 0x9A, 0xB6, 0x2C, + 0x58, 0x55, 0xEE, 0xFC, 0xBB, 0x23, 0x47, 0xA4, 0xEB, 0xF8, + 0x08, 0xB1, 0xF0, 0xAA, 0xE3, 0x7A, 0xDC, 0xEF, 0xD6, 0xB4, + 0x60, 0x39, 0x6F, 0x0F, 0x8A, 0x4C, 0x65, 0x48, 0x65, 0x78, + 0x6D, 0xF8, 0x44, 0x13, 0xA2, 0x9A, 0x76, 0xE8, 0xA7, 0x06, + 0x33, 0x54, 0x74, 0x73, 0xE4, 0x69, 0x66, 0x27, 0xA0, 0x66, + 0xA0, 0x5A, 0x9E, 0x26, 0xF2, 0xA4, 0x3C, 0xA6, 0xCF, 0x86, + 0x0F, 0x9D, 0x0A, 0x75, 0xC1, 0x9C, 0x34, 0xD1, 0x40, 0x21, + 0x64, 0x62, 0x7B, 0xBF, 0xAE, 0xCD, 0x44, 0x17, 0x6D, 0x5F, + 0x21, 0x02, 0x17, 0x1A, 0x2C, 0xA4, 0x18, 0x1D, 0x4F, 0x2E, + 0xC8, 0xE2, 0xCF, 0xAE, 0x25, 0x4A, 0xC4, 0xA2, 0x5A, 0x2E, + 0x10, 0x09, 0x69, 0xB2, 0xEA, 0xF9, 0xB9, 0x4C, 0x36, 0xA4, + 0xD6, 0xCB, 0x03, 0x6E, 0x7B, 0xC1, 0xA4, 0x28, 0x1A, 0x09, + 0xBF, 0xF1, 0xA1, 0x3F, 0x75, 0xB8, 0x5A, 0xF3, 0x9F, 0x12, + 0x35, 0x4B, 0x16, 0x21, 0x3B, 0x8D, 0xF9, 0x87, 0xCB, 0x8A, + 0xEC, 0x29, 0x1B, 0xF0, 0xB3, 0x96, 0x77, 0xB7, 0x7B, 0xA8, + 0x6A, 0x98, 0xE4, 0x8B, 0x61, 0xB6, 0x47, 0xD7, 0x92, 0xB4, + 0x0B, 0x47, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x4B, 0x86, 0xD9, + 0x89, 0x5B, 0x11, 0x29, 0x1D, 0x8E, 0x56, 0xC4, 0x4A, 0x0D, + 0xD4, 0x9F, 0x43, 0x9F, 0xA2, 0x55, 0x58, 0xE1, 0xF6, 0xF6, + 0x58, 0xFB, 0xCD, 0x3F, 0x06, 0x4C, 0xC2, 0x60, 0x6D, 0xB7, + 0xB2, 0xFF, 0xFE, 0x89, 0x77, 0x7A, 0x1E, 0xA0, 0xC8, 0xDD, + 0x7F, 0x3E, 0x6B, 0x38, 0x2F, 0x41, 0x2B, 0xDF, 0x42, 0x14, + 0x50, 0x28, 0xEE, 0xDE, 0x3F, 0xD8, 0xFF, 0x09, 0x43, 0x7A, + 0x22, 0x4F, 0xF3, 0xFC, 0x60, 0x7E, 0x2C, 0x1A, 0xB6, 0x9E, + 0x21, 0x40, 0x76, 0x3B, 0x42, 0xFC, 0xBC, 0x1D, 0x00, 0xA4, + 0x55, 0x95, 0x47, 0xBD, 0x6E, 0x31, 0xAB, 0x05, 0xAD, 0x38, + 0x53, 0xB0, 0x24, 0x83, 0x7D, 0x0E, 0xA8, 0x40, 0xE6, 0x33, + 0x6D, 0xEF, 0x72, 0x35, 0xCF, 0x3C, 0x11, 0x67, 0x1D, 0x28, + 0xEF, 0x7B, 0x7A, 0x7A, 0x0E, 0xD2, 0x7F, 0xBA, 0xEB, 0xA0, + 0x49, 0x46, 0x29, 0x40, 0x5B, 0x62, 0xA9, 0xED, 0xC9, 0xAC, + 0xDD, 0xAF, 0xE9, 0xAF, 0xF9, 0x75, 0x70, 0xC7, 0xAD, 0xB2, + 0xB6, 0x51, 0x08, 0x23, 0x89, 0x1F, 0xCC, 0xDE, 0xB7, 0x6B, + 0x25, 0xC4, 0x77, 0x90, 0x01, 0xBA, 0x80, 0x62, 0x3E, 0xFF, + 0x93, 0x00, 0x15, 0x43, 0x7D, 0xBE, 0x80, 0x83, 0xBB, 0xB0, + 0xAA, 0x3B, 0xF2, 0x0A, 0x9D, 0x86, 0x23, 0xA4, 0xB7, 0xB7, + 0x44, 0x30, 0xA7, 0x17, 0x66, 0x70, 0xEE, 0x2D, 0x1F, 0xDF, + 0xBD, 0xD9, 0x14, 0x3E, 0x55, 0xC6, 0xC9, 0x5B, 0xC3, 0xF2, + 0xE5, 0x10, 0xD5, 0x1A, 0x93, 0xF6, 0x76, 0xAB, 0x71, 0x87, + 0xDE, 0xD5, 0x51, 0x99, 0x37, 0x6F, 0xEE, 0xB1, 0x63, 0xDA, + 0x7F, 0x3B, 0xAC, 0x77, 0x1B, 0x4B, 0xA3, 0xE3, 0x77, 0x41, + 0xEA, 0x23, 0xF3, 0xB9, 0x22, 0x75, 0x07, 0x8E, 0x64, 0x3E, + 0x32, 0xA9, 0x28, 0xAA, 0x93, 0x8F, 0xE8, 0xDA, 0x60, 0xE9, + 0xD7, 0x35, 0x7F, 0xD7, 0x8F, 0xC8, 0xE5, 0x5B, 0x61, 0x47, + 0xD6, 0xD4, 0xA7, 0xFF, 0x25, 0x8F, 0x03, 0xC3, 0x03, 0x07, + 0xED, 0x30, 0x45, 0x86, 0x73, 0x1E, 0x8F, 0x2F, 0x3D, 0xB4, + 0xC0, 0x37, 0x7A, 0xE7, 0x80, 0xEA, 0xA0, 0xDB, 0x98, 0xAE, + 0xF9, 0x24, 0x0C, 0x74, 0x36, 0x54, 0x13, 0x34, 0x30, 0xCF, + 0x0E, 0xC8, 0x9D, 0x94, 0xE7, 0xAF, 0x6A, 0xC0, 0x32, 0x32, + 0xA3, 0xDE, 0x3A, 0x5B, 0x72, 0x72, 0xE3, 0x8F, 0x91, 0xC5, + 0x44, 0xAB, 0x86, 0x7B, 0xE0, 0x6C, 0x80, 0x84, 0x64, 0x1D, + 0xC0, 0xF1, 0x28, 0x7C, 0x6A, 0x35, 0x76, 0xCF, 0x12, 0x56, + 0x84, 0x1C, 0x21, 0x51, 0x33, 0x00, 0xFF, 0xB2, 0x64, 0x30, + 0x44, 0x1C, 0xA5, 0x05, 0x09, 0xE2, 0x14, 0x8E, 0xF3, 0xD8, + 0x91, 0x21, 0x60, 0xC0, 0x51, 0x68, 0x62, 0xF5, 0x7E, 0x06, + 0xD5, 0xC0, 0xEE, 0xB8, 0x91, 0xF1, 0x52, 0x14, 0x6C, 0x27, + 0xB6, 0x6A, 0x1C, 0x64, 0xBF, 0x59, 0x47, 0x64, 0x03, 0x8D, + 0x4E, 0xEB, 0xA3, 0x73, 0x10, 0xE2, 0xBC, 0xA0, 0x30, 0x29, + 0xE6, 0xF5, 0xED, 0x04, 0xCA, 0xAA, 0xC2, 0xBA, 0xDB, 0x8E, + 0xBC, 0x00, 0x34, 0x3D, 0xB6, 0x12, 0xCB, 0xAF, 0xC0, 0x3D, + 0x97, 0xF7, 0x5A, 0x1B, 0x83, 0x90, 0x91, 0xD0, 0xE2, 0xCF, + 0xE6, 0x21, 0x07, 0xCF, 0x2E, 0xFD, 0x71, 0xA1, 0x10, 0x18, + 0x67, 0x3F, 0x8F, 0xE2, 0x86, 0xFA, 0xA6, 0xDF, 0x6D, 0xE4, + 0x31, 0x7D, 0x75, 0x12, 0x99, 0x23, 0xC7, 0xFB, 0xF2, 0x04, + 0x76, 0x4C, 0x93, 0x9B, 0xB9, 0x89, 0x1D, 0x88, 0x5A, 0x0E, + 0xDE, 0x5A, 0x27, 0x35, 0x88, 0xE7, 0x80, 0x14, 0x87, 0xCA, + 0x23, 0xE6, 0xEF, 0xA8, 0xEA, 0x73, 0x7D, 0x93, 0x0C, 0x61, + 0x81, 0x2E, 0x10, 0xDF, 0x13, 0x57, 0x96, 0xD9, 0x36, 0x68, + 0x93, 0x42, 0x7A, 0x67, 0x60, 0x44, 0x57, 0xD8, 0x6C, 0x4B, + 0xD4, 0xCC, 0x7E, 0x70, 0xE2, 0xCD, 0xC7, 0x14, 0x4A, 0xDE, + 0x32, 0x35, 0x8B, 0x4B, 0x14, 0xE0, 0x8D, 0x5C, 0x33, 0x72, + 0xC9, 0x5D, 0x1F, 0xF6, 0xD7, 0xC3, 0xCF, 0x72, 0xA1, 0x2C, + 0x98, 0x2C, 0x0E, 0xEA, 0x02, 0x26, 0xC0, 0x00, 0x02, 0xEC, + 0xFC, 0x5D, 0x99, 0x61, 0x74, 0x77, 0x64, 0xF2, 0x70, 0x18, + 0x1A, 0x0B, 0x9F, 0x5A, 0x64, 0xE4, 0xCE, 0xA9, 0xCE, 0xCF, + 0x15, 0x35, 0x0E, 0x90, 0x95, 0xD1, 0x78, 0xBC, 0x36, 0xDD, + 0x32, 0xB0, 0x72, 0xCF, 0xCE, 0xFE, 0x8D, 0xAA, 0xF4, 0x19, + 0x73, 0x80, 0x37, 0xB6, 0x7B, 0x88, 0xB5, 0x7F, 0x5B, 0x7E, + 0xC7, 0x1F, 0x40, 0x5E, 0xCF, 0xC5, 0xE3, 0x75, 0x43, 0xCA, + 0x9D, 0x7C, 0xA1, 0x5D, 0x12, 0xBE, 0x30, 0x0E, 0x2C, 0x6D, + 0xE1, 0xD4, 0xD9, 0xC0, 0x90, 0x9F, 0x13, 0x6C, 0x00, 0x75, + 0xC9, 0x98, 0xE8, 0x4A, 0x1E, 0x43, 0x27, 0xB2, 0x3D, 0x16, + 0x5D, 0xF7, 0x18, 0xF6, 0xF2, 0x57, 0xA8, 0x54, 0x57, 0x50, + 0xFD, 0x98, 0x0F, 0x99, 0x63, 0x9E, 0x94, 0x71, 0x8B, 0x6B, + 0x6A, 0xAC, 0x27, 0x7A, 0xE5, 0xFE, 0x49, 0x5F, 0xA9, 0x3F, + 0x72, 0x32, 0xE5, 0x67, 0x87, 0xE9, 0xCC, 0xBC, 0x64, 0xE9, + 0x6B, 0x15, 0x06, 0x60, 0x32, 0x43, 0x49, 0x53, 0x47, 0xB2, + 0x56, 0xCE, 0xBF, 0x5F, 0x9B, 0x16, 0x40, 0x7D, 0x90, 0x0E, + 0xFB, 0xFE, 0x66, 0x58, 0xB3, 0xFC, 0x42, 0xB5, 0x90, 0xE6, + 0xCA, 0x6C, 0xD0, 0x3C, 0xA0, 0x2D, 0x84, 0x5E, 0xA0, 0xE7, + 0xD7, 0x8B, 0xB0, 0x42, 0x56, 0x3D, 0x48, 0xAF, 0x18, 0xEF, + 0xAF, 0x27, 0x76, 0xE3, 0x26, 0x0B, 0xCA, 0xA0, 0x01, 0x4B, + 0x79, 0xD1, 0xAC, 0xD5, 0x8B, 0xCD, 0x70, 0x9F, 0x6E, 0xFB, + 0x72, 0xBB, 0x9B, 0xDA, 0x4A, 0xFA, 0x96, 0x45, 0x29, 0x59, + 0x16, 0x4B, 0x57, 0xC1, 0x7B, 0x5D, 0x94, 0x5E, 0xDA, 0xC1, + 0x2B, 0x3C, 0xD9, 0xD5, 0x6B, 0x23, 0xE7, 0x53, 0x9C, 0xAA, + 0x89, 0x07, 0xFC, 0x66, 0xBC, 0xBC, 0xDD, 0x5D, 0xC7, 0xC0, + 0x46, 0xAF, 0xF6, 0xCB, 0xBB, 0xD3, 0x37, 0xC1, 0x7F, 0xCD, + 0xAE, 0x69, 0x1F, 0xCA, 0x20, 0x07, 0x76, 0x3F, 0xD0, 0x71, + 0x4F, 0x19, 0x6A, 0x92, 0xA2, 0xD8, 0x81, 0xE7, 0x84, 0xC3, + 0x24, 0x55, 0xF3, 0x1F, 0xA6, 0x8B, 0xAF, 0x11, 0xA6, 0xAC, + 0x9B, 0x2D, 0x12, 0xD0, 0x0D, 0xBC, 0x20, 0x26, 0x01, 0x76, + 0x39, 0xBF, 0xAB, 0x52, 0xD6, 0x93, 0x76, 0x29, 0x4C, 0xD8, + 0x8F, 0xBA, 0xA9, 0xA1, 0xCE, 0x09, 0xCC, 0xB7, 0xC5, 0x34, + 0xCC, 0xC1, 0x27, 0xE9, 0x47, 0xFB, 0x02, 0xC0, 0x0B, 0xB7, + 0xE2, 0x1B, 0x9A, 0x05, 0x32, 0x99, 0x7E, 0xEF, 0xDA, 0xC3, + 0xE2, 0xB3, 0x0D, 0x2F, 0xD7, 0x32, 0x14, 0xAA, 0x90, 0x00, + 0x5B, 0x8F, 0xA9, 0x6D, 0xBD, 0x54, 0xAF, 0xE2, 0x47, 0x8C, + 0x20, 0xD4, 0x14, 0x34, 0x13, 0x08, 0x17, 0x1B, 0xA2, 0x3B, + 0xDC, 0x6D, 0x5A, 0x08, 0x04, 0x58, 0x38, 0xAC, 0x84, 0xBB, + 0x22, 0x64, 0x6B, 0xE6, 0xB9, 0x46, 0x4A, 0xB6, 0x39, 0xD2, + 0xF4, 0x6D, 0x13, 0x63, 0x7F, 0x79, 0x6F, 0x54, 0x38, 0x72, + 0x1A, 0x3D, 0x45, 0x28, 0x14, 0x8F, 0x9D, 0xFE, 0x51, 0x02, + 0x3F, 0x0C, 0xFD, 0xE4, 0x7A, 0xC4, 0xFC, 0x00, 0xF0, 0xF6, + 0x7E, 0x98, 0x36, 0x40, 0x35, 0x92, 0x3A, 0x42, 0xBE, 0xA6, + 0xAE, 0x3C, 0x55, 0xF5, 0x4E, 0x41, 0xF4, 0x22, 0x63, 0x80, + 0x2E, 0xC9, 0x65, 0x73, 0x43, 0x2F, 0xE7, 0xF9, 0xC5, 0x5C, + 0x21, 0xDD, 0xF5, 0x15, 0x38, 0xE4, 0xDD, 0x92, 0x08, 0x9D, + 0x75, 0x65, 0x13, 0x28, 0xA5, 0xF9, 0x45, 0x13, 0xE0, 0x8F, + 0xB2, 0x36, 0x91, 0xAA, 0xBE, 0x87, 0xD2, 0x78, 0x3F, 0xB0, + 0xEE, 0x0C, 0x4C, 0x8C, 0xD7, 0x56, 0x85, 0x21, 0x43, 0x40, + 0xC4, 0x26, 0x90, 0xC2, 0x63, 0xF0, 0xC3, 0x49, 0xA0, 0xF0, + 0x2A, 0xCA, 0xA3, 0x9A, 0x39, 0xA6, 0xAA, 0x98, 0x2B, 0x8E, + 0xBA, 0x0B, 0xD9, 0x21, 0xC4, 0xC9, 0x97, 0x1B, 0x57, 0x80, + 0x49, 0x3E, 0xC4, 0x4B, 0xD8, 0x5E, 0xE2, 0x43, 0xC2, 0x13, + 0x8D, 0x51, 0x28, 0x8B, 0x30, 0x7C, 0x17, 0xB0, 0x58, 0x15, + 0x5F, 0x56, 0xF8, 0xF3, 0x8F, 0x9A, 0xC0, 0x9B, 0x27, 0x90, + 0x23, 0x48, 0xED, 0x5E, 0x50, 0xE2, 0x02, 0x26, 0xC0, 0x00, + 0x02, 0x02, 0xCA, 0xFA, 0x0D, 0x3A, 0xC4, 0xBF, 0x20, 0x04, + 0xD3, 0xA1, 0x4F, 0xED, 0x80, 0x40, 0x81, 0x15, 0x67, 0x0D, + 0x65, 0x3E, 0x52, 0x9C, 0x30, 0x20, 0xD2, 0xD8, 0xAC, 0xAF, + 0x06, 0xE5, 0xDA, 0x8B, 0x8B, 0x3A, 0xCA, 0xDC, 0x59, 0x8F, + 0x2F, 0x93, 0x53, 0x5B, 0xAC, 0xCE, 0x1F, 0xDF, 0x3B, 0x50, + 0xBF, 0x70, 0xF1, 0x7A, 0xCC, 0xA2, 0x25, 0x88, 0xD1, 0xA0, + 0xBC, 0x9D, 0x41, 0x1F, 0x9C, 0x0A, 0x95, 0x27, 0xE2, 0x71, + 0x4C, 0x1C, 0x14, 0xDB, 0xEA, 0xCD, 0xA3, 0x7C, 0x39, 0x57, + 0x69, 0x95, 0xA5, 0x04, 0x4F, 0xA3, 0xC0, 0x24, 0xC1, 0x5B, + 0x39, 0xF4, 0x9F, 0xBC, 0xB2, 0xC3, 0x37, 0x28, 0x1F, 0xFA, + 0xB9, 0xD7, 0xFF, 0x7A, 0xA2, 0x52, 0x03, 0x1F, 0x96, 0x5B, + 0xC4, 0x83, 0x08, 0x75, 0xFF, 0xF6, 0xF2, 0xF9, 0x7C, 0x1D, + 0x09, 0xB4, 0x3B, 0xAE, 0xCD, 0x2E, 0xF2, 0x6F, 0x2F, 0x4F, + 0xBC, 0x2B, 0x5B, 0x6D, 0x9A, 0x1B, 0xE6, 0x5E, 0xF5, 0xA8, + 0x93, 0x98, 0xDC, 0x6E, 0x5E, 0x17, 0xCA, 0xAB, 0x90, 0xFD, + 0xFB, 0x68, 0x1F, 0x67, 0x88, 0x58, 0x85, 0x4F, 0xAA, 0xC3, + 0x68, 0x40, 0xD5, 0xBC, 0xAC, 0x1D, 0x94, 0xC5, 0xB6, 0x01, + 0x2A, 0xE8, 0xBD, 0xDD, 0xBB, 0x17, 0x9D, 0x0E, 0x55, 0x62, + 0x45, 0xFB, 0x21, 0xB6, 0x71, 0x76, 0xEB, 0xCC, 0xF5, 0xE7, + 0xF1, 0xCD, 0xB7, 0xCA, 0xBD, 0xFF, 0xA9, 0xF7, 0x1A, 0xAA, + 0x1A, 0xCD, 0xC1, 0x71, 0x62, 0xE3, 0xDD, 0x09, 0x06, 0xAA, + 0x23, 0xFD, 0xEF, 0x6B, 0xA7, 0x83, 0xD8, 0xE6, 0x70, 0x01, + 0xF0, 0xEF, 0x69, 0xA9, 0x4B, 0x9B, 0x83, 0x57, 0x77, 0xAD, + 0x51, 0xBE, 0xBA, 0xF6, 0x2A, 0x6F, 0x1F, 0x97, 0x9A, 0xFE, + 0xA8, 0xE2, 0xAA, 0x20, 0x51, 0x95, 0xBA, 0xAE, 0x66, 0xB3, + 0xA8, 0x61, 0xCF, 0x8B, 0xFA, 0x6B, 0x48, 0xC4, 0x22, 0xE1, + 0xDF, 0x3A, 0x0D, 0xA9, 0x09, 0xF1, 0x66, 0x0C, 0x46, 0x74, + 0x90, 0x8B, 0x68, 0x00, 0x4F, 0x4F, 0x3A, 0x90, 0x58, 0x56, + 0xF4, 0x8A, 0x71, 0xB6, 0x1A, 0x91, 0x59, 0x17, 0x5C, 0xC0, + 0x87, 0x82, 0x7E, 0xB0, 0x81, 0x90, 0xF1, 0x6A, 0x03, 0xB8, + 0xA0, 0xAB, 0xDD, 0x63, 0x96, 0x48, 0x19, 0x37, 0x1F, 0x0F, + 0x24, 0x7A, 0x70, 0x48, 0x7D, 0x28, 0x1F, 0xB3, 0xCD, 0x76, + 0x53, 0x83, 0xC5, 0x53, 0xE8, 0xAB, 0x3A, 0xFC, 0x5B, 0x8A, + 0xF0, 0x5A, 0x0F, 0xEF, 0xFF, 0xB0, 0xC1, 0x61, 0x61, 0x58, + 0x4A, 0x8C, 0x1C, 0x20, 0xFC, 0x46, 0x07, 0x58, 0xF0, 0x20, + 0x81, 0x66, 0x28, 0x0E, 0xC2, 0x16, 0xAB, 0x98, 0xFF, 0x6E, + 0x24, 0xAC, 0x78, 0x42, 0xAE, 0x7D, 0xAB, 0x6F, 0xB4, 0x11, + 0x1C, 0x0C, 0x40, 0xF8, 0xF4, 0x93, 0x63, 0xE4, 0x6A, 0xEB, + 0xC5, 0xD9, 0x6E, 0x35, 0xC9, 0xA7, 0x2D, 0x49, 0xEA, 0x5D, + 0x69, 0x73, 0x06, 0x1C, 0xC4, 0x7E, 0x46, 0xFD, 0x09, 0x88, + 0x77, 0x77, 0xE7, 0xEB, 0x31, 0x34, 0x16, 0x72, 0x76, 0x1B, + 0x4E, 0xF8, 0x67, 0x9F, 0xCA, 0x1C, 0x67, 0x4E, 0xD8, 0x88, + 0xAA, 0x01, 0x27, 0x8E, 0x08, 0x70, 0xF8, 0x0B, 0x23, 0xF6, + 0x84, 0x47, 0x2F, 0x4E, 0x5F, 0xB7, 0x2C, 0x39, 0xBF, 0x61, + 0xEC, 0x6D, 0x24, 0x5C, 0x57, 0xBE, 0xAE, 0x19, 0x20, 0xBE, + 0x55, 0x40, 0x1D, 0xB7, 0x5F, 0xC3, 0xF6, 0x5B, 0x19, 0xC6, + 0x8A, 0x94, 0x23, 0x5C, 0x95, 0x33, 0x4C, 0x90, 0xE0, 0x46, + 0xAC, 0x0A, 0x1D, 0x50, 0xFB, 0x0A, 0xAB, 0xA2, 0xEB, 0x2A, + 0x21, 0xBF, 0x15, 0xD5, 0x9E, 0x80, 0x3B, 0x16, 0xB0, 0x3F, + 0x6F, 0x6F, 0xF6, 0xBE, 0x92, 0xA1, 0x2F, 0x83, 0xA8, 0x3C, + 0xA6, 0xE7, 0x86, 0xCD, 0x3B, 0x96, 0xCE, 0xF1, 0x36, 0x7C, + 0x69, 0xD9, 0xD5, 0x0F, 0xC1, 0x4C, 0x7A, 0xE5, 0xAF, 0xAC, + 0x86, 0x90, 0x98, 0x3D, 0x2B, 0x94, 0xA2, 0x7C, 0x5B, 0xF7, + 0x27, 0xCD, 0xE5, 0x93, 0x60, 0x2C, 0x47, 0xE3, 0xFA, 0x18, + 0xCB, 0xEB, 0xDB, 0x0A, 0x49, 0x99, 0x0F, 0xAE, 0x02, 0x26, + 0xC0, 0x00, 0x02, 0xF3, 0x51, 0xA3, 0x96, 0x54, 0xDA, 0xE9, + 0x09, 0x47, 0x82, 0x50, 0xB8, 0x82, 0x39, 0x98, 0x54, 0x81, + 0x54, 0x91, 0x2C, 0xE6, 0xBC, 0x84, 0x03, 0x07, 0x26, 0x6D, + 0x0F, 0x5E, 0x2B, 0x45, 0xF5, 0x1D, 0x7B, 0xD6, 0x14, 0x03, + 0xD7, 0x09, 0x64, 0xEE, 0x05, 0xBA, 0xE0, 0x74, 0x67, 0x02, + 0xF5, 0x7E, 0x42, 0x42, 0xEC, 0x56, 0xE0, 0x9E, 0x82, 0x88, + 0x58, 0x3C, 0x96, 0xAF, 0x37, 0x95, 0x49, 0xC8, 0x87, 0xBD, + 0xFE, 0x7A, 0x6B, 0x4D, 0x37, 0xEE, 0x7C, 0xAA, 0x18, 0x5F, + 0x7E, 0x0B, 0x28, 0xA3, 0x95, 0x23, 0x42, 0xAB, 0xC1, 0xFA, + 0x41, 0xAE, 0xD5, 0xBD, 0x67, 0xA6, 0xC4, 0x7C, 0xAC, 0x2D, + 0xEF, 0x64, 0xC2, 0x5D, 0x30, 0x94, 0xF3, 0x97, 0x49, 0x00, + 0x39, 0x28, 0x57, 0x5D, 0x31, 0xBB, 0x1D, 0x10, 0x17, 0xE7, + 0x56, 0x55, 0xDF, 0x4C, 0xDD, 0xA6, 0x64, 0x02, 0xBC, 0x1C, + 0x2B, 0x4C, 0x30, 0xBF, 0x89, 0x7C, 0xFC, 0x7E, 0x84, 0xBC, + 0x51, 0x97, 0x6C, 0x74, 0x5B, 0x08, 0xE0, 0x96, 0x84, 0x81, + 0xF3, 0x17, 0x6B, 0xD6, 0xF6, 0x66, 0x06, 0x1B, 0x33, 0x4D, + 0xF8, 0xED, 0xC0, 0x53, 0x8B, 0x35, 0x6B, 0x85, 0x4F, 0x37, + 0x0F, 0x87, 0xF3, 0x85, 0x72, 0xAE, 0xCB, 0x3A, 0x23, 0x97, + 0xC0, 0xF6, 0xE7, 0x53, 0xDF, 0x57, 0x0E, 0x8E, 0x0B, 0x66, + 0x2A, 0xA2, 0x9D, 0xA8, 0xE2, 0x60, 0x57, 0xCA, 0x27, 0x7E, + 0xB1, 0xDB, 0x7B, 0x6A, 0xB0, 0xBE, 0xB5, 0x47, 0xEE, 0xE6, + 0xBA, 0x0E, 0xB2, 0x71, 0x0B, 0xF7, 0xE4, 0x27, 0x9D, 0x25, + 0xAA, 0x3F, 0xA9, 0x1A, 0x5B, 0xD9, 0x9D, 0xBB, 0x20, 0x32, + 0x37, 0xE1, 0xD3, 0x4A, 0xBA, 0x45, 0x9E, 0x00, 0x10, 0x3F, + 0x21, 0x6E, 0xA2, 0xCE, 0x30, 0xA0, 0x2A, 0x5B, 0x31, 0x51, + 0x05, 0xA1, 0x51, 0xED, 0x89, 0x5E, 0xB1, 0x09, 0xE6, 0x71, + 0xD8, 0x42, 0xFD, 0xA1, 0x04, 0x83, 0xFB, 0x09, 0x4F, 0x90, + 0x4D, 0x7E, 0x5A, 0xB9, 0x4C, 0xC9, 0xA3, 0x57, 0x4E, 0x54, + 0x98, 0xB3, 0xBD, 0xB7, 0x52, 0x9D, 0xDE, 0xF3, 0xD3, 0xE0, + 0x9C, 0x2D, 0x97, 0x46, 0x1B, 0xF9, 0x75, 0x37, 0x5D, 0x0A, + 0xA3, 0x4A, 0x18, 0x35, 0x80, 0xC5, 0x08, 0xA8, 0x37, 0x09, + 0x44, 0x92, 0xB1, 0x74, 0xFE, 0x28, 0x95, 0x55, 0xB6, 0x08, + 0xA0, 0x75, 0xE9, 0xA0, 0x4B, 0x8E, 0xE6, 0x61, 0x17, 0x2A, + 0xED, 0x15, 0x0B, 0x6C, 0x7C, 0xC3, 0x82, 0x57, 0x90, 0xC5, + 0xFF, 0xD8, 0xA5, 0xBF, 0xAA, 0xBE, 0xCF, 0x8E, 0x06, 0xFF, + 0x27, 0xDA, 0x40, 0x24, 0xDD, 0xC0, 0xBE, 0x4E, 0x19, 0x9D, + 0x23, 0xA2, 0x3A, 0x70, 0x64, 0xEB, 0xF6, 0xA7, 0xE9, 0x71, + 0x57, 0xE9, 0x63, 0x03, 0xAE, 0xEC, 0x73, 0x21, 0x23, 0x8D, + 0x61, 0x5A, 0x10, 0x54, 0xF9, 0x80, 0xE7, 0x47, 0x45, 0xD4, + 0x8B, 0x16, 0xEE, 0x2B, 0xD8, 0xC1, 0xEE, 0x0F, 0x4F, 0x78, + 0x40, 0x00, 0xB6, 0x25, 0x81, 0x2A, 0x37, 0x4D, 0x71, 0x92, + 0xFA, 0x56, 0x3F, 0xDC, 0x91, 0x01, 0x27, 0xC7, 0x17, 0xFD, + 0x27, 0x55, 0x6F, 0x32, 0x14, 0xE7, 0xEA, 0x18, 0xDA, 0x4A, + 0x70, 0x10, 0xF8, 0x72, 0x78, 0xA1, 0xC1, 0x13, 0x5F, 0x1B, + 0x98, 0x93, 0xC2, 0xBF, 0x29, 0xA3, 0x59, 0x79, 0x15, 0x57, + 0x17, 0xE5, 0x66, 0x7A, 0x3B, 0x8E, 0xB3, 0x3B, 0x9E, 0xC0, + 0x77, 0xBD, 0x2D, 0x95, 0x26, 0xF0, 0xD5, 0xB4, 0x30, 0xC8, + 0x0D, 0xCA, 0xB5, 0xDE, 0xB2, 0x21, 0x27, 0x9A, 0x27, 0xAF, + 0x89, 0xB4, 0x0D, 0x1B, 0x5A, 0x43, 0x3E, 0x69, 0x76, 0x25, + 0xAC, 0x42, 0x23, 0x5F, 0x5A, 0xA6, 0xDB, 0xE6, 0x77, 0x9D, + 0x2A, 0x99, 0x1B, 0xE7, 0x47, 0x05, 0x06, 0x47, 0x01, 0x14, + 0x0D, 0xEA, 0xF5, 0x28, 0x3A, 0x5B, 0x87, 0xF0, 0xFB, 0x7C, + 0x96, 0x39, 0x6C, 0x4A, 0x48, 0xA5, 0x7A, 0x94, 0xB0, 0xB8, + 0xBB, 0x03, 0xDA, 0xEA, 0x4F, 0xD1, 0x5B, 0x8B, 0x9D, 0x0A, + 0x5E, 0xAB, 0xD8, 0x89, 0x5C, 0x4D, 0xD1, 0xA7, 0xC4, 0x8A, + 0x02, 0x26, 0xC0, 0x00, 0x02, 0x14, 0x04, 0xA6, 0x12, 0xC1, + 0x4E, 0x67, 0x67, 0x6C, 0xEE, 0x9E, 0x7A, 0x55, 0x00, 0xCB, + 0x12, 0x7B, 0x69, 0x4C, 0x94, 0x57, 0x73, 0x71, 0xC8, 0x45, + 0xAA, 0x04, 0x75, 0x85, 0xED, 0x68, 0x7D, 0x09, 0xD5, 0x4A, + 0xD0, 0x86, 0xDB, 0x0B, 0xC3, 0x80, 0xD1, 0x11, 0xB3, 0x59, + 0xCF, 0xBD, 0x13, 0x7B, 0xD2, 0x30, 0xDF, 0xDD, 0x41, 0xD7, + 0xBC, 0x34, 0x11, 0x85, 0x58, 0x2A, 0x8E, 0x2B, 0xDC, 0x00, + 0x78, 0x94, 0x28, 0x52, 0xD9, 0x0C, 0x70, 0xCB, 0x7D, 0xE9, + 0xCF, 0x7C, 0x11, 0x91, 0x09, 0xA8, 0xD7, 0xBC, 0xC8, 0xA1, + 0xDF, 0xF3, 0xB4, 0x25, 0x3A, 0x88, 0x02, 0xF0, 0xBE, 0x8E, + 0x89, 0x2B, 0xA6, 0x43, 0x88, 0xD0, 0xCC, 0x27, 0x91, 0x77, + 0x8D, 0x01, 0x32, 0xA6, 0x0C, 0x3D, 0x86, 0x76, 0x03, 0x4F, + 0x01, 0xF6, 0x02, 0xB3, 0xD0, 0x7A, 0x39, 0x78, 0x1E, 0xF2, + 0x35, 0xB6, 0xB3, 0xC9, 0x50, 0xE7, 0x0A, 0xD1, 0x3C, 0xB4, + 0xE2, 0x02, 0x60, 0x13, 0x8A, 0x0F, 0x15, 0xEE, 0x48, 0x67, + 0x84, 0x9E, 0x8E, 0x56, 0x22, 0xB9, 0x0A, 0xE2, 0x36, 0xDE, + 0x97, 0x4E, 0x9F, 0x0A, 0xE0, 0xB8, 0x2A, 0x0D, 0x07, 0x7F, + 0xCE, 0x76, 0xEA, 0x58, 0x54, 0xBC, 0x7A, 0xA1, 0x87, 0x15, + 0x3F, 0xCE, 0xDA, 0x58, 0xA4, 0x51, 0x36, 0x49, 0xB0, 0x23, + 0xC0, 0x55, 0xFB, 0xE2, 0x47, 0xB6, 0xD6, 0x31, 0x90, 0xA9, + 0x99, 0x2A, 0xC3, 0x59, 0xAE, 0x60, 0x03, 0xC2, 0x56, 0xC0, + 0x03, 0xA9, 0x3E, 0xF0, 0xE9, 0x59, 0x30, 0xD5, 0x90, 0x15, + 0x72, 0x32, 0x30, 0xD1, 0xFA, 0xDD, 0xB3, 0x09, 0xF0, 0x1A, + 0xA3, 0x6E, 0x5E, 0xBB, 0xDE, 0x58, 0x08, 0x91, 0xFB, 0xA0, + 0xEC, 0x45, 0x7F, 0x05, 0x90, 0x78, 0xCF, 0x6F, 0x66, 0xF4, + 0x2A, 0x79, 0x93, 0x33, 0x17, 0x07, 0x86, 0xE6, 0xEC, 0xFD, + 0xEC, 0x07, 0x74, 0x17, 0x26, 0x84, 0x52, 0x54, 0x9A, 0xBC, + 0xDE, 0xEE, 0xD7, 0xE9, 0x2F, 0xA7, 0x60, 0xA6, 0x54, 0x74, + 0xB9, 0x83, 0x6D, 0xE6, 0xB7, 0x46, 0xDC, 0xC8, 0x09, 0x36, + 0x25, 0x1E, 0x8B, 0x61, 0x94, 0x2D, 0xBA, 0xE2, 0xAB, 0xE6, + 0xD0, 0xDB, 0x9C, 0x13, 0x74, 0x25, 0xDA, 0xD7, 0x69, 0x69, + 0xFA, 0x52, 0x3C, 0x15, 0xBB, 0xFC, 0x5D, 0xE2, 0x6E, 0xA5, + 0x26, 0x35, 0x65, 0xF4, 0xE0, 0x29, 0x77, 0xCF, 0xAB, 0xF9, + 0xAB, 0x8C, 0x9D, 0x7D, 0x60, 0xA4, 0xA0, 0x3D, 0x43, 0xB6, + 0x9D, 0xAE, 0x04, 0x46, 0x8A, 0xE2, 0x3B, 0x4C, 0xC8, 0xA4, + 0x5D, 0x61, 0xB4, 0x5B, 0x8B, 0x2E, 0xD5, 0x2A, 0x07, 0x27, + 0x6A, 0x34, 0x04, 0xBA, 0xF8, 0x72, 0x32, 0x99, 0x97, 0x8C, + 0xC0, 0xCD, 0x35, 0x68, 0xB8, 0xA9, 0x45, 0x76, 0xA5, 0xD4, + 0x17, 0x36, 0xB1, 0x25, 0xF7, 0x47, 0x69, 0x30, 0x68, 0x14, + 0x0B, 0x9C, 0x38, 0xB1, 0x29, 0x16, 0x88, 0xAD, 0xDF, 0x31, + 0x7E, 0x3C, 0x5F, 0xA4, 0x0D, 0x86, 0x5A, 0x29, 0x37, 0xA9, + 0x1B, 0xD5, 0x68, 0x9F, 0xE0, 0xE6, 0x32, 0x42, 0x12, 0x37, + 0x99, 0xC5, 0xB8, 0xA1, 0xD3, 0x5B, 0x90, 0x9C, 0xAD, 0x86, + 0x6B, 0x03, 0x82, 0x91, 0xD9, 0xF9, 0xDC, 0xD5, 0x41, 0x7B, + 0xF3, 0xE4, 0x08, 0x92, 0xCA, 0x6A, 0xAA, 0xBD, 0xFE, 0x25, + 0x50, 0xDC, 0x2C, 0x00, 0x65, 0x59, 0x9B, 0xD3, 0x30, 0xD2, + 0x39, 0xC0, 0x4D, 0xFD, 0x8C, 0x9D, 0x88, 0xD3, 0x52, 0xD6, + 0xC0, 0xA0, 0x1C, 0x08, 0x0B, 0x1F, 0x91, 0xAF, 0x60, 0x56, + 0xED, 0x8B, 0x37, 0xD3, 0x15, 0x08, 0x5C, 0xEA, 0xFA, 0x03, + 0x0A, 0x54, 0x92, 0x96, 0x34, 0x4F, 0x14, 0x0E, 0xD5, 0xB4, + 0xA0, 0x2E, 0xC0, 0xEC, 0x93, 0x8F, 0xA5, 0xF3, 0x82, 0x5F, + 0x0D, 0xA8, 0xBD, 0x28, 0x4B, 0x1C, 0x65, 0xC1, 0x97, 0x5B, + 0xEE, 0x99, 0xC5, 0xC2, 0xB9, 0x34, 0x4D, 0xDB, 0x6E, 0x42, + 0x26, 0x93, 0x49, 0x83, 0x36, 0x25, 0x72, 0x03, 0x08, 0xE2, + 0xE6, 0x67, 0x01, 0xBC, 0x7A, 0x10, 0x7A, 0xBC, 0x6B, 0x0B, + 0x4A, 0x94, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x72, 0x08, 0xBA, + 0x77, 0xE2, 0x2F, 0x48, 0xD4, 0x9E, 0xC4, 0x23, 0x45, 0x55, + 0xF1, 0x0B, 0x1B, 0x50, 0x47, 0x8C, 0x40, 0x7C, 0xF7, 0xE4, + 0xCF, 0xD6, 0x0A, 0x0A, 0xD3, 0x7F, 0x35, 0x85, 0x84, 0x78, + 0xF2, 0x28, 0xEA, 0x14, 0x06, 0x2A, 0xC0, 0x53, 0x22, 0x45, + 0x9B, 0xDA, 0xE9, 0xEE, 0x98, 0x5D, 0xEC, 0xEC, 0xEF, 0xA1, + 0x1A, 0xDD, 0x7C, 0xE2, 0x29, 0xFF, 0x2B, 0x8A, 0x00, 0x49, + 0xD6, 0x2E, 0x7C, 0x50, 0x26, 0x29, 0x65, 0x97, 0xB4, 0xA8, + 0x6B, 0x38, 0x95, 0xC0, 0x7F, 0x41, 0xAD, 0xD5, 0xA2, 0x54, + 0x37, 0xE1, 0x72, 0x3A, 0x28, 0x58, 0xCA, 0x88, 0xB4, 0xF8, + 0x34, 0x43, 0xFF, 0xE4, 0xE4, 0xC2, 0x37, 0x0B, 0x72, 0x77, + 0x2B, 0x94, 0x8C, 0xB8, 0xCD, 0x72, 0x1E, 0xDB, 0x0A, 0xFA, + 0x86, 0x0E, 0xBC, 0x76, 0xDE, 0x89, 0x20, 0xBB, 0x1A, 0xC3, + 0x07, 0xAA, 0x0F, 0x0D, 0xED, 0x58, 0x42, 0x74, 0x44, 0xD0, + 0x89, 0x61, 0x25, 0xAF, 0xC0, 0x18, 0xFE, 0x16, 0xC9, 0x37, + 0x03, 0x11, 0x11, 0xEC, 0x9F, 0xFF, 0x2B, 0x00, 0x4F, 0x37, + 0xB6, 0xEC, 0x54, 0x0A, 0xA1, 0x68, 0xE5, 0x69, 0x38, 0xD5, + 0x55, 0x9E, 0x94, 0xAF, 0x3D, 0x67, 0xFF, 0x4D, 0x5D, 0x66, + 0x1D, 0xD0, 0x45, 0x1B, 0xF9, 0x23, 0x5F, 0xCF, 0x18, 0xFB, + 0x3F, 0x13, 0x0A, 0x2E, 0x86, 0xC4, 0x44, 0x28, 0xAB, 0x72, + 0x78, 0x77, 0x14, 0xCA, 0x70, 0xBF, 0x3E, 0x79, 0x47, 0xAB, + 0x3D, 0x22, 0xB9, 0x57, 0xB8, 0x04, 0x4B, 0x62, 0x2A, 0x26, + 0x4C, 0xEE, 0x80, 0xF4, 0x1C, 0x5C, 0xE3, 0xFF, 0x23, 0xC8, + 0x7C, 0x27, 0x90, 0xC8, 0x61, 0xC3, 0x7C, 0xC8, 0x5B, 0x46, + 0xB8, 0xCC, 0x8A, 0x67, 0xFC, 0xB9, 0xF1, 0xE7, 0x21, 0x68, + 0x47, 0x37, 0x9D, 0xEB, 0x14, 0xC4, 0x55, 0x02, 0x43, 0xA6, + 0xAA, 0x50, 0xE2, 0x78, 0x66, 0xE9, 0x55, 0x2D, 0x4C, 0x84, + 0xDF, 0x81, 0xCF, 0x0C, 0xD4, 0x36, 0xCA, 0x3D, 0xF7, 0xEE, + 0x2A, 0x5D, 0x10, 0xC9, 0xEA, 0x19, 0xF2, 0xF3, 0xBD, 0x42, + 0xA9, 0xE1, 0xA6, 0xD1, 0x84, 0xE9, 0x1A, 0x26, 0xDC, 0xBE, + 0x72, 0x43, 0xC7, 0x79, 0x92, 0xD9, 0x5F, 0x7C, 0x42, 0xCD, + 0xFF, 0x76, 0xBE, 0xB9, 0x99, 0x60, 0x6B, 0x5E, 0xAD, 0xAC, + 0x62, 0xAD, 0xFD, 0x58, 0x1C, 0x4E, 0xC6, 0x6D, 0xE7, 0xF9, + 0x2E, 0xD1, 0xEC, 0x9F, 0x98, 0xAE, 0x4F, 0xB6, 0xE1, 0xB3, + 0x77, 0xDD, 0xA4, 0x5D, 0x24, 0x76, 0xF0, 0xED, 0xBE, 0x19, + 0xB1, 0x98, 0x85, 0x08, 0xAB, 0xF0, 0x39, 0x94, 0x1D, 0x12, + 0xCA, 0x8B, 0xD2, 0xCC, 0x97, 0x44, 0xCB, 0x89, 0x9B, 0x66, + 0x50, 0x51, 0x64, 0x9E, 0xB1, 0x9E, 0x2C, 0xAA, 0xE5, 0x91, + 0x59, 0x53, 0xB1, 0x5E, 0xB3, 0xBB, 0x99, 0x00, 0x53, 0xA9, + 0xC1, 0x6C, 0x59, 0x46, 0xFD, 0xCB, 0x53, 0x83, 0xDD, 0x37, + 0xA1, 0xA3, 0x65, 0x26, 0xC6, 0x48, 0x6D, 0x15, 0xE8, 0xC1, + 0xE3, 0x45, 0x10, 0x6E, 0x8A, 0xE1, 0xDB, 0x10, 0xDB, 0x58, + 0x16, 0x5C, 0x31, 0x2E, 0x06, 0xA8, 0xAE, 0xD7, 0xB2, 0x11, + 0x55, 0x07, 0x2E, 0x57, 0x57, 0x02, 0x48, 0xC0, 0x8B, 0x59, + 0x8C, 0xBE, 0x1A, 0x47, 0x52, 0x3E, 0xD0, 0x05, 0xEA, 0xBC, + 0x86, 0xEA, 0x31, 0xD9, 0x58, 0x52, 0xCF, 0x7D, 0xD2, 0x30, + 0x4E, 0x0D, 0x24, 0x6F, 0x39, 0xF6, 0xEB, 0xC8, 0x5D, 0xE4, + 0xFF, 0x8D, 0xB9, 0x71, 0x02, 0x71, 0x67, 0x89, 0xFA, 0xB8, + 0x4F, 0xC9, 0x77, 0x78, 0x60, 0x36, 0xDF, 0x0E, 0x96, 0xAC, + 0x4F, 0x44, 0x8A, 0x2C, 0xE5, 0x8C, 0xC3, 0x96, 0x79, 0xE2, + 0x43, 0x75, 0xF5, 0x59, 0xC0, 0x81, 0x0A, 0x54, 0xC2, 0xA3, + 0x28, 0x8A, 0x32, 0xCE, 0x91, 0x5A, 0x91, 0x06, 0x45, 0xEB, + 0x34, 0x1A, 0x87, 0xF9, 0x57, 0x91, 0x0D, 0x34, 0x7F, 0x82, + 0x91, 0x82, 0xC5, 0x26, 0xCB, 0xB3, 0x4F, 0xF2, 0x20, 0x6A, + 0x02, 0x95, 0x73, 0x7B, 0x4F, 0x4E, 0xAF, 0x8A, 0x40, 0x83, + 0xFE, 0xF9, 0xD2, 0xFD, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x0E, + 0xA2, 0xA8, 0x59, 0xF0, 0x82, 0x17, 0x4C, 0x0E, 0xF3, 0x83, + 0xA1, 0xB6, 0x36, 0x83, 0xCB, 0xFB, 0xA2, 0x66, 0x53, 0x65, + 0x40, 0x40, 0xAA, 0x3D, 0x82, 0x62, 0x54, 0x0A, 0x27, 0x6A, + 0xD6, 0x07, 0xAF, 0x91, 0xCF, 0x9B, 0x89, 0x58, 0xBC, 0xCE, + 0x74, 0x87, 0x9C, 0x7E, 0x30, 0xF3, 0x06, 0x2B, 0xF1, 0xB4, + 0x70, 0x9D, 0xAA, 0x41, 0xD7, 0x25, 0x75, 0xE5, 0x72, 0x25, + 0x00, 0xC7, 0x21, 0x9D, 0xEE, 0xD1, 0x24, 0x16, 0x0B, 0x12, + 0x22, 0x88, 0xB8, 0x9D, 0xA5, 0x38, 0xA0, 0x50, 0x39, 0x27, + 0xAE, 0x10, 0xF6, 0x9A, 0x0B, 0x77, 0x56, 0x3F, 0x96, 0xDF, + 0x22, 0xE5, 0xEA, 0xAC, 0x8F, 0xDF, 0xDD, 0x78, 0xEF, 0x5A, + 0x7B, 0x50, 0x72, 0x98, 0x92, 0xDD, 0x94, 0xB5, 0xDB, 0x99, + 0xCE, 0xF2, 0x7A, 0xF3, 0xFA, 0x80, 0xD3, 0xCD, 0x1F, 0xCA, + 0xA2, 0x2E, 0x21, 0x94, 0xF2, 0xB3, 0x71, 0x7C, 0x07, 0xE6, + 0xB9, 0x68, 0x1E, 0x13, 0x02, 0x15, 0xC8, 0x34, 0xA0, 0xB5, + 0xD9, 0x95, 0x1A, 0x9B, 0x57, 0xE7, 0xAF, 0xB0, 0xE1, 0xA7, + 0x95, 0xF2, 0x36, 0xA3, 0xF9, 0xC5, 0x2C, 0xF0, 0xC3, 0xE1, + 0xD1, 0x26, 0xA1, 0x8F, 0xE6, 0x07, 0xFB, 0x1F, 0x03, 0xFF, + 0xA5, 0x81, 0xF5, 0x5D, 0x21, 0x3B, 0x93, 0x66, 0x1A, 0x78, + 0x6F, 0xD4, 0x77, 0xB3, 0x91, 0x26, 0x6F, 0x1F, 0x5A, 0x8B, + 0x0F, 0x07, 0xEA, 0x24, 0x5F, 0x5E, 0x68, 0x9F, 0x89, 0x75, + 0x00, 0x23, 0x1C, 0x80, 0x55, 0x86, 0x93, 0x58, 0x94, 0x41, + 0x37, 0x0D, 0x23, 0xD3, 0x09, 0x72, 0x40, 0x79, 0xA2, 0x52, + 0x0D, 0xA3, 0x40, 0x3F, 0x54, 0x7E, 0x59, 0x55, 0x5B, 0x7D, + 0x0C, 0x52, 0xAA, 0x97, 0x0C, 0xC6, 0xCB, 0x0B, 0x6C, 0x83, + 0x45, 0x28, 0x62, 0x09, 0x0A, 0x74, 0x27, 0x1D, 0x4D, 0x02, + 0x07, 0xB3, 0xA5, 0x83, 0x9A, 0x43, 0xB3, 0x68, 0xF7, 0x97, + 0x3E, 0xD7, 0x34, 0x04, 0x83, 0xC7, 0x6F, 0x64, 0xB8, 0x0B, + 0xB9, 0xE9, 0x94, 0x46, 0xB9, 0x4D, 0xA7, 0xB4, 0x26, 0xF7, + 0x9C, 0x05, 0x94, 0x8B, 0xBE, 0x93, 0x03, 0xA7, 0x73, 0x65, + 0xAB, 0xC5, 0xE1, 0x2B, 0x3B, 0x4C, 0x56, 0x1F, 0x11, 0x7B, + 0xD3, 0xC0, 0x77, 0x48, 0x42, 0x27, 0x8D, 0x2A, 0xAA, 0x1E, + 0x18, 0x41, 0x76, 0xA1, 0x80, 0x99, 0x52, 0x50, 0x66, 0x7B, + 0x27, 0x4B, 0x49, 0xA1, 0xE8, 0xCA, 0xF1, 0x3E, 0x60, 0x2E, + 0x93, 0xEF, 0x4A, 0x20, 0x3C, 0xC4, 0xBB, 0x14, 0xD3, 0x8F, + 0x14, 0xAF, 0xC0, 0xF8, 0x4B, 0xC6, 0x49, 0x1A, 0x3B, 0x17, + 0x43, 0xC2, 0xAB, 0xF0, 0x01, 0xFC, 0x6E, 0x67, 0x86, 0xAC, + 0xE4, 0x6F, 0xF2, 0x26, 0xF2, 0xEC, 0x15, 0xA1, 0x96, 0x81, + 0xDD, 0xCF, 0xCA, 0xB4, 0xE1, 0x5A, 0xA0, 0xF5, 0xBB, 0x70, + 0xEB, 0xF9, 0xA6, 0x28, 0x66, 0xC3, 0xBE, 0xB9, 0xBD, 0xDD, + 0xEF, 0x8E, 0x9E, 0x3C, 0x91, 0x50, 0x38, 0x61, 0x40, 0x25, + 0x4D, 0xCD, 0xA0, 0xAF, 0xFE, 0x57, 0xB8, 0x96, 0xDD, 0x2B, + 0x52, 0x29, 0x91, 0x7A, 0x31, 0xE8, 0x9A, 0xBB, 0xC9, 0x70, + 0x2B, 0xE1, 0x40, 0x3A, 0x9F, 0xB7, 0x31, 0xBE, 0xE5, 0x46, + 0xDA, 0x8A, 0xDE, 0x13, 0x22, 0x87, 0x70, 0xFE, 0x96, 0x40, + 0x9F, 0xC1, 0x2B, 0xFE, 0x83, 0x31, 0xE9, 0xA5, 0x4C, 0x37, + 0xEB, 0xFD, 0xFB, 0x2C, 0xBD, 0x0C, 0x1F, 0xB2, 0x62, 0x32, + 0x0E, 0x76, 0x9A, 0x2C, 0xC2, 0x84, 0x34, 0xA0, 0x6D, 0x72, + 0x21, 0x47, 0xF9, 0x3E, 0xC6, 0x5C, 0xEE, 0xB6, 0xE1, 0xD9, + 0x2E, 0xDF, 0x50, 0xD6, 0x2C, 0x9B, 0x44, 0xBE, 0xF0, 0x01, + 0x8E, 0xB4, 0x34, 0x38, 0x9C, 0x6C, 0x3E, 0x26, 0xB2, 0x4C, + 0x8E, 0xF0, 0x41, 0x2F, 0x07, 0x0E, 0xE9, 0x69, 0x1C, 0x0A, + 0x00, 0x05, 0xB0, 0x09, 0xA7, 0x07, 0x18, 0x41, 0xD1, 0xF7, + 0x22, 0xE4, 0x85, 0x64, 0xB7, 0x83, 0xF7, 0xB1, 0xE2, 0xAC, + 0x2E, 0xD9, 0x83, 0x81, 0x18, 0xCB, 0xBD, 0xEE, 0xD9, 0x09, + 0x99, 0xBA, 0x95, 0x66, 0x1F, 0xBA, 0x02, 0x26, 0xC0, 0x00, + 0x02, 0x67, 0x72, 0x24, 0xB5, 0xFE, 0x8C, 0x50, 0x84, 0x47, + 0x41, 0x6A, 0x29, 0x1F, 0x17, 0xB2, 0x9E, 0x02, 0x67, 0x70, + 0x55, 0x03, 0x3F, 0x8F, 0x07, 0x20, 0x91, 0x6B, 0x22, 0x7F, + 0x06, 0xC3, 0xC9, 0x0A, 0xB5, 0x07, 0x0D, 0x91, 0x5F, 0x87, + 0x6D, 0xE2, 0xEE, 0x2B, 0x01, 0xE7, 0x45, 0x3F, 0x89, 0x1C, + 0x8B, 0x12, 0x33, 0x23, 0x61, 0x64, 0x3F, 0x4B, 0xF1, 0x27, + 0x0E, 0x8B, 0x7B, 0x7E, 0x64, 0x2E, 0xDE, 0xE0, 0x3F, 0x3E, + 0x5C, 0xAE, 0x8C, 0x73, 0xB2, 0x8B, 0x62, 0x0F, 0xF9, 0xEB, + 0xF0, 0x74, 0xBD, 0xB9, 0xCC, 0x43, 0x80, 0xC3, 0x05, 0x31, + 0x53, 0x6F, 0x72, 0x42, 0x8E, 0x14, 0xAD, 0xF0, 0x45, 0x36, + 0x88, 0xE4, 0xF9, 0x0F, 0xD9, 0xCA, 0x1E, 0x82, 0xC2, 0x89, + 0x44, 0xC3, 0x69, 0xC6, 0xDD, 0x27, 0xB5, 0xCA, 0xCF, 0x56, + 0x23, 0x5D, 0x50, 0xF9, 0x69, 0x87, 0xCF, 0x4D, 0x2F, 0xA8, + 0xEE, 0xD4, 0x55, 0x2A, 0xC7, 0x3A, 0x2D, 0x03, 0xCD, 0x38, + 0xDE, 0x4F, 0x29, 0x91, 0x14, 0xAD, 0x39, 0x05, 0x77, 0x5F, + 0x41, 0x48, 0x30, 0x63, 0xE6, 0x81, 0x40, 0x68, 0x75, 0x8D, + 0xC5, 0x70, 0x2D, 0xC9, 0xB9, 0x10, 0x75, 0xF3, 0x28, 0x91, + 0x99, 0x97, 0x16, 0x2E, 0x7C, 0xAD, 0x50, 0x80, 0x40, 0x00, + 0xEE, 0x8F, 0x59, 0xA1, 0x8F, 0x82, 0xDE, 0x1E, 0xDB, 0x56, + 0xA1, 0xD6, 0x2E, 0x06, 0x9D, 0x42, 0xCF, 0xA0, 0xB7, 0x1F, + 0x37, 0x22, 0x02, 0x2E, 0x33, 0xAE, 0xE4, 0x7B, 0x7C, 0xC6, + 0x11, 0x5E, 0xF6, 0xA5, 0x5B, 0x54, 0x8B, 0x28, 0x54, 0x01, + 0x4C, 0x41, 0x49, 0x8E, 0xAD, 0x22, 0xBB, 0x67, 0x7A, 0xF3, + 0xEC, 0xE3, 0x93, 0xE4, 0x3A, 0x71, 0xB2, 0x82, 0xC4, 0x8A, + 0x7B, 0x99, 0xA7, 0x6B, 0x69, 0x28, 0xE3, 0xC5, 0x89, 0xF7, + 0x3E, 0xF3, 0xC5, 0xB2, 0x40, 0x91, 0xF8, 0x6A, 0xE3, 0x63, + 0xB1, 0x5C, 0xE3, 0x79, 0xFF, 0x41, 0xE8, 0x2F, 0xCA, 0x11, + 0xA2, 0xED, 0x86, 0x59, 0x53, 0x9D, 0xF9, 0xE1, 0x15, 0x5D, + 0x38, 0x32, 0x69, 0x60, 0x45, 0x20, 0x74, 0xF5, 0xF6, 0x24, + 0xA2, 0x4E, 0xAE, 0xB5, 0x2F, 0xE2, 0xEE, 0xBD, 0xD3, 0x27, + 0xE1, 0x90, 0x89, 0x89, 0xA3, 0x7E, 0x2B, 0x73, 0x63, 0xB8, + 0x36, 0xFA, 0x17, 0x0C, 0x8F, 0x0F, 0xE8, 0xBE, 0xDC, 0x8D, + 0x52, 0x34, 0xB3, 0x52, 0x0E, 0xB1, 0x97, 0x8D, 0x69, 0xC8, + 0x27, 0x2E, 0xBC, 0xFC, 0xDB, 0x6C, 0x98, 0xE8, 0x50, 0xF1, + 0x7A, 0x14, 0xE7, 0xA4, 0x11, 0xD2, 0xDA, 0x71, 0xCB, 0x77, + 0x88, 0x7B, 0xEE, 0x24, 0x52, 0xF4, 0x83, 0x2F, 0x1B, 0x25, + 0x73, 0x7D, 0x57, 0xAE, 0x78, 0x42, 0xC7, 0x7F, 0x84, 0xDB, + 0x67, 0x7A, 0x81, 0xAB, 0xB5, 0xC4, 0x41, 0x38, 0xA0, 0x8D, + 0x8C, 0x50, 0x1F, 0x56, 0xF6, 0x9A, 0x2B, 0x57, 0x89, 0x20, + 0xA9, 0xE9, 0x1E, 0x55, 0x22, 0xD7, 0x88, 0xFA, 0x5D, 0x5F, + 0x51, 0x5C, 0x7C, 0x17, 0x6E, 0x1D, 0x1A, 0xE3, 0xE6, 0x24, + 0x67, 0xFE, 0xAA, 0xEF, 0x28, 0x25, 0xCA, 0xD7, 0x9B, 0x44, + 0x3A, 0x55, 0x6B, 0x2E, 0xDE, 0x7D, 0xD0, 0x1E, 0x16, 0xD6, + 0xA5, 0xA6, 0x97, 0xE0, 0x35, 0x90, 0x13, 0xD4, 0x16, 0x53, + 0xA2, 0x66, 0xCB, 0x12, 0xEE, 0xED, 0xA1, 0x42, 0x2C, 0x6A, + 0xF5, 0x13, 0x63, 0x5B, 0x2A, 0x0C, 0x8C, 0x3A, 0xC4, 0xAA, + 0x77, 0xFD, 0x03, 0x29, 0x47, 0x2E, 0x4E, 0xCE, 0x26, 0x2E, + 0xE2, 0x87, 0xD5, 0x49, 0xBE, 0xCE, 0x07, 0x71, 0x8F, 0xBB, + 0xDF, 0x5E, 0x73, 0x17, 0x28, 0x1B, 0x34, 0x55, 0xA2, 0xB1, + 0x99, 0x72, 0x90, 0xFD, 0xDF, 0xB3, 0xC7, 0x63, 0xFE, 0x1B, + 0x75, 0x6B, 0x6D, 0x73, 0xDE, 0x21, 0xD0, 0x18, 0xBE, 0x87, + 0xE8, 0xDA, 0x74, 0x1E, 0x78, 0x65, 0x6D, 0x30, 0x3B, 0xF1, + 0xEF, 0xE3, 0x32, 0xD6, 0xF8, 0x77, 0x31, 0xAB, 0x72, 0x72, + 0xF1, 0x43, 0x5C, 0x9F, 0xF1, 0x99, 0xA9, 0xB7, 0xD6, 0xEA, + 0x12, 0x4C, 0x96, 0x7E, 0x87, 0x76, 0xD2, 0xAB, 0x02, 0x26, + 0xC0, 0x00, 0x02, 0x91, 0x0F, 0xB9, 0x72, 0xF7, 0x06, 0x0A, + 0x2A, 0x92, 0x77, 0x84, 0x0C, 0xBE, 0x44, 0x6D, 0x58, 0x6C, + 0xBC, 0xE0, 0x19, 0x8A, 0xFC, 0x4C, 0x93, 0xDD, 0xB7, 0xC5, + 0x45, 0xBF, 0x0A, 0x66, 0x29, 0xEF, 0x95, 0x78, 0x07, 0x6D, + 0xD0, 0xAA, 0x6C, 0x32, 0xE9, 0xF8, 0xEA, 0x1A, 0x74, 0x79, + 0x51, 0x39, 0x25, 0xCB, 0x00, 0x7C, 0xD0, 0xE7, 0xBB, 0xC4, + 0x09, 0xC2, 0xFC, 0x0F, 0xA2, 0x29, 0x45, 0x30, 0x3F, 0x89, + 0x76, 0x36, 0xF2, 0x92, 0xAF, 0xAF, 0x60, 0xC3, 0x93, 0x3E, + 0x55, 0x6B, 0x87, 0xAE, 0xBF, 0x6E, 0x2C, 0x54, 0xFD, 0xAF, + 0x74, 0x4F, 0x0F, 0xAA, 0xC7, 0x4F, 0x4C, 0x6B, 0x18, 0xFE, + 0xC6, 0x84, 0x27, 0xC0, 0x78, 0xD2, 0xD9, 0xE3, 0x7B, 0x41, + 0x1C, 0x1C, 0xBF, 0xDA, 0xDF, 0xCC, 0x49, 0x41, 0xC0, 0xC0, + 0x65, 0xE0, 0x8F, 0x44, 0x19, 0xE4, 0x78, 0xAD, 0xCD, 0xC5, + 0x5A, 0x9D, 0x11, 0x22, 0x43, 0xD7, 0x6E, 0x39, 0xD5, 0x2B, + 0xA7, 0x73, 0x3F, 0x99, 0xA8, 0xA3, 0x02, 0x73, 0x99, 0xF0, + 0x62, 0x87, 0xF4, 0x8B, 0xD7, 0x4F, 0x47, 0x9C, 0x18, 0x72, + 0x98, 0xB0, 0x33, 0x1B, 0x5E, 0x29, 0x04, 0xEA, 0x71, 0x6B, + 0x45, 0xCB, 0xC0, 0x9E, 0x15, 0x6E, 0x92, 0xDA, 0x50, 0xC3, + 0x58, 0x07, 0x29, 0x5E, 0xC5, 0xBD, 0x3B, 0xCE, 0xAC, 0x11, + 0xE5, 0xBB, 0x3D, 0x7E, 0xB8, 0xC3, 0x1F, 0x94, 0x9F, 0xD9, + 0x63, 0x35, 0x56, 0x23, 0x45, 0xAF, 0x23, 0xF0, 0x0B, 0x7B, + 0xE3, 0xFB, 0x81, 0x2E, 0xD3, 0x20, 0xE3, 0x1D, 0x97, 0x84, + 0xC1, 0x88, 0x77, 0x87, 0x3C, 0xAB, 0xE9, 0x1E, 0x69, 0x04, + 0x7D, 0x7B, 0xE6, 0x6B, 0xDB, 0xE9, 0xF2, 0xB6, 0x66, 0x10, + 0x0F, 0x4D, 0x57, 0x3F, 0xF5, 0x3E, 0xDA, 0xEA, 0xBC, 0xD4, + 0x5B, 0xA1, 0x20, 0xB0, 0x69, 0xC0, 0x8A, 0xA1, 0x28, 0xC0, + 0xEF, 0xFE, 0x2D, 0x0B, 0xF8, 0x06, 0x23, 0x4B, 0x1C, 0x77, + 0x0A, 0x10, 0xBF, 0xA7, 0xD9, 0x24, 0x9E, 0xA2, 0x1B, 0x90, + 0x6C, 0xFD, 0x85, 0x3A, 0xD3, 0xC6, 0x39, 0xA7, 0xA2, 0x28, + 0xC5, 0xC1, 0x2F, 0xD2, 0x28, 0xDC, 0x4F, 0x63, 0x0D, 0x6B, + 0x54, 0xB4, 0x27, 0x95, 0xC3, 0xC1, 0xE0, 0x08, 0xB0, 0x9D, + 0x7F, 0x6C, 0xFE, 0xF5, 0x65, 0xCE, 0x0E, 0xCE, 0x24, 0xCD, + 0xAE, 0x4C, 0x0F, 0x82, 0x54, 0x48, 0xAF, 0x37, 0xAE, 0x64, + 0x31, 0x07, 0xEE, 0xE6, 0x6B, 0xEF, 0xAF, 0x7F, 0x2A, 0x07, + 0x2E, 0xB6, 0xD0, 0xAC, 0x70, 0x87, 0x19, 0x9E, 0xD3, 0xFB, + 0x89, 0xBD, 0xBA, 0xFF, 0xB9, 0x92, 0x4B, 0x25, 0x65, 0xA3, + 0x09, 0xCD, 0xFE, 0x32, 0x19, 0xF3, 0xF4, 0x05, 0xA4, 0x13, + 0xDF, 0x65, 0xA3, 0x4C, 0xE8, 0xF3, 0x3C, 0xA3, 0x11, 0x95, + 0xEA, 0xC3, 0x34, 0xCA, 0xC6, 0xB9, 0x34, 0x6B, 0x53, 0x18, + 0xCC, 0xF9, 0x44, 0x28, 0x1E, 0x90, 0x74, 0xA6, 0xB1, 0x59, + 0x4D, 0xAE, 0x18, 0x53, 0x1D, 0x60, 0xCF, 0xCC, 0x15, 0xDA, + 0x4E, 0x2B, 0x6F, 0x8F, 0x4E, 0x39, 0x89, 0xE3, 0x67, 0x05, + 0xB5, 0x9C, 0x36, 0x5B, 0x3C, 0xA0, 0x9F, 0x46, 0x24, 0xE7, + 0x61, 0x42, 0x1C, 0xA7, 0xD7, 0x27, 0x5B, 0x5C, 0xF5, 0xFD, + 0x5F, 0x03, 0x79, 0x5F, 0x36, 0xA0, 0x85, 0x13, 0x40, 0x48, + 0x8C, 0x44, 0xB4, 0x64, 0x54, 0x83, 0xD8, 0xB6, 0x83, 0xB8, + 0x4E, 0x46, 0xCF, 0x98, 0xA5, 0x1C, 0xAA, 0xF0, 0x03, 0xD6, + 0x26, 0x80, 0x0F, 0x2A, 0xC5, 0xF4, 0xD1, 0x28, 0x0C, 0x5F, + 0xF8, 0x63, 0x8D, 0x68, 0x26, 0x3A, 0xE5, 0x5D, 0xAE, 0x17, + 0x64, 0xF2, 0x60, 0x73, 0x6D, 0xBD, 0x75, 0x90, 0xD2, 0x50, + 0xC4, 0x9A, 0x4C, 0x3E, 0x4B, 0xAE, 0x57, 0xBE, 0xCD, 0x42, + 0xC1, 0xA7, 0xCB, 0xAD, 0x73, 0x15, 0xF6, 0x69, 0x36, 0xB5, + 0xC3, 0x15, 0x1D, 0xC0, 0x09, 0x4B, 0x6B, 0x4F, 0xA3, 0xD2, + 0xAF, 0x9E, 0xF4, 0x9A, 0xC1, 0x5F, 0xF5, 0x0A, 0x95, 0x93, + 0xA4, 0x57, 0xA9, 0x61, 0x8D, 0x98, 0xB1, 0x19, 0xCC, 0x95, + 0x02, 0x26, 0xC0, 0x00, 0x02, 0x6E, 0x4C, 0x0F, 0xB4, 0x2D, + 0xBC, 0x3A, 0x51, 0xAE, 0x16, 0xBA, 0xEC, 0x72, 0x04, 0x3E, + 0x8D, 0x3D, 0x4E, 0x0E, 0x29, 0x4B, 0x6F, 0x00, 0xF5, 0xE2, + 0x12, 0x0B, 0xAC, 0x73, 0x7E, 0xA5, 0x12, 0x8D, 0x59, 0x45, + 0x73, 0xC8, 0xB9, 0x57, 0xCB, 0x78, 0xAD, 0xA3, 0xBD, 0x95, + 0x18, 0x04, 0x86, 0xB9, 0xFE, 0x9F, 0xBF, 0x67, 0x03, 0x08, + 0xA9, 0x91, 0xF3, 0x71, 0x1A, 0x6C, 0xD2, 0x74, 0xAA, 0x40, + 0xCC, 0x30, 0x7D, 0x0B, 0x78, 0xEF, 0xC7, 0xDC, 0x95, 0xC3, + 0x29, 0x5D, 0x18, 0xBC, 0x38, 0x7C, 0xFE, 0x65, 0xEF, 0x44, + 0xF0, 0x61, 0x91, 0x3E, 0x59, 0x75, 0x96, 0x84, 0x75, 0xD9, + 0xA2, 0x99, 0xDB, 0xFA, 0x9B, 0x7D, 0x09, 0x06, 0x8D, 0xDA, + 0xCC, 0xA1, 0x6E, 0x2E, 0xDB, 0x12, 0x83, 0xA6, 0x2E, 0x9C, + 0xC8, 0x5A, 0xE9, 0xBB, 0xC3, 0x70, 0x16, 0x0C, 0x6E, 0x2A, + 0xDA, 0xD0, 0xDF, 0xF4, 0xAF, 0xAA, 0x42, 0x0A, 0x16, 0x8C, + 0x73, 0xAA, 0xAD, 0x75, 0x7B, 0xCC, 0x29, 0xB5, 0x18, 0xB9, + 0x58, 0xBF, 0xDB, 0x91, 0x44, 0x74, 0x25, 0x3E, 0x54, 0xC3, + 0x2D, 0x8A, 0x2E, 0x85, 0xD0, 0x92, 0x02, 0xAE, 0xA1, 0xF9, + 0x70, 0xC5, 0x33, 0x49, 0x57, 0xE1, 0x90, 0x48, 0x54, 0x73, + 0x04, 0xAD, 0x1E, 0x41, 0xE8, 0xD7, 0x24, 0xFE, 0x85, 0x83, + 0x47, 0x0F, 0x9C, 0x33, 0xF9, 0xF5, 0x10, 0xAD, 0x42, 0xFA, + 0x7B, 0xE7, 0x1C, 0x35, 0xB3, 0x8D, 0x0E, 0x2E, 0xD7, 0xCB, + 0x40, 0x32, 0x9C, 0x64, 0x3A, 0x68, 0x33, 0xF3, 0xBE, 0xD9, + 0xCD, 0xC9, 0x73, 0xEB, 0x67, 0x6E, 0x52, 0x25, 0x2F, 0xD9, + 0x7A, 0x93, 0x8B, 0x1D, 0x9D, 0xB2, 0xAF, 0xF3, 0xEE, 0x6F, + 0xB5, 0xC7, 0x8F, 0xD5, 0x4F, 0xC9, 0x7C, 0xAC, 0x05, 0x9A, + 0x16, 0x82, 0x04, 0xC4, 0xF5, 0x47, 0xD7, 0x61, 0xC7, 0xBC, + 0x8D, 0x76, 0xA9, 0xFA, 0xA6, 0x17, 0x32, 0x3A, 0x2C, 0x93, + 0x4D, 0x0B, 0x57, 0x50, 0xF5, 0xD8, 0xE6, 0xB2, 0x52, 0x4F, + 0xE5, 0x1F, 0xDB, 0xA0, 0x17, 0xEF, 0x44, 0x9A, 0x8D, 0xBF, + 0x8D, 0xB4, 0x66, 0x11, 0xF2, 0xB1, 0x51, 0x50, 0xB4, 0xDE, + 0xE0, 0x30, 0x5B, 0x1F, 0x92, 0xAC, 0x30, 0x43, 0xB3, 0x1F, + 0x32, 0xDC, 0x84, 0x2F, 0x29, 0xE9, 0x78, 0xBC, 0x5A, 0xA2, + 0x9A, 0xA8, 0xFC, 0xE2, 0xB4, 0xE7, 0x8C, 0xCC, 0x65, 0xA9, + 0x37, 0x85, 0xD8, 0x0B, 0xB3, 0xA3, 0x4F, 0x28, 0xBE, 0x4D, + 0x45, 0x97, 0xAA, 0x2E, 0xEC, 0x6D, 0x4C, 0x9E, 0x19, 0x5F, + 0xD1, 0x47, 0x87, 0x8A, 0x76, 0xCF, 0x20, 0xCC, 0xDC, 0xC5, + 0x37, 0xDD, 0x45, 0xE8, 0x13, 0xFD, 0x72, 0x92, 0x7E, 0x97, + 0xA4, 0xA7, 0x58, 0xC1, 0x0E, 0xB6, 0x9E, 0x20, 0xCC, 0xD3, + 0x5F, 0x94, 0x25, 0xD3, 0xB8, 0xB0, 0x51, 0x82, 0x45, 0x64, + 0x4B, 0x6D, 0xCB, 0x9F, 0xC6, 0x5F, 0xDD, 0x1D, 0x1B, 0xB0, + 0x7D, 0xEB, 0xEC, 0x85, 0xB0, 0x90, 0x36, 0xE0, 0xE5, 0x5F, + 0x66, 0xA3, 0x69, 0x72, 0x2C, 0x35, 0x52, 0x45, 0x8A, 0xD9, + 0x31, 0xCB, 0xD9, 0xDD, 0xF0, 0x62, 0x6A, 0x4B, 0x47, 0xEF, + 0x13, 0xD7, 0x65, 0x17, 0xC4, 0xE9, 0xD1, 0xA3, 0xF4, 0x5E, + 0x17, 0x73, 0x4C, 0xA5, 0x81, 0xD7, 0xBD, 0xB3, 0x34, 0x98, + 0x61, 0x01, 0x50, 0x1D, 0x7D, 0x7A, 0x82, 0x38, 0x93, 0x9F, + 0x0A, 0xAC, 0x42, 0x5B, 0x10, 0x4C, 0x57, 0x10, 0x4A, 0x97, + 0xD3, 0xCC, 0x8F, 0x23, 0xD1, 0xA6, 0xCB, 0xAD, 0x47, 0x8F, + 0x41, 0x24, 0x2B, 0xEB, 0xB9, 0x0B, 0x71, 0x1C, 0x27, 0x31, + 0x91, 0x21, 0x77, 0xA2, 0x01, 0x2D, 0x6F, 0x9B, 0x99, 0x5F, + 0xAC, 0xD4, 0x8E, 0x1D, 0xBB, 0x2C, 0xA3, 0xA1, 0xA2, 0xC3, + 0x2A, 0xAD, 0x6B, 0xA4, 0x62, 0xAA, 0xAE, 0xEA, 0xEE, 0x10, + 0x30, 0xB3, 0x9E, 0x2A, 0x13, 0x09, 0xF8, 0xC4, 0x2B, 0x8C, + 0xE1, 0x51, 0x62, 0xE7, 0x5D, 0xE8, 0x00, 0x50, 0x46, 0x7E, + 0xC7, 0x9A, 0x3F, 0x21, 0xD9, 0x0C, 0xB3, 0xA7, 0x2E, 0x5F, + 0x4B, 0x42, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x12, 0xA7, 0x07, + 0x49, 0x33, 0x98, 0x05, 0x3D, 0xD0, 0x14, 0xD2, 0x03, 0xA9, + 0xA5, 0x66, 0x6B, 0x53, 0x43, 0x97, 0x83, 0x21, 0x8F, 0x46, + 0x67, 0x3C, 0x86, 0xDB, 0x7B, 0xBA, 0xD2, 0xC5, 0xB4, 0x09, + 0x0F, 0x2D, 0xD3, 0x4E, 0xD2, 0xB7, 0xFC, 0x75, 0x52, 0x16, + 0x8A, 0x56, 0x5A, 0xCC, 0xE6, 0xFE, 0x5C, 0xE8, 0xAE, 0x48, + 0x7F, 0x81, 0xF2, 0x46, 0x00, 0xE5, 0x53, 0xAF, 0xC7, 0x01, + 0x12, 0x9A, 0xF9, 0xDC, 0x96, 0x79, 0xC6, 0x61, 0xC6, 0xAC, + 0xCE, 0x0B, 0x6C, 0x9F, 0xFD, 0x16, 0xCA, 0xD1, 0xD6, 0xAB, + 0xE4, 0xCB, 0x64, 0x88, 0xF7, 0x17, 0x7F, 0xCD, 0xBB, 0x8F, + 0xF9, 0x5C, 0x75, 0x7C, 0x3D, 0xBE, 0x03, 0x68, 0x30, 0xA8, + 0xC7, 0x82, 0x62, 0xDD, 0x5A, 0x42, 0x3D, 0x8D, 0x02, 0xD1, + 0x68, 0xF2, 0x04, 0x0B, 0xFA, 0xC2, 0x23, 0xB9, 0x26, 0xAA, + 0x5F, 0x43, 0x7D, 0xE5, 0xD2, 0x97, 0xB8, 0xD5, 0x6F, 0xBE, + 0x56, 0xC6, 0xCA, 0xE7, 0x56, 0xDA, 0x14, 0x4A, 0xA6, 0x35, + 0x3F, 0xBF, 0xBC, 0x9D, 0xCD, 0x51, 0x55, 0x98, 0xAB, 0xC0, + 0x42, 0xC8, 0x7D, 0x67, 0xB3, 0xDD, 0x2B, 0x6B, 0xA0, 0x06, + 0x9F, 0x13, 0x79, 0xBC, 0xE2, 0xC8, 0x9E, 0xC3, 0xFF, 0x94, + 0x9E, 0x3D, 0x60, 0xAE, 0xB3, 0x28, 0x44, 0xC5, 0xE1, 0xD8, + 0x40, 0x7F, 0xC0, 0x8F, 0x93, 0xFC, 0xDA, 0xEC, 0x70, 0x14, + 0xB1, 0x07, 0xA1, 0x21, 0x6D, 0xA2, 0xA3, 0xEF, 0x80, 0xF1, + 0xC4, 0xCC, 0xA1, 0x77, 0xD9, 0xA3, 0xD9, 0x31, 0xFB, 0xC5, + 0xE5, 0xDE, 0xC1, 0xF2, 0x6F, 0xFC, 0x73, 0x35, 0xC4, 0x1D, + 0x2C, 0x15, 0x57, 0x64, 0x57, 0x4A, 0x0D, 0x4F, 0xCB, 0xD3, + 0x3E, 0x12, 0x82, 0x5C, 0xFC, 0xED, 0x7B, 0xA1, 0x3F, 0x72, + 0x1E, 0x6B, 0x12, 0x6A, 0xB9, 0x55, 0xD2, 0xC3, 0x04, 0x52, + 0x01, 0xBB, 0x54, 0x20, 0x0A, 0xA5, 0xDA, 0xDD, 0x2D, 0x56, + 0xF4, 0xD0, 0x08, 0x62, 0x1E, 0x68, 0x30, 0x40, 0x57, 0x8A, + 0xC2, 0xDD, 0xBF, 0x0D, 0x7B, 0x28, 0xE0, 0x82, 0x1A, 0x3F, + 0xDC, 0xEA, 0x07, 0xC4, 0x32, 0x74, 0x14, 0x18, 0x9C, 0x00, + 0x9C, 0x91, 0xC0, 0x7A, 0x0A, 0x18, 0x89, 0xAD, 0xA8, 0x3D, + 0x42, 0x21, 0x0F, 0x08, 0x8D, 0xA4, 0xD5, 0xA7, 0x08, 0x09, + 0x3C, 0x21, 0x7E, 0x4E, 0x17, 0xB9, 0x1A, 0x80, 0x22, 0x45, + 0x33, 0x43, 0x24, 0xDD, 0xC4, 0x66, 0xD2, 0xB4, 0x4E, 0x40, + 0xD5, 0x5F, 0xEA, 0x86, 0x9F, 0x8B, 0x41, 0x9D, 0xD0, 0x96, + 0xC9, 0x64, 0x32, 0x39, 0xA1, 0x89, 0x56, 0x7E, 0x1D, 0x22, + 0x08, 0x08, 0xB5, 0x60, 0x1F, 0x52, 0x41, 0xA4, 0x8F, 0xC0, + 0x52, 0x6B, 0xA7, 0xBB, 0x52, 0x0E, 0x96, 0xEE, 0x62, 0x62, + 0x1A, 0xCF, 0x4C, 0x65, 0x59, 0x32, 0x2D, 0x3C, 0x1D, 0x40, + 0x57, 0xB0, 0xE9, 0xF2, 0xBA, 0x04, 0xD2, 0xBE, 0x22, 0xA9, + 0x93, 0x8E, 0xC2, 0x32, 0x06, 0x20, 0xDC, 0x9F, 0xE5, 0xC2, + 0x57, 0xFC, 0xC5, 0xDE, 0xE7, 0xD3, 0xCA, 0xB6, 0xD8, 0x85, + 0xB2, 0xE1, 0xAD, 0x23, 0x47, 0x02, 0x3F, 0xD7, 0xBD, 0x51, + 0x2A, 0x6B, 0x33, 0x2D, 0x23, 0x6D, 0xD5, 0x72, 0x1F, 0xEC, + 0x8F, 0x7F, 0x1B, 0x22, 0x2D, 0x9E, 0x44, 0x58, 0xE0, 0xA3, + 0x50, 0x54, 0xCF, 0x6B, 0x5E, 0x59, 0x7A, 0xF0, 0xDA, 0x2E, + 0x9C, 0xC4, 0xD3, 0xD9, 0x83, 0x56, 0xBB, 0x09, 0x58, 0xFF, + 0x00, 0xDD, 0xDA, 0x57, 0x5C, 0xC3, 0xED, 0x10, 0x6E, 0xD6, + 0xD0, 0xF0, 0xB9, 0xD1, 0x2C, 0x1E, 0x4E, 0x33, 0xA7, 0x44, + 0x9C, 0x87, 0xB2, 0x91, 0x16, 0x2C, 0x44, 0x1E, 0x66, 0x79, + 0x06, 0x12, 0x26, 0xB6, 0x36, 0x1F, 0xBA, 0x56, 0x9F, 0xAB, + 0x64, 0x63, 0xE4, 0x90, 0x75, 0x72, 0xF9, 0x35, 0x77, 0x2B, + 0x38, 0xE5, 0x4F, 0x29, 0xF1, 0x4C, 0xD8, 0xBD, 0x20, 0x60, + 0x65, 0x26, 0x57, 0xCE, 0x52, 0x4B, 0x18, 0xD4, 0xDF, 0xCE, + 0xC0, 0x78, 0x60, 0x83, 0xD4, 0xDF, 0xE9, 0xA2, 0x61, 0x37, + 0x78, 0x7D, 0xEB, 0xE5, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x47, + 0xA5, 0x8E, 0xA4, 0x38, 0x2C, 0xDC, 0x61, 0xFB, 0xD1, 0x29, + 0xFD, 0x30, 0xA5, 0xEE, 0xB0, 0x2F, 0xF6, 0x53, 0x4B, 0x4E, + 0xE9, 0x26, 0x67, 0x28, 0xC0, 0x06, 0x59, 0x13, 0x88, 0xF8, + 0x9B, 0xE8, 0x6B, 0x9E, 0x5A, 0xCF, 0x8D, 0x8D, 0xE1, 0x80, + 0x1A, 0xE1, 0x4A, 0x59, 0x92, 0x6A, 0x57, 0x38, 0x79, 0x1E, + 0x5D, 0xA4, 0x35, 0xA5, 0xD3, 0x80, 0x41, 0x97, 0x69, 0xB7, + 0xDF, 0xE8, 0x07, 0xFA, 0xA6, 0x64, 0xFD, 0xB2, 0xD0, 0x66, + 0xB4, 0x35, 0x52, 0xCC, 0xC9, 0x82, 0xCF, 0xFA, 0xB3, 0xE0, + 0xE6, 0x96, 0x35, 0xEF, 0xD5, 0xF6, 0xA1, 0x0B, 0xAD, 0xE0, + 0x50, 0x7D, 0x9B, 0x36, 0x8D, 0xD2, 0x6E, 0x27, 0x14, 0x2D, + 0x6D, 0xCE, 0xC2, 0xF8, 0xDA, 0x64, 0xDC, 0xFD, 0xC8, 0x79, + 0x72, 0x00, 0xE3, 0xF9, 0x3F, 0x40, 0x0D, 0x0F, 0x40, 0x3A, + 0xE3, 0xFE, 0xEA, 0x93, 0x18, 0x7F, 0x2D, 0xFA, 0x7C, 0x6B, + 0xCB, 0x45, 0x8C, 0xD5, 0x8E, 0xE3, 0x95, 0x4C, 0xF9, 0x60, + 0x83, 0x8E, 0x07, 0xC0, 0x17, 0xE9, 0x6C, 0xAF, 0x2C, 0x08, + 0x04, 0xF5, 0x8B, 0xB7, 0xB8, 0x09, 0xAD, 0x91, 0x02, 0x9A, + 0x28, 0x25, 0xE7, 0x80, 0x5C, 0xCB, 0x69, 0xA0, 0xDA, 0x43, + 0x4F, 0x4C, 0x4A, 0xA1, 0xCB, 0x45, 0x0E, 0x2F, 0x87, 0x77, + 0x43, 0x7E, 0x0E, 0x42, 0xE7, 0x21, 0x2B, 0x73, 0x90, 0x21, + 0x7B, 0x9B, 0x87, 0xEC, 0x27, 0x76, 0xFF, 0x9F, 0xEB, 0x79, + 0xF9, 0x70, 0xE6, 0x73, 0x51, 0x4B, 0x8D, 0xE4, 0xB6, 0x76, + 0xFF, 0x23, 0x71, 0xD9, 0x87, 0x43, 0x29, 0xE4, 0xA0, 0xDE, + 0xB7, 0xCF, 0x92, 0x03, 0x84, 0x07, 0x17, 0xA1, 0xE6, 0x7B, + 0x43, 0x14, 0xA3, 0x30, 0xC0, 0x1B, 0x44, 0x91, 0xCF, 0x80, + 0x48, 0x92, 0x2B, 0x6D, 0x59, 0x8E, 0x63, 0x8C, 0xE8, 0xC3, + 0xA9, 0x04, 0x33, 0x3F, 0x75, 0x6A, 0x2B, 0x7B, 0xEC, 0x74, + 0x26, 0xAD, 0x34, 0x68, 0xB9, 0x9F, 0x63, 0xEE, 0xEA, 0x42, + 0x0D, 0xC7, 0x24, 0x7B, 0xD4, 0x5E, 0x5A, 0x91, 0xF1, 0x41, + 0x2E, 0x6B, 0x0D, 0xB9, 0x75, 0xCE, 0x51, 0x1E, 0x6E, 0xF2, + 0x6B, 0x9C, 0xD4, 0xBD, 0xAF, 0x54, 0x63, 0x1A, 0xA0, 0x29, + 0x65, 0x22, 0x04, 0x9D, 0xE2, 0x6F, 0x37, 0x4B, 0xC2, 0xC2, + 0x62, 0x1B, 0x94, 0xE0, 0xF9, 0xC8, 0xB0, 0x94, 0x43, 0x29, + 0x0D, 0x4F, 0x23, 0x4A, 0xBA, 0x83, 0x15, 0x97, 0x96, 0xC8, + 0x0A, 0x85, 0xD2, 0x80, 0x8B, 0x0C, 0x16, 0x57, 0x32, 0xCA, + 0xA4, 0xF6, 0x20, 0xB5, 0x49, 0x30, 0xCC, 0xD3, 0x1C, 0xAB, + 0xE0, 0xAE, 0x52, 0x7B, 0x71, 0x40, 0x80, 0xAC, 0x30, 0x78, + 0xEE, 0x5A, 0xD3, 0x82, 0x3F, 0x51, 0x34, 0xE8, 0x38, 0xD4, + 0x8D, 0x09, 0xEB, 0xDC, 0x9E, 0x82, 0xF7, 0xE2, 0xAA, 0xCD, + 0x2D, 0x17, 0x0C, 0x08, 0x22, 0xAF, 0xED, 0xE4, 0xC0, 0xC1, + 0xBB, 0x9C, 0x47, 0xC1, 0x23, 0x81, 0x03, 0x85, 0xDD, 0x00, + 0x5C, 0x4D, 0x7F, 0xF1, 0x02, 0xF8, 0xA9, 0xA1, 0x8E, 0xB1, + 0xCD, 0xFC, 0x6F, 0xC5, 0x0D, 0x37, 0xD9, 0x83, 0x15, 0x23, + 0x14, 0x03, 0x54, 0x37, 0xFC, 0xAC, 0xB6, 0xC8, 0x0A, 0x47, + 0x3F, 0x22, 0x6F, 0xD7, 0xFA, 0xBB, 0x8D, 0x17, 0xB2, 0x7C, + 0x0F, 0x65, 0xB4, 0xA2, 0x3A, 0x5F, 0x55, 0x34, 0xEC, 0xCA, + 0x89, 0xDD, 0xD4, 0x44, 0x77, 0x30, 0x9A, 0x20, 0x6A, 0x1A, + 0x9D, 0xBE, 0x39, 0x25, 0x2E, 0xE2, 0x0C, 0xDD, 0xE0, 0x50, + 0x8F, 0xD7, 0x38, 0x01, 0xB1, 0x25, 0xC1, 0xFD, 0x06, 0xD0, + 0x60, 0xC9, 0xEB, 0x1D, 0x77, 0x6D, 0xA2, 0x18, 0xB2, 0x0B, + 0x03, 0xE6, 0xF7, 0x07, 0x51, 0xFC, 0xAF, 0xE9, 0xD4, 0xFC, + 0x80, 0x69, 0x1C, 0xE1, 0x82, 0x96, 0x39, 0x37, 0xC1, 0xD3, + 0xB1, 0x81, 0x62, 0xB7, 0x20, 0x7F, 0xDF, 0xB7, 0x84, 0xD2, + 0xCC, 0xFB, 0x7E, 0x90, 0xBB, 0x05, 0x1B, 0x81, 0xA2, 0xE0, + 0x66, 0x11, 0x8A, 0x37, 0x93, 0x0F, 0x67, 0x81, 0x77, 0x03, + 0xA6, 0xE2, 0x52, 0xB6, 0x0F, 0x9A, 0x02, 0x26, 0xC0, 0x00, + 0x02, 0x1D, 0x9D, 0x63, 0xD2, 0x5B, 0xB0, 0x79, 0x8A, 0xF4, + 0x7F, 0x08, 0x9B, 0x5E, 0xAB, 0x6E, 0xD1, 0xCC, 0x2B, 0x7C, + 0xFF, 0x0D, 0x0E, 0xDD, 0x5F, 0xAA, 0x4C, 0x53, 0x45, 0x53, + 0x48, 0xCD, 0xCD, 0xF7, 0xBA, 0x5B, 0xB9, 0x84, 0xBB, 0x00, + 0xC2, 0xF0, 0xFB, 0x30, 0x5F, 0x04, 0x4E, 0x25, 0x4C, 0x06, + 0x03, 0x8D, 0xC5, 0x37, 0xA6, 0x9D, 0x1C, 0xD8, 0x13, 0xA7, + 0x96, 0xBE, 0xED, 0x22, 0xD7, 0xBA, 0x9F, 0x4C, 0x2E, 0xF9, + 0xD0, 0x5B, 0xBB, 0xF8, 0xB8, 0x0A, 0xF3, 0xEC, 0x31, 0x3F, + 0x84, 0x6E, 0x3A, 0x12, 0x8B, 0x6A, 0x2E, 0x28, 0xCE, 0xB8, + 0x1A, 0xC6, 0xE6, 0x4A, 0xD9, 0x74, 0x04, 0x24, 0xD8, 0x79, + 0x8D, 0x62, 0x0C, 0xB0, 0xAE, 0xAF, 0x67, 0xB4, 0xA1, 0x3D, + 0x93, 0x1D, 0xA2, 0x52, 0x98, 0x3F, 0x57, 0x73, 0x94, 0xB6, + 0x94, 0xBD, 0x0F, 0x42, 0x6A, 0x64, 0x7B, 0x17, 0xAC, 0x8D, + 0x46, 0xD0, 0xE4, 0x1B, 0x8C, 0x56, 0xB6, 0x47, 0xCB, 0xFD, + 0x56, 0x61, 0x6E, 0xA0, 0xBF, 0x6B, 0x8E, 0x68, 0x05, 0x55, + 0xA4, 0xB3, 0x8C, 0x76, 0x48, 0x73, 0x4C, 0x8D, 0x9D, 0xA2, + 0xA0, 0xA1, 0xFB, 0xD0, 0x33, 0x32, 0x39, 0xD2, 0x10, 0x1C, + 0x3C, 0x93, 0xC9, 0xCA, 0x6A, 0x6E, 0x7C, 0xB6, 0xF1, 0x03, + 0xF3, 0x45, 0x51, 0x05, 0x48, 0x30, 0xF0, 0xC6, 0x84, 0xFD, + 0x4E, 0x3B, 0x03, 0xE0, 0x62, 0xB8, 0x53, 0x55, 0xB6, 0xB8, + 0x02, 0x7C, 0xB9, 0xD5, 0x5C, 0xA2, 0x9B, 0x97, 0x8A, 0xA4, + 0xDF, 0x42, 0xEB, 0x91, 0x2C, 0x98, 0x82, 0xA9, 0xAE, 0xB0, + 0x13, 0xF6, 0x6E, 0x90, 0x42, 0xFE, 0xD3, 0xAA, 0x1E, 0xBA, + 0x69, 0xFC, 0xF8, 0x20, 0xEA, 0x5D, 0xA8, 0xFE, 0x64, 0x56, + 0x26, 0x4C, 0x6C, 0x69, 0x8F, 0xAC, 0x30, 0xCF, 0xAE, 0x8B, + 0xD5, 0x63, 0x10, 0xDD, 0xCE, 0x6E, 0x0C, 0xAB, 0x31, 0x46, + 0xDF, 0x8A, 0x33, 0x28, 0x8A, 0x1C, 0xEB, 0xBE, 0xAA, 0x71, + 0x44, 0x5C, 0x89, 0xEA, 0x00, 0x34, 0x23, 0xEB, 0x18, 0x83, + 0x7F, 0xB1, 0x9B, 0x3A, 0xBF, 0x08, 0x68, 0xB6, 0xC8, 0xE2, + 0xD8, 0x2D, 0x5E, 0xA2, 0x99, 0xB9, 0xBC, 0xF8, 0x31, 0xD1, + 0xFD, 0x31, 0xD4, 0x32, 0x05, 0x58, 0x5C, 0xFB, 0xCD, 0x8C, + 0xFF, 0x75, 0x99, 0x93, 0xC8, 0x0C, 0xE8, 0xE8, 0x60, 0x11, + 0xB8, 0x5F, 0x15, 0xB5, 0x89, 0x47, 0xE1, 0x1C, 0x23, 0x1B, + 0x8E, 0x56, 0x02, 0xD3, 0x5F, 0xBD, 0xA9, 0x9F, 0x67, 0x06, + 0xCA, 0x0C, 0x6E, 0x9C, 0xFB, 0x2D, 0x3A, 0xE3, 0xF6, 0x2C, + 0x72, 0x86, 0xCD, 0x68, 0xAC, 0x7B, 0x22, 0xA3, 0x01, 0x15, + 0x50, 0xB7, 0xA0, 0x05, 0x88, 0xD0, 0xDF, 0xBD, 0xDA, 0x3B, + 0xC4, 0xFF, 0x40, 0xA1, 0x46, 0x55, 0x28, 0xB3, 0x0C, 0x1E, + 0xF8, 0xE9, 0x0A, 0x39, 0xD1, 0x66, 0xDF, 0x5B, 0x2B, 0x2C, + 0xCA, 0xA5, 0x36, 0x32, 0x0D, 0xAC, 0x8E, 0xDF, 0x75, 0x9A, + 0xE5, 0x8B, 0xE5, 0x99, 0x6B, 0xD6, 0xB7, 0x83, 0x6B, 0xFE, + 0xEA, 0xC9, 0x71, 0xB5, 0xB9, 0xAE, 0xBE, 0x74, 0xB6, 0x58, + 0x28, 0x06, 0x23, 0xCF, 0x8D, 0x09, 0xBC, 0xE3, 0x18, 0x6C, + 0xFA, 0x53, 0x02, 0xE8, 0x3D, 0x44, 0xB3, 0xFE, 0xB3, 0x11, + 0x70, 0x10, 0xDF, 0xC3, 0x93, 0x64, 0x0F, 0x19, 0x35, 0xF0, + 0x82, 0x3A, 0xE3, 0x04, 0xE3, 0x1D, 0xFE, 0x52, 0xE8, 0x52, + 0xA1, 0x7B, 0x19, 0x23, 0x8E, 0x3F, 0x5D, 0x16, 0x60, 0xCB, + 0x13, 0x1A, 0x26, 0x6D, 0xDB, 0x82, 0xEB, 0x72, 0xEE, 0x76, + 0x77, 0x36, 0xEC, 0xEE, 0x09, 0x90, 0xAF, 0x35, 0x25, 0x5A, + 0x29, 0x61, 0x7A, 0xE6, 0x8C, 0x6C, 0x2A, 0x3B, 0x3B, 0xC4, + 0xC5, 0xD4, 0xCF, 0x41, 0x40, 0x04, 0xF3, 0x0F, 0x4B, 0x1B, + 0x99, 0x7D, 0xCF, 0x1F, 0xC5, 0xEB, 0xC5, 0xF5, 0xA1, 0x16, + 0xA2, 0x2A, 0x2E, 0xD5, 0x78, 0xC5, 0xAD, 0x9C, 0x48, 0x76, + 0xF2, 0x58, 0xDE, 0x68, 0x19, 0x58, 0x8C, 0xEA, 0xF5, 0xD0, + 0x54, 0x4F, 0x73, 0x60, 0x92, 0x71, 0x27, 0xF7, 0x02, 0x26, + 0xC0, 0x00, 0x02, 0x24, 0xC2, 0xE1, 0xD7, 0x77, 0x1A, 0x4D, + 0x5F, 0x7B, 0xC6, 0xC7, 0x52, 0x42, 0x9C, 0x26, 0xBE, 0x75, + 0x2E, 0x37, 0x00, 0xD8, 0x2C, 0xEF, 0x37, 0xC2, 0xF8, 0x88, + 0x89, 0xBA, 0x60, 0x35, 0xCE, 0xD5, 0xC4, 0x3D, 0x00, 0x6A, + 0xF1, 0xE1, 0x66, 0x4C, 0xFF, 0x79, 0xC7, 0xDF, 0x04, 0x99, + 0x02, 0xEB, 0x0E, 0x9D, 0xBE, 0x2C, 0x06, 0xB8, 0xE1, 0xC8, + 0xAE, 0xC4, 0xE8, 0xB7, 0xE7, 0x66, 0xEF, 0x01, 0x72, 0x45, + 0xB2, 0xBF, 0x69, 0xF7, 0xA2, 0x72, 0xEC, 0x91, 0x82, 0x9D, + 0xE5, 0x91, 0x9A, 0x6D, 0x4D, 0x0D, 0x29, 0x58, 0xE3, 0xA2, + 0xBB, 0x4F, 0x7B, 0xED, 0xA6, 0xEC, 0x0D, 0x91, 0xF6, 0xE7, + 0x68, 0x61, 0xDF, 0x8A, 0x1A, 0x5A, 0x2A, 0x21, 0x51, 0x80, + 0x31, 0xD5, 0xD6, 0xFB, 0xE5, 0x0D, 0x01, 0x49, 0x22, 0x05, + 0xEE, 0xA2, 0x7A, 0xF6, 0x6C, 0xCD, 0x9D, 0x95, 0x79, 0x7E, + 0x9D, 0x22, 0x91, 0x59, 0x31, 0x80, 0x55, 0xC9, 0x66, 0xC8, + 0x33, 0x36, 0x56, 0x65, 0xCC, 0x26, 0x88, 0xE7, 0xC0, 0x01, + 0xF4, 0x22, 0xF9, 0xE6, 0xF1, 0x18, 0x69, 0xAB, 0x93, 0x80, + 0x95, 0xBF, 0xA4, 0xB7, 0x7F, 0x56, 0x7D, 0xC0, 0xEE, 0xA7, + 0x01, 0x5B, 0x9B, 0xA6, 0x80, 0x5A, 0x17, 0x31, 0xC8, 0x93, + 0xF6, 0x6F, 0xFD, 0x27, 0x9A, 0x09, 0xB8, 0x48, 0x04, 0xD5, + 0x1F, 0xBB, 0x8B, 0xED, 0xB7, 0x08, 0x43, 0xBF, 0x82, 0xB1, + 0xAF, 0xD9, 0x35, 0x03, 0xE8, 0x36, 0xB4, 0xCD, 0x74, 0x74, + 0x30, 0x85, 0x73, 0x1F, 0x51, 0xED, 0xA5, 0xFD, 0x64, 0xFC, + 0xF1, 0x22, 0x21, 0x36, 0x3C, 0x5E, 0x46, 0x74, 0x9D, 0x94, + 0x2C, 0x0F, 0xDF, 0x2B, 0x6E, 0x5E, 0xA8, 0x7C, 0x80, 0xA4, + 0x4C, 0xE4, 0x1A, 0xE2, 0x80, 0x29, 0x5F, 0x85, 0x76, 0x95, + 0xD0, 0x2D, 0x26, 0x50, 0xB2, 0x14, 0x37, 0xA3, 0x3A, 0x4E, + 0xB9, 0x68, 0xCB, 0x1D, 0x9A, 0x9B, 0x33, 0xD0, 0x3D, 0x1B, + 0x0F, 0x3F, 0xA2, 0x95, 0xE0, 0x80, 0xA1, 0x39, 0x03, 0x14, + 0x5F, 0x21, 0x27, 0x54, 0xB5, 0x4D, 0x1F, 0x7A, 0x9A, 0x1E, + 0xB1, 0xC9, 0x63, 0xBE, 0xEC, 0x0C, 0xC1, 0x16, 0x80, 0x0F, + 0xFD, 0x3B, 0x3F, 0xFD, 0x97, 0xF8, 0x4F, 0xD9, 0xFE, 0xC7, + 0x6A, 0xE5, 0x40, 0x5B, 0xB8, 0x50, 0xA8, 0x94, 0x6F, 0x9F, + 0xD8, 0x23, 0xE8, 0xBC, 0x16, 0x9B, 0xF8, 0xC5, 0x0C, 0x48, + 0x28, 0x1B, 0x51, 0x8B, 0x1C, 0x9F, 0x37, 0x97, 0x6B, 0x0B, + 0x1C, 0x2B, 0xCF, 0x7F, 0x9E, 0xC4, 0x54, 0x8F, 0x4D, 0xBF, + 0x43, 0xBB, 0x40, 0x20, 0x79, 0x1F, 0x29, 0xF2, 0x43, 0x65, + 0x0D, 0xC8, 0x16, 0xAC, 0xE4, 0xF3, 0x82, 0x67, 0x01, 0xD9, + 0x19, 0x80, 0xAD, 0x16, 0x1F, 0xF6, 0xFA, 0xD3, 0xD8, 0x74, + 0x6F, 0xE5, 0x00, 0x8E, 0x77, 0x95, 0x51, 0x83, 0xD4, 0xF2, + 0x8B, 0x79, 0x2D, 0xBA, 0xB1, 0x10, 0x0C, 0x0F, 0xCC, 0x7D, + 0x24, 0x7A, 0xF5, 0xDF, 0x54, 0x54, 0xC0, 0xAF, 0x80, 0x3D, + 0x7E, 0x9C, 0x8F, 0x27, 0xA7, 0x0A, 0xE4, 0x8C, 0xB7, 0x5C, + 0x61, 0xF4, 0xAD, 0xB3, 0xD8, 0xA9, 0x1B, 0xEC, 0x13, 0xCB, + 0xD8, 0xD3, 0x81, 0xBA, 0x9D, 0xCA, 0xD9, 0xAE, 0xC4, 0x43, + 0x69, 0xF4, 0xDE, 0xF9, 0xE0, 0xFE, 0x5D, 0x53, 0x6D, 0xDA, + 0x5F, 0xED, 0x5F, 0x30, 0x81, 0x2C, 0xDE, 0x92, 0x04, 0xDE, + 0x94, 0xBB, 0x45, 0xAF, 0x14, 0x84, 0xC9, 0xE3, 0xBD, 0xBD, + 0x7F, 0x52, 0xE9, 0x6B, 0x34, 0xCA, 0x06, 0x3A, 0xE1, 0x79, + 0x22, 0x3C, 0xA8, 0x34, 0xED, 0x7E, 0x26, 0x18, 0x84, 0xDB, + 0x92, 0x48, 0xFD, 0xD6, 0x82, 0x04, 0x1D, 0x82, 0x1A, 0xA6, + 0x28, 0x74, 0x31, 0xA5, 0x74, 0x1F, 0xD9, 0x0F, 0xF2, 0xC8, + 0x4C, 0x38, 0x8F, 0xAF, 0x2A, 0xE0, 0x5F, 0xD6, 0xA4, 0x1C, + 0xE3, 0xF8, 0x70, 0xD5, 0x4C, 0xF8, 0x3C, 0x92, 0x0A, 0x01, + 0xEF, 0xB7, 0xEA, 0x57, 0xA5, 0x88, 0x4C, 0x10, 0x68, 0x99, + 0xC8, 0x4F, 0x1D, 0x67, 0x8E, 0x43, 0x7D, 0x3D, 0x5E, 0x20, + 0x02, 0x26, 0xC0, 0x00, 0x02, 0x68, 0x4F, 0x5F, 0x8D, 0xC4, + 0x7F, 0x74, 0xCD, 0xFE, 0xFB, 0x21, 0x22, 0x03, 0x06, 0xFA, + 0x2E, 0x4C, 0xFF, 0x35, 0xBB, 0x9E, 0x93, 0x44, 0x35, 0x8A, + 0xFF, 0x97, 0x39, 0x36, 0x8D, 0x53, 0x4D, 0xFA, 0x04, 0xA8, + 0x98, 0x13, 0x9C, 0xAA, 0x87, 0x0D, 0x8B, 0x50, 0x0D, 0x9C, + 0xB1, 0xAC, 0x4C, 0x59, 0x9B, 0xA2, 0xE4, 0x4C, 0xFC, 0x46, + 0xC5, 0xA6, 0x00, 0x4A, 0xA8, 0xD3, 0x24, 0x40, 0x9E, 0x48, + 0x8F, 0xC0, 0x8C, 0x0E, 0x16, 0x02, 0x3C, 0xF5, 0x12, 0x3D, + 0x97, 0xCE, 0xDE, 0x11, 0xBE, 0x46, 0xE8, 0x8F, 0x15, 0x3B, + 0xB3, 0x1D, 0x74, 0xCB, 0xEE, 0x77, 0x2D, 0xEB, 0xAD, 0x87, + 0x39, 0x85, 0xD7, 0xBC, 0x38, 0x87, 0x2A, 0x0B, 0xB5, 0xB0, + 0xD1, 0x09, 0x7D, 0x12, 0xC6, 0x4D, 0x9A, 0xF8, 0x00, 0xC5, + 0xA2, 0xF9, 0x9A, 0xFF, 0x30, 0x5D, 0x6E, 0x79, 0xD7, 0xBA, + 0xB3, 0xCC, 0x2A, 0x43, 0x61, 0xAC, 0x38, 0x99, 0x10, 0xDF, + 0x60, 0x94, 0x7B, 0x49, 0xD9, 0xC2, 0x4C, 0x6D, 0x3F, 0xD7, + 0x38, 0x85, 0xE7, 0x91, 0x26, 0x9E, 0x7F, 0x7E, 0xA4, 0x91, + 0x9B, 0x92, 0x02, 0xC1, 0x1F, 0xAF, 0x5C, 0x6B, 0xBA, 0x27, + 0xAD, 0x33, 0xCC, 0xE6, 0x20, 0x23, 0x61, 0xBE, 0x4A, 0xDA, + 0x28, 0x63, 0xB2, 0xE2, 0xAC, 0xA9, 0x51, 0x50, 0x9A, 0xAB, + 0xCA, 0x8C, 0x5C, 0xF3, 0x0A, 0x44, 0x03, 0xA9, 0x94, 0x92, + 0x1D, 0xC5, 0xB2, 0x09, 0xF3, 0x0E, 0xB3, 0x6A, 0x1D, 0x72, + 0xDC, 0x71, 0x4A, 0xAE, 0x4E, 0x0B, 0x1B, 0xCF, 0xF3, 0xCF, + 0x4B, 0x38, 0xD1, 0xCA, 0x27, 0xC2, 0x6A, 0x41, 0x0F, 0x3A, + 0x1D, 0xCD, 0x3E, 0xB1, 0x1A, 0xF7, 0x16, 0x48, 0x4A, 0xAA, + 0xA7, 0x28, 0x16, 0x07, 0x9B, 0xE0, 0x41, 0x99, 0xF1, 0x47, + 0x8C, 0x48, 0x6C, 0x2D, 0x93, 0x9E, 0x47, 0x2B, 0x9A, 0x96, + 0x20, 0x44, 0xF4, 0x2A, 0xCB, 0xB0, 0xDA, 0xBD, 0x17, 0x38, + 0xCB, 0x45, 0x9F, 0x21, 0xA8, 0x93, 0x26, 0x67, 0x51, 0x36, + 0x6F, 0x05, 0x4A, 0x08, 0x72, 0xFB, 0xA3, 0x98, 0xBF, 0x9E, + 0x39, 0xEC, 0xAF, 0xDA, 0x8A, 0xFD, 0xC1, 0xB2, 0xC4, 0x4D, + 0xFE, 0xCD, 0xBD, 0x7F, 0xF8, 0xCE, 0x4F, 0x7E, 0x4E, 0xBA, + 0xD1, 0x87, 0x3E, 0x5F, 0x77, 0xA2, 0x96, 0x3E, 0x8B, 0x15, + 0xDE, 0xE7, 0xBF, 0x7F, 0x97, 0x0F, 0xE1, 0xE7, 0x2F, 0x58, + 0x5D, 0xEF, 0x56, 0x39, 0x66, 0x63, 0x61, 0x94, 0x3D, 0x31, + 0xC8, 0x8D, 0xA8, 0xAC, 0xB5, 0x4C, 0x20, 0x1A, 0xD4, 0x18, + 0x34, 0x61, 0xA2, 0x4F, 0x65, 0xB3, 0x12, 0xFE, 0xA9, 0x02, + 0xCC, 0x47, 0x8F, 0x1C, 0x39, 0xFD, 0xDB, 0x08, 0x62, 0xFD, + 0x74, 0x8D, 0xF9, 0xAA, 0x34, 0xCA, 0x20, 0x67, 0xE8, 0xBC, + 0xAB, 0xED, 0x8C, 0x09, 0xC1, 0xA1, 0xE2, 0x3A, 0x41, 0xB7, + 0x1D, 0x82, 0x99, 0xAA, 0x79, 0x93, 0xB5, 0x1D, 0x6A, 0xE8, + 0xFC, 0x31, 0xBF, 0x67, 0xD8, 0xE9, 0x36, 0xD4, 0xBF, 0x9E, + 0xBF, 0xAB, 0x13, 0x20, 0xE3, 0x01, 0x29, 0x60, 0x28, 0x19, + 0xD2, 0x0E, 0xBC, 0x21, 0x3E, 0xD6, 0xC0, 0xC3, 0xDD, 0x64, + 0xFC, 0x98, 0x45, 0x26, 0x9B, 0x5C, 0xCB, 0xE2, 0x76, 0x0A, + 0x0D, 0x13, 0x1A, 0x7F, 0xEF, 0xE2, 0x44, 0xA3, 0xD8, 0xCE, + 0xD6, 0x0E, 0x5A, 0xA8, 0x40, 0x7B, 0x9E, 0xA0, 0xBE, 0xD6, + 0x63, 0x56, 0x77, 0x57, 0x69, 0x2C, 0xF8, 0xB6, 0x8D, 0x08, + 0xF3, 0x80, 0xA1, 0x2F, 0x53, 0xE2, 0x2F, 0xFD, 0xE6, 0x86, + 0x91, 0x83, 0x12, 0x7E, 0x73, 0xCF, 0xC8, 0x12, 0x58, 0xCD, + 0x9B, 0x30, 0x2C, 0x1E, 0xB8, 0x1E, 0xA3, 0x66, 0x27, 0xE9, + 0x33, 0xB2, 0x57, 0x9B, 0xF7, 0xFC, 0x04, 0xE1, 0xDF, 0xA4, + 0xC5, 0x7A, 0x39, 0xCE, 0xDF, 0xEB, 0x03, 0x89, 0x37, 0xFB, + 0xB0, 0x17, 0x12, 0x55, 0x52, 0x60, 0x25, 0xD1, 0xA6, 0x54, + 0xED, 0xD2, 0xBA, 0xE9, 0x66, 0x5A, 0xCA, 0xE3, 0x71, 0xF8, + 0xE7, 0x35, 0x1C, 0xAC, 0x00, 0x2C, 0xBD, 0x52, 0x6F, 0xE0, + 0x96, 0x91, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x02, 0xB1, 0x96, + 0x3E, 0x04, 0x9B, 0x7A, 0x13, 0x3F, 0xA3, 0x05, 0x16, 0xBF, + 0x79, 0xE5, 0x67, 0x77, 0x23, 0x1E, 0x4D, 0x4C, 0x26, 0x7C, + 0x9D, 0x3E, 0xF5, 0x37, 0x49, 0xAC, 0x5C, 0xA7, 0x9F, 0xD7, + 0x8B, 0x61, 0x4B, 0x21, 0xEC, 0x27, 0x9A, 0x62, 0x75, 0xD1, + 0xCB, 0xEB, 0x58, 0x98, 0x84, 0xD1, 0xD9, 0xD8, 0x00, 0x0E, + 0x38, 0xCB, 0x40, 0xE9, 0xC0, 0x87, 0x62, 0x6D, 0xD6, 0xBE, + 0x5E, 0x47, 0x40, 0xCE, 0x39, 0xD2, 0x28, 0xFF, 0x32, 0x08, + 0xFB, 0xF1, 0x86, 0xEF, 0xF1, 0x1F, 0xC7, 0x28, 0xE0, 0x2A, + 0x9B, 0xAA, 0xA7, 0xEC, 0xBA, 0x63, 0x27, 0x98, 0xCC, 0x4C, + 0x35, 0x48, 0xE2, 0x83, 0xE2, 0xE4, 0x7E, 0xCF, 0xF2, 0x38, + 0xED, 0x1C, 0xE7, 0x17, 0xCB, 0xAC, 0xCC, 0xDA, 0xF5, 0x3B, + 0xD3, 0xC5, 0xFE, 0xB5, 0x04, 0x3A, 0xFC, 0xF7, 0x66, 0x66, + 0x89, 0xB5, 0xAD, 0x1C, 0x18, 0xFE, 0x63, 0xF6, 0x9E, 0x8D, + 0x73, 0xDC, 0x9D, 0x54, 0xDD, 0x02, 0x3B, 0x1D, 0x3F, 0x3D, + 0xD1, 0x4C, 0xCB, 0x3C, 0x09, 0x8E, 0x5A, 0x06, 0x5C, 0x03, + 0x59, 0xF4, 0x7B, 0xF6, 0x39, 0x02, 0x2B, 0xDC, 0x76, 0x82, + 0x2A, 0x33, 0x34, 0x34, 0x57, 0x9F, 0xC8, 0xF0, 0xF0, 0x14, + 0x29, 0x0C, 0x6E, 0x92, 0x36, 0x56, 0x3B, 0xA6, 0x68, 0xF0, + 0x3B, 0x3C, 0xA7, 0x8F, 0x60, 0x85, 0x5D, 0xAD, 0x14, 0xBF, + 0xA7, 0x8B, 0x8E, 0xED, 0x20, 0x0A, 0x64, 0xB2, 0x05, 0xF9, + 0x59, 0x45, 0xC0, 0x97, 0x2D, 0x0D, 0x3A, 0x77, 0xC0, 0xBD, + 0xA2, 0x9F, 0xD4, 0x21, 0xA5, 0x23, 0x7D, 0x1A, 0xE2, 0x4D, + 0x72, 0x44, 0xF6, 0x3E, 0x2A, 0x12, 0xF6, 0xB3, 0xDD, 0x15, + 0x63, 0xCC, 0x7A, 0x5E, 0x60, 0xC2, 0xB0, 0xEE, 0x2C, 0x35, + 0x08, 0x35, 0xE8, 0xA8, 0x08, 0x86, 0xA6, 0xC9, 0xA2, 0x84, + 0xBF, 0x90, 0x14, 0x92, 0x95, 0x6A, 0x08, 0x39, 0x30, 0xB2, + 0x94, 0x3E, 0x0D, 0xE9, 0x3B, 0x28, 0xC7, 0x89, 0x6F, 0xFE, + 0xB9, 0x83, 0x00, 0xE9, 0x9A, 0xA5, 0x47, 0x82, 0xEB, 0xAE, + 0xA8, 0x2F, 0xD4, 0x89, 0xDB, 0x00, 0xC0, 0xA3, 0xE8, 0x79, + 0xC8, 0x5D, 0x90, 0xA5, 0x5F, 0xB6, 0x11, 0x42, 0x99, 0x1E, + 0x7C, 0x9C, 0xB5, 0xA6, 0x90, 0x85, 0xE8, 0xED, 0x14, 0x55, + 0x99, 0x13, 0x10, 0xFD, 0x94, 0xF6, 0x48, 0x86, 0x26, 0x5A, + 0x36, 0x15, 0x53, 0xE5, 0x02, 0xD4, 0x46, 0xA4, 0x3B, 0x97, + 0xB0, 0x65, 0x25, 0xD2, 0x52, 0x08, 0x7D, 0x12, 0x28, 0xC3, + 0x0A, 0x26, 0xF1, 0xCD, 0x10, 0x90, 0xB0, 0x61, 0x6C, 0x31, + 0xEE, 0xC4, 0x79, 0x86, 0x36, 0x94, 0x38, 0x26, 0xD8, 0xA0, + 0x44, 0x90, 0x38, 0x08, 0xCA, 0xCA, 0x8A, 0xEF, 0x6D, 0xFD, + 0xBF, 0xAC, 0xE2, 0x87, 0xC4, 0xD3, 0xB6, 0x68, 0xA5, 0x02, + 0x05, 0xB4, 0xC1, 0xA3, 0x38, 0x60, 0x1B, 0x7F, 0xA5, 0xF2, + 0xA8, 0x17, 0xB0, 0x17, 0x88, 0x0F, 0xE8, 0xE1, 0x25, 0x9C, + 0x4E, 0x82, 0x37, 0x0C, 0xC3, 0xFF, 0x6D, 0x99, 0x9F, 0xB3, + 0x8B, 0x92, 0x2B, 0x96, 0x6B, 0xD3, 0xDF, 0x3F, 0x45, 0xD8, + 0xA2, 0x46, 0xAA, 0x06, 0x7D, 0xA7, 0x57, 0xEC, 0x87, 0x99, + 0xFA, 0x2F, 0x93, 0x6D, 0x65, 0x77, 0xD3, 0x72, 0x2B, 0x3D, + 0xFC, 0x9D, 0x0D, 0x2C, 0x88, 0x75, 0x37, 0x4B, 0x18, 0xA9, + 0x2D, 0xA9, 0xD6, 0xE3, 0x75, 0xFA, 0x29, 0xCE, 0x91, 0x51, + 0x74, 0xF9, 0x71, 0xFB, 0x0B, 0x1F, 0x24, 0x3D, 0xA8, 0xF3, + 0x56, 0x67, 0x7A, 0x13, 0xAA, 0xFF, 0x1C, 0x6D, 0xDD, 0x0F, + 0x14, 0xBC, 0x34, 0x35, 0xE0, 0xAF, 0x7A, 0x55, 0x8C, 0x9A, + 0xE0, 0xA6, 0x35, 0x1F, 0xAB, 0xC3, 0xF7, 0x14, 0x7E, 0xFF, + 0x13, 0x64, 0xAF, 0x1C, 0x11, 0x68, 0x25, 0x4D, 0x07, 0x05, + 0x3F, 0x76, 0x61, 0x29, 0x32, 0xB5, 0xEF, 0xF7, 0x7E, 0xE8, + 0x5C, 0xE2, 0xAA, 0x17, 0x3F, 0x5C, 0x48, 0xFA, 0x05, 0xB0, + 0xDF, 0x1F, 0x2B, 0x9B, 0x25, 0xAA, 0xA8, 0x1F, 0x80, 0xF5, + 0xE5, 0x9C, 0xC2, 0xF5, 0x02, 0x06, 0xC0, 0x00, 0x02, 0x96, + 0xA3, 0xD9, 0x49, 0x25, 0x73, 0x8B, 0x32, 0xB3, 0xD6, 0x68, + 0x6E, 0x3F, 0xDE, 0x58, 0xCB, 0xA8, 0x00, 0x34, 0xB2, 0x7D, + 0x5A, 0x88, 0x7F, 0x1B, 0x3A, 0xA7, 0xD2, 0x56, 0x5B, 0x20, + 0x6F, 0x6B, 0x43, 0x58, 0xC9, 0x48, 0x1F, 0x76, 0xE3, 0xA5, + 0x79, 0x0D, 0xD3, 0xC7, 0xBB, 0x76, 0xE8, 0xC2, 0xD5, 0x77, + 0x2B, 0x39, 0x93, 0x7F, 0x9B, 0x33, 0xB3, 0x0C, 0x12, 0x50, + 0x8A, 0x95, 0xB3, 0x27, 0xCB, 0x49, 0xDB, 0x3C, 0x6A, 0xB9, + 0x06, 0xD8, 0x31, 0x8E, 0x14, 0x6A, 0x3F, 0x5B, 0x03, 0x98, + 0xD8, 0x5C, 0xCA, 0x46, 0x14, 0xDA, 0xAB, 0x51, 0xDF, 0x72, + 0x3A, 0xAD, 0x8E, 0xDA, 0x9A, 0x44, 0x0E, 0x4C, 0xB0, 0x92, + 0xF6, 0x6A, 0x0E, 0xC8, 0x37, 0x0F, 0x93, 0x73, 0xB0, 0xB5, + 0x11, 0x12, 0x3F, 0xCF, 0x29, 0x50, 0x6B, 0xD9, 0x22, 0x2C, + 0x76, 0x71, 0x07, 0xBC, 0x00, 0x10, 0xB8, 0x54, 0x6A, 0x9A, + 0x59, 0x82, 0x4E, 0xE9, 0x02, 0x8B, 0x9C, 0xC9, 0x4B, 0xD3, + 0x7F, 0xAD, 0xA5, 0xF9, 0x7C, 0xB4, 0x00, 0xB4, 0x5A, 0xAF, + 0x23, 0x12, 0xF2, 0x5B, 0xB9, 0x2C, 0xFD, 0x73, 0xB9, 0xFC, + 0x4B, 0x4F, 0xAF, 0xD2, 0x80, 0xC2, 0xF7, 0x15, 0xEC, 0xE1, + 0x4B, 0xEF, 0xA3, 0x99, 0x59, 0x0C, 0xD5, 0x2F, 0x98, 0xF5, + 0x38, 0xD2, 0xFC, 0xF3, 0x82, 0xA7, 0xE0, 0x15, 0x35, 0x27, + 0xCD, 0xCF, 0xCE, 0xA4, 0x65, 0x92, 0x1E, 0x6C, 0x25, 0x8F, + 0xB7, 0x78, 0x15, 0x5B, 0x7A, 0x9D, 0xB0, 0xEC, 0xDE, 0x0A, + 0xF5, 0x0B, 0xCD, 0xD4, 0xF6, 0xC4, 0xD5, 0xA9, 0xC1, 0x4E, + 0xE0, 0xA2, 0x8B, 0xC4, 0x43, 0x97, 0xAC, 0xC9, 0x41, 0xF2, + 0x5A, 0x36, 0xD1, 0xD6, 0x7E, 0xC2, 0xD3, 0x06, 0xCB, 0x78, + 0x47, 0x78, 0x05, 0x35, 0x61, 0xE6, 0xD4, 0xDC, 0x65, 0x75, + 0x63, 0x5B, 0x71, 0xD7, 0x3C, 0x27, 0x9B, 0x26, 0x70, 0xAB, + 0x4D, 0x97, 0xE5, 0x83, 0x7C, 0xEB, 0x5B, 0x8F, 0xD6, 0xBC, + 0x84, 0x9D, 0xF8, 0x08, 0x65, 0x10, 0x6E, 0x48, 0xBE, 0xD2, + 0x86, 0xC0, 0xEB, 0x08, 0x27, 0x38, 0xF8, 0x6E, 0x5D, 0xBA, + 0x5B, 0xC6, 0x78, 0xED, 0xB1, 0x8D, 0x57, 0xFC, 0xA4, 0xDD, + 0xF3, 0xDF, 0xB9, 0x36, 0x92, 0xB8, 0x00, 0x06, 0x5F, 0xAD, + 0x04, 0xE3, 0x8D, 0x64, 0x64, 0x7A, 0xE0, 0x57, 0x4C, 0x68, + 0x56, 0xDC, 0x1F, 0x93, 0xA5, 0xD7, 0xEE, 0xFC, 0x8A, 0xB9, + 0x26, 0x99, 0xC5, 0x1A, 0x63, 0xD6, 0x9B, 0xBC, 0xA2, 0xF3, + 0xE1, 0x84, 0xDC, 0xFB, 0x0C, 0x4F, 0xB4, 0x0D, 0x75, 0x8B, + 0xDD, 0xB6, 0x76, 0x2C, 0x33, 0x46, 0xDD, 0x94, 0xE0, 0x8C, + 0x37, 0x03, 0x14, 0x44, 0xC2, 0x0F, 0x6C, 0x03, 0xA6, 0x39, + 0x1E, 0xB5, 0x00, 0x83, 0xC6, 0x59, 0x81, 0xD6, 0x11, 0x3A, + 0x22, 0x6F, 0x74, 0x1C, 0x8B, 0x4C, 0xF3, 0x1C, 0x59, 0x2F, + 0x19, 0x18, 0xB5, 0x20, 0x24, 0x9C, 0x14, 0x45, 0x7E, 0x98, + 0xFB, 0x71, 0xC4, 0xCC, 0x19, 0x99, 0x28, 0x9E, 0x63, 0xC2, + 0xD6, 0x0D, 0x47, 0x2A, 0x3B, 0x36, 0xB7, 0x8C, 0xF1, 0x98, + 0x33, 0x96, 0x9D, 0x09, 0x99, 0x74, 0xE3, 0x41, 0xCD, 0x67, + 0xCE, 0x11, 0xBA, 0x35, 0xE3, 0x44, 0x3D, 0xE0, 0xB9, 0x53, + 0x79, 0x58, 0x0F, 0xC5, 0x98, 0xCC, 0xAB, 0xF8, 0x37, 0x5C, + 0x96, 0xCE, 0xB5, 0xDA, 0xB5, 0x05, 0x79, 0xD6, 0x96, 0x82, + 0xCA, 0x3F, 0x2C, 0x8A, 0x44, 0xCE, 0xCE, 0x99, 0xA2, 0x77, + 0x9E, 0xE0, 0xFE, 0x58, 0x97, 0x5A, 0xDA, 0x8B, 0xB8, 0x0A, + 0xA2, 0x3F, 0x26, 0x00, 0x5C, 0xAC, 0xD8, 0x33, 0x95, 0xBF, + 0x43, 0x0D, 0x09, 0xB5, 0x9A, 0x89, 0x4C, 0x46, 0x83, 0xAF, + 0xD1, 0xD3, 0x61, 0x33, 0xA1, 0x19, 0xD3, 0xD6, 0x81, 0xB0, + 0xDA, 0x55, 0x4B, 0xD3, +}; + +const uint32_t gphDnldNfc_DlSeqSz = sizeof(gphDnldNfc_DlSequence); diff --git a/nfc/recovery_seq.c b/nfc/recovery_seq.c new file mode 100644 index 0000000000..5842284e8e --- /dev/null +++ b/nfc/recovery_seq.c @@ -0,0 +1,281 @@ +/****************************************************************************** + * Copyright (C) 2021 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#if defined(RECOVERY_ENABLE) +#include "recovery_seq.h" + +recovery_info_t g_recovery_info; +recovery_frame_t g_recovery_frame; + +extern const uint32_t gphDnldNfc_DlSeqSz; /* Recovery user buffer size */ +extern const uint8_t gphDnldNfc_DlSequence[]; /* Recovery user buffer */ + +/** @brief Function to calculate crc value. + * + * @param pbuffer: input buffer for crc calculation. + * dwLength: length of input buffer + * @return calculated uint16_t crc valueof input buffer. + */ +static uint16_t calcCrc16(uint8_t* pbuffer, uint32_t dwLength) { + uint32_t i = 0; + uint16_t crc_new = 0; + uint16_t crc = DL_INVALID_CRC_VALUE; + if(NULL == pbuffer) { + pr_err("%s, invalid params", __func__); + return crc; + } + for (i = 0; i < dwLength; i++) { + crc_new = (uint8_t)(crc >> MSB_POS) | (crc << MSB_POS ); + crc_new ^= pbuffer[i]; + crc_new ^= (uint8_t)(crc_new & DL_CRC_MASK) >> 4; + crc_new ^= crc_new << 12; + crc_new ^= (crc_new & DL_CRC_MASK) << 5; + crc = crc_new; + } + return crc; +} + +/** @brief Function to build command frame for recover. + * + * @return status code of recovery_status_t type. + */ +static recovery_status_t build_cmd_frame() { + uint16_t len = 0; + uint16_t wCrc = 0; + uint16_t writeOffset = 0; + pr_debug(" %s Entry", __func__); + if(gphDnldNfc_DlSeqSz == 0) { + pr_err(" %s invalid params", __func__); + return STATUS_FAILED; + } + memset(g_recovery_frame.p_buffer, 0x00, MAX_FRAME_SIZE); + g_recovery_frame.len = 0; + if(g_recovery_info.bFrameSegmented == false) { + len = gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset]; + len <<= MSB_POS; + len |= gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset + 1]; + } else { + /* last frame was segmented frame + * read length reamaining length */ + len = g_recovery_info.wRemChunkBytes; + } + if(len > MAX_DATA_SIZE) { + /* set remaining chunk */ + g_recovery_info.wRemChunkBytes = (len - MAX_DATA_SIZE); + len = MAX_DATA_SIZE; + /* set chunk bit to write in header */ + len = DL_SET_HDR_FRAGBIT(len); + g_recovery_frame.p_buffer[writeOffset++] = (len >> MSB_POS) & SHIFT_MASK; + g_recovery_frame.p_buffer[writeOffset++] = len & SHIFT_MASK; + /* clear chunk bit for length variable */ + len = DL_CLR_HDR_FRAGBIT(len); + /* first chunk of segmented frame*/ + if(!g_recovery_info.bFrameSegmented) { + /* ignore header from user buffer */ + g_recovery_info.currentReadOffset += FW_HDR_LEN; + g_recovery_info.remBytes -= FW_HDR_LEN; + } + g_recovery_frame.len += FW_HDR_LEN; + g_recovery_info.bFrameSegmented = true; + } else { + /* last chunk of segmented frame */ + if(g_recovery_info.bFrameSegmented) { + /* write header with user chunk length */ + g_recovery_frame.p_buffer[writeOffset++] = (len >> MSB_POS) & SHIFT_MASK; + g_recovery_frame.p_buffer[writeOffset++] = len & SHIFT_MASK; + g_recovery_frame.len += FW_HDR_LEN; + } else { + /* normal Frame with in supported size increase + * len to read header from user data */ + len += FW_HDR_LEN; + } + g_recovery_info.wRemChunkBytes = 0; + g_recovery_info.bFrameSegmented = false; + } + if(((writeOffset + len) > MAX_FRAME_SIZE) || + ((g_recovery_info.currentReadOffset + len) > gphDnldNfc_DlSeqSz)) { + pr_err("%s frame offsets out of bound",__func__); + return STATUS_FAILED; + } + memcpy(&g_recovery_frame.p_buffer[writeOffset], + &gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset], len); + g_recovery_info.currentReadOffset += len; + g_recovery_frame.len += len; + writeOffset += len; + g_recovery_info.remBytes -= len; + wCrc = calcCrc16(g_recovery_frame.p_buffer, + g_recovery_frame.len); + g_recovery_frame.p_buffer[writeOffset++] = (wCrc >> MSB_POS) & SHIFT_MASK; + g_recovery_frame.p_buffer[writeOffset++] = wCrc & SHIFT_MASK; + g_recovery_frame.len += FW_CRC_LEN; + return STATUS_SUCCESS; +} + +/** @brief Function to tramsmit recovery frame. + * @param nfc_dev nfc driver object. + * @return status code of recovery_status_t type. + */ +static recovery_status_t transmit(nfc_dev_t* nfc_dev) { + char rsp_buf[MAX_BUFFER_SIZE]; + int ret = 0; + int frame_resp_len = 0; + uint16_t respCRC = 0; + uint16_t respCRCOffset = 0; + + pr_debug("%s Entry", __func__); + if(NULL == nfc_dev || g_recovery_frame.len <= 0) { + pr_err("%s invalid Params ", __func__); + return STATUS_FAILED; + } + ret = nfc_dev->nfc_write(nfc_dev, g_recovery_frame.p_buffer, + g_recovery_frame.len, MAX_RETRY_COUNT); + if (ret <= 0) { + pr_err(" %s: Write recovery frame error %d\n", __func__, ret); + return STATUS_FAILED; + } + pr_debug(" %s Reading response \n", __func__); + memset(rsp_buf, 0x00, MAX_BUFFER_SIZE); + ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, FW_HDR_LEN, NCI_CMD_RSP_TIMEOUT); + if (ret < FW_HDR_LEN) { + pr_err(" %s - Read recovery frame response error ret %d\n", __func__, ret); + return STATUS_FAILED; + } + if( rsp_buf[0] != FW_MSG_CMD_RSP || + rsp_buf[DL_FRAME_RESP_LEN_OFFSET] != DL_FRAME_RESP_LEN) { + pr_err("%s, invalid response", __func__); + return STATUS_FAILED; + } + frame_resp_len = rsp_buf[DL_FRAME_RESP_LEN_OFFSET] + FW_CRC_LEN; + ret = nfc_dev->nfc_read(nfc_dev, rsp_buf + FW_HDR_LEN, frame_resp_len, NCI_CMD_RSP_TIMEOUT); + if (ret < frame_resp_len) { + pr_err(" %s - Read recovery frame response error ret %d\n", __func__, ret); + return STATUS_FAILED; + } + pr_debug(" %s: recovery frame Response 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + __func__, rsp_buf[0], rsp_buf[1],rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5]); + respCRCOffset = FW_HDR_LEN + rsp_buf[DL_FRAME_RESP_LEN_OFFSET]; + respCRC = rsp_buf[respCRCOffset++]; + respCRC <<= MSB_POS; + respCRC |= rsp_buf[respCRCOffset]; + if(respCRC != calcCrc16(rsp_buf, DL_FRAME_RESP_LEN + FW_HDR_LEN)) { + pr_err("%s, invalid response crc", __func__); + return STATUS_FAILED; + } + if(g_recovery_info.bFrameSegmented && + (rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT1 + && rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT2)) { + pr_err("%s, invalid stat flag in chunk response", __func__); + return STATUS_FAILED; + } + if(!g_recovery_info.bFrameSegmented && + rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_NON_SEGMENTED_FRAME_RESP_STAT) { + pr_err("%s, invalid stat flag in response", __func__); + return STATUS_FAILED; + } + return STATUS_SUCCESS; +} + +/** @brief Function to detect the fw state and print. + * @param nfc_dev nfc driver object. + * @return no return. + */ +static void detect_fw_state(nfc_dev_t* nfc_dev) { + const char get_session_state_cmd[] = { 0x00, 0x04, 0xF2, 0x00, 0x00, 0x00, 0xF5, 0x33 }; + char rsp_buf[MAX_BUFFER_SIZE]; + int ret = 0; + pr_debug("%s:Sending GET_SESSION_STATE cmd \n", __func__); + ret = nfc_dev->nfc_write(nfc_dev, get_session_state_cmd, + sizeof(get_session_state_cmd), MAX_RETRY_COUNT); + if (ret <= 0) { + pr_err("%s: - nfc get session state cmd err ret %d\n", __func__, ret); + return; + } + memset(rsp_buf, 0x00, DL_GET_SESSION_STATE_RSP_LEN); + pr_debug("%s: Reading response of GET_SESSION_STATE cmd\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT); + if (ret <= 0) { + pr_err("%s: - nfc get session state rsp err %d\n", __func__, ret); + return; + } + pr_debug("Response bytes are %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x", + rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5], + rsp_buf[6], rsp_buf[7]); + /*verify fw in non-teared state */ + if (rsp_buf[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) { + pr_err("%s NFCC is in teared state %d\n", __func__, __LINE__); + } else { + pr_info("%s NFCC is in recoverd state %d\n", __func__, __LINE__); + } +} + +/** @brief Function to check input version with recovery fw version. + * @param fw_major_version: input major_version to check. + * @return true if input major_version matches with recovery fw major version + * otherwise returns false. + */ +static bool check_major_version(uint8_t fw_major_version) { + if(gphDnldNfc_DlSeqSz < RECOVERY_FW_MJ_VER_OFFSET) { + /* Recovery data corrupted */ + pr_err("%s Not able to extract major version from recovery fw\n", __func__); + return false; + } + return (fw_major_version == gphDnldNfc_DlSequence[RECOVERY_FW_MJ_VER_OFFSET]); +} + +/** @brief Function to recover the nfcc. + * @param nfc_dev nfc driver object. + * @return status code of type recovery_status_t. + */ +recovery_status_t do_recovery(nfc_dev_t *nfc_dev) { + recovery_status_t status = STATUS_SUCCESS; + g_recovery_info.remBytes = gphDnldNfc_DlSeqSz; + g_recovery_info.currentReadOffset = 0; + g_recovery_info.bFrameSegmented = false; + g_recovery_info.wRemChunkBytes = 0; + + pr_debug("%s Entry", __func__); + if(NULL == nfc_dev) { + pr_err("%s invalid params ", __func__); + return STATUS_FAILED; + } + if(!nfc_dev->recovery_required + || !(check_major_version(nfc_dev->fw_major_version))) { + pr_err("%s recovery not required or unsupported version", __func__); + status = STATUS_FAILED; + goto EXIT_RECOVERY; + } + while(g_recovery_info.remBytes > 0) { + status = build_cmd_frame(); + if(status != STATUS_SUCCESS) { + pr_err(" %s Unable to create recovery frame"); + break; + } + status = transmit(nfc_dev); + if(status != STATUS_SUCCESS) { + pr_err(" %s Unable to send recovery frame"); + break; + } + } +EXIT_RECOVERY: + detect_fw_state(nfc_dev); + /*set NCI mode for i2c products with dwl pin */ + enable_dwnld_mode(nfc_dev, false); + pr_info("%s Recovery done status %d", __func__, status); + return status; +} +#endif diff --git a/nfc/recovery_seq.h b/nfc/recovery_seq.h new file mode 100644 index 0000000000..86671de262 --- /dev/null +++ b/nfc/recovery_seq.h @@ -0,0 +1,80 @@ +/****************************************************************************** + * Copyright (C) 2021 NXP + * * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#if defined(RECOVERY_ENABLE) + +#ifndef __RECOVERY_SEQ_H_ +#define __RECOVERY_SEQ_H_ + +#include "common.h" + +#define MAX_FRAME_SIZE 0x22A /* support for 256(0x100) & 554(0x22A) frame size*/ + +#define MAX_DATA_SIZE \ + (MAX_FRAME_SIZE - FW_CRC_LEN - FW_HDR_LEN) + +#define FW_ROM_CODE_VER_OFFSET 4 +#define FW_MAJOR_VER_OFFSET 7 +#define RECOVERY_FW_SUPPORTED_ROM_VER 0x01 +#define RECOVERY_FW_SUPPORTED_MAJOR_VER 0x10 +#define RECOVERY_FW_MJ_VER_OFFSET 5 + +#define DL_SET_HDR_FRAGBIT(n) \ + ((n) | (1 << 10)) /* Header chunk bit set macro */ +#define DL_CLR_HDR_FRAGBIT(n) \ + ((n) & ~(1U << 10)) /* Header chunk bit clear macro */ + +#define DL_FRAME_RESP_LEN 0x04 +#define DL_FRAME_RESP_LEN_OFFSET 1 +#define DL_FRAME_RESP_STAT_OFFSET 2 +#define DL_SEGMENTED_FRAME_RESP_STAT1 0x2D +#define DL_SEGMENTED_FRAME_RESP_STAT2 0x2E +#define DL_NON_SEGMENTED_FRAME_RESP_STAT 0x00 +#define DL_INVALID_CRC_VALUE 0xffffU +#define DL_CRC_MASK 0xff + +#define SHIFT_MASK 0x00FF +#define MSB_POS 8 + +/* Data buffer for frame to write */ +typedef struct recovery_frame { + uint32_t len; + uint8_t p_buffer[MAX_FRAME_SIZE]; +} recovery_frame_t; + +/* Contains Info about user buffer and last data frame */ +typedef struct recovery_info { + uint32_t currentReadOffset; /* current offset within the user buffer to read/write */ + uint32_t remBytes; /* Remaining bytes to write */ + uint16_t wRemChunkBytes; /* Remaining bytes within the chunked frame */ + bool bFrameSegmented; /* Indicates the current frame is segmented */ +} recovery_info_t; + +/* indicates the error codes for nfc recovery module */ +typedef enum recovery_status { + STATUS_SUCCESS = 0x00, + STATUS_FAILED = 0x01, +} recovery_status_t; + +/** @brief Function to recover the nfcc. + * @param nfc_dev nfc driver object. + * @return status code of type recovery_status_t. + */ +recovery_status_t do_recovery(nfc_dev_t *nfc_dev); +#endif// end __RECOVERY_SEQ_H_ +#endif From 0d82b80e370ab92400950757b44e2f6a52070f99 Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Fri, 26 Feb 2021 15:55:00 +0530 Subject: [PATCH 038/100] Updated corresponding to - NFC_AR_00_E000_12.02.01_OpnSrc --- nfc/Makefile | 8 +- nfc/common.c | 506 +++++---- nfc/common.h | 83 +- nfc/common_ese.c | 143 +-- nfc/common_ese.h | 42 +- nfc/i2c_drv.c | 227 ++-- nfc/i2c_drv.h | 5 +- nfc/recovery_fw.c | 2651 ++++++++++++++++++++++---------------------- nfc/recovery_seq.c | 136 +-- nfc/recovery_seq.h | 31 +- 10 files changed, 1946 insertions(+), 1886 deletions(-) diff --git a/nfc/Makefile b/nfc/Makefile index debebf6b79..ddbea678de 100644 --- a/nfc/Makefile +++ b/nfc/Makefile @@ -1,6 +1,8 @@ # # Makefile for nfc devices # -obj-$(CONFIG_NXP_NFC_I2C) += pn553_i2c.o -pn553_i2c-objs := common.o common_ese.o i2c_drv.o recovery_seq.o recovery_fw.o -ccflags-y += -DRECOVERY_ENABLE -UDEBUG +obj-$(CONFIG_NXP_NFC_I2C) += pn553_i2c.o +pn553_i2c-objs := common.o common_ese.o i2c_drv.o +pn553_i2c-$(CONFIG_NXP_NFC_RECOVERY) += recovery_seq.o recovery_fw.o +#ccflags-y += -DDEBUG + diff --git a/nfc/common.c b/nfc/common.c index 4f0264d9fb..cf80332049 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -1,4 +1,5 @@ /****************************************************************************** + * Copyright (C) 2015, The Linux Foundation. All rights reserved. * Copyright (C) 2019-2021 NXP * * * This program is free software; you can redistribute it and/or modify @@ -22,16 +23,13 @@ #include #include "common.h" #include "common_ese.h" - -#if defined(RECOVERY_ENABLE) #include "recovery_seq.h" -#endif -int nfc_parse_dt(struct device *dev, platform_configs_t *nfc_configs, +int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface) { struct device_node *np = dev->of_node; - platform_gpio_t *nfc_gpio = &nfc_configs->gpio; + struct platform_gpio *nfc_gpio = &nfc_configs->gpio; if (!np) { pr_err("nfc of_node NULL\n"); @@ -58,9 +56,8 @@ int nfc_parse_dt(struct device *dev, platform_configs_t *nfc_configs, } nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); - if ((!gpio_is_valid(nfc_gpio->dwl_req))) { + if ((!gpio_is_valid(nfc_gpio->dwl_req))) pr_warn("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req); - } pr_info("%s: %d, %d, %d, %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven, nfc_gpio->dwl_req); @@ -80,7 +77,8 @@ void set_valid_gpio(int gpio, int value) int get_valid_gpio(int gpio) { - int value = -1; + int value = -EINVAL; + if (gpio_is_valid(gpio)) { value = gpio_get_value(gpio); pr_debug("%s gpio %d value %d\n", __func__, gpio, value); @@ -90,13 +88,14 @@ int get_valid_gpio(int gpio) void gpio_set_ven(struct nfc_dev *nfc_dev, int value) { - platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + if (gpio_get_value(nfc_gpio->ven) != value) { - pr_debug("%s: gpio_set_ven %d\n", __func__, value); + pr_debug("%s: value %d\n", __func__, value); /*reset on change in level from high to low */ - if (value) { - common_ese_on_hard_reset(nfc_dev); - } + if (value) + ese_cold_reset_release(nfc_dev); + gpio_set_value(nfc_gpio->ven, value); // hardware dependent delay usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, @@ -107,6 +106,7 @@ void gpio_set_ven(struct nfc_dev *nfc_dev, int value) int configure_gpio(unsigned int gpio, int flag) { int ret; + pr_debug("%s: nfc gpio [%d] flag [%01x]\n", __func__, gpio, flag); if (gpio_is_valid(gpio)) { ret = gpio_request(gpio, "nfc_gpio"); @@ -146,21 +146,21 @@ int configure_gpio(unsigned int gpio, int flag) return ret; } -void gpio_free_all(nfc_dev_t *nfc_dev) +void gpio_free_all(struct nfc_dev *nfc_dev) { - platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; - if (gpio_is_valid(nfc_gpio->dwl_req)) { + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + if (gpio_is_valid(nfc_gpio->dwl_req)) gpio_free(nfc_gpio->dwl_req); - } - if (gpio_is_valid(nfc_gpio->irq)) { + + if (gpio_is_valid(nfc_gpio->irq)) gpio_free(nfc_gpio->irq); - } - if (gpio_is_valid(nfc_gpio->ven)) { + + if (gpio_is_valid(nfc_gpio->ven)) gpio_free(nfc_gpio->ven); - } } -void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count) +void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count) { pr_debug("%s: entry\n", __func__); device_destroy(nfc_dev->nfc_class, nfc_dev->devno); @@ -169,11 +169,12 @@ void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count) unregister_chrdev_region(nfc_dev->devno, count); } -int nfc_misc_register(nfc_dev_t *nfc_dev, +int nfc_misc_register(struct nfc_dev *nfc_dev, const struct file_operations *nfc_fops, int count, char *devname, char *classname) { int ret = 0; + ret = alloc_chrdev_region(&nfc_dev->devno, 0, count, devname); if (ret < 0) { pr_err("%s: failed to alloc chrdev region ret %d\n", __func__, ret); @@ -217,10 +218,11 @@ int nfc_misc_register(nfc_dev_t *nfc_dev, * * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case */ -static int nfc_ioctl_power_states(nfc_dev_t *nfc_dev, unsigned long arg) +static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) { int ret = 0; - platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + if (arg == NFC_POWER_OFF) { /* * We are attempting a hardware reset so let us disable @@ -287,6 +289,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) { int ret = 0; struct nfc_dev *nfc_dev = pfile->private_data; + if (!nfc_dev) return -ENODEV; @@ -301,13 +304,6 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) case ESE_GET_PWR: ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE); break; - case NFC_GET_PLATFORM_TYPE: - ret = nfc_dev->interface; - break; - case NFC_GET_NFC_STATE: - ret = nfc_dev->nfc_state; - pr_debug("nfc get state %d\n", ret); - break; case NFC_GET_IRQ_STATE: ret = gpio_get_value(nfc_dev->configs.gpio.irq); break; @@ -320,7 +316,8 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) int nfc_dev_open(struct inode *inode, struct file *filp) { - nfc_dev_t *nfc_dev = container_of(inode->i_cdev, nfc_dev_t, c_dev); + struct nfc_dev *nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev); + pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); mutex_lock(&nfc_dev->dev_ref_mutex); @@ -339,7 +336,8 @@ int nfc_dev_open(struct inode *inode, struct file *filp) int nfc_dev_close(struct inode *inode, struct file *filp) { - nfc_dev_t *nfc_dev = container_of(inode->i_cdev, nfc_dev_t, c_dev); + struct nfc_dev *nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev); + pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); mutex_lock(&nfc_dev->dev_ref_mutex); if (nfc_dev->dev_ref_count == 1) { @@ -351,7 +349,8 @@ int nfc_dev_close(struct inode *inode, struct file *filp) else { nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS_NFC); /* Uncomment below line incase of eSE calls flow is via NFC driver - * i.e. direct calls from SPI HAL to NFC driver*/ + * i.e. direct calls from SPI HAL to NFC driver + */ //nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS); } filp->private_data = NULL; @@ -360,248 +359,321 @@ int nfc_dev_close(struct inode *inode, struct file *filp) return 0; } -static int get_nfcc_boot_state(struct nfc_dev *nfc_dev) +/** + * get_nfcc_chip_type_dl() - get chip type in fw download command; + * @nfc_dev: nfc device data structure + * + * Perform get version command and determine chip + * type from response. + * + * @Return: enum chip_types value + * + */ +static enum chip_types get_nfcc_chip_type_dl(struct nfc_dev *nfc_dev) { int ret = 0; - char get_version_cmd[] = { 0x00, 0x04, 0xF1, 0x00, 0x00, 0x00, 0x6E, 0xEF }; - char get_session_state_cmd[] = { 0x00, 0x04, 0xF2, 0x00, 0x00, 0x00, 0xF5, 0x33 }; - char rsp_buf[MAX_BUFFER_SIZE]; + int cmd_length = 0; + uint8_t *cmd = nfc_dev->write_kbuf; + uint8_t *rsp = nfc_dev->read_kbuf; + enum chip_types chip_type = CHIP_UNKNOWN; - pr_debug("%s:Sending GET_VERSION cmd\n", __func__); - ret = nfc_dev->nfc_write(nfc_dev, get_version_cmd, - sizeof(get_version_cmd), MAX_RETRY_COUNT); + *cmd++ = 0x00; + *cmd++ = 0x04; + *cmd++ = 0xF1; + *cmd++ = 0x00; + *cmd++ = 0x00; + *cmd++ = 0x00; + *cmd++ = 0x6E; + *cmd++ = 0xEF; + cmd_length = cmd - nfc_dev->write_kbuf; + + pr_debug("%s:Sending GET_VERSION cmd of size=%d\n", __func__, cmd_length); + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, MAX_RETRY_COUNT); if (ret <= 0) { pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret); goto err; } - memset(rsp_buf, 0x00, MAX_BUFFER_SIZE); + memset(rsp, 0x00, DL_GET_VERSION_RSP_LEN_2); pr_debug("%s:Reading response of GET_VERSION cmd\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_VERSION_RSP_LEN_2, NCI_CMD_RSP_TIMEOUT); + ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_VERSION_RSP_LEN_2, NCI_CMD_RSP_TIMEOUT); if (ret <= 0) { pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret); goto err; - } else if (rsp_buf[0] == FW_MSG_CMD_RSP - && ret >= DL_GET_VERSION_RSP_LEN_2) { -#if defined(RECOVERY_ENABLE) - nfc_dev->fw_major_version = rsp_buf[FW_MAJOR_VER_OFFSET]; - /* recvoery neeeded only for SN1xx */ - if(rsp_buf[FW_ROM_CODE_VER_OFFSET] == RECOVERY_FW_SUPPORTED_ROM_VER && - nfc_dev->fw_major_version == RECOVERY_FW_SUPPORTED_MAJOR_VER) - nfc_dev->recovery_required = true; -#endif - pr_info("%s:NFC chip_type 0x%02x rom_version 0x%02x fw_minor 0x%02x fw_major 0x%02x\n", - __func__, rsp_buf[3], rsp_buf[4], rsp_buf[6], rsp_buf[7]); - } else if (rsp_buf[0] != FW_MSG_CMD_RSP - && ret >= (NCI_HDR_LEN + rsp_buf[NCI_PAYLOAD_LEN_IDX])) { - pr_info("%s:NFC response bytes 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, - rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[3]); - pr_debug("%s NFCC booted in NCI mode %d\n", __func__, __LINE__); - return NFC_STATE_NCI; } + if (rsp[0] == FW_MSG_CMD_RSP && ret >= DL_GET_VERSION_RSP_LEN_2) { - pr_debug("%s:Sending GET_SESSION_STATE cmd \n", __func__); - ret = nfc_dev->nfc_write(nfc_dev, get_session_state_cmd, - sizeof(get_session_state_cmd), - MAX_RETRY_COUNT); - if (ret <= 0) { - pr_err("%s: - nfc get session state cmd err ret %d\n", __func__, ret); - goto err; + nfc_dev->fw_major_version = rsp[FW_MAJOR_VER_OFFSET]; + + if (rsp[FW_ROM_CODE_VER_OFFSET] == SN1XX_ROM_VER && + rsp[FW_MAJOR_VER_OFFSET] == SN1xx_MAJOR_VER) + chip_type = CHIP_SN1XX; + else if (rsp[FW_ROM_CODE_VER_OFFSET] == SN220_ROM_VER && + rsp[FW_MAJOR_VER_OFFSET] == SN220_MAJOR_VER) + chip_type = CHIP_SN220; + pr_info("%s:NFC Chip Type 0x%02x Rom Version 0x%02x FW Minor 0x%02x Major 0x%02x\n", + __func__, rsp[3], rsp[4], rsp[6], rsp[7]); } - memset(rsp_buf, 0x00, DL_GET_SESSION_STATE_RSP_LEN); - pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT); - if (ret <= 0) { - pr_err("%s: - nfc get session state rsp err %d\n", __func__, ret); - goto err; - } - pr_debug("Response bytes are %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x", - rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5], - rsp_buf[6], rsp_buf[7]); - /*verify fw in non-teared state */ - if (rsp_buf[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) { - pr_debug("%s NFCC booted in teared fw state %d\n", __func__, __LINE__); - return NFC_STATE_FW_TEARED; - } - pr_debug("%s NFCC booted in FW DN mode %d\n", __func__, __LINE__); - return NFC_STATE_FW_DWL; err: - pr_err("%s Unlikely NFCC not booted in FW DN mode %d\n", __func__, __LINE__); - return NFC_STATE_UNKNOWN; + return chip_type; } -int validate_nfc_state_nci(nfc_dev_t *nfc_dev) -{ - platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; - if (!gpio_get_value(nfc_gpio->ven)) { - pr_err("VEN LOW - NFCC powered off\n"); - return -ENODEV; - } else { - if (get_valid_gpio(nfc_gpio->dwl_req) == 1) { - pr_err("FW download in-progress\n"); - return -EBUSY; - } else if (nfc_dev->nfc_state == NFC_STATE_FW_DWL) { - pr_err("FW download state \n"); - return -EBUSY; - } - } - return 0; -} - -static int set_nfcc_nci_state(struct nfc_dev *nfc_dev) +/** + * get_nfcc_session_state_dl() - gets the session state + * @nfc_dev: nfc device data structure + * + * Performs get session command and determine + * the nfcc state based on session status. + * + * @Return nfcc state based on session status. + * NFC_STATE_FW_TEARED if sessionis not closed + * NFC_STATE_FW_DWL if session closed + * NFC_STATE_UNKNOWN in error cases. + */ +enum nfc_state_flags get_nfcc_session_state_dl(struct nfc_dev *nfc_dev) { int ret = 0; - char dl_reset_cmd[] = { 0x00, 0x04, 0xF0, 0x00, 0x00, 0x00, 0x18, 0x5B }; + int cmd_length = 0; + uint8_t *cmd = nfc_dev->write_kbuf; + uint8_t *rsp = nfc_dev->read_kbuf; + enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN; - pr_debug("%s:Sending DL_RESET to boot in NCI mode\n", __func__); - ret = nfc_dev->nfc_write(nfc_dev, dl_reset_cmd, - sizeof(dl_reset_cmd), MAX_RETRY_COUNT); + *cmd++ = 0x00; + *cmd++ = 0x04; + *cmd++ = 0xF2; + *cmd++ = 0x00; + *cmd++ = 0x00; + *cmd++ = 0x00; + *cmd++ = 0xF5; + *cmd++ = 0x33; + cmd_length = cmd - nfc_dev->write_kbuf; + + pr_debug("%s:Sending GET_SESSION_STATE cmd of size=%d\n", __func__, cmd_length); + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, MAX_RETRY_COUNT); if (ret <= 0) { - pr_err("%s: nfc dl reset cmd err ret %d\n", __func__, ret); + pr_err("%s: - nfc get session cmd error ret %d\n", __func__, ret); goto err; } - usleep_range(NFC_SOFT_RESET_WAIT_TIME_USEC, - NFC_SOFT_RESET_WAIT_TIME_USEC + 100); - pr_debug("%s NFCC booted in NCI mode %d\n", __func__, __LINE__); - return 0; - + memset(rsp, 0x00, DL_GET_SESSION_STATE_RSP_LEN); + pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT); + if (ret <= 0) { + pr_err("%s: - nfc get session rsp error ret %d\n", __func__, ret); + goto err; + } + if (rsp[0] != FW_MSG_CMD_RSP) { + pr_err("%s: - nfc invalid get session state rsp\n", __func__); + goto err; + } + pr_debug("Response bytes are %02x%02x%02x%02x%02x%02x%02x%02x", + rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6], rsp[7]); + /*verify fw in non-teared state */ + if (rsp[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) { + pr_err("%s NFCC booted in FW teared state\n", __func__); + nfc_state = NFC_STATE_FW_TEARED; + } else { + pr_info("%s NFCC booted in FW DN mode\n", __func__); + nfc_state = NFC_STATE_FW_DWL; + } err: - pr_err("%s Unlikely NFCC not booted in NCI mode %d\n", __func__, __LINE__); - return -1; + return nfc_state; } -static bool do_nci_reset(nfc_dev_t *nfc_dev) { - const uint8_t cmd_reset_nci[] = {0x20, 0x00, 0x01, 0x00}; - char rsp_buf[MAX_BUFFER_SIZE]; - int status = 0; +/** + * get_nfcc_chip_type() - get nfcc chip type in nci mode. + * @nfc_dev: nfc device data structure. + * + * Function to perform nci core reset and extract + * chip type from the response. + * + * @Return: enum chip_types value + * + */ +static enum chip_types get_nfcc_chip_type(struct nfc_dev *nfc_dev) +{ + int ret = 0; + int cmd_length = 0; + uint8_t major_version = 0; + uint8_t rom_version = 0; + uint8_t *cmd = nfc_dev->write_kbuf; + uint8_t *rsp = nfc_dev->read_kbuf; + enum chip_types chip_type = CHIP_UNKNOWN; - if (NULL == nfc_dev) { - pr_err("%s invalid params ", __func__); - return false; - } - pr_debug("%s Entry \n", __func__); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - pr_debug(" %s send core reset cmd \n", __func__); - status = nfc_dev->nfc_write(nfc_dev, cmd_reset_nci, - sizeof(cmd_reset_nci), NO_RETRY); - if (status <= 0) { - pr_err(" %s: nfc nci core reset cmd err status %d\n", __func__, status); - return false; + *cmd++ = 0x20; + *cmd++ = 0x00; + *cmd++ = 0x01; + *cmd++ = 0x00; + cmd_length = cmd - nfc_dev->write_kbuf; + + pr_debug("%s:Sending NCI Core Reset cmd of size=%d\n", __func__, cmd_length); + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, NO_RETRY); + if (ret <= 0) { + pr_err("%s: - nfc nci core reset cmd error ret %d\n", __func__, ret); + goto err; } usleep_range(NCI_RESET_RESP_READ_DELAY, NCI_RESET_RESP_READ_DELAY + 100); nfc_dev->nfc_enable_intr(nfc_dev); - pr_debug(" %s Reading response of NCI reset \n", __func__); - memset(rsp_buf, 0x00, MAX_BUFFER_SIZE); - status = nfc_dev->nfc_read(nfc_dev, rsp_buf, MAX_BUFFER_SIZE, NCI_RESET_RESP_TIMEOUT); - if (status <= 0) { - pr_err(" %s - nfc nci rest rsp error status %d\n", __func__, status); - nfc_dev->nfc_disable_intr(nfc_dev); - return false; + + memset(rsp, 0x00, NCI_RESET_RSP_LEN); + pr_debug("%s:Reading NCI Core Reset rsp\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_RSP_LEN, NCI_CMD_RSP_TIMEOUT); + if (ret <= 0) { + pr_err("%s: - nfc nci core reset rsp error ret %d\n", __func__, ret); + goto err_disable_intr; } - pr_debug(" %s: nci core reset response 0x%02x 0x%02x 0x%02x 0x%02x \n", - __func__, rsp_buf[0], rsp_buf[1],rsp_buf[2], rsp_buf[3]); - if(rsp_buf[0] != NCI_MSG_RSP) { + + pr_debug(" %s: nci core reset response 0x%02x%02x%02x%02x\n", + __func__, rsp[0], rsp[1], rsp[2], rsp[3]); + if (rsp[0] != NCI_MSG_RSP) { /* reset response failed response*/ - pr_err("%s invalid nci core reset response"); - nfc_dev->nfc_disable_intr(nfc_dev); - return false; + pr_err("%s invalid nci core reset response", __func__); + goto err_disable_intr; } - memset(rsp_buf, 0x00, MAX_BUFFER_SIZE); + + memset(rsp, 0x00, NCI_RESET_NTF_LEN); /* read nci rest response ntf */ - status = nfc_dev->nfc_read(nfc_dev, rsp_buf, MAX_BUFFER_SIZE, NCI_CMD_RSP_TIMEOUT); - if (status <= 0) { - pr_err("%s - nfc nci rest rsp ntf error status %d\n" - , __func__, status); + ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_NTF_LEN, NCI_CMD_RSP_TIMEOUT); + if (ret <= 0) { + pr_err("%s - nfc nci rest rsp ntf error status %d\n", __func__, ret); + goto err_disable_intr; } - pr_debug(" %s:NFC NCI Reset Response ntf 0x%02x 0x%02x 0x%02x 0x%02x \n", - __func__, rsp_buf[0], rsp_buf[1],rsp_buf[2], rsp_buf[3]); + if (rsp[0] == NCI_MSG_NTF) { + /* read version info from NCI Reset Notification */ + rom_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 3]; + major_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 2]; + /* determine chip type based on version info */ + if (rom_version == SN1XX_ROM_VER && major_version == SN1xx_MAJOR_VER) + chip_type = CHIP_SN1XX; + else if (rom_version == SN220_ROM_VER && major_version == SN220_MAJOR_VER) + chip_type = CHIP_SN220; + pr_debug(" %s:NCI Core Reset ntf 0x%02x%02x%02x%02x\n", + __func__, rsp[0], rsp[1], rsp[2], rsp[3]); + } +err_disable_intr: nfc_dev->nfc_disable_intr(nfc_dev); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - return true; +err: + return chip_type; +} + +/** + * validate_download_gpio() - validate download gpio. + * @nfc_dev: nfc_dev device data structure. + * @chip_type: chip type of the platform. + * + * Validates dwnld gpio should configured for supported and + * should not be configured for unsupported platform. + * + * @Return: true if gpio validation successful ortherwise + * false if validation fails. + */ +static bool validate_download_gpio(struct nfc_dev *nfc_dev, enum chip_types chip_type) +{ + bool status = false; + struct platform_gpio *nfc_gpio; + + if (nfc_dev == NULL) { + pr_err("%s nfc devices structure is null\n"); + return status; + } + nfc_gpio = &nfc_dev->configs.gpio; + if (chip_type == CHIP_SN1XX) { + /* gpio should be configured for SN1xx */ + status = gpio_is_valid(nfc_gpio->dwl_req); + } else if (chip_type == CHIP_SN220) { + /* gpio should not be configured for SN220 */ + set_valid_gpio(nfc_gpio->dwl_req, 0); + gpio_free(nfc_gpio->dwl_req); + nfc_gpio->dwl_req = -EINVAL; + status = true; + } + return status; } /* Check for availability of NFC controller hardware */ int nfcc_hw_check(struct nfc_dev *nfc_dev) { int ret = 0; - uint8_t nfc_state = NFC_STATE_UNKNOWN; - if(do_nci_reset(nfc_dev)) { - pr_info("%s recovery not required", __func__); - return ret; + enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN; + enum chip_types chip_type = CHIP_UNKNOWN; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + /*get fw version in nci mode*/ + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + chip_type = get_nfcc_chip_type(nfc_dev); + + /*get fw version in fw dwl mode*/ + if (chip_type == CHIP_UNKNOWN) { + nfc_dev->nfc_enable_intr(nfc_dev); + /*Chip is unknown, initially assume with fw dwl pin enabled*/ + set_valid_gpio(nfc_gpio->dwl_req, 1); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + chip_type = get_nfcc_chip_type_dl(nfc_dev); + /*get the state of nfcc normal/teared in fw dwl mode*/ + } else { + nfc_state = NFC_STATE_NCI; } - nfc_dev->nfc_enable_intr(nfc_dev); - /*set download mode for i2c products with dwl pin */ - enable_dwnld_mode(nfc_dev, true); + /*validate gpio config required as per the chip*/ + if (!validate_download_gpio(nfc_dev, chip_type)) { + pr_info("%s gpio validation fail", __func__); + ret = -ENXIO; + goto err; + } - nfc_state = get_nfcc_boot_state(nfc_dev); + /*check whether the NFCC is in FW DN or Teared state*/ + if (nfc_state != NFC_STATE_NCI) + nfc_state = get_nfcc_session_state_dl(nfc_dev); + + /*nfcc state specific operations */ switch (nfc_state) { - case NFC_STATE_FW_DWL: - usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, - NFC_GPIO_SET_WAIT_TIME_USEC + 100); - if (set_nfcc_nci_state(nfc_dev)) { - pr_debug("%s: - NFCC DL Reset Fails\n", __func__); - } else { - nfc_state = NFC_STATE_NCI; - /*set NCI mode for i2c products with dwl pin */ - enable_dwnld_mode(nfc_dev, false); - } - /* fall-through */ - case NFC_STATE_NCI: - nfc_dev->nfc_ven_enabled = true; - pr_debug("%s: - NFCC HW detected\n", __func__); - break; case NFC_STATE_FW_TEARED: pr_warn("%s: - NFCC FW Teared State\n", __func__); -#if defined(RECOVERY_ENABLE) - if(nfc_dev->recovery_required && - (do_recovery(nfc_dev) == STATUS_SUCCESS)) { - pr_debug("%s: - NFCC HW detected\n", __func__); +#if IS_ENABLED(CONFIG_NXP_NFC_RECOVERY) + /* recovery neeeded only for SN1xx */ + if (chip_type == CHIP_SN1XX) { + if (do_recovery(nfc_dev) == STATUS_FAILED) + pr_debug("%s: - nfcc recoverey failed\n", __func__); + else + pr_debug("%s: - nfcc recovered successfully\n", __func__); + nfc_state = get_nfcc_session_state_dl(nfc_dev); } #endif - nfc_dev->nfc_ven_enabled = true; + /*fallthrough*/ + case NFC_STATE_FW_DWL: + case NFC_STATE_NCI: break; case NFC_STATE_UNKNOWN: default: ret = -ENXIO; - pr_debug("%s: - NFCC HW not available\n", __func__); + pr_err("%s: - NFCC HW not available\n", __func__); + goto err; }; - - nfc_dev->nfc_disable_intr(nfc_dev); - if (nfc_state == NFC_STATE_FW_TEARED) { - nfc_state = NFC_STATE_FW_DWL; - } nfc_dev->nfc_state = nfc_state; + nfc_dev->nfc_ven_enabled = true; +err: + nfc_dev->nfc_disable_intr(nfc_dev); + set_valid_gpio(nfc_gpio->dwl_req, 0); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); return ret; } -void enable_dwnld_mode(nfc_dev_t* nfc_dev, bool value) { - if(nfc_dev != NULL) { - platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; - if (get_valid_gpio(nfc_gpio->dwl_req) != -1) { - set_valid_gpio(nfc_gpio->dwl_req, value); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - } - } -} - -void set_nfcc_state_from_rsp(struct nfc_dev *dev, const char *buf, - const int count) +int validate_nfc_state_nci(struct nfc_dev *nfc_dev) { - int packet_size = 0; - if (buf[0] == FW_MSG_CMD_RSP && buf[1] >= FW_MIN_PAYLOAD_LEN) { - packet_size = FW_HDR_LEN + buf[FW_PAYLOAD_LEN_IDX] + FW_CRC_LEN; - if (packet_size == count && dev->nfc_state == NFC_STATE_NCI) - dev->nfc_state = NFC_STATE_FW_DWL; - } else { - packet_size = NCI_HDR_LEN + buf[NCI_PAYLOAD_LEN_IDX]; - if (packet_size == count && dev->nfc_state == NFC_STATE_FW_DWL) - dev->nfc_state = NFC_STATE_NCI; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + if (!gpio_get_value(nfc_gpio->ven)) { + pr_err("VEN LOW - NFCC powered off\n"); + return -ENODEV; } - if (count != packet_size) { - pr_err("%s: Unlikely mismatch in packet size received (%d/%d)/\n", __func__, - packet_size, count); + if (get_valid_gpio(nfc_gpio->dwl_req) == 1) { + pr_err("FW download in-progress\n"); + return -EBUSY; } + if (nfc_dev->nfc_state != NFC_STATE_NCI) { + pr_err("FW download state\n"); + return -EBUSY; + } + return 0; } diff --git a/nfc/common.h b/nfc/common.h index 65dabf2858..363c6f3f83 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -1,4 +1,5 @@ /****************************************************************************** + * Copyright (C) 2015, The Linux Foundation. All rights reserved. * Copyright (C) 2019-2021 NXP * * * This program is free software; you can redistribute it and/or modify @@ -38,6 +39,7 @@ // NCI packet details #define NCI_MSG_CMD 0x20 #define NCI_MSG_RSP 0x40 +#define NCI_MSG_NTF 0x60 #define NCI_HDR_LEN 3 #define NCI_PAYLOAD_IDX 3 #define NCI_PAYLOAD_LEN_IDX 2 @@ -57,6 +59,13 @@ #define NCI_RESET_RSP_LEN (4) #define NCI_RESET_NTF_LEN (13) +#define SN1XX_ROM_VER 0x01 +#define SN1xx_MAJOR_VER 0x10 +#define SN220_ROM_VER 0x01 +#define SN220_MAJOR_VER 0x01 +#define FW_ROM_CODE_VER_OFFSET 4 +#define FW_MAJOR_VER_OFFSET 7 + #define DL_GET_VERSION_CMD_LEN (8) #define DL_GET_VERSION_RSP_LEN_1 (12) #define DL_GET_VERSION_RSP_LEN_2 (20) @@ -77,14 +86,13 @@ #define MAX_IRQ_WAIT_TIME (90) #define WAKEUP_SRC_TIMEOUT (2000) -#define NCI_MAX_CMD_RSP_TIMEOUT (5000) //5s /*command response timeout*/ #define NCI_CMD_RSP_TIMEOUT (2000) //2s /*Time to wait for NFCC to be ready again after any change in the GPIO*/ #define NFC_GPIO_SET_WAIT_TIME_USEC (10000) /*Time to wait after soft reset via any NCI/DL cmd*/ #define NFC_SOFT_RESET_WAIT_TIME_USEC (5000) -/*Time to wait before retrying i2c writes*/ +/*Time to wait before retrying i2c/I3C writes*/ #define WRITE_RETRY_WAIT_TIME_USEC (1000) /*Time to wait before retrying read for some specific usecases*/ #define READ_RETRY_WAIT_TIME_USEC (3500) @@ -95,8 +103,6 @@ #define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, long) #define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, long) #define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, long) -#define NFC_GET_PLATFORM_TYPE _IO(NFC_MAGIC, 0x04) -#define NFC_GET_NFC_STATE _IO(NFC_MAGIC, 0x05) /* NFC HAL can call this ioctl to get the current IRQ state */ #define NFC_GET_IRQ_STATE _IO(NFC_MAGIC, 0x06) @@ -158,34 +164,41 @@ enum gpio_values { }; // NFC GPIO variables -typedef struct platform_gpio { +struct platform_gpio { unsigned int irq; unsigned int ven; unsigned int dwl_req; -} platform_gpio_t; +}; -// NFC Struct to get all the required configs from DTS*/ -typedef struct platform_configs { - platform_gpio_t gpio; -} platform_configs_t; +// NFC Struct to get all the required configs from DTS +struct platform_configs { + struct platform_gpio gpio; +}; //cold reset Features specific Parameters -typedef struct cold_reset { +struct cold_reset { bool rsp_pending; /*cmd rsp pending status */ bool in_progress; /*for cold reset when gurad timer in progress */ bool reset_protection; /*reset protection enabled/disabled */ uint8_t status; /*status from response buffer */ uint8_t rst_prot_src; /*reset protection source (SPI, NFC) */ - struct mutex sync_mutex; struct timer_list timer; wait_queue_head_t read_wq; -} cold_reset_t; +}; + +enum chip_types { + CHIP_SN1XX = 0x01, + CHIP_SN220 = 0x02, + CHIP_UNKNOWN = 0xFF, +}; /* Device specific structure */ -typedef struct nfc_dev { +struct nfc_dev { wait_queue_head_t read_wq; struct mutex read_mutex; - struct mutex ese_access_mutex; + struct mutex write_mutex; + uint8_t *read_kbuf; + uint8_t *write_kbuf; struct mutex dev_ref_mutex; unsigned int dev_ref_count; struct class *nfc_class; @@ -198,42 +211,34 @@ typedef struct nfc_dev { uint8_t nfc_state; /* NFC VEN pin state */ bool nfc_ven_enabled; -#if defined(RECOVERY_ENABLE) /* current firmware major version */ uint8_t fw_major_version; - /* NFC recovery Required */ - bool recovery_required; -#endif union { - i2c_dev_t i2c_dev; + struct i2c_dev i2c_dev; }; - platform_configs_t configs; - cold_reset_t cold_reset; + struct platform_configs configs; + struct cold_reset cold_reset; - /*funtion pointers for the common i2c functionality */ - int (*nfc_read) (struct nfc_dev *dev, char *buf, size_t count, int timeout); - int (*nfc_write) (struct nfc_dev *dev, const char *buf, const size_t count, + /*function pointers for the common i2c functionality */ + int (*nfc_read)(struct nfc_dev *dev, char *buf, size_t count, int timeout); + int (*nfc_write)(struct nfc_dev *dev, const char *buf, const size_t count, int max_retry_cnt); - int (*nfc_enable_intr) (struct nfc_dev *dev); - int (*nfc_disable_intr) (struct nfc_dev *dev); - int (*nfc_flush_readq) (struct nfc_dev *dev); -} nfc_dev_t; + int (*nfc_enable_intr)(struct nfc_dev *dev); + int (*nfc_disable_intr)(struct nfc_dev *dev); +}; int nfc_dev_open(struct inode *inode, struct file *filp); int nfc_dev_close(struct inode *inode, struct file *filp); long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); -int nfc_parse_dt(struct device *dev, platform_configs_t *nfc_configs, +int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface); -int nfc_misc_register(nfc_dev_t *nfc_dev, +int nfc_misc_register(struct nfc_dev *nfc_dev, const struct file_operations *nfc_fops, int count, char *devname, char *classname); -void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count); +void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count); int configure_gpio(unsigned int gpio, int flag); -void gpio_set_ven(nfc_dev_t *nfc_dev, int value); -void gpio_free_all(nfc_dev_t *nfc_dev); -int validate_nfc_state_nci(nfc_dev_t *nfc_dev); -int nfcc_hw_check(nfc_dev_t *nfc_dev); -void set_nfcc_state_from_rsp(nfc_dev_t *dev, const char *buf, - const int count); -void enable_dwnld_mode(nfc_dev_t* nfc_dev, bool value); +void gpio_set_ven(struct nfc_dev *nfc_dev, int value); +void gpio_free_all(struct nfc_dev *nfc_dev); +int validate_nfc_state_nci(struct nfc_dev *nfc_dev); +int nfcc_hw_check(struct nfc_dev *nfc_dev); #endif //_COMMON_H_ diff --git a/nfc/common_ese.c b/nfc/common_ese.c index 9c418036f3..cf63a15690 100644 --- a/nfc/common_ese.c +++ b/nfc/common_ese.c @@ -30,17 +30,18 @@ static void cold_reset_gaurd_timer_callback(struct timer_list *t) { - cold_reset_t *cold_reset = from_timer(cold_reset, t, timer); + struct cold_reset *cold_reset = from_timer(cold_reset, t, timer); + pr_debug("%s: Enter\n", __func__); cold_reset->in_progress = false; - return; } -static long start_cold_reset_guard_timer(cold_reset_t *cold_reset) +static long start_cold_reset_guard_timer(struct cold_reset *cold_reset) { long ret = -EINVAL; + if (timer_pending(&cold_reset->timer) == 1) { - pr_debug("ese_cold_reset_guard_timer: delete pending timer \n"); + pr_debug("ese_cold_reset_guard_timer: delete pending timer\n"); /* delete timer if already pending */ del_timer(&cold_reset->timer); } @@ -51,34 +52,33 @@ static long start_cold_reset_guard_timer(cold_reset_t *cold_reset) return ret; } -static int send_cold_reset_protection_cmd(nfc_dev_t *nfc_dev, bool requestType) +static int send_cold_reset_protection_cmd(struct nfc_dev *nfc_dev, bool requestType) { int ret = 0; - int length = 0; - uint8_t *cmd = NULL; - uint8_t cld_rst_cmd[] = { NCI_PROP_MSG_CMD, CLD_RST_OID, - CLD_RST_PAYLOAD_SIZE - }; - uint8_t rst_prot_cmd[] = { NCI_PROP_MSG_CMD, RST_PROT_OID, - RST_PROT_PAYLOAD_SIZE, 0x00 - }; + int cmd_length = 0; + uint8_t *cmd = nfc_dev->write_kbuf; + struct cold_reset *cold_reset = &nfc_dev->cold_reset; - cold_reset_t *cold_reset = &nfc_dev->cold_reset; - if (requestType) { - length = sizeof(rst_prot_cmd); - rst_prot_cmd[NCI_PAYLOAD_IDX] = (!cold_reset->reset_protection) ? 1 : 0; - cmd = rst_prot_cmd; - } else { - length = sizeof(cld_rst_cmd); - cmd = cld_rst_cmd; + mutex_lock(&nfc_dev->write_mutex); + *cmd++ = NCI_PROP_MSG_CMD; + + if (requestType) { /*reset protection*/ + *cmd++ = RST_PROT_OID; + *cmd++ = RST_PROT_PAYLOAD_SIZE; + *cmd++ = (!cold_reset->reset_protection) ? 1 : 0; + } else { /*cold reset*/ + *cmd++ = CLD_RST_OID; + *cmd++ = CLD_RST_PAYLOAD_SIZE; } + cmd_length = cmd - nfc_dev->write_kbuf; - ret = nfc_dev->nfc_write(nfc_dev, cmd, length, MAX_RETRY_COUNT); - if (ret != length) { + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, MAX_RETRY_COUNT); + if (ret != cmd_length) { + ret = -EIO; pr_err("%s : nfc_write returned %d\n", __func__, ret); - return -EIO; + goto exit; } - + cmd = nfc_dev->write_kbuf; if (requestType) { pr_debug("%s: NxpNciX: %d > %02X%02X%02X%02X\n", __func__, ret, cmd[0], cmd[1], cmd[2], cmd[3]); @@ -86,19 +86,21 @@ static int send_cold_reset_protection_cmd(nfc_dev_t *nfc_dev, bool requestType) pr_debug("%s: NxpNciX: %d > %02X%02X%02X\n", __func__, ret, cmd[0], cmd[1], cmd[2]); } +exit: + mutex_unlock(&nfc_dev->write_mutex); return ret; } -void wakeup_on_prop_rsp(nfc_dev_t *nfc_dev, uint8_t *buf) +void wakeup_on_prop_rsp(struct nfc_dev *nfc_dev, uint8_t *buf) { - cold_reset_t *cold_reset = &nfc_dev->cold_reset; - cold_reset->status = -EIO; + struct cold_reset *cold_reset = &nfc_dev->cold_reset; - if ((NCI_HDR_LEN + buf[NCI_PAYLOAD_LEN_IDX]) != NCI_PROP_MSG_RSP_LEN) { - pr_err("%s: - invalid response for cold_reset/protection \n", __func__); - } else { + cold_reset->status = -EIO; + if ((NCI_HDR_LEN + buf[NCI_PAYLOAD_LEN_IDX]) != NCI_PROP_MSG_RSP_LEN) + pr_err("%s: - invalid response for cold_reset/protection\n", __func__); + else cold_reset->status = buf[NCI_PAYLOAD_IDX]; - } + pr_debug("%s NxpNciR : len = 4 > %02X%02X%02X%02X\n", __func__, buf[0], buf[1], buf[2], buf[3]); @@ -106,9 +108,11 @@ void wakeup_on_prop_rsp(nfc_dev_t *nfc_dev, uint8_t *buf) wake_up_interruptible(&cold_reset->read_wq); } -static int validate_cold_reset_protection_request(cold_reset_t *cold_reset, +static int validate_cold_reset_protection_request(struct cold_reset *cold_reset, unsigned long arg) { + int ret = 0; + if (!cold_reset->reset_protection) { if (IS_RST_PROT_EN_REQ(arg) && IS_SRC_VALID_PROT(arg)) { pr_debug("%s:req - reset protection enable\n", __func__); @@ -116,10 +120,10 @@ static int validate_cold_reset_protection_request(cold_reset_t *cold_reset, pr_debug("%s:req - cold reset\n", __func__); } else if (IS_RST_PROT_DIS_REQ(arg) && IS_SRC_VALID_PROT(arg)) { pr_debug("%s:req - reset protection already disable\n", __func__); - return -EINVAL; + ret = -EINVAL; } else { - pr_err("%s:Operation not permitted \n", __func__); - return -EPERM; + pr_err("%s:Operation not permitted\n", __func__); + ret = -EPERM; } } else { if (IS_RST_PROT_DIS_REQ(arg) @@ -130,21 +134,21 @@ static int validate_cold_reset_protection_request(cold_reset_t *cold_reset, pr_debug("%s:req - cold reset from same source\n", __func__); } else if (IS_RST_PROT_EN_REQ(arg) && IS_SRC(arg, cold_reset->rst_prot_src)) { - pr_debug("%s:request - enable reset protection from same source\n", __func__); + pr_debug("%s:req - enable reset protection from same src\n", __func__); } else { - pr_err("%s: Operation not permitted \n", __func__); - return -EPERM; + pr_err("%s: Operation not permitted\n", __func__); + ret = -EPERM; } } - return 0; + return ret; } -static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg) +static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, unsigned long arg) { int ret = 0; struct file filp; - uint8_t cld_rst_rsp[MAX_BUFFER_SIZE]; - cold_reset_t *cold_reset = &nfc_dev->cold_reset; + char *rsp = nfc_dev->read_kbuf; + struct cold_reset *cold_reset = &nfc_dev->cold_reset; bool nfc_dev_opened = false; /*check if NFCC not in the FW download or hard reset state */ @@ -157,9 +161,7 @@ static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg) /* check if NFC is enabled */ mutex_lock(&nfc_dev->dev_ref_mutex); nfc_dev_opened = (nfc_dev->dev_ref_count > 0) ? true : false; - mutex_unlock(&nfc_dev->dev_ref_mutex); - mutex_lock(&cold_reset->sync_mutex); /*check if NFCC not in the FW download or hard reset state */ ret = validate_cold_reset_protection_request(cold_reset, arg); if (ret < 0) { @@ -191,7 +193,7 @@ static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg) /*start the cold reset guard timer */ if (IS_CLD_RST_REQ(arg)) { /*Guard timer not needed when OSU over NFC*/ - if(!(cold_reset->reset_protection && IS_SRC_NFC(arg))) { + if (!(cold_reset->reset_protection && IS_SRC_NFC(arg))) { ret = start_cold_reset_guard_timer(cold_reset); if (ret) { pr_err("%s: Error in mod_timer\n", __func__); @@ -213,12 +215,14 @@ static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg) } else { /* Read data as NFC thread is not active */ filp.private_data = nfc_dev; - filp.f_flags &= ~O_NONBLOCK; - ret = nfc_dev->nfc_read(nfc_dev, cld_rst_rsp, 3, NCI_CMD_RSP_TIMEOUT); - if (!ret) - break; - usleep_range(READ_RETRY_WAIT_TIME_USEC, - READ_RETRY_WAIT_TIME_USEC + 500); + if (nfc_dev->interface == PLATFORM_IF_I2C) { + filp.f_flags &= ~O_NONBLOCK; + ret = nfc_dev->nfc_read(nfc_dev, rsp, 3, NCI_CMD_RSP_TIMEOUT); + if (!ret) + break; + usleep_range(READ_RETRY_WAIT_TIME_USEC, + READ_RETRY_WAIT_TIME_USEC + 500); + } } } while (ret == -ERESTARTSYS || ret == -EFAULT); @@ -237,7 +241,7 @@ static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg) } } err: - mutex_unlock(&cold_reset->sync_mutex); + mutex_unlock(&nfc_dev->dev_ref_mutex); return ret; } @@ -247,10 +251,11 @@ err: * VEN HIGH - eSE and NFCC both are powered on * VEN LOW - eSE and NFCC both are power down */ -int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg) +int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) { int ret = 0; - platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + if (arg == ESE_POWER_ON) { /** * Let's store the NFC VEN pin state @@ -284,64 +289,62 @@ int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg) } return ret; } - EXPORT_SYMBOL(nfc_ese_pwr); #define ESE_LEGACY_INTERFACE #ifdef ESE_LEGACY_INTERFACE -static nfc_dev_t *nfc_dev_legacy = NULL; +static struct nfc_dev *nfc_dev_legacy; /****************************************************************************** * perform_ese_cold_reset() - It shall be called by others driver(not nfc/ese) * to perform cold reset only * @arg: request of cold reset from other drivers should be ESE_CLD_RST_OTHER * - * Returns:- 0 in case of sucess and negative values in case of failure + * Returns:- 0 in case of success and negative values in case of failure *****************************************************************************/ int perform_ese_cold_reset(unsigned long arg) { int ret = 0; + if (nfc_dev_legacy) { if (IS_CLD_RST_REQ(arg) && IS_SRC_OTHER(arg)) { ret = nfc_ese_pwr(nfc_dev_legacy, arg); } else { - pr_err("%s : Operation not permitted \n", __func__); + pr_err("%s : Operation not permitted\n", __func__); return -EPERM; } } pr_debug("%s:%d exit, status:%lu", __func__, arg, ret); return ret; } - EXPORT_SYMBOL(perform_ese_cold_reset); #endif //ESE_LEGACY_INTERFACE -void common_ese_on_hard_reset(nfc_dev_t *nfc_dev) +void ese_cold_reset_release(struct nfc_dev *nfc_dev) { - cold_reset_t *cold_reset = &nfc_dev->cold_reset; + struct cold_reset *cold_reset = &nfc_dev->cold_reset; + cold_reset->rsp_pending = false; cold_reset->in_progress = false; - if (timer_pending(&cold_reset->timer) == 1) { + if (timer_pending(&cold_reset->timer) == 1) del_timer(&cold_reset->timer); - } } -void common_ese_init(nfc_dev_t *nfc_dev) +void common_ese_init(struct nfc_dev *nfc_dev) { - cold_reset_t *cold_reset = &nfc_dev->cold_reset; + struct cold_reset *cold_reset = &nfc_dev->cold_reset; + cold_reset->reset_protection = false; cold_reset->rst_prot_src = SRC_NONE; init_waitqueue_head(&cold_reset->read_wq); - mutex_init(&cold_reset->sync_mutex); - common_ese_on_hard_reset(nfc_dev); + ese_cold_reset_release(nfc_dev); #ifdef ESE_LEGACY_INTERFACE nfc_dev_legacy = nfc_dev; #endif //ESE_LEGACY_INTERFACE } -void common_ese_exit(nfc_dev_t *nfc_dev) +void common_ese_exit(struct nfc_dev *nfc_dev) { - mutex_destroy(&nfc_dev->cold_reset.sync_mutex); #ifdef ESE_LEGACY_INTERFACE nfc_dev_legacy = NULL; #endif //ESE_LEGACY_INTERFACE diff --git a/nfc/common_ese.h b/nfc/common_ese.h index f4ebb5d57a..46d8d2f27c 100644 --- a/nfc/common_ese.h +++ b/nfc/common_ese.h @@ -23,32 +23,32 @@ #include "common.h" /*nci prop msg 1st byte*/ -#define NCI_PROP_MSG_GID 0x0F -#define NCI_PROP_MSG_CMD (NCI_MSG_CMD | NCI_PROP_MSG_GID) -#define NCI_PROP_MSG_RSP (NCI_MSG_RSP | NCI_PROP_MSG_GID) +#define NCI_PROP_MSG_GID 0x0F +#define NCI_PROP_MSG_CMD (NCI_MSG_CMD | NCI_PROP_MSG_GID) +#define NCI_PROP_MSG_RSP (NCI_MSG_RSP | NCI_PROP_MSG_GID) /*nci prop msg 2nd byte*/ -#define CLD_RST_OID 0x1E -#define RST_PROT_OID 0x1F +#define CLD_RST_OID 0x1E +#define RST_PROT_OID 0x1F /*nci prop msg 3rd byte*/ -#define CLD_RST_PAYLOAD_SIZE 0x00 -#define RST_PROT_PAYLOAD_SIZE 0x01 +#define CLD_RST_PAYLOAD_SIZE 0x00 +#define RST_PROT_PAYLOAD_SIZE 0x01 /*nci prop msg response length*/ -#define NCI_PROP_MSG_RSP_LEN 0x04 +#define NCI_PROP_MSG_RSP_LEN 0x04 /*cold reset guard time to allow back to back cold reset after some time*/ -#define ESE_CLD_RST_GUARD_TIME (3000) //3s +#define ESE_CLD_RST_GUARD_TIME (3000) //3s /*guard time to reboot after reset*/ -#define ESE_CLD_RST_REBOOT_GUARD_TIME (50) //50ms +#define ESE_CLD_RST_REBOOT_GUARD_TIME (50) //50ms /*sources of reset protection and cold reset*/ -typedef enum reset_source { +enum reset_source { SRC_SPI = 0, SRC_NFC = 0x10, SRC_OTHER = 0x20, SRC_NONE = 0x80, -} reset_source_t; +}; enum ese_ioctl_request { ESE_POWER_ON = 0, /* eSE POWER ON */ @@ -75,7 +75,7 @@ enum ese_ioctl_request { #define IS_SRC_NFC(arg) IS_SRC(arg, SRC_NFC) #define IS_SRC_OTHER(arg) IS_SRC(arg, SRC_OTHER) #define IS_SRC_VALID(arg) (IS_SRC_SPI(arg) || IS_SRC_NFC(arg) || \ - IS_SRC_OTHER(arg)) + IS_SRC_OTHER(arg)) #define IS_SRC_VALID_PROT(arg) (IS_SRC_SPI(arg) || IS_SRC_NFC(arg)) #define IS_RST(arg, type) ((arg & 0xF) == type) @@ -84,14 +84,14 @@ enum ese_ioctl_request { #define IS_RST_PROT_DIS_REQ(arg) IS_RST(arg, ESE_RST_PROT_DIS) #define IS_RST_PROT_REQ(arg) (IS_RST_PROT_EN_REQ(arg) || IS_RST_PROT_DIS_REQ(arg)) /* This macro evaluates to 1 if prop cmd response is received */ -#define IS_PROP_CMD_RSP(buf) \ - ((NCI_PROP_MSG_RSP == buf[0]) && ((CLD_RST_OID == buf[1]) || \ - (RST_PROT_OID == buf[1]))) +#define IS_PROP_CMD_RSP(buf) \ + ((buf[0] == NCI_PROP_MSG_RSP) && ((buf[1] == CLD_RST_OID) || \ + (buf[1] == RST_PROT_OID))) -void wakeup_on_prop_rsp(nfc_dev_t *nfc_dev, uint8_t *buf); -int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg); -void common_ese_on_hard_reset(nfc_dev_t *nfc_dev); -void common_ese_init(nfc_dev_t *nfc_dev); -void common_ese_exit(nfc_dev_t *nfc_dev); +void wakeup_on_prop_rsp(struct nfc_dev *nfc_dev, uint8_t *buf); +int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg); +void ese_cold_reset_release(struct nfc_dev *nfc_dev); +void common_ese_init(struct nfc_dev *nfc_dev); +void common_ese_exit(struct nfc_dev *nfc_dev); #endif /* _COMMON_ESE_H_ */ diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 2a0954e1d0..d6768858d7 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -1,4 +1,5 @@ /****************************************************************************** + * Copyright (C) 2015, The Linux Foundation. All rights reserved. * Copyright (C) 2013-2021 NXP * * * This program is free software; you can redistribute it and/or modify @@ -44,7 +45,6 @@ #include "common.h" #include "common_ese.h" -static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, int timeout); /** * i2c_disable_irq() * @@ -91,8 +91,9 @@ int i2c_enable_irq(struct nfc_dev *dev) static irqreturn_t i2c_irq_handler(int irq, void *dev_id) { - nfc_dev_t *nfc_dev = dev_id; - i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + struct nfc_dev *nfc_dev = dev_id; + struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; + if (device_may_wakeup(&i2c_dev->client->dev)) pm_wakeup_event(&i2c_dev->client->dev, WAKEUP_SRC_TIMEOUT); @@ -102,52 +103,22 @@ static irqreturn_t i2c_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout){ + +int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) +{ + int ret; + struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; pr_debug("%s : reading %zu bytes.\n", __func__, count); - if(timeout > NCI_MAX_CMD_RSP_TIMEOUT) - timeout = NCI_MAX_CMD_RSP_TIMEOUT; - - return i2c_read_internal(dev, buf, count, timeout); -} - -int i2c_write(struct nfc_dev *dev, const char *buf, size_t count, - int max_retry_cnt) -{ - int ret = -EINVAL; - int retry_cnt; - - pr_debug("%s : writing %zu bytes.\n", __func__, count); - - for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) { - ret = i2c_master_send(dev->i2c_dev.client, buf, count); - if (ret <= 0) { - pr_warn("%s: write failed, Maybe in Standby Mode - Retry(%d)\n", __func__, - retry_cnt); - usleep_range(WRITE_RETRY_WAIT_TIME_USEC, - WRITE_RETRY_WAIT_TIME_USEC + 100); - } else if (ret == count) - break; - } - return ret; -} - -static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, int timeout) -{ - int ret; - char tmp[MAX_BUFFER_SIZE]; - nfc_dev_t *nfc_dev = dev; - i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; - platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio; + if (timeout > NCI_CMD_RSP_TIMEOUT) + timeout = NCI_CMD_RSP_TIMEOUT; if (count > MAX_BUFFER_SIZE) count = MAX_BUFFER_SIZE; - pr_debug("%s : reading %zu bytes.\n", __func__, count); - mutex_lock(&nfc_dev->read_mutex); if (!gpio_get_value(nfc_gpio->irq)) { - while (1) { ret = 0; if (!i2c_dev->irq_enabled) { @@ -155,9 +126,9 @@ static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, i enable_irq(i2c_dev->client->irq); } if (!gpio_get_value(nfc_gpio->irq)) { - if(timeout) { + if (timeout) { ret = wait_event_interruptible_timeout(nfc_dev->read_wq, - !i2c_dev-> irq_enabled, msecs_to_jiffies(timeout)); + !i2c_dev->irq_enabled, msecs_to_jiffies(timeout)); if (ret <= 0) { pr_err("%s timeout/error in read\n", __func__); @@ -185,11 +156,11 @@ static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, i } } - memset(tmp, 0x00, count); + memset(buf, 0x00, count); /* Read data */ - ret = i2c_master_recv(nfc_dev->i2c_dev.client, tmp, count); + ret = i2c_master_recv(nfc_dev->i2c_dev.client, buf, count); if (ret <= 0) { - pr_err("%s: i2c_read returned %d\n", __func__, ret); + pr_err("%s: returned %d\n", __func__, ret); goto err; } /* check if it's response of cold reset command @@ -197,16 +168,15 @@ static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, i * command was sent by driver */ if (nfc_dev->cold_reset.rsp_pending) { - if (IS_PROP_CMD_RSP(tmp)) { + if (IS_PROP_CMD_RSP(buf)) { /* Read data */ - ret = i2c_master_recv(nfc_dev->i2c_dev.client, &tmp[NCI_PAYLOAD_IDX], - tmp[NCI_PAYLOAD_LEN_IDX]); + ret = i2c_master_recv(nfc_dev->i2c_dev.client, &buf[NCI_PAYLOAD_IDX], + buf[NCI_PAYLOAD_LEN_IDX]); if (ret <= 0) { - pr_err("%s: failure to read prop cold reset/protection rsp header\n", __func__); + pr_err("%s: error reading cold reset/prot rsp header\n", __func__); goto err; } - wakeup_on_prop_rsp(nfc_dev, tmp); - mutex_unlock(&nfc_dev->read_mutex); + wakeup_on_prop_rsp(nfc_dev, buf); /* * NFC process doesn't know about cold reset command * being sent as it was initiated by eSE process @@ -215,47 +185,76 @@ static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, i return 0; } } - if (copy_to_user(buf, tmp, ret)) { - pr_warn("%s : failed to copy to user space\n", __func__); - ret = -EFAULT; - } - err: - mutex_unlock(&nfc_dev->read_mutex); return ret; } -ssize_t nfc_i2c_dev_read(struct file * filp, char __user *buf, - size_t count, loff_t * offset) +int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, + int max_retry_cnt) { - pr_debug("%s : reading %zu bytes.\n", __func__, count); - if (filp->f_flags & O_NONBLOCK) { - pr_err(":f_falg has O_NONBLOCK. EAGAIN\n"); - return -EAGAIN; - } - return i2c_read_internal((nfc_dev_t *)filp->private_data, buf, count, 0); -} - -ssize_t nfc_i2c_dev_write(struct file * filp, const char __user *buf, - size_t count, loff_t * offset) -{ - int ret; - char tmp[MAX_DL_BUFFER_SIZE]; - nfc_dev_t *nfc_dev = filp->private_data; + int ret = -EINVAL; + int retry_cnt; if (count > MAX_DL_BUFFER_SIZE) count = MAX_DL_BUFFER_SIZE; - if (copy_from_user(tmp, buf, count)) { + pr_debug("%s : writing %zu bytes.\n", __func__, count); + + for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) { + ret = i2c_master_send(nfc_dev->i2c_dev.client, buf, count); + if (ret <= 0) { + pr_warn("%s: failed to write ret(%d), Maybe in Standby Mode - Retry(%d)\n", __func__, + ret, retry_cnt); + usleep_range(WRITE_RETRY_WAIT_TIME_USEC, + WRITE_RETRY_WAIT_TIME_USEC + 100); + } else if (ret != count) { + pr_err("%s: failed to write %d\n", __func__, ret); + ret = -EIO; + } else if (ret == count) + break; + } + return ret; +} + +ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + int ret = 0; + struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; + + if (filp->f_flags & O_NONBLOCK) { + pr_err(":f_falg has O_NONBLOCK. EAGAIN\n"); + return -EAGAIN; + } + mutex_lock(&nfc_dev->read_mutex); + ret = i2c_read(nfc_dev, nfc_dev->read_kbuf, count, 0); + if (ret > 0) { + if (copy_to_user(buf, nfc_dev->read_kbuf, ret)) { + pr_warn("%s : failed to copy to user space\n", __func__); + ret = -EFAULT; + } + } + mutex_unlock(&nfc_dev->read_mutex); + return ret; +} + +ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + int ret = 0; + struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; + + if (count > MAX_DL_BUFFER_SIZE) + count = MAX_DL_BUFFER_SIZE; + + mutex_lock(&nfc_dev->write_mutex); + if (copy_from_user(nfc_dev->write_kbuf, buf, count)) { pr_err("%s : failed to copy from user space\n", __func__); + mutex_unlock(&nfc_dev->write_mutex); return -EFAULT; } - ret = i2c_write(nfc_dev, tmp, count, NO_RETRY); - if (ret != count) { - pr_err("%s: failed to write %d\n", __func__, ret); - ret = -EIO; - } - + ret = i2c_write(nfc_dev, nfc_dev->write_kbuf, count, NO_RETRY); + mutex_unlock(&nfc_dev->write_mutex); return ret; } @@ -272,12 +271,13 @@ static const struct file_operations nfc_i2c_dev_fops = { int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; - nfc_dev_t *nfc_dev = NULL; - i2c_dev_t *i2c_dev = NULL; - platform_configs_t nfc_configs; - platform_gpio_t *nfc_gpio = &nfc_configs.gpio; + struct nfc_dev *nfc_dev = NULL; + struct i2c_dev *i2c_dev = NULL; + struct platform_configs nfc_configs; + struct platform_gpio *nfc_gpio = &nfc_configs.gpio; + pr_debug("%s: enter\n", __func__); - /*retrive details of gpios from dt */ + /*retrieve details of gpios from dt */ ret = nfc_parse_dt(&client->dev, &nfc_configs, PLATFORM_IF_I2C); if (ret) { pr_err("%s : failed to parse dt\n", __func__); @@ -289,11 +289,21 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) ret = -ENODEV; goto err; } - nfc_dev = kzalloc(sizeof(nfc_dev_t), GFP_KERNEL); + nfc_dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL); if (nfc_dev == NULL) { ret = -ENOMEM; goto err; } + nfc_dev->read_kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); + if (!nfc_dev->read_kbuf) { + ret = -ENOMEM; + goto err; + } + nfc_dev->write_kbuf = kzalloc(MAX_DL_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); + if (!nfc_dev->write_kbuf) { + ret = -ENOMEM; + goto err; + } nfc_dev->interface = PLATFORM_IF_I2C; nfc_dev->nfc_state = NFC_STATE_NCI; nfc_dev->i2c_dev.client = client; @@ -302,11 +312,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) nfc_dev->nfc_write = i2c_write; nfc_dev->nfc_enable_intr = i2c_enable_irq; nfc_dev->nfc_disable_intr = i2c_disable_irq; -#if defined(RECOVERY_ENABLE) - nfc_dev->recovery_required = false; nfc_dev->fw_major_version = 0; -#endif - ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT); if (ret) { pr_err("%s: unable to request nfc reset gpio [%d]\n", __func__, nfc_gpio->ven); @@ -324,14 +330,14 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) nfc_gpio->dwl_req); } - /*copy the retrived gpio details from DT */ + /*copy the retrieved gpio details from DT */ memcpy(&nfc_dev->configs, &nfc_configs, sizeof(struct platform_configs)); /* init mutex and queues */ init_waitqueue_head(&nfc_dev->read_wq); mutex_init(&nfc_dev->read_mutex); + mutex_init(&nfc_dev->write_mutex); mutex_init(&nfc_dev->dev_ref_mutex); - mutex_init(&nfc_dev->ese_access_mutex); spin_lock_init(&i2c_dev->irq_enabled_lock); common_ese_init(nfc_dev); ret = nfc_misc_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT, @@ -352,8 +358,9 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) i2c_disable_irq(nfc_dev); ret = nfcc_hw_check(nfc_dev); - if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { + if (ret != 0) { pr_err("nfc hw check failed ret %d\n", ret); + goto err_nfc_misc_unregister; } device_init_wakeup(&client->dev, true); @@ -368,21 +375,21 @@ err_nfc_misc_unregister: err_mutex_destroy: mutex_destroy(&nfc_dev->dev_ref_mutex); mutex_destroy(&nfc_dev->read_mutex); - mutex_destroy(&nfc_dev->ese_access_mutex); - mutex_destroy(&nfc_dev->cold_reset.sync_mutex); + mutex_destroy(&nfc_dev->write_mutex); err: - if (nfc_dev) { - gpio_free_all(nfc_dev); - kfree(nfc_dev); - } - pr_err("%s: probing not successful, check hardware\n", __func__); - return ret; + gpio_free_all(nfc_dev); + kfree(nfc_dev->read_kbuf); + kfree(nfc_dev->write_kbuf); + kfree(nfc_dev); + pr_err("%s: probing not successful, check hardware\n", __func__); + return ret; } int nfc_i2c_dev_remove(struct i2c_client *client) { int ret = 0; - nfc_dev_t *nfc_dev = NULL; + struct nfc_dev *nfc_dev = NULL; + pr_info("%s: remove device\n", __func__); nfc_dev = i2c_get_clientdata(client); if (!nfc_dev) { @@ -398,9 +405,10 @@ int nfc_i2c_dev_remove(struct i2c_client *client) free_irq(client->irq, nfc_dev); nfc_misc_unregister(nfc_dev, DEV_COUNT); mutex_destroy(&nfc_dev->read_mutex); - mutex_destroy(&nfc_dev->ese_access_mutex); - mutex_destroy(&nfc_dev->cold_reset.sync_mutex); + mutex_destroy(&nfc_dev->write_mutex); gpio_free_all(nfc_dev); + kfree(nfc_dev->read_kbuf); + kfree(nfc_dev->write_kbuf); kfree(nfc_dev); return ret; } @@ -408,8 +416,8 @@ int nfc_i2c_dev_remove(struct i2c_client *client) int nfc_i2c_dev_suspend(struct device *device) { struct i2c_client *client = to_i2c_client(device); - nfc_dev_t *nfc_dev = i2c_get_clientdata(client); - i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + struct nfc_dev *nfc_dev = i2c_get_clientdata(client); + struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; if (device_may_wakeup(&client->dev) && i2c_dev->irq_enabled) { if (!enable_irq_wake(client->irq)) @@ -421,8 +429,8 @@ int nfc_i2c_dev_suspend(struct device *device) int nfc_i2c_dev_resume(struct device *device) { struct i2c_client *client = to_i2c_client(device); - nfc_dev_t *nfc_dev = i2c_get_clientdata(client); - i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev; + struct nfc_dev *nfc_dev = i2c_get_clientdata(client); + struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; if (device_may_wakeup(&client->dev) && i2c_dev->irq_wake_up) { if (!disable_irq_wake(client->irq)) @@ -462,6 +470,7 @@ MODULE_DEVICE_TABLE(of, nfc_i2c_dev_match_table); static int __init nfc_i2c_dev_init(void) { int ret = 0; + pr_info("Loading NXP NFC I2C driver\n"); ret = i2c_add_driver(&nfc_i2c_dev_driver); if (ret != 0) diff --git a/nfc/i2c_drv.h b/nfc/i2c_drv.h index 745c211d72..47b8884687 100644 --- a/nfc/i2c_drv.h +++ b/nfc/i2c_drv.h @@ -1,4 +1,5 @@ /****************************************************************************** + * Copyright (C) 2015, The Linux Foundation. All rights reserved. * Copyright (C) 2019-2021 NXP * * * This program is free software; you can redistribute it and/or modify @@ -25,14 +26,14 @@ #define NFC_I2C_DEV_ID "pn553" //Interface specific parameters -typedef struct i2c_dev { +struct i2c_dev { struct i2c_client *client; /*IRQ parameters */ bool irq_enabled; spinlock_t irq_enabled_lock; /* NFC_IRQ wake-up state */ bool irq_wake_up; -} i2c_dev_t; +}; long nfc_i2c_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); int nfc_i2c_dev_probe(struct i2c_client *client, diff --git a/nfc/recovery_fw.c b/nfc/recovery_fw.c index c210337bd4..f19c046402 100644 --- a/nfc/recovery_fw.c +++ b/nfc/recovery_fw.c @@ -1,1325 +1,1326 @@ -/******************************************************************************************** - * - * Copyright 2021 NXP - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"),to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - ********************************************************************************************/ -#include -const uint8_t gphDnldNfc_DlSequence[] = { - 0x01, 0x34, 0xC0, 0x00, 0xDE, 0x10, 0xAD, 0x69, 0xE0, 0x28, - 0xAC, 0xFA, 0xF2, 0x4A, 0x0F, 0x49, 0x7E, 0x6A, 0x61, 0xD1, - 0x00, 0xFD, 0x4A, 0x66, 0xDD, 0x42, 0x4D, 0xFF, 0x90, 0xA5, - 0x6C, 0x54, 0xF0, 0x53, 0x5E, 0x17, 0x1E, 0x28, 0x8B, 0xF2, - 0x56, 0x6D, 0x74, 0x7B, 0x4E, 0xBA, 0xEB, 0x8D, 0x22, 0x43, - 0x01, 0xE9, 0xC4, 0x85, 0x2B, 0xFB, 0xA7, 0xD9, 0x3C, 0x64, - 0x63, 0x2D, 0xBB, 0x63, 0x5C, 0xDB, 0x14, 0x4D, 0x86, 0xA0, - 0x73, 0xC1, 0x32, 0xA4, 0x12, 0xD0, 0xED, 0x12, 0x90, 0xCF, - 0xAF, 0x56, 0x35, 0x3D, 0x97, 0x6B, 0xAC, 0x81, 0x1B, 0xD6, - 0x77, 0x9A, 0x4F, 0x9C, 0x90, 0x7D, 0x16, 0x6E, 0xC4, 0xCD, - 0x2D, 0xD2, 0x57, 0x49, 0x99, 0x24, 0xBC, 0x06, 0x71, 0x04, - 0xA8, 0x14, 0xEF, 0x21, 0x55, 0x0D, 0xAD, 0x82, 0x88, 0x5C, - 0xEF, 0xDF, 0x03, 0x93, 0xB5, 0xE8, 0x21, 0x18, 0xE0, 0x54, - 0xB8, 0xE1, 0x7E, 0x88, 0xE9, 0xF7, 0xEE, 0x86, 0xD2, 0x36, - 0xD7, 0x4B, 0x99, 0x6C, 0x35, 0x8B, 0xE0, 0xA2, 0xA2, 0xFB, - 0xED, 0xB5, 0x9A, 0xA0, 0xEE, 0x19, 0x67, 0x66, 0x14, 0x14, - 0xEC, 0xEF, 0x3F, 0xC0, 0x25, 0x7C, 0xA8, 0x9F, 0x58, 0x11, - 0xCD, 0x99, 0x00, 0xBF, 0xB8, 0x6D, 0xD5, 0x06, 0x8A, 0x5D, - 0x40, 0xB0, 0x2C, 0x9A, 0x20, 0xA2, 0x30, 0xDA, 0xFD, 0xB0, - 0xE3, 0x05, 0x5F, 0xB7, 0x3B, 0x9C, 0xD6, 0xB8, 0x92, 0xAE, - 0x4B, 0xDC, 0xF2, 0x1D, 0xA4, 0x11, 0xCE, 0x0C, 0xFD, 0x37, - 0x6E, 0xBA, 0x8B, 0x6C, 0x84, 0x3E, 0x3A, 0x3D, 0x20, 0xBE, - 0x64, 0xA6, 0x56, 0x7F, 0x06, 0x66, 0x04, 0x38, 0x1D, 0x97, - 0xD9, 0x96, 0xE6, 0x07, 0x29, 0xE2, 0x1A, 0xC4, 0x5F, 0x0A, - 0xAC, 0x62, 0x50, 0xF8, 0xD2, 0x33, 0x3F, 0x7A, 0x50, 0x89, - 0x98, 0x44, 0xCB, 0xFD, 0x75, 0x79, 0x25, 0xB1, 0x3A, 0xDE, - 0x53, 0x86, 0x13, 0x54, 0x46, 0x0B, 0x5F, 0x94, 0xEC, 0x1B, - 0x72, 0x24, 0x35, 0x84, 0x67, 0xC8, 0xBE, 0xDB, 0xAC, 0xB2, - 0x0C, 0x94, 0x88, 0xE1, 0xC4, 0x36, 0xD1, 0x6B, 0xB9, 0x4C, - 0xAE, 0xB0, 0x55, 0xF8, 0xBE, 0xD4, 0x7D, 0x16, 0x76, 0x84, - 0x2E, 0x46, 0x0B, 0xF6, 0x0D, 0x43, 0xB6, 0xBB, 0x5F, 0x98, - 0x02, 0x26, 0xC0, 0x00, 0x02, 0x35, 0x79, 0x26, 0x91, 0x8C, - 0x34, 0x8D, 0x69, 0x6E, 0x7F, 0x6B, 0xBF, 0xBD, 0x81, 0x3F, - 0x9C, 0x94, 0x0C, 0x65, 0x47, 0xC5, 0x08, 0xA7, 0x14, 0x6F, - 0x5A, 0xAC, 0x7C, 0xAC, 0x0C, 0x15, 0xD5, 0x6F, 0xBF, 0xDC, - 0xCE, 0x97, 0xD0, 0xD5, 0xEB, 0x1D, 0x3C, 0x7A, 0xEB, 0x2A, - 0x4E, 0x76, 0x08, 0xF2, 0xEA, 0x3A, 0xA0, 0xB8, 0xFC, 0xA0, - 0x74, 0x92, 0x8F, 0x86, 0xB1, 0x15, 0x0D, 0x7D, 0x92, 0x0F, - 0x64, 0xCE, 0xCA, 0xC1, 0xC4, 0x20, 0xA2, 0x48, 0x2D, 0xB0, - 0x47, 0x24, 0xF1, 0x20, 0x77, 0xDF, 0x87, 0x0D, 0xFA, 0xC6, - 0x89, 0xEE, 0xBD, 0x5E, 0xD5, 0x85, 0x64, 0xBC, 0x40, 0x6E, - 0x86, 0x01, 0x3D, 0xB6, 0x83, 0x8C, 0xAA, 0xF3, 0x2D, 0x3A, - 0xBB, 0x0D, 0xE6, 0xA5, 0xC0, 0x64, 0x07, 0xCB, 0x57, 0x81, - 0x7E, 0xD8, 0x3C, 0x3D, 0x4A, 0x9F, 0x8E, 0xF0, 0x57, 0x2E, - 0x5E, 0x41, 0x42, 0x00, 0xB0, 0xC7, 0x4E, 0x17, 0xED, 0xC6, - 0xAB, 0x73, 0x71, 0x65, 0x1D, 0x60, 0x34, 0x2A, 0x2B, 0xAF, - 0x59, 0x82, 0x5E, 0x16, 0x48, 0x48, 0x0F, 0x86, 0x62, 0x0C, - 0x84, 0x56, 0x00, 0x03, 0x2A, 0xA6, 0x2C, 0x21, 0xD0, 0x70, - 0xF9, 0xE5, 0x37, 0x0E, 0x81, 0x20, 0x36, 0x4E, 0x86, 0x8D, - 0xCF, 0xED, 0xBD, 0x0D, 0x49, 0x75, 0x0E, 0x5B, 0x80, 0xF7, - 0xAF, 0x40, 0x56, 0x8B, 0xD8, 0xFC, 0xC6, 0xE4, 0x6D, 0xD6, - 0x2E, 0x0D, 0xD0, 0x76, 0x75, 0x39, 0x3E, 0xF0, 0xEA, 0xC5, - 0x23, 0x12, 0x06, 0x45, 0xEA, 0x04, 0x6D, 0xC1, 0xA2, 0x95, - 0x95, 0x40, 0xD6, 0x6B, 0x65, 0xD6, 0x7D, 0x62, 0xA5, 0xB4, - 0x6B, 0x6C, 0x24, 0x3E, 0xFB, 0xAB, 0x71, 0x4D, 0xFC, 0x24, - 0x9F, 0x71, 0x8C, 0x04, 0x9A, 0xEE, 0x6D, 0x72, 0x3A, 0x01, - 0x11, 0xC1, 0x01, 0xB2, 0xC2, 0xC8, 0xBA, 0x7D, 0x53, 0x56, - 0x0D, 0x3F, 0x35, 0xF6, 0x86, 0x46, 0x7C, 0x67, 0xBF, 0x83, - 0x04, 0x01, 0x98, 0xBC, 0x06, 0x08, 0xF3, 0x89, 0x88, 0x8E, - 0x93, 0xB3, 0xA9, 0x21, 0x18, 0x71, 0xFF, 0xFC, 0x4E, 0xF7, - 0xFE, 0x1A, 0x5D, 0xC9, 0x21, 0xF6, 0x3B, 0x27, 0x2C, 0x26, - 0x37, 0xE2, 0x4F, 0x8C, 0x94, 0x77, 0xC7, 0x0D, 0xB9, 0x74, - 0xCD, 0x9F, 0xE1, 0x70, 0xFD, 0x35, 0x11, 0xA2, 0xB6, 0xAC, - 0x39, 0x3D, 0xC9, 0x57, 0x94, 0x3F, 0x10, 0x89, 0x9F, 0x0F, - 0x7D, 0x49, 0x0E, 0xFE, 0x84, 0x34, 0x87, 0x5B, 0xA5, 0xA0, - 0x5E, 0x0D, 0xE4, 0x05, 0x5A, 0x45, 0x8B, 0x31, 0x28, 0xF0, - 0x80, 0x7A, 0xF9, 0x56, 0xE7, 0x60, 0xB0, 0x31, 0xBB, 0x75, - 0x7E, 0x30, 0x74, 0x53, 0x14, 0xF6, 0xDE, 0x24, 0x9E, 0xE0, - 0xB9, 0x9F, 0xE6, 0xB0, 0x5D, 0x5B, 0x7A, 0xF3, 0xFD, 0x0D, - 0x4C, 0xCA, 0xAD, 0x01, 0xE4, 0x3F, 0xFE, 0x1D, 0x03, 0xE7, - 0xD4, 0xC6, 0xC1, 0xE9, 0xF5, 0x9E, 0x72, 0x9C, 0x4A, 0x09, - 0x85, 0x2C, 0xBE, 0x46, 0x49, 0xE1, 0x0F, 0xBF, 0x27, 0xF2, - 0x81, 0xC3, 0x33, 0x95, 0xEC, 0xBE, 0x37, 0x2B, 0x65, 0xA5, - 0xEC, 0xF7, 0x69, 0x23, 0x3B, 0xA6, 0xA6, 0xC3, 0xC7, 0x9F, - 0x9B, 0x79, 0xE6, 0x37, 0xB4, 0xDB, 0x33, 0x3B, 0xC5, 0x19, - 0x50, 0x7B, 0xBB, 0x7B, 0x4B, 0xFF, 0x0A, 0x3A, 0x0F, 0xDE, - 0x9D, 0x1F, 0x70, 0xE0, 0x9C, 0x37, 0x9B, 0x61, 0x01, 0xD9, - 0xCB, 0x9F, 0xC7, 0x1F, 0x9B, 0x25, 0x7D, 0x18, 0xF0, 0x6F, - 0x12, 0x54, 0xC2, 0x17, 0x8F, 0xB2, 0x1F, 0x5D, 0x0F, 0x73, - 0xB2, 0xEE, 0xE9, 0x0E, 0xC4, 0xA1, 0x70, 0x48, 0xDF, 0x0B, - 0xB4, 0xDD, 0xFF, 0xC7, 0x01, 0xA6, 0xBC, 0x08, 0xCE, 0x0E, - 0xB4, 0x4A, 0xAE, 0xFF, 0x88, 0xA6, 0x4D, 0x60, 0xC7, 0x55, - 0x38, 0x74, 0x3C, 0x1D, 0x8F, 0x82, 0xD3, 0xD3, 0x31, 0x60, - 0xE4, 0xB2, 0x24, 0x76, 0xE7, 0xD8, 0x53, 0x05, 0x20, 0x3E, - 0x5C, 0xEF, 0x17, 0x4C, 0x20, 0x6F, 0x6A, 0x6D, 0x10, 0xA3, - 0xA4, 0xE9, 0xFB, 0x76, 0x66, 0x99, 0x5D, 0xD1, 0x34, 0x52, - 0x42, 0xBF, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x9E, 0xED, 0xAE, - 0xE5, 0x23, 0x85, 0x5C, 0xFF, 0xAD, 0x6E, 0x89, 0x02, 0x33, - 0x97, 0x74, 0x05, 0x59, 0x1E, 0x73, 0x4E, 0xD3, 0x9A, 0x97, - 0xD3, 0x85, 0x2B, 0x12, 0xFB, 0xA2, 0xF0, 0xA4, 0x4C, 0x2A, - 0x58, 0xFB, 0x56, 0x6C, 0xE9, 0xA6, 0x04, 0x07, 0x9F, 0xBC, - 0x76, 0x66, 0x01, 0x80, 0xB8, 0x1E, 0x4A, 0x8A, 0x0C, 0x76, - 0x8A, 0x3C, 0x5F, 0x25, 0xAD, 0x83, 0xF3, 0x10, 0x02, 0xE1, - 0x38, 0x4B, 0xFA, 0x81, 0xD2, 0xC5, 0x6D, 0x18, 0xA7, 0xD8, - 0x0A, 0x4E, 0xC9, 0xC7, 0xA3, 0x19, 0x52, 0x0D, 0xBB, 0xA9, - 0xDE, 0x9C, 0x90, 0x57, 0x71, 0x1A, 0x37, 0xA8, 0x70, 0x4D, - 0x75, 0x7E, 0x34, 0x90, 0x74, 0x0E, 0x02, 0xC8, 0x8A, 0x80, - 0x3D, 0x06, 0x67, 0xF4, 0xF2, 0xD4, 0x15, 0x66, 0x0D, 0x23, - 0xAE, 0x46, 0x0A, 0x23, 0x7B, 0x36, 0x96, 0x48, 0x7D, 0x99, - 0xF4, 0x09, 0xE3, 0xA9, 0x53, 0xAC, 0x94, 0xB7, 0x23, 0x7E, - 0x57, 0xCF, 0x90, 0xCD, 0x13, 0x0D, 0x50, 0xBD, 0xC9, 0xE4, - 0xC2, 0x22, 0x5F, 0x28, 0x11, 0xF8, 0x1F, 0x42, 0x33, 0xEE, - 0xF3, 0xB4, 0xED, 0x8F, 0xF4, 0xA0, 0xAE, 0xF5, 0xAE, 0x56, - 0x59, 0xC3, 0x65, 0xDB, 0xF2, 0x51, 0x6D, 0x15, 0xA3, 0xAF, - 0xA5, 0xC7, 0x9F, 0x7A, 0xE8, 0xCC, 0xB4, 0xD8, 0xCA, 0x39, - 0x3F, 0x79, 0xB3, 0x86, 0xDB, 0x37, 0x52, 0xDA, 0x5E, 0xDB, - 0x7F, 0x53, 0x60, 0x43, 0x75, 0x53, 0x93, 0xD4, 0xA2, 0xE2, - 0xE7, 0xB7, 0x42, 0xF0, 0x97, 0xA5, 0xB5, 0x52, 0xD3, 0xCF, - 0xE7, 0x70, 0x6F, 0x10, 0xD4, 0x85, 0xC4, 0x4B, 0x3D, 0x09, - 0xE1, 0x02, 0xB8, 0xED, 0xA5, 0xCC, 0x7B, 0x2D, 0x68, 0xEF, - 0xEF, 0x9E, 0x87, 0x8C, 0xB7, 0xC9, 0x85, 0xA8, 0x01, 0xC2, - 0xCF, 0x43, 0xB5, 0x6D, 0x30, 0x2A, 0x9F, 0x06, 0x96, 0xE0, - 0x43, 0xEC, 0x3F, 0xC1, 0x2F, 0x7D, 0x4D, 0x85, 0x76, 0xD3, - 0xF7, 0xFA, 0xC8, 0x84, 0x20, 0xA8, 0x3C, 0xD9, 0x3E, 0x4A, - 0xB4, 0x87, 0x05, 0xCF, 0x9B, 0x51, 0x68, 0xF9, 0x49, 0xBA, - 0x4D, 0x68, 0x97, 0x6E, 0x79, 0xDB, 0x04, 0x51, 0x66, 0x6F, - 0xF9, 0x59, 0x2D, 0x55, 0x96, 0x13, 0x59, 0x52, 0x30, 0xB8, - 0x73, 0xD1, 0x12, 0x33, 0x31, 0xEC, 0x4C, 0x0C, 0x8E, 0xD4, - 0x47, 0xE7, 0x30, 0xC6, 0x98, 0xB5, 0x5B, 0x35, 0x1B, 0xAC, - 0x51, 0xBB, 0xFA, 0xC3, 0x8D, 0x3E, 0x89, 0x83, 0x1C, 0xED, - 0xB1, 0x03, 0x9C, 0xC7, 0x5C, 0x89, 0xF9, 0xC2, 0xE3, 0x45, - 0x91, 0xDB, 0x41, 0x0A, 0x22, 0xD1, 0x90, 0x39, 0xD6, 0x9D, - 0x0A, 0xD8, 0x36, 0xDC, 0xDB, 0xDD, 0x63, 0x22, 0xF8, 0x7B, - 0x4D, 0x90, 0x4C, 0x27, 0x0F, 0xCC, 0x16, 0x0E, 0x32, 0x46, - 0xD7, 0x20, 0x5A, 0x43, 0xC4, 0xC5, 0x37, 0x2E, 0xEB, 0x3F, - 0x42, 0x2C, 0xFA, 0x99, 0xE2, 0xF9, 0x70, 0xB3, 0xC3, 0xCF, - 0x4C, 0x67, 0xEB, 0x7C, 0x9D, 0xAF, 0x96, 0x15, 0x97, 0xD2, - 0x07, 0x3B, 0xF6, 0xEF, 0x2F, 0x98, 0xAA, 0x1D, 0x45, 0xDC, - 0x11, 0xBA, 0xF6, 0x0C, 0x18, 0x64, 0x80, 0xF2, 0x6B, 0xBD, - 0x3C, 0x85, 0xC1, 0xCD, 0x78, 0xD0, 0x62, 0x79, 0x0F, 0xCD, - 0xCA, 0x3D, 0x94, 0x0A, 0x11, 0xEF, 0x11, 0x86, 0xFA, 0x3F, - 0x31, 0xB2, 0xF1, 0x2C, 0x74, 0x1B, 0x57, 0x05, 0xD4, 0x4F, - 0xAF, 0xE7, 0xCB, 0x60, 0x9E, 0x78, 0x82, 0xAD, 0xF3, 0x34, - 0x6A, 0x2F, 0xDC, 0xA1, 0xC9, 0xEA, 0x3E, 0x6E, 0x01, 0x80, - 0x17, 0x5B, 0xCC, 0xBB, 0xED, 0xD0, 0x30, 0x11, 0xBE, 0xEE, - 0x2E, 0x9F, 0xCE, 0xE1, 0xFF, 0x32, 0xB8, 0x7D, 0x40, 0xC8, - 0x46, 0x0F, 0x41, 0x16, 0xE1, 0xB3, 0x98, 0x47, 0xCE, 0xE1, - 0x41, 0xDE, 0x80, 0xA7, 0x56, 0x83, 0xA8, 0xDA, 0xC3, 0x49, - 0x33, 0x6F, 0x93, 0x68, 0xA0, 0xC6, 0x1A, 0x0B, 0x82, 0x38, - 0x56, 0xEE, 0xBB, 0x97, 0x5D, 0xBD, 0x8A, 0x32, 0x2D, 0xFE, - 0x40, 0xC7, 0x0D, 0xCA, 0x32, 0x08, 0xCC, 0xE2, 0x18, 0x57, - 0xBB, 0xC1, 0x60, 0x43, 0x02, 0x26, 0xC0, 0x00, 0x02, 0xAD, - 0x9E, 0x61, 0x0D, 0x67, 0x25, 0xE4, 0x6E, 0x8F, 0x6D, 0xEA, - 0x16, 0x98, 0xFA, 0x76, 0x6D, 0x6D, 0x3C, 0xED, 0x4B, 0x25, - 0x60, 0xC6, 0xAB, 0x59, 0x91, 0x43, 0xAA, 0xAA, 0xEC, 0x8F, - 0xA1, 0x3E, 0xB1, 0x78, 0x72, 0xEE, 0xD1, 0x91, 0xBA, 0xD9, - 0x9B, 0xE3, 0x55, 0x61, 0x98, 0x46, 0x4B, 0xC5, 0x41, 0x3B, - 0x9C, 0x88, 0x1D, 0x82, 0xD5, 0xD5, 0x99, 0x13, 0x64, 0x44, - 0x00, 0xBD, 0xBE, 0xC4, 0xF6, 0x6A, 0x2D, 0xE3, 0xD0, 0xE7, - 0x88, 0xD3, 0xA1, 0x48, 0x88, 0x84, 0x8A, 0x25, 0xAB, 0x90, - 0x43, 0xFB, 0x3D, 0x1B, 0x06, 0xB2, 0xFD, 0x24, 0x58, 0x0C, - 0xFA, 0x0A, 0xD3, 0x23, 0x73, 0xA7, 0xF8, 0x50, 0xC5, 0x1B, - 0x3A, 0x75, 0xF4, 0x24, 0xA8, 0x52, 0xFB, 0x1B, 0x61, 0xAB, - 0x79, 0x06, 0x54, 0xD9, 0x1D, 0x3A, 0x72, 0x4F, 0x8F, 0xD3, - 0xC7, 0x71, 0xA8, 0x66, 0x80, 0x49, 0x8D, 0x50, 0xD1, 0xBF, - 0xC8, 0x70, 0xAE, 0x4F, 0x64, 0x53, 0x26, 0x37, 0xDA, 0x6B, - 0x62, 0xFE, 0xF9, 0x60, 0xAD, 0xAD, 0x49, 0x51, 0x37, 0x2E, - 0x61, 0xA9, 0xAA, 0x72, 0xFD, 0x02, 0x20, 0x0B, 0xB0, 0xB0, - 0x07, 0x95, 0x0C, 0x38, 0x13, 0xB6, 0xA4, 0x33, 0xFA, 0xFA, - 0x12, 0xE1, 0x62, 0x00, 0x92, 0x46, 0x23, 0xAA, 0xD7, 0x9D, - 0xBD, 0xAF, 0x15, 0xCA, 0x8C, 0x88, 0x2A, 0x4B, 0x1B, 0xA8, - 0x06, 0xA0, 0xC2, 0x80, 0x8E, 0x98, 0x46, 0xA1, 0x84, 0x2C, - 0x4A, 0x0F, 0xEA, 0x70, 0xE6, 0xDD, 0x17, 0x30, 0x8A, 0x41, - 0x69, 0x8A, 0x1B, 0xC2, 0xC7, 0x18, 0xD5, 0xB3, 0x94, 0x4F, - 0x51, 0x15, 0xCC, 0x37, 0x9A, 0x9E, 0xFD, 0x12, 0x40, 0xC1, - 0xA3, 0x06, 0x0F, 0x36, 0xFC, 0x04, 0x18, 0x35, 0x40, 0x9C, - 0x9E, 0x46, 0x5E, 0x14, 0xB6, 0xF7, 0xBF, 0xE5, 0x21, 0x12, - 0xF2, 0xE2, 0x17, 0xB3, 0x63, 0x8C, 0xD1, 0xE3, 0xA9, 0x0A, - 0x80, 0x1B, 0x74, 0x7A, 0x58, 0x91, 0x88, 0x9D, 0xAE, 0xE6, - 0x05, 0x1D, 0x3C, 0x1E, 0xE9, 0x95, 0x08, 0x75, 0xEE, 0x20, - 0xA8, 0x4B, 0x3D, 0x36, 0xAF, 0xB0, 0xFA, 0x94, 0x62, 0x5D, - 0x9F, 0xD5, 0x50, 0x2A, 0x24, 0xFC, 0x1D, 0xDC, 0x39, 0xCB, - 0x0D, 0x5A, 0xA1, 0xDA, 0xEF, 0xC9, 0xB3, 0x62, 0xF8, 0x7D, - 0x0C, 0xE4, 0x6B, 0xEC, 0xF0, 0xF7, 0x96, 0x63, 0x58, 0x80, - 0x55, 0x22, 0x6D, 0x42, 0x38, 0xE9, 0x1D, 0x69, 0xD5, 0x2F, - 0x03, 0x3C, 0xCD, 0x27, 0x34, 0x99, 0x39, 0xF0, 0x5C, 0xE0, - 0x23, 0x70, 0x85, 0x4B, 0x30, 0xBD, 0x21, 0x01, 0xF6, 0x06, - 0x0B, 0xED, 0xBA, 0xA1, 0x6F, 0xE0, 0x6E, 0xD3, 0x78, 0xA8, - 0x56, 0x94, 0x92, 0x84, 0xA8, 0x60, 0x35, 0xA8, 0x86, 0x56, - 0x41, 0xEA, 0x12, 0x34, 0x86, 0x52, 0x18, 0x75, 0x43, 0x01, - 0x0A, 0xCE, 0xBA, 0x04, 0xF7, 0x32, 0x09, 0x2D, 0xB1, 0xAC, - 0x04, 0xB0, 0x4E, 0xEA, 0xBE, 0xDE, 0xDE, 0x95, 0x37, 0xDA, - 0x86, 0x72, 0xFE, 0x10, 0x16, 0xBB, 0xA7, 0xE9, 0x67, 0xC9, - 0x3C, 0x85, 0x18, 0xFF, 0xD7, 0x74, 0x25, 0x3A, 0x95, 0x04, - 0xD5, 0x7F, 0x99, 0x41, 0x6A, 0x6A, 0x2C, 0xF6, 0x3E, 0x3C, - 0x4B, 0xA7, 0xB9, 0xDA, 0x13, 0xFC, 0xF6, 0x46, 0xEF, 0x7E, - 0xB4, 0xA6, 0x1B, 0x36, 0x93, 0x5B, 0xDA, 0xDB, 0x6A, 0xC7, - 0x37, 0x58, 0x3C, 0x4F, 0x52, 0x7E, 0x39, 0xD7, 0xE2, 0xBA, - 0x79, 0xA7, 0x9A, 0x05, 0x8A, 0xF5, 0x65, 0x86, 0xF4, 0x52, - 0xBC, 0x79, 0x6D, 0xA9, 0xFE, 0xEE, 0xE6, 0xC5, 0x2B, 0x28, - 0x62, 0x8E, 0xF6, 0x6E, 0xD5, 0x08, 0x90, 0x96, 0x72, 0x7A, - 0x6B, 0x61, 0x8B, 0x6A, 0xE6, 0xCD, 0x05, 0x63, 0x12, 0x9A, - 0xF7, 0x01, 0xAC, 0xF7, 0x8F, 0x1F, 0xE0, 0xCA, 0x1E, 0xF9, - 0x86, 0xC1, 0xF6, 0x0D, 0x2D, 0x9F, 0x8A, 0x2C, 0x8B, 0x3C, - 0xE4, 0x89, 0xDF, 0x72, 0x86, 0x17, 0xA8, 0x7F, 0x9D, 0x8B, - 0x0D, 0x87, 0xCB, 0xC5, 0xAE, 0xE3, 0x90, 0xB1, 0xD9, 0x8B, - 0x5E, 0x04, 0x97, 0xAA, 0x19, 0x85, 0x02, 0x26, 0xC0, 0x00, - 0x02, 0x26, 0xDA, 0x00, 0x7E, 0x08, 0xC0, 0x08, 0x12, 0x9A, - 0x78, 0x4E, 0x9D, 0xA7, 0xB0, 0x5E, 0x0D, 0x76, 0x6D, 0x4D, - 0xC7, 0x89, 0x35, 0xDD, 0xB5, 0x58, 0x9F, 0x20, 0x3C, 0x41, - 0x77, 0x9B, 0x85, 0x06, 0x21, 0xA4, 0x99, 0x56, 0xF9, 0x5B, - 0x07, 0x01, 0x06, 0x1A, 0xE1, 0x1B, 0xC7, 0x9F, 0x46, 0x5D, - 0x1F, 0xB8, 0xB2, 0x91, 0xA5, 0xC2, 0x01, 0x94, 0xFA, 0x53, - 0x74, 0xFA, 0x6A, 0x5B, 0x63, 0x08, 0x2E, 0x24, 0xB0, 0xCF, - 0x03, 0x40, 0x9C, 0xA1, 0xF2, 0xDB, 0xA2, 0x35, 0xD7, 0xCA, - 0x78, 0x4E, 0x9D, 0x8B, 0x92, 0x4A, 0xD1, 0xEA, 0xF8, 0x14, - 0xCA, 0xA0, 0x32, 0x55, 0x95, 0xA0, 0x1F, 0xB7, 0x1D, 0x8B, - 0x8E, 0x8E, 0xA6, 0xF0, 0x2A, 0x30, 0x76, 0xB4, 0x9B, 0x6F, - 0xAB, 0xBC, 0xC7, 0xA8, 0xF6, 0x2B, 0x9D, 0x1D, 0xC2, 0x24, - 0x06, 0x10, 0x06, 0xE7, 0x59, 0x34, 0xE9, 0x30, 0xA8, 0xF5, - 0x61, 0x55, 0xEC, 0xFB, 0xA1, 0x43, 0x17, 0x10, 0x08, 0xFF, - 0x3C, 0x93, 0x03, 0xFF, 0x83, 0x35, 0x81, 0x77, 0x7E, 0x97, - 0xC2, 0xA0, 0x53, 0x2A, 0x26, 0xD4, 0xDF, 0xC0, 0xA3, 0x21, - 0x07, 0x14, 0x41, 0xD3, 0x7C, 0xE5, 0x40, 0x00, 0xDE, 0x32, - 0xF5, 0xB9, 0xBB, 0x61, 0x44, 0xBC, 0xA4, 0xFD, 0x67, 0xAA, - 0x69, 0xF4, 0x96, 0x93, 0xD2, 0xAF, 0xEA, 0xC5, 0x72, 0xDB, - 0xEA, 0x88, 0x2A, 0x5F, 0xC5, 0xAB, 0x00, 0xFA, 0xA9, 0x32, - 0x61, 0x58, 0xBE, 0xC0, 0x42, 0xA9, 0xFA, 0xB6, 0x44, 0xD6, - 0x59, 0xF8, 0x26, 0x8B, 0xB9, 0x0A, 0xD9, 0xE2, 0x5B, 0x1B, - 0x20, 0xD1, 0x34, 0x91, 0x81, 0xF3, 0xFF, 0xED, 0x6D, 0x81, - 0xF9, 0x7D, 0xE3, 0x73, 0x37, 0xC1, 0x01, 0x12, 0x28, 0x9B, - 0xEA, 0xDA, 0x0E, 0x3D, 0x68, 0x16, 0x23, 0xE1, 0x68, 0xFF, - 0x1A, 0x59, 0xCC, 0x89, 0xF8, 0x44, 0x70, 0x13, 0xB2, 0x98, - 0xB1, 0x31, 0xEA, 0xEC, 0x65, 0x21, 0x36, 0xEF, 0xCC, 0x85, - 0x62, 0xC3, 0xEC, 0x62, 0xE9, 0x06, 0xEC, 0xB3, 0x47, 0x94, - 0xE5, 0xF2, 0x6F, 0xFD, 0x80, 0xEE, 0x70, 0xB0, 0x06, 0x56, - 0x8B, 0xF2, 0xDC, 0x7A, 0x52, 0x90, 0xC2, 0xE4, 0x77, 0xDD, - 0xF7, 0xC2, 0x0C, 0x9C, 0xBE, 0x5A, 0x0F, 0xC6, 0x45, 0xB1, - 0x3A, 0x63, 0x38, 0x2C, 0xD9, 0xC4, 0x45, 0x08, 0x44, 0x90, - 0xE2, 0xBC, 0xA2, 0x5A, 0xE6, 0x2E, 0xFD, 0xCB, 0x36, 0x7F, - 0xA9, 0xAC, 0x8C, 0x34, 0x1A, 0x3C, 0xE2, 0x9B, 0x24, 0x45, - 0xE3, 0x9C, 0xCF, 0xF9, 0x96, 0xFE, 0x58, 0xB5, 0x29, 0x20, - 0x0B, 0xC9, 0x5C, 0xAF, 0xCF, 0x7F, 0xCB, 0x8A, 0x14, 0xE1, - 0xCD, 0xF7, 0x5B, 0x93, 0xBC, 0x7D, 0x7A, 0x3B, 0xD2, 0xF2, - 0xFA, 0x2B, 0x57, 0x02, 0x9C, 0xAC, 0xA2, 0x16, 0x11, 0x2D, - 0xDB, 0x3D, 0x42, 0x26, 0x87, 0xBE, 0x9F, 0x8B, 0x7B, 0x00, - 0x20, 0x09, 0x41, 0x05, 0xB0, 0x42, 0x98, 0x44, 0xD6, 0xCC, - 0x08, 0xA2, 0x20, 0x1F, 0x2A, 0x59, 0xB3, 0x05, 0x4F, 0xB4, - 0xA6, 0xF8, 0xF8, 0xFD, 0x27, 0xBB, 0xC5, 0xC3, 0x52, 0x4D, - 0x63, 0x37, 0xCF, 0xAE, 0x4C, 0x60, 0x1E, 0x98, 0x26, 0x12, - 0x3D, 0xB9, 0xE6, 0x87, 0x09, 0x17, 0xB1, 0xE4, 0x81, 0x2C, - 0x8E, 0x73, 0xA1, 0x40, 0x53, 0x96, 0xD8, 0x17, 0x7F, 0x39, - 0xA8, 0x4F, 0xE9, 0xEF, 0x30, 0xE2, 0x5E, 0xEF, 0x9C, 0x13, - 0x70, 0x21, 0x14, 0xA3, 0x5D, 0xEA, 0x43, 0xFB, 0xA6, 0x80, - 0x70, 0xB9, 0x4B, 0x68, 0x9C, 0x5A, 0x82, 0x59, 0x00, 0xFA, - 0x5E, 0x4C, 0x4F, 0x76, 0xB1, 0xF4, 0x45, 0xCD, 0xE6, 0x18, - 0x09, 0xE2, 0x36, 0x8A, 0x60, 0x4B, 0xF4, 0x61, 0x55, 0xC4, - 0xE9, 0x69, 0xC1, 0x03, 0x9E, 0x9C, 0xAF, 0x1C, 0xE5, 0xD1, - 0xFF, 0x45, 0x16, 0x43, 0xD7, 0xE5, 0x4B, 0xCC, 0xEA, 0x24, - 0x2E, 0xCE, 0xE3, 0x90, 0x17, 0xDB, 0xC4, 0x57, 0x4D, 0xF9, - 0xCB, 0xEC, 0x09, 0x62, 0xBD, 0xD8, 0x7A, 0x89, 0x55, 0x92, - 0x90, 0x7B, 0x22, 0x20, 0xD9, 0x9A, 0xC9, 0x19, 0x02, 0x26, - 0xC0, 0x00, 0x02, 0x2E, 0xA2, 0xCF, 0xDE, 0xE3, 0xDE, 0xA9, - 0x10, 0x3D, 0xEB, 0xD9, 0x4B, 0x51, 0x68, 0x41, 0x57, 0xCD, - 0x7C, 0xF4, 0x28, 0x84, 0x22, 0x1C, 0xA7, 0xA6, 0x8A, 0xDD, - 0x97, 0x5B, 0x8A, 0x07, 0x01, 0x97, 0x13, 0x20, 0x06, 0x12, - 0xC9, 0xBB, 0x6D, 0x12, 0x25, 0x6D, 0x08, 0x13, 0x3C, 0x32, - 0x48, 0xFE, 0x49, 0xD9, 0xC1, 0x3E, 0x00, 0x1C, 0xD9, 0xF0, - 0xE2, 0xB3, 0xE0, 0x07, 0xE1, 0x8F, 0xDF, 0x75, 0xE0, 0xB9, - 0x61, 0x1A, 0xBF, 0xAF, 0x66, 0xE0, 0xAB, 0x8A, 0x4B, 0x71, - 0xCB, 0x4F, 0xB7, 0x4C, 0x30, 0xC8, 0xB0, 0xC4, 0xC0, 0x38, - 0x73, 0xDD, 0x3C, 0xDC, 0x5D, 0x81, 0x40, 0x14, 0x23, 0x9C, - 0xD2, 0x48, 0xF9, 0xCB, 0xC4, 0x1B, 0xD5, 0xC7, 0x85, 0xB0, - 0x57, 0xC1, 0xF5, 0x41, 0x7A, 0x2E, 0xC6, 0x03, 0x86, 0x8C, - 0x4E, 0xAF, 0x24, 0x21, 0xB9, 0x0B, 0xE9, 0x24, 0x12, 0x02, - 0x3E, 0x35, 0x7C, 0x1D, 0x9A, 0x2D, 0x5E, 0xB7, 0xEE, 0x08, - 0x34, 0x2C, 0x2B, 0xAD, 0x8D, 0x02, 0xF6, 0xFE, 0x06, 0x88, - 0xD0, 0xA5, 0xA2, 0x1E, 0x5B, 0xD2, 0x88, 0x09, 0x9F, 0x43, - 0xDF, 0xC4, 0x85, 0x59, 0x50, 0x7B, 0x94, 0xD9, 0xBB, 0xBE, - 0xF5, 0x1D, 0x60, 0xD0, 0x90, 0x6F, 0xD5, 0x1E, 0x49, 0xF1, - 0x76, 0x04, 0x96, 0xCA, 0x3F, 0x44, 0x64, 0xBE, 0x41, 0xE7, - 0x4A, 0x6E, 0xA8, 0x11, 0x14, 0x21, 0xEA, 0x9E, 0x43, 0x6D, - 0x2E, 0xF6, 0x49, 0x7A, 0x8C, 0xD6, 0xF1, 0x4A, 0xC3, 0x17, - 0x16, 0x23, 0x3B, 0x02, 0x6A, 0xA7, 0x90, 0x1D, 0x8C, 0xBF, - 0xB4, 0x25, 0xDA, 0xB6, 0x0F, 0x2A, 0x60, 0xF5, 0xC1, 0x7F, - 0xFA, 0x1D, 0x0B, 0xAF, 0x28, 0x8A, 0x00, 0x8A, 0xBE, 0xA8, - 0x72, 0x20, 0x5F, 0xEC, 0x3F, 0x16, 0x6E, 0xAB, 0xC4, 0xFC, - 0x6B, 0x75, 0xD7, 0xFB, 0x73, 0x60, 0x7E, 0x25, 0xE5, 0xA3, - 0x91, 0x6A, 0x33, 0xD3, 0x9E, 0xAC, 0xFB, 0x8C, 0xD1, 0xC6, - 0x63, 0xF4, 0x3F, 0xB7, 0xD1, 0xD3, 0x88, 0x90, 0x4C, 0xA2, - 0x7E, 0x6B, 0x19, 0x61, 0xCC, 0xAB, 0x48, 0xDD, 0x8D, 0xE2, - 0x1B, 0xB7, 0x9E, 0x2F, 0x58, 0x10, 0x78, 0xAC, 0x94, 0xF6, - 0xD6, 0x62, 0x4D, 0x66, 0x78, 0x67, 0x9F, 0x1B, 0x3A, 0x78, - 0x4E, 0xA0, 0xDB, 0x47, 0x92, 0xC4, 0x43, 0x1A, 0x22, 0xFC, - 0x26, 0x38, 0xA4, 0xF2, 0x7A, 0x52, 0x31, 0x71, 0x63, 0x16, - 0x58, 0xF5, 0xA4, 0x4A, 0xCA, 0x73, 0xD5, 0x90, 0x39, 0x55, - 0x8F, 0xB2, 0xC0, 0x3F, 0x3A, 0xEC, 0x69, 0xC4, 0x42, 0xCE, - 0xB9, 0x1B, 0xA4, 0x32, 0x52, 0x14, 0x7C, 0xBB, 0xF6, 0xB3, - 0x5A, 0x7C, 0xF1, 0x75, 0x1E, 0x4B, 0xB8, 0xB0, 0xB3, 0x8E, - 0x13, 0x63, 0x7B, 0xF5, 0xB9, 0x93, 0x22, 0x98, 0xDF, 0x6C, - 0xEC, 0x51, 0x4F, 0xC8, 0x0B, 0xA0, 0x14, 0x57, 0x75, 0x1B, - 0xF6, 0xE9, 0x5D, 0xC2, 0x47, 0x65, 0xDF, 0x79, 0x0D, 0x48, - 0xBE, 0x4F, 0x46, 0xF0, 0x37, 0xA5, 0x7C, 0xA3, 0x6B, 0x3E, - 0xE6, 0xA2, 0x0E, 0x69, 0xAF, 0x3C, 0x46, 0x8A, 0x77, 0xD2, - 0xBF, 0x2A, 0x16, 0x00, 0x17, 0x2F, 0x9C, 0x4E, 0xD8, 0xA8, - 0x48, 0xD4, 0xCC, 0x0C, 0x29, 0xD1, 0x7A, 0xAE, 0x81, 0x4F, - 0x04, 0x76, 0x53, 0xCF, 0x22, 0x76, 0x39, 0x61, 0xB6, 0x76, - 0x42, 0xE6, 0x4E, 0x71, 0xB3, 0x06, 0xB9, 0x31, 0x04, 0x60, - 0x88, 0x04, 0x02, 0x89, 0x72, 0x13, 0xD8, 0x8E, 0xD7, 0xE7, - 0x88, 0xCC, 0x3B, 0x88, 0x4A, 0xC7, 0x96, 0x58, 0x12, 0xDA, - 0x75, 0x15, 0xE2, 0x9A, 0xFA, 0x9E, 0x7C, 0x0E, 0xD6, 0x86, - 0x64, 0x7F, 0x31, 0xE3, 0x5C, 0xD8, 0xCF, 0xC0, 0x6D, 0x9B, - 0x1A, 0x1D, 0x8E, 0x90, 0xED, 0x8E, 0x7B, 0xFD, 0xAF, 0xE0, - 0x85, 0xE2, 0x51, 0x49, 0xAE, 0xE6, 0x03, 0x78, 0x41, 0xB9, - 0x05, 0xA0, 0xB8, 0x25, 0x03, 0x51, 0xD1, 0x93, 0x05, 0xE1, - 0xAA, 0x19, 0x0F, 0x1A, 0xF0, 0xD6, 0x18, 0xB6, 0x23, 0xFD, - 0xBC, 0x6E, 0x10, 0xA5, 0x18, 0xE9, 0x3B, 0xE5, 0xA4, 0x22, - 0x02, 0x26, 0xC0, 0x00, 0x02, 0x55, 0x43, 0x38, 0x66, 0x6B, - 0x96, 0x00, 0x6F, 0x33, 0xEE, 0x72, 0x7A, 0x9E, 0xD2, 0x5C, - 0x1F, 0x87, 0x4C, 0xFC, 0xE9, 0x3C, 0xAB, 0xC7, 0x5E, 0x55, - 0xD6, 0xEF, 0x78, 0xB1, 0x4D, 0xA7, 0x92, 0x3F, 0x57, 0x3B, - 0xF5, 0x7F, 0xE0, 0xD6, 0xE0, 0xD0, 0x8D, 0xE5, 0xE1, 0xAE, - 0x48, 0xC1, 0xF7, 0xF3, 0xC3, 0xA4, 0xF7, 0x8F, 0xE7, 0x6F, - 0xB2, 0xB1, 0xA5, 0x6F, 0x6A, 0xCF, 0x5F, 0x3C, 0xF2, 0x50, - 0x31, 0x19, 0x89, 0xF1, 0x74, 0x55, 0xA2, 0xFF, 0x7A, 0x5D, - 0xCB, 0x96, 0xED, 0xE4, 0xEA, 0x28, 0x4B, 0xF7, 0xE4, 0x45, - 0x7D, 0x99, 0xAF, 0xC5, 0xDB, 0xC1, 0x2D, 0xE8, 0xE9, 0xEA, - 0x2B, 0xAD, 0x7E, 0x8E, 0x96, 0x25, 0xA0, 0x9E, 0xDA, 0x31, - 0xE4, 0xCD, 0xC6, 0x8D, 0x69, 0x39, 0x04, 0x53, 0x1B, 0xCA, - 0xEF, 0x96, 0x8E, 0xEF, 0xFB, 0x4E, 0xC8, 0x11, 0x8E, 0x42, - 0x03, 0xC2, 0x96, 0x1A, 0x2C, 0xD8, 0xCF, 0x17, 0x05, 0x36, - 0xF7, 0x02, 0xAB, 0xBD, 0x1A, 0xF3, 0x51, 0xC0, 0xE2, 0x1E, - 0x0D, 0x8D, 0xE9, 0x81, 0x57, 0xD1, 0xA1, 0x9A, 0x2C, 0x7D, - 0x43, 0xBD, 0x23, 0x50, 0xA9, 0x3D, 0x77, 0xC1, 0x5F, 0x2D, - 0x3A, 0x61, 0x56, 0xE1, 0x47, 0xB4, 0x6C, 0xB1, 0xDF, 0xD7, - 0x1E, 0x95, 0x00, 0x02, 0x5B, 0xDA, 0xBD, 0x39, 0x2A, 0x06, - 0x98, 0x2B, 0x54, 0x63, 0xC9, 0xDB, 0x30, 0xF2, 0xB6, 0xB6, - 0xC8, 0x22, 0xAB, 0xB5, 0x68, 0xA3, 0xB7, 0x94, 0x6C, 0x97, - 0x5B, 0xC0, 0x6F, 0xA5, 0x11, 0xFD, 0x9A, 0x52, 0x5A, 0xB5, - 0x3D, 0xEA, 0xC3, 0x23, 0xD1, 0xA7, 0x31, 0xA1, 0xCE, 0xA8, - 0x4A, 0x7C, 0x5D, 0xF6, 0x21, 0xC1, 0x38, 0x73, 0xA3, 0x83, - 0x00, 0x28, 0x9D, 0x76, 0x5A, 0xC5, 0x63, 0xDB, 0x47, 0x25, - 0xAB, 0xD7, 0x25, 0xAE, 0x7D, 0x87, 0xF1, 0xA1, 0xE6, 0x9C, - 0x83, 0x33, 0x30, 0xE1, 0xAD, 0x65, 0xFD, 0x0F, 0xBB, 0xD0, - 0xEF, 0xF5, 0xC3, 0x19, 0x9B, 0x9D, 0x13, 0xBA, 0xEF, 0x9F, - 0x13, 0x2F, 0x76, 0x55, 0x2C, 0x2A, 0xC3, 0x8B, 0x40, 0x79, - 0x49, 0x02, 0x88, 0xE7, 0x4B, 0x57, 0xF5, 0xC5, 0x56, 0x30, - 0xF2, 0xB8, 0x2D, 0x83, 0x6F, 0xB6, 0xBF, 0xE2, 0x7E, 0xFF, - 0x18, 0x61, 0x11, 0x6B, 0x77, 0xCC, 0x04, 0x8B, 0xE4, 0x7C, - 0xF9, 0x48, 0x9C, 0xE0, 0x10, 0x7F, 0x68, 0xFE, 0x40, 0xF0, - 0x23, 0x5C, 0x13, 0x56, 0xD7, 0xCC, 0xDA, 0x83, 0xD6, 0x5C, - 0xB2, 0xED, 0x3F, 0x4C, 0x1E, 0x0A, 0x2F, 0x9D, 0xA2, 0x08, - 0x95, 0xB1, 0x80, 0xFB, 0x04, 0xAC, 0xED, 0x88, 0x01, 0xDC, - 0x69, 0xC7, 0x2D, 0xE8, 0xEB, 0xD1, 0xCE, 0x8E, 0x32, 0x04, - 0x0B, 0xA5, 0x1E, 0xFA, 0x47, 0xA2, 0x8F, 0xB6, 0xF4, 0xC8, - 0xFE, 0x81, 0xFC, 0x68, 0xFF, 0x82, 0x9A, 0x9A, 0xB6, 0x2C, - 0x58, 0x55, 0xEE, 0xFC, 0xBB, 0x23, 0x47, 0xA4, 0xEB, 0xF8, - 0x08, 0xB1, 0xF0, 0xAA, 0xE3, 0x7A, 0xDC, 0xEF, 0xD6, 0xB4, - 0x60, 0x39, 0x6F, 0x0F, 0x8A, 0x4C, 0x65, 0x48, 0x65, 0x78, - 0x6D, 0xF8, 0x44, 0x13, 0xA2, 0x9A, 0x76, 0xE8, 0xA7, 0x06, - 0x33, 0x54, 0x74, 0x73, 0xE4, 0x69, 0x66, 0x27, 0xA0, 0x66, - 0xA0, 0x5A, 0x9E, 0x26, 0xF2, 0xA4, 0x3C, 0xA6, 0xCF, 0x86, - 0x0F, 0x9D, 0x0A, 0x75, 0xC1, 0x9C, 0x34, 0xD1, 0x40, 0x21, - 0x64, 0x62, 0x7B, 0xBF, 0xAE, 0xCD, 0x44, 0x17, 0x6D, 0x5F, - 0x21, 0x02, 0x17, 0x1A, 0x2C, 0xA4, 0x18, 0x1D, 0x4F, 0x2E, - 0xC8, 0xE2, 0xCF, 0xAE, 0x25, 0x4A, 0xC4, 0xA2, 0x5A, 0x2E, - 0x10, 0x09, 0x69, 0xB2, 0xEA, 0xF9, 0xB9, 0x4C, 0x36, 0xA4, - 0xD6, 0xCB, 0x03, 0x6E, 0x7B, 0xC1, 0xA4, 0x28, 0x1A, 0x09, - 0xBF, 0xF1, 0xA1, 0x3F, 0x75, 0xB8, 0x5A, 0xF3, 0x9F, 0x12, - 0x35, 0x4B, 0x16, 0x21, 0x3B, 0x8D, 0xF9, 0x87, 0xCB, 0x8A, - 0xEC, 0x29, 0x1B, 0xF0, 0xB3, 0x96, 0x77, 0xB7, 0x7B, 0xA8, - 0x6A, 0x98, 0xE4, 0x8B, 0x61, 0xB6, 0x47, 0xD7, 0x92, 0xB4, - 0x0B, 0x47, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x4B, 0x86, 0xD9, - 0x89, 0x5B, 0x11, 0x29, 0x1D, 0x8E, 0x56, 0xC4, 0x4A, 0x0D, - 0xD4, 0x9F, 0x43, 0x9F, 0xA2, 0x55, 0x58, 0xE1, 0xF6, 0xF6, - 0x58, 0xFB, 0xCD, 0x3F, 0x06, 0x4C, 0xC2, 0x60, 0x6D, 0xB7, - 0xB2, 0xFF, 0xFE, 0x89, 0x77, 0x7A, 0x1E, 0xA0, 0xC8, 0xDD, - 0x7F, 0x3E, 0x6B, 0x38, 0x2F, 0x41, 0x2B, 0xDF, 0x42, 0x14, - 0x50, 0x28, 0xEE, 0xDE, 0x3F, 0xD8, 0xFF, 0x09, 0x43, 0x7A, - 0x22, 0x4F, 0xF3, 0xFC, 0x60, 0x7E, 0x2C, 0x1A, 0xB6, 0x9E, - 0x21, 0x40, 0x76, 0x3B, 0x42, 0xFC, 0xBC, 0x1D, 0x00, 0xA4, - 0x55, 0x95, 0x47, 0xBD, 0x6E, 0x31, 0xAB, 0x05, 0xAD, 0x38, - 0x53, 0xB0, 0x24, 0x83, 0x7D, 0x0E, 0xA8, 0x40, 0xE6, 0x33, - 0x6D, 0xEF, 0x72, 0x35, 0xCF, 0x3C, 0x11, 0x67, 0x1D, 0x28, - 0xEF, 0x7B, 0x7A, 0x7A, 0x0E, 0xD2, 0x7F, 0xBA, 0xEB, 0xA0, - 0x49, 0x46, 0x29, 0x40, 0x5B, 0x62, 0xA9, 0xED, 0xC9, 0xAC, - 0xDD, 0xAF, 0xE9, 0xAF, 0xF9, 0x75, 0x70, 0xC7, 0xAD, 0xB2, - 0xB6, 0x51, 0x08, 0x23, 0x89, 0x1F, 0xCC, 0xDE, 0xB7, 0x6B, - 0x25, 0xC4, 0x77, 0x90, 0x01, 0xBA, 0x80, 0x62, 0x3E, 0xFF, - 0x93, 0x00, 0x15, 0x43, 0x7D, 0xBE, 0x80, 0x83, 0xBB, 0xB0, - 0xAA, 0x3B, 0xF2, 0x0A, 0x9D, 0x86, 0x23, 0xA4, 0xB7, 0xB7, - 0x44, 0x30, 0xA7, 0x17, 0x66, 0x70, 0xEE, 0x2D, 0x1F, 0xDF, - 0xBD, 0xD9, 0x14, 0x3E, 0x55, 0xC6, 0xC9, 0x5B, 0xC3, 0xF2, - 0xE5, 0x10, 0xD5, 0x1A, 0x93, 0xF6, 0x76, 0xAB, 0x71, 0x87, - 0xDE, 0xD5, 0x51, 0x99, 0x37, 0x6F, 0xEE, 0xB1, 0x63, 0xDA, - 0x7F, 0x3B, 0xAC, 0x77, 0x1B, 0x4B, 0xA3, 0xE3, 0x77, 0x41, - 0xEA, 0x23, 0xF3, 0xB9, 0x22, 0x75, 0x07, 0x8E, 0x64, 0x3E, - 0x32, 0xA9, 0x28, 0xAA, 0x93, 0x8F, 0xE8, 0xDA, 0x60, 0xE9, - 0xD7, 0x35, 0x7F, 0xD7, 0x8F, 0xC8, 0xE5, 0x5B, 0x61, 0x47, - 0xD6, 0xD4, 0xA7, 0xFF, 0x25, 0x8F, 0x03, 0xC3, 0x03, 0x07, - 0xED, 0x30, 0x45, 0x86, 0x73, 0x1E, 0x8F, 0x2F, 0x3D, 0xB4, - 0xC0, 0x37, 0x7A, 0xE7, 0x80, 0xEA, 0xA0, 0xDB, 0x98, 0xAE, - 0xF9, 0x24, 0x0C, 0x74, 0x36, 0x54, 0x13, 0x34, 0x30, 0xCF, - 0x0E, 0xC8, 0x9D, 0x94, 0xE7, 0xAF, 0x6A, 0xC0, 0x32, 0x32, - 0xA3, 0xDE, 0x3A, 0x5B, 0x72, 0x72, 0xE3, 0x8F, 0x91, 0xC5, - 0x44, 0xAB, 0x86, 0x7B, 0xE0, 0x6C, 0x80, 0x84, 0x64, 0x1D, - 0xC0, 0xF1, 0x28, 0x7C, 0x6A, 0x35, 0x76, 0xCF, 0x12, 0x56, - 0x84, 0x1C, 0x21, 0x51, 0x33, 0x00, 0xFF, 0xB2, 0x64, 0x30, - 0x44, 0x1C, 0xA5, 0x05, 0x09, 0xE2, 0x14, 0x8E, 0xF3, 0xD8, - 0x91, 0x21, 0x60, 0xC0, 0x51, 0x68, 0x62, 0xF5, 0x7E, 0x06, - 0xD5, 0xC0, 0xEE, 0xB8, 0x91, 0xF1, 0x52, 0x14, 0x6C, 0x27, - 0xB6, 0x6A, 0x1C, 0x64, 0xBF, 0x59, 0x47, 0x64, 0x03, 0x8D, - 0x4E, 0xEB, 0xA3, 0x73, 0x10, 0xE2, 0xBC, 0xA0, 0x30, 0x29, - 0xE6, 0xF5, 0xED, 0x04, 0xCA, 0xAA, 0xC2, 0xBA, 0xDB, 0x8E, - 0xBC, 0x00, 0x34, 0x3D, 0xB6, 0x12, 0xCB, 0xAF, 0xC0, 0x3D, - 0x97, 0xF7, 0x5A, 0x1B, 0x83, 0x90, 0x91, 0xD0, 0xE2, 0xCF, - 0xE6, 0x21, 0x07, 0xCF, 0x2E, 0xFD, 0x71, 0xA1, 0x10, 0x18, - 0x67, 0x3F, 0x8F, 0xE2, 0x86, 0xFA, 0xA6, 0xDF, 0x6D, 0xE4, - 0x31, 0x7D, 0x75, 0x12, 0x99, 0x23, 0xC7, 0xFB, 0xF2, 0x04, - 0x76, 0x4C, 0x93, 0x9B, 0xB9, 0x89, 0x1D, 0x88, 0x5A, 0x0E, - 0xDE, 0x5A, 0x27, 0x35, 0x88, 0xE7, 0x80, 0x14, 0x87, 0xCA, - 0x23, 0xE6, 0xEF, 0xA8, 0xEA, 0x73, 0x7D, 0x93, 0x0C, 0x61, - 0x81, 0x2E, 0x10, 0xDF, 0x13, 0x57, 0x96, 0xD9, 0x36, 0x68, - 0x93, 0x42, 0x7A, 0x67, 0x60, 0x44, 0x57, 0xD8, 0x6C, 0x4B, - 0xD4, 0xCC, 0x7E, 0x70, 0xE2, 0xCD, 0xC7, 0x14, 0x4A, 0xDE, - 0x32, 0x35, 0x8B, 0x4B, 0x14, 0xE0, 0x8D, 0x5C, 0x33, 0x72, - 0xC9, 0x5D, 0x1F, 0xF6, 0xD7, 0xC3, 0xCF, 0x72, 0xA1, 0x2C, - 0x98, 0x2C, 0x0E, 0xEA, 0x02, 0x26, 0xC0, 0x00, 0x02, 0xEC, - 0xFC, 0x5D, 0x99, 0x61, 0x74, 0x77, 0x64, 0xF2, 0x70, 0x18, - 0x1A, 0x0B, 0x9F, 0x5A, 0x64, 0xE4, 0xCE, 0xA9, 0xCE, 0xCF, - 0x15, 0x35, 0x0E, 0x90, 0x95, 0xD1, 0x78, 0xBC, 0x36, 0xDD, - 0x32, 0xB0, 0x72, 0xCF, 0xCE, 0xFE, 0x8D, 0xAA, 0xF4, 0x19, - 0x73, 0x80, 0x37, 0xB6, 0x7B, 0x88, 0xB5, 0x7F, 0x5B, 0x7E, - 0xC7, 0x1F, 0x40, 0x5E, 0xCF, 0xC5, 0xE3, 0x75, 0x43, 0xCA, - 0x9D, 0x7C, 0xA1, 0x5D, 0x12, 0xBE, 0x30, 0x0E, 0x2C, 0x6D, - 0xE1, 0xD4, 0xD9, 0xC0, 0x90, 0x9F, 0x13, 0x6C, 0x00, 0x75, - 0xC9, 0x98, 0xE8, 0x4A, 0x1E, 0x43, 0x27, 0xB2, 0x3D, 0x16, - 0x5D, 0xF7, 0x18, 0xF6, 0xF2, 0x57, 0xA8, 0x54, 0x57, 0x50, - 0xFD, 0x98, 0x0F, 0x99, 0x63, 0x9E, 0x94, 0x71, 0x8B, 0x6B, - 0x6A, 0xAC, 0x27, 0x7A, 0xE5, 0xFE, 0x49, 0x5F, 0xA9, 0x3F, - 0x72, 0x32, 0xE5, 0x67, 0x87, 0xE9, 0xCC, 0xBC, 0x64, 0xE9, - 0x6B, 0x15, 0x06, 0x60, 0x32, 0x43, 0x49, 0x53, 0x47, 0xB2, - 0x56, 0xCE, 0xBF, 0x5F, 0x9B, 0x16, 0x40, 0x7D, 0x90, 0x0E, - 0xFB, 0xFE, 0x66, 0x58, 0xB3, 0xFC, 0x42, 0xB5, 0x90, 0xE6, - 0xCA, 0x6C, 0xD0, 0x3C, 0xA0, 0x2D, 0x84, 0x5E, 0xA0, 0xE7, - 0xD7, 0x8B, 0xB0, 0x42, 0x56, 0x3D, 0x48, 0xAF, 0x18, 0xEF, - 0xAF, 0x27, 0x76, 0xE3, 0x26, 0x0B, 0xCA, 0xA0, 0x01, 0x4B, - 0x79, 0xD1, 0xAC, 0xD5, 0x8B, 0xCD, 0x70, 0x9F, 0x6E, 0xFB, - 0x72, 0xBB, 0x9B, 0xDA, 0x4A, 0xFA, 0x96, 0x45, 0x29, 0x59, - 0x16, 0x4B, 0x57, 0xC1, 0x7B, 0x5D, 0x94, 0x5E, 0xDA, 0xC1, - 0x2B, 0x3C, 0xD9, 0xD5, 0x6B, 0x23, 0xE7, 0x53, 0x9C, 0xAA, - 0x89, 0x07, 0xFC, 0x66, 0xBC, 0xBC, 0xDD, 0x5D, 0xC7, 0xC0, - 0x46, 0xAF, 0xF6, 0xCB, 0xBB, 0xD3, 0x37, 0xC1, 0x7F, 0xCD, - 0xAE, 0x69, 0x1F, 0xCA, 0x20, 0x07, 0x76, 0x3F, 0xD0, 0x71, - 0x4F, 0x19, 0x6A, 0x92, 0xA2, 0xD8, 0x81, 0xE7, 0x84, 0xC3, - 0x24, 0x55, 0xF3, 0x1F, 0xA6, 0x8B, 0xAF, 0x11, 0xA6, 0xAC, - 0x9B, 0x2D, 0x12, 0xD0, 0x0D, 0xBC, 0x20, 0x26, 0x01, 0x76, - 0x39, 0xBF, 0xAB, 0x52, 0xD6, 0x93, 0x76, 0x29, 0x4C, 0xD8, - 0x8F, 0xBA, 0xA9, 0xA1, 0xCE, 0x09, 0xCC, 0xB7, 0xC5, 0x34, - 0xCC, 0xC1, 0x27, 0xE9, 0x47, 0xFB, 0x02, 0xC0, 0x0B, 0xB7, - 0xE2, 0x1B, 0x9A, 0x05, 0x32, 0x99, 0x7E, 0xEF, 0xDA, 0xC3, - 0xE2, 0xB3, 0x0D, 0x2F, 0xD7, 0x32, 0x14, 0xAA, 0x90, 0x00, - 0x5B, 0x8F, 0xA9, 0x6D, 0xBD, 0x54, 0xAF, 0xE2, 0x47, 0x8C, - 0x20, 0xD4, 0x14, 0x34, 0x13, 0x08, 0x17, 0x1B, 0xA2, 0x3B, - 0xDC, 0x6D, 0x5A, 0x08, 0x04, 0x58, 0x38, 0xAC, 0x84, 0xBB, - 0x22, 0x64, 0x6B, 0xE6, 0xB9, 0x46, 0x4A, 0xB6, 0x39, 0xD2, - 0xF4, 0x6D, 0x13, 0x63, 0x7F, 0x79, 0x6F, 0x54, 0x38, 0x72, - 0x1A, 0x3D, 0x45, 0x28, 0x14, 0x8F, 0x9D, 0xFE, 0x51, 0x02, - 0x3F, 0x0C, 0xFD, 0xE4, 0x7A, 0xC4, 0xFC, 0x00, 0xF0, 0xF6, - 0x7E, 0x98, 0x36, 0x40, 0x35, 0x92, 0x3A, 0x42, 0xBE, 0xA6, - 0xAE, 0x3C, 0x55, 0xF5, 0x4E, 0x41, 0xF4, 0x22, 0x63, 0x80, - 0x2E, 0xC9, 0x65, 0x73, 0x43, 0x2F, 0xE7, 0xF9, 0xC5, 0x5C, - 0x21, 0xDD, 0xF5, 0x15, 0x38, 0xE4, 0xDD, 0x92, 0x08, 0x9D, - 0x75, 0x65, 0x13, 0x28, 0xA5, 0xF9, 0x45, 0x13, 0xE0, 0x8F, - 0xB2, 0x36, 0x91, 0xAA, 0xBE, 0x87, 0xD2, 0x78, 0x3F, 0xB0, - 0xEE, 0x0C, 0x4C, 0x8C, 0xD7, 0x56, 0x85, 0x21, 0x43, 0x40, - 0xC4, 0x26, 0x90, 0xC2, 0x63, 0xF0, 0xC3, 0x49, 0xA0, 0xF0, - 0x2A, 0xCA, 0xA3, 0x9A, 0x39, 0xA6, 0xAA, 0x98, 0x2B, 0x8E, - 0xBA, 0x0B, 0xD9, 0x21, 0xC4, 0xC9, 0x97, 0x1B, 0x57, 0x80, - 0x49, 0x3E, 0xC4, 0x4B, 0xD8, 0x5E, 0xE2, 0x43, 0xC2, 0x13, - 0x8D, 0x51, 0x28, 0x8B, 0x30, 0x7C, 0x17, 0xB0, 0x58, 0x15, - 0x5F, 0x56, 0xF8, 0xF3, 0x8F, 0x9A, 0xC0, 0x9B, 0x27, 0x90, - 0x23, 0x48, 0xED, 0x5E, 0x50, 0xE2, 0x02, 0x26, 0xC0, 0x00, - 0x02, 0x02, 0xCA, 0xFA, 0x0D, 0x3A, 0xC4, 0xBF, 0x20, 0x04, - 0xD3, 0xA1, 0x4F, 0xED, 0x80, 0x40, 0x81, 0x15, 0x67, 0x0D, - 0x65, 0x3E, 0x52, 0x9C, 0x30, 0x20, 0xD2, 0xD8, 0xAC, 0xAF, - 0x06, 0xE5, 0xDA, 0x8B, 0x8B, 0x3A, 0xCA, 0xDC, 0x59, 0x8F, - 0x2F, 0x93, 0x53, 0x5B, 0xAC, 0xCE, 0x1F, 0xDF, 0x3B, 0x50, - 0xBF, 0x70, 0xF1, 0x7A, 0xCC, 0xA2, 0x25, 0x88, 0xD1, 0xA0, - 0xBC, 0x9D, 0x41, 0x1F, 0x9C, 0x0A, 0x95, 0x27, 0xE2, 0x71, - 0x4C, 0x1C, 0x14, 0xDB, 0xEA, 0xCD, 0xA3, 0x7C, 0x39, 0x57, - 0x69, 0x95, 0xA5, 0x04, 0x4F, 0xA3, 0xC0, 0x24, 0xC1, 0x5B, - 0x39, 0xF4, 0x9F, 0xBC, 0xB2, 0xC3, 0x37, 0x28, 0x1F, 0xFA, - 0xB9, 0xD7, 0xFF, 0x7A, 0xA2, 0x52, 0x03, 0x1F, 0x96, 0x5B, - 0xC4, 0x83, 0x08, 0x75, 0xFF, 0xF6, 0xF2, 0xF9, 0x7C, 0x1D, - 0x09, 0xB4, 0x3B, 0xAE, 0xCD, 0x2E, 0xF2, 0x6F, 0x2F, 0x4F, - 0xBC, 0x2B, 0x5B, 0x6D, 0x9A, 0x1B, 0xE6, 0x5E, 0xF5, 0xA8, - 0x93, 0x98, 0xDC, 0x6E, 0x5E, 0x17, 0xCA, 0xAB, 0x90, 0xFD, - 0xFB, 0x68, 0x1F, 0x67, 0x88, 0x58, 0x85, 0x4F, 0xAA, 0xC3, - 0x68, 0x40, 0xD5, 0xBC, 0xAC, 0x1D, 0x94, 0xC5, 0xB6, 0x01, - 0x2A, 0xE8, 0xBD, 0xDD, 0xBB, 0x17, 0x9D, 0x0E, 0x55, 0x62, - 0x45, 0xFB, 0x21, 0xB6, 0x71, 0x76, 0xEB, 0xCC, 0xF5, 0xE7, - 0xF1, 0xCD, 0xB7, 0xCA, 0xBD, 0xFF, 0xA9, 0xF7, 0x1A, 0xAA, - 0x1A, 0xCD, 0xC1, 0x71, 0x62, 0xE3, 0xDD, 0x09, 0x06, 0xAA, - 0x23, 0xFD, 0xEF, 0x6B, 0xA7, 0x83, 0xD8, 0xE6, 0x70, 0x01, - 0xF0, 0xEF, 0x69, 0xA9, 0x4B, 0x9B, 0x83, 0x57, 0x77, 0xAD, - 0x51, 0xBE, 0xBA, 0xF6, 0x2A, 0x6F, 0x1F, 0x97, 0x9A, 0xFE, - 0xA8, 0xE2, 0xAA, 0x20, 0x51, 0x95, 0xBA, 0xAE, 0x66, 0xB3, - 0xA8, 0x61, 0xCF, 0x8B, 0xFA, 0x6B, 0x48, 0xC4, 0x22, 0xE1, - 0xDF, 0x3A, 0x0D, 0xA9, 0x09, 0xF1, 0x66, 0x0C, 0x46, 0x74, - 0x90, 0x8B, 0x68, 0x00, 0x4F, 0x4F, 0x3A, 0x90, 0x58, 0x56, - 0xF4, 0x8A, 0x71, 0xB6, 0x1A, 0x91, 0x59, 0x17, 0x5C, 0xC0, - 0x87, 0x82, 0x7E, 0xB0, 0x81, 0x90, 0xF1, 0x6A, 0x03, 0xB8, - 0xA0, 0xAB, 0xDD, 0x63, 0x96, 0x48, 0x19, 0x37, 0x1F, 0x0F, - 0x24, 0x7A, 0x70, 0x48, 0x7D, 0x28, 0x1F, 0xB3, 0xCD, 0x76, - 0x53, 0x83, 0xC5, 0x53, 0xE8, 0xAB, 0x3A, 0xFC, 0x5B, 0x8A, - 0xF0, 0x5A, 0x0F, 0xEF, 0xFF, 0xB0, 0xC1, 0x61, 0x61, 0x58, - 0x4A, 0x8C, 0x1C, 0x20, 0xFC, 0x46, 0x07, 0x58, 0xF0, 0x20, - 0x81, 0x66, 0x28, 0x0E, 0xC2, 0x16, 0xAB, 0x98, 0xFF, 0x6E, - 0x24, 0xAC, 0x78, 0x42, 0xAE, 0x7D, 0xAB, 0x6F, 0xB4, 0x11, - 0x1C, 0x0C, 0x40, 0xF8, 0xF4, 0x93, 0x63, 0xE4, 0x6A, 0xEB, - 0xC5, 0xD9, 0x6E, 0x35, 0xC9, 0xA7, 0x2D, 0x49, 0xEA, 0x5D, - 0x69, 0x73, 0x06, 0x1C, 0xC4, 0x7E, 0x46, 0xFD, 0x09, 0x88, - 0x77, 0x77, 0xE7, 0xEB, 0x31, 0x34, 0x16, 0x72, 0x76, 0x1B, - 0x4E, 0xF8, 0x67, 0x9F, 0xCA, 0x1C, 0x67, 0x4E, 0xD8, 0x88, - 0xAA, 0x01, 0x27, 0x8E, 0x08, 0x70, 0xF8, 0x0B, 0x23, 0xF6, - 0x84, 0x47, 0x2F, 0x4E, 0x5F, 0xB7, 0x2C, 0x39, 0xBF, 0x61, - 0xEC, 0x6D, 0x24, 0x5C, 0x57, 0xBE, 0xAE, 0x19, 0x20, 0xBE, - 0x55, 0x40, 0x1D, 0xB7, 0x5F, 0xC3, 0xF6, 0x5B, 0x19, 0xC6, - 0x8A, 0x94, 0x23, 0x5C, 0x95, 0x33, 0x4C, 0x90, 0xE0, 0x46, - 0xAC, 0x0A, 0x1D, 0x50, 0xFB, 0x0A, 0xAB, 0xA2, 0xEB, 0x2A, - 0x21, 0xBF, 0x15, 0xD5, 0x9E, 0x80, 0x3B, 0x16, 0xB0, 0x3F, - 0x6F, 0x6F, 0xF6, 0xBE, 0x92, 0xA1, 0x2F, 0x83, 0xA8, 0x3C, - 0xA6, 0xE7, 0x86, 0xCD, 0x3B, 0x96, 0xCE, 0xF1, 0x36, 0x7C, - 0x69, 0xD9, 0xD5, 0x0F, 0xC1, 0x4C, 0x7A, 0xE5, 0xAF, 0xAC, - 0x86, 0x90, 0x98, 0x3D, 0x2B, 0x94, 0xA2, 0x7C, 0x5B, 0xF7, - 0x27, 0xCD, 0xE5, 0x93, 0x60, 0x2C, 0x47, 0xE3, 0xFA, 0x18, - 0xCB, 0xEB, 0xDB, 0x0A, 0x49, 0x99, 0x0F, 0xAE, 0x02, 0x26, - 0xC0, 0x00, 0x02, 0xF3, 0x51, 0xA3, 0x96, 0x54, 0xDA, 0xE9, - 0x09, 0x47, 0x82, 0x50, 0xB8, 0x82, 0x39, 0x98, 0x54, 0x81, - 0x54, 0x91, 0x2C, 0xE6, 0xBC, 0x84, 0x03, 0x07, 0x26, 0x6D, - 0x0F, 0x5E, 0x2B, 0x45, 0xF5, 0x1D, 0x7B, 0xD6, 0x14, 0x03, - 0xD7, 0x09, 0x64, 0xEE, 0x05, 0xBA, 0xE0, 0x74, 0x67, 0x02, - 0xF5, 0x7E, 0x42, 0x42, 0xEC, 0x56, 0xE0, 0x9E, 0x82, 0x88, - 0x58, 0x3C, 0x96, 0xAF, 0x37, 0x95, 0x49, 0xC8, 0x87, 0xBD, - 0xFE, 0x7A, 0x6B, 0x4D, 0x37, 0xEE, 0x7C, 0xAA, 0x18, 0x5F, - 0x7E, 0x0B, 0x28, 0xA3, 0x95, 0x23, 0x42, 0xAB, 0xC1, 0xFA, - 0x41, 0xAE, 0xD5, 0xBD, 0x67, 0xA6, 0xC4, 0x7C, 0xAC, 0x2D, - 0xEF, 0x64, 0xC2, 0x5D, 0x30, 0x94, 0xF3, 0x97, 0x49, 0x00, - 0x39, 0x28, 0x57, 0x5D, 0x31, 0xBB, 0x1D, 0x10, 0x17, 0xE7, - 0x56, 0x55, 0xDF, 0x4C, 0xDD, 0xA6, 0x64, 0x02, 0xBC, 0x1C, - 0x2B, 0x4C, 0x30, 0xBF, 0x89, 0x7C, 0xFC, 0x7E, 0x84, 0xBC, - 0x51, 0x97, 0x6C, 0x74, 0x5B, 0x08, 0xE0, 0x96, 0x84, 0x81, - 0xF3, 0x17, 0x6B, 0xD6, 0xF6, 0x66, 0x06, 0x1B, 0x33, 0x4D, - 0xF8, 0xED, 0xC0, 0x53, 0x8B, 0x35, 0x6B, 0x85, 0x4F, 0x37, - 0x0F, 0x87, 0xF3, 0x85, 0x72, 0xAE, 0xCB, 0x3A, 0x23, 0x97, - 0xC0, 0xF6, 0xE7, 0x53, 0xDF, 0x57, 0x0E, 0x8E, 0x0B, 0x66, - 0x2A, 0xA2, 0x9D, 0xA8, 0xE2, 0x60, 0x57, 0xCA, 0x27, 0x7E, - 0xB1, 0xDB, 0x7B, 0x6A, 0xB0, 0xBE, 0xB5, 0x47, 0xEE, 0xE6, - 0xBA, 0x0E, 0xB2, 0x71, 0x0B, 0xF7, 0xE4, 0x27, 0x9D, 0x25, - 0xAA, 0x3F, 0xA9, 0x1A, 0x5B, 0xD9, 0x9D, 0xBB, 0x20, 0x32, - 0x37, 0xE1, 0xD3, 0x4A, 0xBA, 0x45, 0x9E, 0x00, 0x10, 0x3F, - 0x21, 0x6E, 0xA2, 0xCE, 0x30, 0xA0, 0x2A, 0x5B, 0x31, 0x51, - 0x05, 0xA1, 0x51, 0xED, 0x89, 0x5E, 0xB1, 0x09, 0xE6, 0x71, - 0xD8, 0x42, 0xFD, 0xA1, 0x04, 0x83, 0xFB, 0x09, 0x4F, 0x90, - 0x4D, 0x7E, 0x5A, 0xB9, 0x4C, 0xC9, 0xA3, 0x57, 0x4E, 0x54, - 0x98, 0xB3, 0xBD, 0xB7, 0x52, 0x9D, 0xDE, 0xF3, 0xD3, 0xE0, - 0x9C, 0x2D, 0x97, 0x46, 0x1B, 0xF9, 0x75, 0x37, 0x5D, 0x0A, - 0xA3, 0x4A, 0x18, 0x35, 0x80, 0xC5, 0x08, 0xA8, 0x37, 0x09, - 0x44, 0x92, 0xB1, 0x74, 0xFE, 0x28, 0x95, 0x55, 0xB6, 0x08, - 0xA0, 0x75, 0xE9, 0xA0, 0x4B, 0x8E, 0xE6, 0x61, 0x17, 0x2A, - 0xED, 0x15, 0x0B, 0x6C, 0x7C, 0xC3, 0x82, 0x57, 0x90, 0xC5, - 0xFF, 0xD8, 0xA5, 0xBF, 0xAA, 0xBE, 0xCF, 0x8E, 0x06, 0xFF, - 0x27, 0xDA, 0x40, 0x24, 0xDD, 0xC0, 0xBE, 0x4E, 0x19, 0x9D, - 0x23, 0xA2, 0x3A, 0x70, 0x64, 0xEB, 0xF6, 0xA7, 0xE9, 0x71, - 0x57, 0xE9, 0x63, 0x03, 0xAE, 0xEC, 0x73, 0x21, 0x23, 0x8D, - 0x61, 0x5A, 0x10, 0x54, 0xF9, 0x80, 0xE7, 0x47, 0x45, 0xD4, - 0x8B, 0x16, 0xEE, 0x2B, 0xD8, 0xC1, 0xEE, 0x0F, 0x4F, 0x78, - 0x40, 0x00, 0xB6, 0x25, 0x81, 0x2A, 0x37, 0x4D, 0x71, 0x92, - 0xFA, 0x56, 0x3F, 0xDC, 0x91, 0x01, 0x27, 0xC7, 0x17, 0xFD, - 0x27, 0x55, 0x6F, 0x32, 0x14, 0xE7, 0xEA, 0x18, 0xDA, 0x4A, - 0x70, 0x10, 0xF8, 0x72, 0x78, 0xA1, 0xC1, 0x13, 0x5F, 0x1B, - 0x98, 0x93, 0xC2, 0xBF, 0x29, 0xA3, 0x59, 0x79, 0x15, 0x57, - 0x17, 0xE5, 0x66, 0x7A, 0x3B, 0x8E, 0xB3, 0x3B, 0x9E, 0xC0, - 0x77, 0xBD, 0x2D, 0x95, 0x26, 0xF0, 0xD5, 0xB4, 0x30, 0xC8, - 0x0D, 0xCA, 0xB5, 0xDE, 0xB2, 0x21, 0x27, 0x9A, 0x27, 0xAF, - 0x89, 0xB4, 0x0D, 0x1B, 0x5A, 0x43, 0x3E, 0x69, 0x76, 0x25, - 0xAC, 0x42, 0x23, 0x5F, 0x5A, 0xA6, 0xDB, 0xE6, 0x77, 0x9D, - 0x2A, 0x99, 0x1B, 0xE7, 0x47, 0x05, 0x06, 0x47, 0x01, 0x14, - 0x0D, 0xEA, 0xF5, 0x28, 0x3A, 0x5B, 0x87, 0xF0, 0xFB, 0x7C, - 0x96, 0x39, 0x6C, 0x4A, 0x48, 0xA5, 0x7A, 0x94, 0xB0, 0xB8, - 0xBB, 0x03, 0xDA, 0xEA, 0x4F, 0xD1, 0x5B, 0x8B, 0x9D, 0x0A, - 0x5E, 0xAB, 0xD8, 0x89, 0x5C, 0x4D, 0xD1, 0xA7, 0xC4, 0x8A, - 0x02, 0x26, 0xC0, 0x00, 0x02, 0x14, 0x04, 0xA6, 0x12, 0xC1, - 0x4E, 0x67, 0x67, 0x6C, 0xEE, 0x9E, 0x7A, 0x55, 0x00, 0xCB, - 0x12, 0x7B, 0x69, 0x4C, 0x94, 0x57, 0x73, 0x71, 0xC8, 0x45, - 0xAA, 0x04, 0x75, 0x85, 0xED, 0x68, 0x7D, 0x09, 0xD5, 0x4A, - 0xD0, 0x86, 0xDB, 0x0B, 0xC3, 0x80, 0xD1, 0x11, 0xB3, 0x59, - 0xCF, 0xBD, 0x13, 0x7B, 0xD2, 0x30, 0xDF, 0xDD, 0x41, 0xD7, - 0xBC, 0x34, 0x11, 0x85, 0x58, 0x2A, 0x8E, 0x2B, 0xDC, 0x00, - 0x78, 0x94, 0x28, 0x52, 0xD9, 0x0C, 0x70, 0xCB, 0x7D, 0xE9, - 0xCF, 0x7C, 0x11, 0x91, 0x09, 0xA8, 0xD7, 0xBC, 0xC8, 0xA1, - 0xDF, 0xF3, 0xB4, 0x25, 0x3A, 0x88, 0x02, 0xF0, 0xBE, 0x8E, - 0x89, 0x2B, 0xA6, 0x43, 0x88, 0xD0, 0xCC, 0x27, 0x91, 0x77, - 0x8D, 0x01, 0x32, 0xA6, 0x0C, 0x3D, 0x86, 0x76, 0x03, 0x4F, - 0x01, 0xF6, 0x02, 0xB3, 0xD0, 0x7A, 0x39, 0x78, 0x1E, 0xF2, - 0x35, 0xB6, 0xB3, 0xC9, 0x50, 0xE7, 0x0A, 0xD1, 0x3C, 0xB4, - 0xE2, 0x02, 0x60, 0x13, 0x8A, 0x0F, 0x15, 0xEE, 0x48, 0x67, - 0x84, 0x9E, 0x8E, 0x56, 0x22, 0xB9, 0x0A, 0xE2, 0x36, 0xDE, - 0x97, 0x4E, 0x9F, 0x0A, 0xE0, 0xB8, 0x2A, 0x0D, 0x07, 0x7F, - 0xCE, 0x76, 0xEA, 0x58, 0x54, 0xBC, 0x7A, 0xA1, 0x87, 0x15, - 0x3F, 0xCE, 0xDA, 0x58, 0xA4, 0x51, 0x36, 0x49, 0xB0, 0x23, - 0xC0, 0x55, 0xFB, 0xE2, 0x47, 0xB6, 0xD6, 0x31, 0x90, 0xA9, - 0x99, 0x2A, 0xC3, 0x59, 0xAE, 0x60, 0x03, 0xC2, 0x56, 0xC0, - 0x03, 0xA9, 0x3E, 0xF0, 0xE9, 0x59, 0x30, 0xD5, 0x90, 0x15, - 0x72, 0x32, 0x30, 0xD1, 0xFA, 0xDD, 0xB3, 0x09, 0xF0, 0x1A, - 0xA3, 0x6E, 0x5E, 0xBB, 0xDE, 0x58, 0x08, 0x91, 0xFB, 0xA0, - 0xEC, 0x45, 0x7F, 0x05, 0x90, 0x78, 0xCF, 0x6F, 0x66, 0xF4, - 0x2A, 0x79, 0x93, 0x33, 0x17, 0x07, 0x86, 0xE6, 0xEC, 0xFD, - 0xEC, 0x07, 0x74, 0x17, 0x26, 0x84, 0x52, 0x54, 0x9A, 0xBC, - 0xDE, 0xEE, 0xD7, 0xE9, 0x2F, 0xA7, 0x60, 0xA6, 0x54, 0x74, - 0xB9, 0x83, 0x6D, 0xE6, 0xB7, 0x46, 0xDC, 0xC8, 0x09, 0x36, - 0x25, 0x1E, 0x8B, 0x61, 0x94, 0x2D, 0xBA, 0xE2, 0xAB, 0xE6, - 0xD0, 0xDB, 0x9C, 0x13, 0x74, 0x25, 0xDA, 0xD7, 0x69, 0x69, - 0xFA, 0x52, 0x3C, 0x15, 0xBB, 0xFC, 0x5D, 0xE2, 0x6E, 0xA5, - 0x26, 0x35, 0x65, 0xF4, 0xE0, 0x29, 0x77, 0xCF, 0xAB, 0xF9, - 0xAB, 0x8C, 0x9D, 0x7D, 0x60, 0xA4, 0xA0, 0x3D, 0x43, 0xB6, - 0x9D, 0xAE, 0x04, 0x46, 0x8A, 0xE2, 0x3B, 0x4C, 0xC8, 0xA4, - 0x5D, 0x61, 0xB4, 0x5B, 0x8B, 0x2E, 0xD5, 0x2A, 0x07, 0x27, - 0x6A, 0x34, 0x04, 0xBA, 0xF8, 0x72, 0x32, 0x99, 0x97, 0x8C, - 0xC0, 0xCD, 0x35, 0x68, 0xB8, 0xA9, 0x45, 0x76, 0xA5, 0xD4, - 0x17, 0x36, 0xB1, 0x25, 0xF7, 0x47, 0x69, 0x30, 0x68, 0x14, - 0x0B, 0x9C, 0x38, 0xB1, 0x29, 0x16, 0x88, 0xAD, 0xDF, 0x31, - 0x7E, 0x3C, 0x5F, 0xA4, 0x0D, 0x86, 0x5A, 0x29, 0x37, 0xA9, - 0x1B, 0xD5, 0x68, 0x9F, 0xE0, 0xE6, 0x32, 0x42, 0x12, 0x37, - 0x99, 0xC5, 0xB8, 0xA1, 0xD3, 0x5B, 0x90, 0x9C, 0xAD, 0x86, - 0x6B, 0x03, 0x82, 0x91, 0xD9, 0xF9, 0xDC, 0xD5, 0x41, 0x7B, - 0xF3, 0xE4, 0x08, 0x92, 0xCA, 0x6A, 0xAA, 0xBD, 0xFE, 0x25, - 0x50, 0xDC, 0x2C, 0x00, 0x65, 0x59, 0x9B, 0xD3, 0x30, 0xD2, - 0x39, 0xC0, 0x4D, 0xFD, 0x8C, 0x9D, 0x88, 0xD3, 0x52, 0xD6, - 0xC0, 0xA0, 0x1C, 0x08, 0x0B, 0x1F, 0x91, 0xAF, 0x60, 0x56, - 0xED, 0x8B, 0x37, 0xD3, 0x15, 0x08, 0x5C, 0xEA, 0xFA, 0x03, - 0x0A, 0x54, 0x92, 0x96, 0x34, 0x4F, 0x14, 0x0E, 0xD5, 0xB4, - 0xA0, 0x2E, 0xC0, 0xEC, 0x93, 0x8F, 0xA5, 0xF3, 0x82, 0x5F, - 0x0D, 0xA8, 0xBD, 0x28, 0x4B, 0x1C, 0x65, 0xC1, 0x97, 0x5B, - 0xEE, 0x99, 0xC5, 0xC2, 0xB9, 0x34, 0x4D, 0xDB, 0x6E, 0x42, - 0x26, 0x93, 0x49, 0x83, 0x36, 0x25, 0x72, 0x03, 0x08, 0xE2, - 0xE6, 0x67, 0x01, 0xBC, 0x7A, 0x10, 0x7A, 0xBC, 0x6B, 0x0B, - 0x4A, 0x94, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x72, 0x08, 0xBA, - 0x77, 0xE2, 0x2F, 0x48, 0xD4, 0x9E, 0xC4, 0x23, 0x45, 0x55, - 0xF1, 0x0B, 0x1B, 0x50, 0x47, 0x8C, 0x40, 0x7C, 0xF7, 0xE4, - 0xCF, 0xD6, 0x0A, 0x0A, 0xD3, 0x7F, 0x35, 0x85, 0x84, 0x78, - 0xF2, 0x28, 0xEA, 0x14, 0x06, 0x2A, 0xC0, 0x53, 0x22, 0x45, - 0x9B, 0xDA, 0xE9, 0xEE, 0x98, 0x5D, 0xEC, 0xEC, 0xEF, 0xA1, - 0x1A, 0xDD, 0x7C, 0xE2, 0x29, 0xFF, 0x2B, 0x8A, 0x00, 0x49, - 0xD6, 0x2E, 0x7C, 0x50, 0x26, 0x29, 0x65, 0x97, 0xB4, 0xA8, - 0x6B, 0x38, 0x95, 0xC0, 0x7F, 0x41, 0xAD, 0xD5, 0xA2, 0x54, - 0x37, 0xE1, 0x72, 0x3A, 0x28, 0x58, 0xCA, 0x88, 0xB4, 0xF8, - 0x34, 0x43, 0xFF, 0xE4, 0xE4, 0xC2, 0x37, 0x0B, 0x72, 0x77, - 0x2B, 0x94, 0x8C, 0xB8, 0xCD, 0x72, 0x1E, 0xDB, 0x0A, 0xFA, - 0x86, 0x0E, 0xBC, 0x76, 0xDE, 0x89, 0x20, 0xBB, 0x1A, 0xC3, - 0x07, 0xAA, 0x0F, 0x0D, 0xED, 0x58, 0x42, 0x74, 0x44, 0xD0, - 0x89, 0x61, 0x25, 0xAF, 0xC0, 0x18, 0xFE, 0x16, 0xC9, 0x37, - 0x03, 0x11, 0x11, 0xEC, 0x9F, 0xFF, 0x2B, 0x00, 0x4F, 0x37, - 0xB6, 0xEC, 0x54, 0x0A, 0xA1, 0x68, 0xE5, 0x69, 0x38, 0xD5, - 0x55, 0x9E, 0x94, 0xAF, 0x3D, 0x67, 0xFF, 0x4D, 0x5D, 0x66, - 0x1D, 0xD0, 0x45, 0x1B, 0xF9, 0x23, 0x5F, 0xCF, 0x18, 0xFB, - 0x3F, 0x13, 0x0A, 0x2E, 0x86, 0xC4, 0x44, 0x28, 0xAB, 0x72, - 0x78, 0x77, 0x14, 0xCA, 0x70, 0xBF, 0x3E, 0x79, 0x47, 0xAB, - 0x3D, 0x22, 0xB9, 0x57, 0xB8, 0x04, 0x4B, 0x62, 0x2A, 0x26, - 0x4C, 0xEE, 0x80, 0xF4, 0x1C, 0x5C, 0xE3, 0xFF, 0x23, 0xC8, - 0x7C, 0x27, 0x90, 0xC8, 0x61, 0xC3, 0x7C, 0xC8, 0x5B, 0x46, - 0xB8, 0xCC, 0x8A, 0x67, 0xFC, 0xB9, 0xF1, 0xE7, 0x21, 0x68, - 0x47, 0x37, 0x9D, 0xEB, 0x14, 0xC4, 0x55, 0x02, 0x43, 0xA6, - 0xAA, 0x50, 0xE2, 0x78, 0x66, 0xE9, 0x55, 0x2D, 0x4C, 0x84, - 0xDF, 0x81, 0xCF, 0x0C, 0xD4, 0x36, 0xCA, 0x3D, 0xF7, 0xEE, - 0x2A, 0x5D, 0x10, 0xC9, 0xEA, 0x19, 0xF2, 0xF3, 0xBD, 0x42, - 0xA9, 0xE1, 0xA6, 0xD1, 0x84, 0xE9, 0x1A, 0x26, 0xDC, 0xBE, - 0x72, 0x43, 0xC7, 0x79, 0x92, 0xD9, 0x5F, 0x7C, 0x42, 0xCD, - 0xFF, 0x76, 0xBE, 0xB9, 0x99, 0x60, 0x6B, 0x5E, 0xAD, 0xAC, - 0x62, 0xAD, 0xFD, 0x58, 0x1C, 0x4E, 0xC6, 0x6D, 0xE7, 0xF9, - 0x2E, 0xD1, 0xEC, 0x9F, 0x98, 0xAE, 0x4F, 0xB6, 0xE1, 0xB3, - 0x77, 0xDD, 0xA4, 0x5D, 0x24, 0x76, 0xF0, 0xED, 0xBE, 0x19, - 0xB1, 0x98, 0x85, 0x08, 0xAB, 0xF0, 0x39, 0x94, 0x1D, 0x12, - 0xCA, 0x8B, 0xD2, 0xCC, 0x97, 0x44, 0xCB, 0x89, 0x9B, 0x66, - 0x50, 0x51, 0x64, 0x9E, 0xB1, 0x9E, 0x2C, 0xAA, 0xE5, 0x91, - 0x59, 0x53, 0xB1, 0x5E, 0xB3, 0xBB, 0x99, 0x00, 0x53, 0xA9, - 0xC1, 0x6C, 0x59, 0x46, 0xFD, 0xCB, 0x53, 0x83, 0xDD, 0x37, - 0xA1, 0xA3, 0x65, 0x26, 0xC6, 0x48, 0x6D, 0x15, 0xE8, 0xC1, - 0xE3, 0x45, 0x10, 0x6E, 0x8A, 0xE1, 0xDB, 0x10, 0xDB, 0x58, - 0x16, 0x5C, 0x31, 0x2E, 0x06, 0xA8, 0xAE, 0xD7, 0xB2, 0x11, - 0x55, 0x07, 0x2E, 0x57, 0x57, 0x02, 0x48, 0xC0, 0x8B, 0x59, - 0x8C, 0xBE, 0x1A, 0x47, 0x52, 0x3E, 0xD0, 0x05, 0xEA, 0xBC, - 0x86, 0xEA, 0x31, 0xD9, 0x58, 0x52, 0xCF, 0x7D, 0xD2, 0x30, - 0x4E, 0x0D, 0x24, 0x6F, 0x39, 0xF6, 0xEB, 0xC8, 0x5D, 0xE4, - 0xFF, 0x8D, 0xB9, 0x71, 0x02, 0x71, 0x67, 0x89, 0xFA, 0xB8, - 0x4F, 0xC9, 0x77, 0x78, 0x60, 0x36, 0xDF, 0x0E, 0x96, 0xAC, - 0x4F, 0x44, 0x8A, 0x2C, 0xE5, 0x8C, 0xC3, 0x96, 0x79, 0xE2, - 0x43, 0x75, 0xF5, 0x59, 0xC0, 0x81, 0x0A, 0x54, 0xC2, 0xA3, - 0x28, 0x8A, 0x32, 0xCE, 0x91, 0x5A, 0x91, 0x06, 0x45, 0xEB, - 0x34, 0x1A, 0x87, 0xF9, 0x57, 0x91, 0x0D, 0x34, 0x7F, 0x82, - 0x91, 0x82, 0xC5, 0x26, 0xCB, 0xB3, 0x4F, 0xF2, 0x20, 0x6A, - 0x02, 0x95, 0x73, 0x7B, 0x4F, 0x4E, 0xAF, 0x8A, 0x40, 0x83, - 0xFE, 0xF9, 0xD2, 0xFD, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x0E, - 0xA2, 0xA8, 0x59, 0xF0, 0x82, 0x17, 0x4C, 0x0E, 0xF3, 0x83, - 0xA1, 0xB6, 0x36, 0x83, 0xCB, 0xFB, 0xA2, 0x66, 0x53, 0x65, - 0x40, 0x40, 0xAA, 0x3D, 0x82, 0x62, 0x54, 0x0A, 0x27, 0x6A, - 0xD6, 0x07, 0xAF, 0x91, 0xCF, 0x9B, 0x89, 0x58, 0xBC, 0xCE, - 0x74, 0x87, 0x9C, 0x7E, 0x30, 0xF3, 0x06, 0x2B, 0xF1, 0xB4, - 0x70, 0x9D, 0xAA, 0x41, 0xD7, 0x25, 0x75, 0xE5, 0x72, 0x25, - 0x00, 0xC7, 0x21, 0x9D, 0xEE, 0xD1, 0x24, 0x16, 0x0B, 0x12, - 0x22, 0x88, 0xB8, 0x9D, 0xA5, 0x38, 0xA0, 0x50, 0x39, 0x27, - 0xAE, 0x10, 0xF6, 0x9A, 0x0B, 0x77, 0x56, 0x3F, 0x96, 0xDF, - 0x22, 0xE5, 0xEA, 0xAC, 0x8F, 0xDF, 0xDD, 0x78, 0xEF, 0x5A, - 0x7B, 0x50, 0x72, 0x98, 0x92, 0xDD, 0x94, 0xB5, 0xDB, 0x99, - 0xCE, 0xF2, 0x7A, 0xF3, 0xFA, 0x80, 0xD3, 0xCD, 0x1F, 0xCA, - 0xA2, 0x2E, 0x21, 0x94, 0xF2, 0xB3, 0x71, 0x7C, 0x07, 0xE6, - 0xB9, 0x68, 0x1E, 0x13, 0x02, 0x15, 0xC8, 0x34, 0xA0, 0xB5, - 0xD9, 0x95, 0x1A, 0x9B, 0x57, 0xE7, 0xAF, 0xB0, 0xE1, 0xA7, - 0x95, 0xF2, 0x36, 0xA3, 0xF9, 0xC5, 0x2C, 0xF0, 0xC3, 0xE1, - 0xD1, 0x26, 0xA1, 0x8F, 0xE6, 0x07, 0xFB, 0x1F, 0x03, 0xFF, - 0xA5, 0x81, 0xF5, 0x5D, 0x21, 0x3B, 0x93, 0x66, 0x1A, 0x78, - 0x6F, 0xD4, 0x77, 0xB3, 0x91, 0x26, 0x6F, 0x1F, 0x5A, 0x8B, - 0x0F, 0x07, 0xEA, 0x24, 0x5F, 0x5E, 0x68, 0x9F, 0x89, 0x75, - 0x00, 0x23, 0x1C, 0x80, 0x55, 0x86, 0x93, 0x58, 0x94, 0x41, - 0x37, 0x0D, 0x23, 0xD3, 0x09, 0x72, 0x40, 0x79, 0xA2, 0x52, - 0x0D, 0xA3, 0x40, 0x3F, 0x54, 0x7E, 0x59, 0x55, 0x5B, 0x7D, - 0x0C, 0x52, 0xAA, 0x97, 0x0C, 0xC6, 0xCB, 0x0B, 0x6C, 0x83, - 0x45, 0x28, 0x62, 0x09, 0x0A, 0x74, 0x27, 0x1D, 0x4D, 0x02, - 0x07, 0xB3, 0xA5, 0x83, 0x9A, 0x43, 0xB3, 0x68, 0xF7, 0x97, - 0x3E, 0xD7, 0x34, 0x04, 0x83, 0xC7, 0x6F, 0x64, 0xB8, 0x0B, - 0xB9, 0xE9, 0x94, 0x46, 0xB9, 0x4D, 0xA7, 0xB4, 0x26, 0xF7, - 0x9C, 0x05, 0x94, 0x8B, 0xBE, 0x93, 0x03, 0xA7, 0x73, 0x65, - 0xAB, 0xC5, 0xE1, 0x2B, 0x3B, 0x4C, 0x56, 0x1F, 0x11, 0x7B, - 0xD3, 0xC0, 0x77, 0x48, 0x42, 0x27, 0x8D, 0x2A, 0xAA, 0x1E, - 0x18, 0x41, 0x76, 0xA1, 0x80, 0x99, 0x52, 0x50, 0x66, 0x7B, - 0x27, 0x4B, 0x49, 0xA1, 0xE8, 0xCA, 0xF1, 0x3E, 0x60, 0x2E, - 0x93, 0xEF, 0x4A, 0x20, 0x3C, 0xC4, 0xBB, 0x14, 0xD3, 0x8F, - 0x14, 0xAF, 0xC0, 0xF8, 0x4B, 0xC6, 0x49, 0x1A, 0x3B, 0x17, - 0x43, 0xC2, 0xAB, 0xF0, 0x01, 0xFC, 0x6E, 0x67, 0x86, 0xAC, - 0xE4, 0x6F, 0xF2, 0x26, 0xF2, 0xEC, 0x15, 0xA1, 0x96, 0x81, - 0xDD, 0xCF, 0xCA, 0xB4, 0xE1, 0x5A, 0xA0, 0xF5, 0xBB, 0x70, - 0xEB, 0xF9, 0xA6, 0x28, 0x66, 0xC3, 0xBE, 0xB9, 0xBD, 0xDD, - 0xEF, 0x8E, 0x9E, 0x3C, 0x91, 0x50, 0x38, 0x61, 0x40, 0x25, - 0x4D, 0xCD, 0xA0, 0xAF, 0xFE, 0x57, 0xB8, 0x96, 0xDD, 0x2B, - 0x52, 0x29, 0x91, 0x7A, 0x31, 0xE8, 0x9A, 0xBB, 0xC9, 0x70, - 0x2B, 0xE1, 0x40, 0x3A, 0x9F, 0xB7, 0x31, 0xBE, 0xE5, 0x46, - 0xDA, 0x8A, 0xDE, 0x13, 0x22, 0x87, 0x70, 0xFE, 0x96, 0x40, - 0x9F, 0xC1, 0x2B, 0xFE, 0x83, 0x31, 0xE9, 0xA5, 0x4C, 0x37, - 0xEB, 0xFD, 0xFB, 0x2C, 0xBD, 0x0C, 0x1F, 0xB2, 0x62, 0x32, - 0x0E, 0x76, 0x9A, 0x2C, 0xC2, 0x84, 0x34, 0xA0, 0x6D, 0x72, - 0x21, 0x47, 0xF9, 0x3E, 0xC6, 0x5C, 0xEE, 0xB6, 0xE1, 0xD9, - 0x2E, 0xDF, 0x50, 0xD6, 0x2C, 0x9B, 0x44, 0xBE, 0xF0, 0x01, - 0x8E, 0xB4, 0x34, 0x38, 0x9C, 0x6C, 0x3E, 0x26, 0xB2, 0x4C, - 0x8E, 0xF0, 0x41, 0x2F, 0x07, 0x0E, 0xE9, 0x69, 0x1C, 0x0A, - 0x00, 0x05, 0xB0, 0x09, 0xA7, 0x07, 0x18, 0x41, 0xD1, 0xF7, - 0x22, 0xE4, 0x85, 0x64, 0xB7, 0x83, 0xF7, 0xB1, 0xE2, 0xAC, - 0x2E, 0xD9, 0x83, 0x81, 0x18, 0xCB, 0xBD, 0xEE, 0xD9, 0x09, - 0x99, 0xBA, 0x95, 0x66, 0x1F, 0xBA, 0x02, 0x26, 0xC0, 0x00, - 0x02, 0x67, 0x72, 0x24, 0xB5, 0xFE, 0x8C, 0x50, 0x84, 0x47, - 0x41, 0x6A, 0x29, 0x1F, 0x17, 0xB2, 0x9E, 0x02, 0x67, 0x70, - 0x55, 0x03, 0x3F, 0x8F, 0x07, 0x20, 0x91, 0x6B, 0x22, 0x7F, - 0x06, 0xC3, 0xC9, 0x0A, 0xB5, 0x07, 0x0D, 0x91, 0x5F, 0x87, - 0x6D, 0xE2, 0xEE, 0x2B, 0x01, 0xE7, 0x45, 0x3F, 0x89, 0x1C, - 0x8B, 0x12, 0x33, 0x23, 0x61, 0x64, 0x3F, 0x4B, 0xF1, 0x27, - 0x0E, 0x8B, 0x7B, 0x7E, 0x64, 0x2E, 0xDE, 0xE0, 0x3F, 0x3E, - 0x5C, 0xAE, 0x8C, 0x73, 0xB2, 0x8B, 0x62, 0x0F, 0xF9, 0xEB, - 0xF0, 0x74, 0xBD, 0xB9, 0xCC, 0x43, 0x80, 0xC3, 0x05, 0x31, - 0x53, 0x6F, 0x72, 0x42, 0x8E, 0x14, 0xAD, 0xF0, 0x45, 0x36, - 0x88, 0xE4, 0xF9, 0x0F, 0xD9, 0xCA, 0x1E, 0x82, 0xC2, 0x89, - 0x44, 0xC3, 0x69, 0xC6, 0xDD, 0x27, 0xB5, 0xCA, 0xCF, 0x56, - 0x23, 0x5D, 0x50, 0xF9, 0x69, 0x87, 0xCF, 0x4D, 0x2F, 0xA8, - 0xEE, 0xD4, 0x55, 0x2A, 0xC7, 0x3A, 0x2D, 0x03, 0xCD, 0x38, - 0xDE, 0x4F, 0x29, 0x91, 0x14, 0xAD, 0x39, 0x05, 0x77, 0x5F, - 0x41, 0x48, 0x30, 0x63, 0xE6, 0x81, 0x40, 0x68, 0x75, 0x8D, - 0xC5, 0x70, 0x2D, 0xC9, 0xB9, 0x10, 0x75, 0xF3, 0x28, 0x91, - 0x99, 0x97, 0x16, 0x2E, 0x7C, 0xAD, 0x50, 0x80, 0x40, 0x00, - 0xEE, 0x8F, 0x59, 0xA1, 0x8F, 0x82, 0xDE, 0x1E, 0xDB, 0x56, - 0xA1, 0xD6, 0x2E, 0x06, 0x9D, 0x42, 0xCF, 0xA0, 0xB7, 0x1F, - 0x37, 0x22, 0x02, 0x2E, 0x33, 0xAE, 0xE4, 0x7B, 0x7C, 0xC6, - 0x11, 0x5E, 0xF6, 0xA5, 0x5B, 0x54, 0x8B, 0x28, 0x54, 0x01, - 0x4C, 0x41, 0x49, 0x8E, 0xAD, 0x22, 0xBB, 0x67, 0x7A, 0xF3, - 0xEC, 0xE3, 0x93, 0xE4, 0x3A, 0x71, 0xB2, 0x82, 0xC4, 0x8A, - 0x7B, 0x99, 0xA7, 0x6B, 0x69, 0x28, 0xE3, 0xC5, 0x89, 0xF7, - 0x3E, 0xF3, 0xC5, 0xB2, 0x40, 0x91, 0xF8, 0x6A, 0xE3, 0x63, - 0xB1, 0x5C, 0xE3, 0x79, 0xFF, 0x41, 0xE8, 0x2F, 0xCA, 0x11, - 0xA2, 0xED, 0x86, 0x59, 0x53, 0x9D, 0xF9, 0xE1, 0x15, 0x5D, - 0x38, 0x32, 0x69, 0x60, 0x45, 0x20, 0x74, 0xF5, 0xF6, 0x24, - 0xA2, 0x4E, 0xAE, 0xB5, 0x2F, 0xE2, 0xEE, 0xBD, 0xD3, 0x27, - 0xE1, 0x90, 0x89, 0x89, 0xA3, 0x7E, 0x2B, 0x73, 0x63, 0xB8, - 0x36, 0xFA, 0x17, 0x0C, 0x8F, 0x0F, 0xE8, 0xBE, 0xDC, 0x8D, - 0x52, 0x34, 0xB3, 0x52, 0x0E, 0xB1, 0x97, 0x8D, 0x69, 0xC8, - 0x27, 0x2E, 0xBC, 0xFC, 0xDB, 0x6C, 0x98, 0xE8, 0x50, 0xF1, - 0x7A, 0x14, 0xE7, 0xA4, 0x11, 0xD2, 0xDA, 0x71, 0xCB, 0x77, - 0x88, 0x7B, 0xEE, 0x24, 0x52, 0xF4, 0x83, 0x2F, 0x1B, 0x25, - 0x73, 0x7D, 0x57, 0xAE, 0x78, 0x42, 0xC7, 0x7F, 0x84, 0xDB, - 0x67, 0x7A, 0x81, 0xAB, 0xB5, 0xC4, 0x41, 0x38, 0xA0, 0x8D, - 0x8C, 0x50, 0x1F, 0x56, 0xF6, 0x9A, 0x2B, 0x57, 0x89, 0x20, - 0xA9, 0xE9, 0x1E, 0x55, 0x22, 0xD7, 0x88, 0xFA, 0x5D, 0x5F, - 0x51, 0x5C, 0x7C, 0x17, 0x6E, 0x1D, 0x1A, 0xE3, 0xE6, 0x24, - 0x67, 0xFE, 0xAA, 0xEF, 0x28, 0x25, 0xCA, 0xD7, 0x9B, 0x44, - 0x3A, 0x55, 0x6B, 0x2E, 0xDE, 0x7D, 0xD0, 0x1E, 0x16, 0xD6, - 0xA5, 0xA6, 0x97, 0xE0, 0x35, 0x90, 0x13, 0xD4, 0x16, 0x53, - 0xA2, 0x66, 0xCB, 0x12, 0xEE, 0xED, 0xA1, 0x42, 0x2C, 0x6A, - 0xF5, 0x13, 0x63, 0x5B, 0x2A, 0x0C, 0x8C, 0x3A, 0xC4, 0xAA, - 0x77, 0xFD, 0x03, 0x29, 0x47, 0x2E, 0x4E, 0xCE, 0x26, 0x2E, - 0xE2, 0x87, 0xD5, 0x49, 0xBE, 0xCE, 0x07, 0x71, 0x8F, 0xBB, - 0xDF, 0x5E, 0x73, 0x17, 0x28, 0x1B, 0x34, 0x55, 0xA2, 0xB1, - 0x99, 0x72, 0x90, 0xFD, 0xDF, 0xB3, 0xC7, 0x63, 0xFE, 0x1B, - 0x75, 0x6B, 0x6D, 0x73, 0xDE, 0x21, 0xD0, 0x18, 0xBE, 0x87, - 0xE8, 0xDA, 0x74, 0x1E, 0x78, 0x65, 0x6D, 0x30, 0x3B, 0xF1, - 0xEF, 0xE3, 0x32, 0xD6, 0xF8, 0x77, 0x31, 0xAB, 0x72, 0x72, - 0xF1, 0x43, 0x5C, 0x9F, 0xF1, 0x99, 0xA9, 0xB7, 0xD6, 0xEA, - 0x12, 0x4C, 0x96, 0x7E, 0x87, 0x76, 0xD2, 0xAB, 0x02, 0x26, - 0xC0, 0x00, 0x02, 0x91, 0x0F, 0xB9, 0x72, 0xF7, 0x06, 0x0A, - 0x2A, 0x92, 0x77, 0x84, 0x0C, 0xBE, 0x44, 0x6D, 0x58, 0x6C, - 0xBC, 0xE0, 0x19, 0x8A, 0xFC, 0x4C, 0x93, 0xDD, 0xB7, 0xC5, - 0x45, 0xBF, 0x0A, 0x66, 0x29, 0xEF, 0x95, 0x78, 0x07, 0x6D, - 0xD0, 0xAA, 0x6C, 0x32, 0xE9, 0xF8, 0xEA, 0x1A, 0x74, 0x79, - 0x51, 0x39, 0x25, 0xCB, 0x00, 0x7C, 0xD0, 0xE7, 0xBB, 0xC4, - 0x09, 0xC2, 0xFC, 0x0F, 0xA2, 0x29, 0x45, 0x30, 0x3F, 0x89, - 0x76, 0x36, 0xF2, 0x92, 0xAF, 0xAF, 0x60, 0xC3, 0x93, 0x3E, - 0x55, 0x6B, 0x87, 0xAE, 0xBF, 0x6E, 0x2C, 0x54, 0xFD, 0xAF, - 0x74, 0x4F, 0x0F, 0xAA, 0xC7, 0x4F, 0x4C, 0x6B, 0x18, 0xFE, - 0xC6, 0x84, 0x27, 0xC0, 0x78, 0xD2, 0xD9, 0xE3, 0x7B, 0x41, - 0x1C, 0x1C, 0xBF, 0xDA, 0xDF, 0xCC, 0x49, 0x41, 0xC0, 0xC0, - 0x65, 0xE0, 0x8F, 0x44, 0x19, 0xE4, 0x78, 0xAD, 0xCD, 0xC5, - 0x5A, 0x9D, 0x11, 0x22, 0x43, 0xD7, 0x6E, 0x39, 0xD5, 0x2B, - 0xA7, 0x73, 0x3F, 0x99, 0xA8, 0xA3, 0x02, 0x73, 0x99, 0xF0, - 0x62, 0x87, 0xF4, 0x8B, 0xD7, 0x4F, 0x47, 0x9C, 0x18, 0x72, - 0x98, 0xB0, 0x33, 0x1B, 0x5E, 0x29, 0x04, 0xEA, 0x71, 0x6B, - 0x45, 0xCB, 0xC0, 0x9E, 0x15, 0x6E, 0x92, 0xDA, 0x50, 0xC3, - 0x58, 0x07, 0x29, 0x5E, 0xC5, 0xBD, 0x3B, 0xCE, 0xAC, 0x11, - 0xE5, 0xBB, 0x3D, 0x7E, 0xB8, 0xC3, 0x1F, 0x94, 0x9F, 0xD9, - 0x63, 0x35, 0x56, 0x23, 0x45, 0xAF, 0x23, 0xF0, 0x0B, 0x7B, - 0xE3, 0xFB, 0x81, 0x2E, 0xD3, 0x20, 0xE3, 0x1D, 0x97, 0x84, - 0xC1, 0x88, 0x77, 0x87, 0x3C, 0xAB, 0xE9, 0x1E, 0x69, 0x04, - 0x7D, 0x7B, 0xE6, 0x6B, 0xDB, 0xE9, 0xF2, 0xB6, 0x66, 0x10, - 0x0F, 0x4D, 0x57, 0x3F, 0xF5, 0x3E, 0xDA, 0xEA, 0xBC, 0xD4, - 0x5B, 0xA1, 0x20, 0xB0, 0x69, 0xC0, 0x8A, 0xA1, 0x28, 0xC0, - 0xEF, 0xFE, 0x2D, 0x0B, 0xF8, 0x06, 0x23, 0x4B, 0x1C, 0x77, - 0x0A, 0x10, 0xBF, 0xA7, 0xD9, 0x24, 0x9E, 0xA2, 0x1B, 0x90, - 0x6C, 0xFD, 0x85, 0x3A, 0xD3, 0xC6, 0x39, 0xA7, 0xA2, 0x28, - 0xC5, 0xC1, 0x2F, 0xD2, 0x28, 0xDC, 0x4F, 0x63, 0x0D, 0x6B, - 0x54, 0xB4, 0x27, 0x95, 0xC3, 0xC1, 0xE0, 0x08, 0xB0, 0x9D, - 0x7F, 0x6C, 0xFE, 0xF5, 0x65, 0xCE, 0x0E, 0xCE, 0x24, 0xCD, - 0xAE, 0x4C, 0x0F, 0x82, 0x54, 0x48, 0xAF, 0x37, 0xAE, 0x64, - 0x31, 0x07, 0xEE, 0xE6, 0x6B, 0xEF, 0xAF, 0x7F, 0x2A, 0x07, - 0x2E, 0xB6, 0xD0, 0xAC, 0x70, 0x87, 0x19, 0x9E, 0xD3, 0xFB, - 0x89, 0xBD, 0xBA, 0xFF, 0xB9, 0x92, 0x4B, 0x25, 0x65, 0xA3, - 0x09, 0xCD, 0xFE, 0x32, 0x19, 0xF3, 0xF4, 0x05, 0xA4, 0x13, - 0xDF, 0x65, 0xA3, 0x4C, 0xE8, 0xF3, 0x3C, 0xA3, 0x11, 0x95, - 0xEA, 0xC3, 0x34, 0xCA, 0xC6, 0xB9, 0x34, 0x6B, 0x53, 0x18, - 0xCC, 0xF9, 0x44, 0x28, 0x1E, 0x90, 0x74, 0xA6, 0xB1, 0x59, - 0x4D, 0xAE, 0x18, 0x53, 0x1D, 0x60, 0xCF, 0xCC, 0x15, 0xDA, - 0x4E, 0x2B, 0x6F, 0x8F, 0x4E, 0x39, 0x89, 0xE3, 0x67, 0x05, - 0xB5, 0x9C, 0x36, 0x5B, 0x3C, 0xA0, 0x9F, 0x46, 0x24, 0xE7, - 0x61, 0x42, 0x1C, 0xA7, 0xD7, 0x27, 0x5B, 0x5C, 0xF5, 0xFD, - 0x5F, 0x03, 0x79, 0x5F, 0x36, 0xA0, 0x85, 0x13, 0x40, 0x48, - 0x8C, 0x44, 0xB4, 0x64, 0x54, 0x83, 0xD8, 0xB6, 0x83, 0xB8, - 0x4E, 0x46, 0xCF, 0x98, 0xA5, 0x1C, 0xAA, 0xF0, 0x03, 0xD6, - 0x26, 0x80, 0x0F, 0x2A, 0xC5, 0xF4, 0xD1, 0x28, 0x0C, 0x5F, - 0xF8, 0x63, 0x8D, 0x68, 0x26, 0x3A, 0xE5, 0x5D, 0xAE, 0x17, - 0x64, 0xF2, 0x60, 0x73, 0x6D, 0xBD, 0x75, 0x90, 0xD2, 0x50, - 0xC4, 0x9A, 0x4C, 0x3E, 0x4B, 0xAE, 0x57, 0xBE, 0xCD, 0x42, - 0xC1, 0xA7, 0xCB, 0xAD, 0x73, 0x15, 0xF6, 0x69, 0x36, 0xB5, - 0xC3, 0x15, 0x1D, 0xC0, 0x09, 0x4B, 0x6B, 0x4F, 0xA3, 0xD2, - 0xAF, 0x9E, 0xF4, 0x9A, 0xC1, 0x5F, 0xF5, 0x0A, 0x95, 0x93, - 0xA4, 0x57, 0xA9, 0x61, 0x8D, 0x98, 0xB1, 0x19, 0xCC, 0x95, - 0x02, 0x26, 0xC0, 0x00, 0x02, 0x6E, 0x4C, 0x0F, 0xB4, 0x2D, - 0xBC, 0x3A, 0x51, 0xAE, 0x16, 0xBA, 0xEC, 0x72, 0x04, 0x3E, - 0x8D, 0x3D, 0x4E, 0x0E, 0x29, 0x4B, 0x6F, 0x00, 0xF5, 0xE2, - 0x12, 0x0B, 0xAC, 0x73, 0x7E, 0xA5, 0x12, 0x8D, 0x59, 0x45, - 0x73, 0xC8, 0xB9, 0x57, 0xCB, 0x78, 0xAD, 0xA3, 0xBD, 0x95, - 0x18, 0x04, 0x86, 0xB9, 0xFE, 0x9F, 0xBF, 0x67, 0x03, 0x08, - 0xA9, 0x91, 0xF3, 0x71, 0x1A, 0x6C, 0xD2, 0x74, 0xAA, 0x40, - 0xCC, 0x30, 0x7D, 0x0B, 0x78, 0xEF, 0xC7, 0xDC, 0x95, 0xC3, - 0x29, 0x5D, 0x18, 0xBC, 0x38, 0x7C, 0xFE, 0x65, 0xEF, 0x44, - 0xF0, 0x61, 0x91, 0x3E, 0x59, 0x75, 0x96, 0x84, 0x75, 0xD9, - 0xA2, 0x99, 0xDB, 0xFA, 0x9B, 0x7D, 0x09, 0x06, 0x8D, 0xDA, - 0xCC, 0xA1, 0x6E, 0x2E, 0xDB, 0x12, 0x83, 0xA6, 0x2E, 0x9C, - 0xC8, 0x5A, 0xE9, 0xBB, 0xC3, 0x70, 0x16, 0x0C, 0x6E, 0x2A, - 0xDA, 0xD0, 0xDF, 0xF4, 0xAF, 0xAA, 0x42, 0x0A, 0x16, 0x8C, - 0x73, 0xAA, 0xAD, 0x75, 0x7B, 0xCC, 0x29, 0xB5, 0x18, 0xB9, - 0x58, 0xBF, 0xDB, 0x91, 0x44, 0x74, 0x25, 0x3E, 0x54, 0xC3, - 0x2D, 0x8A, 0x2E, 0x85, 0xD0, 0x92, 0x02, 0xAE, 0xA1, 0xF9, - 0x70, 0xC5, 0x33, 0x49, 0x57, 0xE1, 0x90, 0x48, 0x54, 0x73, - 0x04, 0xAD, 0x1E, 0x41, 0xE8, 0xD7, 0x24, 0xFE, 0x85, 0x83, - 0x47, 0x0F, 0x9C, 0x33, 0xF9, 0xF5, 0x10, 0xAD, 0x42, 0xFA, - 0x7B, 0xE7, 0x1C, 0x35, 0xB3, 0x8D, 0x0E, 0x2E, 0xD7, 0xCB, - 0x40, 0x32, 0x9C, 0x64, 0x3A, 0x68, 0x33, 0xF3, 0xBE, 0xD9, - 0xCD, 0xC9, 0x73, 0xEB, 0x67, 0x6E, 0x52, 0x25, 0x2F, 0xD9, - 0x7A, 0x93, 0x8B, 0x1D, 0x9D, 0xB2, 0xAF, 0xF3, 0xEE, 0x6F, - 0xB5, 0xC7, 0x8F, 0xD5, 0x4F, 0xC9, 0x7C, 0xAC, 0x05, 0x9A, - 0x16, 0x82, 0x04, 0xC4, 0xF5, 0x47, 0xD7, 0x61, 0xC7, 0xBC, - 0x8D, 0x76, 0xA9, 0xFA, 0xA6, 0x17, 0x32, 0x3A, 0x2C, 0x93, - 0x4D, 0x0B, 0x57, 0x50, 0xF5, 0xD8, 0xE6, 0xB2, 0x52, 0x4F, - 0xE5, 0x1F, 0xDB, 0xA0, 0x17, 0xEF, 0x44, 0x9A, 0x8D, 0xBF, - 0x8D, 0xB4, 0x66, 0x11, 0xF2, 0xB1, 0x51, 0x50, 0xB4, 0xDE, - 0xE0, 0x30, 0x5B, 0x1F, 0x92, 0xAC, 0x30, 0x43, 0xB3, 0x1F, - 0x32, 0xDC, 0x84, 0x2F, 0x29, 0xE9, 0x78, 0xBC, 0x5A, 0xA2, - 0x9A, 0xA8, 0xFC, 0xE2, 0xB4, 0xE7, 0x8C, 0xCC, 0x65, 0xA9, - 0x37, 0x85, 0xD8, 0x0B, 0xB3, 0xA3, 0x4F, 0x28, 0xBE, 0x4D, - 0x45, 0x97, 0xAA, 0x2E, 0xEC, 0x6D, 0x4C, 0x9E, 0x19, 0x5F, - 0xD1, 0x47, 0x87, 0x8A, 0x76, 0xCF, 0x20, 0xCC, 0xDC, 0xC5, - 0x37, 0xDD, 0x45, 0xE8, 0x13, 0xFD, 0x72, 0x92, 0x7E, 0x97, - 0xA4, 0xA7, 0x58, 0xC1, 0x0E, 0xB6, 0x9E, 0x20, 0xCC, 0xD3, - 0x5F, 0x94, 0x25, 0xD3, 0xB8, 0xB0, 0x51, 0x82, 0x45, 0x64, - 0x4B, 0x6D, 0xCB, 0x9F, 0xC6, 0x5F, 0xDD, 0x1D, 0x1B, 0xB0, - 0x7D, 0xEB, 0xEC, 0x85, 0xB0, 0x90, 0x36, 0xE0, 0xE5, 0x5F, - 0x66, 0xA3, 0x69, 0x72, 0x2C, 0x35, 0x52, 0x45, 0x8A, 0xD9, - 0x31, 0xCB, 0xD9, 0xDD, 0xF0, 0x62, 0x6A, 0x4B, 0x47, 0xEF, - 0x13, 0xD7, 0x65, 0x17, 0xC4, 0xE9, 0xD1, 0xA3, 0xF4, 0x5E, - 0x17, 0x73, 0x4C, 0xA5, 0x81, 0xD7, 0xBD, 0xB3, 0x34, 0x98, - 0x61, 0x01, 0x50, 0x1D, 0x7D, 0x7A, 0x82, 0x38, 0x93, 0x9F, - 0x0A, 0xAC, 0x42, 0x5B, 0x10, 0x4C, 0x57, 0x10, 0x4A, 0x97, - 0xD3, 0xCC, 0x8F, 0x23, 0xD1, 0xA6, 0xCB, 0xAD, 0x47, 0x8F, - 0x41, 0x24, 0x2B, 0xEB, 0xB9, 0x0B, 0x71, 0x1C, 0x27, 0x31, - 0x91, 0x21, 0x77, 0xA2, 0x01, 0x2D, 0x6F, 0x9B, 0x99, 0x5F, - 0xAC, 0xD4, 0x8E, 0x1D, 0xBB, 0x2C, 0xA3, 0xA1, 0xA2, 0xC3, - 0x2A, 0xAD, 0x6B, 0xA4, 0x62, 0xAA, 0xAE, 0xEA, 0xEE, 0x10, - 0x30, 0xB3, 0x9E, 0x2A, 0x13, 0x09, 0xF8, 0xC4, 0x2B, 0x8C, - 0xE1, 0x51, 0x62, 0xE7, 0x5D, 0xE8, 0x00, 0x50, 0x46, 0x7E, - 0xC7, 0x9A, 0x3F, 0x21, 0xD9, 0x0C, 0xB3, 0xA7, 0x2E, 0x5F, - 0x4B, 0x42, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x12, 0xA7, 0x07, - 0x49, 0x33, 0x98, 0x05, 0x3D, 0xD0, 0x14, 0xD2, 0x03, 0xA9, - 0xA5, 0x66, 0x6B, 0x53, 0x43, 0x97, 0x83, 0x21, 0x8F, 0x46, - 0x67, 0x3C, 0x86, 0xDB, 0x7B, 0xBA, 0xD2, 0xC5, 0xB4, 0x09, - 0x0F, 0x2D, 0xD3, 0x4E, 0xD2, 0xB7, 0xFC, 0x75, 0x52, 0x16, - 0x8A, 0x56, 0x5A, 0xCC, 0xE6, 0xFE, 0x5C, 0xE8, 0xAE, 0x48, - 0x7F, 0x81, 0xF2, 0x46, 0x00, 0xE5, 0x53, 0xAF, 0xC7, 0x01, - 0x12, 0x9A, 0xF9, 0xDC, 0x96, 0x79, 0xC6, 0x61, 0xC6, 0xAC, - 0xCE, 0x0B, 0x6C, 0x9F, 0xFD, 0x16, 0xCA, 0xD1, 0xD6, 0xAB, - 0xE4, 0xCB, 0x64, 0x88, 0xF7, 0x17, 0x7F, 0xCD, 0xBB, 0x8F, - 0xF9, 0x5C, 0x75, 0x7C, 0x3D, 0xBE, 0x03, 0x68, 0x30, 0xA8, - 0xC7, 0x82, 0x62, 0xDD, 0x5A, 0x42, 0x3D, 0x8D, 0x02, 0xD1, - 0x68, 0xF2, 0x04, 0x0B, 0xFA, 0xC2, 0x23, 0xB9, 0x26, 0xAA, - 0x5F, 0x43, 0x7D, 0xE5, 0xD2, 0x97, 0xB8, 0xD5, 0x6F, 0xBE, - 0x56, 0xC6, 0xCA, 0xE7, 0x56, 0xDA, 0x14, 0x4A, 0xA6, 0x35, - 0x3F, 0xBF, 0xBC, 0x9D, 0xCD, 0x51, 0x55, 0x98, 0xAB, 0xC0, - 0x42, 0xC8, 0x7D, 0x67, 0xB3, 0xDD, 0x2B, 0x6B, 0xA0, 0x06, - 0x9F, 0x13, 0x79, 0xBC, 0xE2, 0xC8, 0x9E, 0xC3, 0xFF, 0x94, - 0x9E, 0x3D, 0x60, 0xAE, 0xB3, 0x28, 0x44, 0xC5, 0xE1, 0xD8, - 0x40, 0x7F, 0xC0, 0x8F, 0x93, 0xFC, 0xDA, 0xEC, 0x70, 0x14, - 0xB1, 0x07, 0xA1, 0x21, 0x6D, 0xA2, 0xA3, 0xEF, 0x80, 0xF1, - 0xC4, 0xCC, 0xA1, 0x77, 0xD9, 0xA3, 0xD9, 0x31, 0xFB, 0xC5, - 0xE5, 0xDE, 0xC1, 0xF2, 0x6F, 0xFC, 0x73, 0x35, 0xC4, 0x1D, - 0x2C, 0x15, 0x57, 0x64, 0x57, 0x4A, 0x0D, 0x4F, 0xCB, 0xD3, - 0x3E, 0x12, 0x82, 0x5C, 0xFC, 0xED, 0x7B, 0xA1, 0x3F, 0x72, - 0x1E, 0x6B, 0x12, 0x6A, 0xB9, 0x55, 0xD2, 0xC3, 0x04, 0x52, - 0x01, 0xBB, 0x54, 0x20, 0x0A, 0xA5, 0xDA, 0xDD, 0x2D, 0x56, - 0xF4, 0xD0, 0x08, 0x62, 0x1E, 0x68, 0x30, 0x40, 0x57, 0x8A, - 0xC2, 0xDD, 0xBF, 0x0D, 0x7B, 0x28, 0xE0, 0x82, 0x1A, 0x3F, - 0xDC, 0xEA, 0x07, 0xC4, 0x32, 0x74, 0x14, 0x18, 0x9C, 0x00, - 0x9C, 0x91, 0xC0, 0x7A, 0x0A, 0x18, 0x89, 0xAD, 0xA8, 0x3D, - 0x42, 0x21, 0x0F, 0x08, 0x8D, 0xA4, 0xD5, 0xA7, 0x08, 0x09, - 0x3C, 0x21, 0x7E, 0x4E, 0x17, 0xB9, 0x1A, 0x80, 0x22, 0x45, - 0x33, 0x43, 0x24, 0xDD, 0xC4, 0x66, 0xD2, 0xB4, 0x4E, 0x40, - 0xD5, 0x5F, 0xEA, 0x86, 0x9F, 0x8B, 0x41, 0x9D, 0xD0, 0x96, - 0xC9, 0x64, 0x32, 0x39, 0xA1, 0x89, 0x56, 0x7E, 0x1D, 0x22, - 0x08, 0x08, 0xB5, 0x60, 0x1F, 0x52, 0x41, 0xA4, 0x8F, 0xC0, - 0x52, 0x6B, 0xA7, 0xBB, 0x52, 0x0E, 0x96, 0xEE, 0x62, 0x62, - 0x1A, 0xCF, 0x4C, 0x65, 0x59, 0x32, 0x2D, 0x3C, 0x1D, 0x40, - 0x57, 0xB0, 0xE9, 0xF2, 0xBA, 0x04, 0xD2, 0xBE, 0x22, 0xA9, - 0x93, 0x8E, 0xC2, 0x32, 0x06, 0x20, 0xDC, 0x9F, 0xE5, 0xC2, - 0x57, 0xFC, 0xC5, 0xDE, 0xE7, 0xD3, 0xCA, 0xB6, 0xD8, 0x85, - 0xB2, 0xE1, 0xAD, 0x23, 0x47, 0x02, 0x3F, 0xD7, 0xBD, 0x51, - 0x2A, 0x6B, 0x33, 0x2D, 0x23, 0x6D, 0xD5, 0x72, 0x1F, 0xEC, - 0x8F, 0x7F, 0x1B, 0x22, 0x2D, 0x9E, 0x44, 0x58, 0xE0, 0xA3, - 0x50, 0x54, 0xCF, 0x6B, 0x5E, 0x59, 0x7A, 0xF0, 0xDA, 0x2E, - 0x9C, 0xC4, 0xD3, 0xD9, 0x83, 0x56, 0xBB, 0x09, 0x58, 0xFF, - 0x00, 0xDD, 0xDA, 0x57, 0x5C, 0xC3, 0xED, 0x10, 0x6E, 0xD6, - 0xD0, 0xF0, 0xB9, 0xD1, 0x2C, 0x1E, 0x4E, 0x33, 0xA7, 0x44, - 0x9C, 0x87, 0xB2, 0x91, 0x16, 0x2C, 0x44, 0x1E, 0x66, 0x79, - 0x06, 0x12, 0x26, 0xB6, 0x36, 0x1F, 0xBA, 0x56, 0x9F, 0xAB, - 0x64, 0x63, 0xE4, 0x90, 0x75, 0x72, 0xF9, 0x35, 0x77, 0x2B, - 0x38, 0xE5, 0x4F, 0x29, 0xF1, 0x4C, 0xD8, 0xBD, 0x20, 0x60, - 0x65, 0x26, 0x57, 0xCE, 0x52, 0x4B, 0x18, 0xD4, 0xDF, 0xCE, - 0xC0, 0x78, 0x60, 0x83, 0xD4, 0xDF, 0xE9, 0xA2, 0x61, 0x37, - 0x78, 0x7D, 0xEB, 0xE5, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x47, - 0xA5, 0x8E, 0xA4, 0x38, 0x2C, 0xDC, 0x61, 0xFB, 0xD1, 0x29, - 0xFD, 0x30, 0xA5, 0xEE, 0xB0, 0x2F, 0xF6, 0x53, 0x4B, 0x4E, - 0xE9, 0x26, 0x67, 0x28, 0xC0, 0x06, 0x59, 0x13, 0x88, 0xF8, - 0x9B, 0xE8, 0x6B, 0x9E, 0x5A, 0xCF, 0x8D, 0x8D, 0xE1, 0x80, - 0x1A, 0xE1, 0x4A, 0x59, 0x92, 0x6A, 0x57, 0x38, 0x79, 0x1E, - 0x5D, 0xA4, 0x35, 0xA5, 0xD3, 0x80, 0x41, 0x97, 0x69, 0xB7, - 0xDF, 0xE8, 0x07, 0xFA, 0xA6, 0x64, 0xFD, 0xB2, 0xD0, 0x66, - 0xB4, 0x35, 0x52, 0xCC, 0xC9, 0x82, 0xCF, 0xFA, 0xB3, 0xE0, - 0xE6, 0x96, 0x35, 0xEF, 0xD5, 0xF6, 0xA1, 0x0B, 0xAD, 0xE0, - 0x50, 0x7D, 0x9B, 0x36, 0x8D, 0xD2, 0x6E, 0x27, 0x14, 0x2D, - 0x6D, 0xCE, 0xC2, 0xF8, 0xDA, 0x64, 0xDC, 0xFD, 0xC8, 0x79, - 0x72, 0x00, 0xE3, 0xF9, 0x3F, 0x40, 0x0D, 0x0F, 0x40, 0x3A, - 0xE3, 0xFE, 0xEA, 0x93, 0x18, 0x7F, 0x2D, 0xFA, 0x7C, 0x6B, - 0xCB, 0x45, 0x8C, 0xD5, 0x8E, 0xE3, 0x95, 0x4C, 0xF9, 0x60, - 0x83, 0x8E, 0x07, 0xC0, 0x17, 0xE9, 0x6C, 0xAF, 0x2C, 0x08, - 0x04, 0xF5, 0x8B, 0xB7, 0xB8, 0x09, 0xAD, 0x91, 0x02, 0x9A, - 0x28, 0x25, 0xE7, 0x80, 0x5C, 0xCB, 0x69, 0xA0, 0xDA, 0x43, - 0x4F, 0x4C, 0x4A, 0xA1, 0xCB, 0x45, 0x0E, 0x2F, 0x87, 0x77, - 0x43, 0x7E, 0x0E, 0x42, 0xE7, 0x21, 0x2B, 0x73, 0x90, 0x21, - 0x7B, 0x9B, 0x87, 0xEC, 0x27, 0x76, 0xFF, 0x9F, 0xEB, 0x79, - 0xF9, 0x70, 0xE6, 0x73, 0x51, 0x4B, 0x8D, 0xE4, 0xB6, 0x76, - 0xFF, 0x23, 0x71, 0xD9, 0x87, 0x43, 0x29, 0xE4, 0xA0, 0xDE, - 0xB7, 0xCF, 0x92, 0x03, 0x84, 0x07, 0x17, 0xA1, 0xE6, 0x7B, - 0x43, 0x14, 0xA3, 0x30, 0xC0, 0x1B, 0x44, 0x91, 0xCF, 0x80, - 0x48, 0x92, 0x2B, 0x6D, 0x59, 0x8E, 0x63, 0x8C, 0xE8, 0xC3, - 0xA9, 0x04, 0x33, 0x3F, 0x75, 0x6A, 0x2B, 0x7B, 0xEC, 0x74, - 0x26, 0xAD, 0x34, 0x68, 0xB9, 0x9F, 0x63, 0xEE, 0xEA, 0x42, - 0x0D, 0xC7, 0x24, 0x7B, 0xD4, 0x5E, 0x5A, 0x91, 0xF1, 0x41, - 0x2E, 0x6B, 0x0D, 0xB9, 0x75, 0xCE, 0x51, 0x1E, 0x6E, 0xF2, - 0x6B, 0x9C, 0xD4, 0xBD, 0xAF, 0x54, 0x63, 0x1A, 0xA0, 0x29, - 0x65, 0x22, 0x04, 0x9D, 0xE2, 0x6F, 0x37, 0x4B, 0xC2, 0xC2, - 0x62, 0x1B, 0x94, 0xE0, 0xF9, 0xC8, 0xB0, 0x94, 0x43, 0x29, - 0x0D, 0x4F, 0x23, 0x4A, 0xBA, 0x83, 0x15, 0x97, 0x96, 0xC8, - 0x0A, 0x85, 0xD2, 0x80, 0x8B, 0x0C, 0x16, 0x57, 0x32, 0xCA, - 0xA4, 0xF6, 0x20, 0xB5, 0x49, 0x30, 0xCC, 0xD3, 0x1C, 0xAB, - 0xE0, 0xAE, 0x52, 0x7B, 0x71, 0x40, 0x80, 0xAC, 0x30, 0x78, - 0xEE, 0x5A, 0xD3, 0x82, 0x3F, 0x51, 0x34, 0xE8, 0x38, 0xD4, - 0x8D, 0x09, 0xEB, 0xDC, 0x9E, 0x82, 0xF7, 0xE2, 0xAA, 0xCD, - 0x2D, 0x17, 0x0C, 0x08, 0x22, 0xAF, 0xED, 0xE4, 0xC0, 0xC1, - 0xBB, 0x9C, 0x47, 0xC1, 0x23, 0x81, 0x03, 0x85, 0xDD, 0x00, - 0x5C, 0x4D, 0x7F, 0xF1, 0x02, 0xF8, 0xA9, 0xA1, 0x8E, 0xB1, - 0xCD, 0xFC, 0x6F, 0xC5, 0x0D, 0x37, 0xD9, 0x83, 0x15, 0x23, - 0x14, 0x03, 0x54, 0x37, 0xFC, 0xAC, 0xB6, 0xC8, 0x0A, 0x47, - 0x3F, 0x22, 0x6F, 0xD7, 0xFA, 0xBB, 0x8D, 0x17, 0xB2, 0x7C, - 0x0F, 0x65, 0xB4, 0xA2, 0x3A, 0x5F, 0x55, 0x34, 0xEC, 0xCA, - 0x89, 0xDD, 0xD4, 0x44, 0x77, 0x30, 0x9A, 0x20, 0x6A, 0x1A, - 0x9D, 0xBE, 0x39, 0x25, 0x2E, 0xE2, 0x0C, 0xDD, 0xE0, 0x50, - 0x8F, 0xD7, 0x38, 0x01, 0xB1, 0x25, 0xC1, 0xFD, 0x06, 0xD0, - 0x60, 0xC9, 0xEB, 0x1D, 0x77, 0x6D, 0xA2, 0x18, 0xB2, 0x0B, - 0x03, 0xE6, 0xF7, 0x07, 0x51, 0xFC, 0xAF, 0xE9, 0xD4, 0xFC, - 0x80, 0x69, 0x1C, 0xE1, 0x82, 0x96, 0x39, 0x37, 0xC1, 0xD3, - 0xB1, 0x81, 0x62, 0xB7, 0x20, 0x7F, 0xDF, 0xB7, 0x84, 0xD2, - 0xCC, 0xFB, 0x7E, 0x90, 0xBB, 0x05, 0x1B, 0x81, 0xA2, 0xE0, - 0x66, 0x11, 0x8A, 0x37, 0x93, 0x0F, 0x67, 0x81, 0x77, 0x03, - 0xA6, 0xE2, 0x52, 0xB6, 0x0F, 0x9A, 0x02, 0x26, 0xC0, 0x00, - 0x02, 0x1D, 0x9D, 0x63, 0xD2, 0x5B, 0xB0, 0x79, 0x8A, 0xF4, - 0x7F, 0x08, 0x9B, 0x5E, 0xAB, 0x6E, 0xD1, 0xCC, 0x2B, 0x7C, - 0xFF, 0x0D, 0x0E, 0xDD, 0x5F, 0xAA, 0x4C, 0x53, 0x45, 0x53, - 0x48, 0xCD, 0xCD, 0xF7, 0xBA, 0x5B, 0xB9, 0x84, 0xBB, 0x00, - 0xC2, 0xF0, 0xFB, 0x30, 0x5F, 0x04, 0x4E, 0x25, 0x4C, 0x06, - 0x03, 0x8D, 0xC5, 0x37, 0xA6, 0x9D, 0x1C, 0xD8, 0x13, 0xA7, - 0x96, 0xBE, 0xED, 0x22, 0xD7, 0xBA, 0x9F, 0x4C, 0x2E, 0xF9, - 0xD0, 0x5B, 0xBB, 0xF8, 0xB8, 0x0A, 0xF3, 0xEC, 0x31, 0x3F, - 0x84, 0x6E, 0x3A, 0x12, 0x8B, 0x6A, 0x2E, 0x28, 0xCE, 0xB8, - 0x1A, 0xC6, 0xE6, 0x4A, 0xD9, 0x74, 0x04, 0x24, 0xD8, 0x79, - 0x8D, 0x62, 0x0C, 0xB0, 0xAE, 0xAF, 0x67, 0xB4, 0xA1, 0x3D, - 0x93, 0x1D, 0xA2, 0x52, 0x98, 0x3F, 0x57, 0x73, 0x94, 0xB6, - 0x94, 0xBD, 0x0F, 0x42, 0x6A, 0x64, 0x7B, 0x17, 0xAC, 0x8D, - 0x46, 0xD0, 0xE4, 0x1B, 0x8C, 0x56, 0xB6, 0x47, 0xCB, 0xFD, - 0x56, 0x61, 0x6E, 0xA0, 0xBF, 0x6B, 0x8E, 0x68, 0x05, 0x55, - 0xA4, 0xB3, 0x8C, 0x76, 0x48, 0x73, 0x4C, 0x8D, 0x9D, 0xA2, - 0xA0, 0xA1, 0xFB, 0xD0, 0x33, 0x32, 0x39, 0xD2, 0x10, 0x1C, - 0x3C, 0x93, 0xC9, 0xCA, 0x6A, 0x6E, 0x7C, 0xB6, 0xF1, 0x03, - 0xF3, 0x45, 0x51, 0x05, 0x48, 0x30, 0xF0, 0xC6, 0x84, 0xFD, - 0x4E, 0x3B, 0x03, 0xE0, 0x62, 0xB8, 0x53, 0x55, 0xB6, 0xB8, - 0x02, 0x7C, 0xB9, 0xD5, 0x5C, 0xA2, 0x9B, 0x97, 0x8A, 0xA4, - 0xDF, 0x42, 0xEB, 0x91, 0x2C, 0x98, 0x82, 0xA9, 0xAE, 0xB0, - 0x13, 0xF6, 0x6E, 0x90, 0x42, 0xFE, 0xD3, 0xAA, 0x1E, 0xBA, - 0x69, 0xFC, 0xF8, 0x20, 0xEA, 0x5D, 0xA8, 0xFE, 0x64, 0x56, - 0x26, 0x4C, 0x6C, 0x69, 0x8F, 0xAC, 0x30, 0xCF, 0xAE, 0x8B, - 0xD5, 0x63, 0x10, 0xDD, 0xCE, 0x6E, 0x0C, 0xAB, 0x31, 0x46, - 0xDF, 0x8A, 0x33, 0x28, 0x8A, 0x1C, 0xEB, 0xBE, 0xAA, 0x71, - 0x44, 0x5C, 0x89, 0xEA, 0x00, 0x34, 0x23, 0xEB, 0x18, 0x83, - 0x7F, 0xB1, 0x9B, 0x3A, 0xBF, 0x08, 0x68, 0xB6, 0xC8, 0xE2, - 0xD8, 0x2D, 0x5E, 0xA2, 0x99, 0xB9, 0xBC, 0xF8, 0x31, 0xD1, - 0xFD, 0x31, 0xD4, 0x32, 0x05, 0x58, 0x5C, 0xFB, 0xCD, 0x8C, - 0xFF, 0x75, 0x99, 0x93, 0xC8, 0x0C, 0xE8, 0xE8, 0x60, 0x11, - 0xB8, 0x5F, 0x15, 0xB5, 0x89, 0x47, 0xE1, 0x1C, 0x23, 0x1B, - 0x8E, 0x56, 0x02, 0xD3, 0x5F, 0xBD, 0xA9, 0x9F, 0x67, 0x06, - 0xCA, 0x0C, 0x6E, 0x9C, 0xFB, 0x2D, 0x3A, 0xE3, 0xF6, 0x2C, - 0x72, 0x86, 0xCD, 0x68, 0xAC, 0x7B, 0x22, 0xA3, 0x01, 0x15, - 0x50, 0xB7, 0xA0, 0x05, 0x88, 0xD0, 0xDF, 0xBD, 0xDA, 0x3B, - 0xC4, 0xFF, 0x40, 0xA1, 0x46, 0x55, 0x28, 0xB3, 0x0C, 0x1E, - 0xF8, 0xE9, 0x0A, 0x39, 0xD1, 0x66, 0xDF, 0x5B, 0x2B, 0x2C, - 0xCA, 0xA5, 0x36, 0x32, 0x0D, 0xAC, 0x8E, 0xDF, 0x75, 0x9A, - 0xE5, 0x8B, 0xE5, 0x99, 0x6B, 0xD6, 0xB7, 0x83, 0x6B, 0xFE, - 0xEA, 0xC9, 0x71, 0xB5, 0xB9, 0xAE, 0xBE, 0x74, 0xB6, 0x58, - 0x28, 0x06, 0x23, 0xCF, 0x8D, 0x09, 0xBC, 0xE3, 0x18, 0x6C, - 0xFA, 0x53, 0x02, 0xE8, 0x3D, 0x44, 0xB3, 0xFE, 0xB3, 0x11, - 0x70, 0x10, 0xDF, 0xC3, 0x93, 0x64, 0x0F, 0x19, 0x35, 0xF0, - 0x82, 0x3A, 0xE3, 0x04, 0xE3, 0x1D, 0xFE, 0x52, 0xE8, 0x52, - 0xA1, 0x7B, 0x19, 0x23, 0x8E, 0x3F, 0x5D, 0x16, 0x60, 0xCB, - 0x13, 0x1A, 0x26, 0x6D, 0xDB, 0x82, 0xEB, 0x72, 0xEE, 0x76, - 0x77, 0x36, 0xEC, 0xEE, 0x09, 0x90, 0xAF, 0x35, 0x25, 0x5A, - 0x29, 0x61, 0x7A, 0xE6, 0x8C, 0x6C, 0x2A, 0x3B, 0x3B, 0xC4, - 0xC5, 0xD4, 0xCF, 0x41, 0x40, 0x04, 0xF3, 0x0F, 0x4B, 0x1B, - 0x99, 0x7D, 0xCF, 0x1F, 0xC5, 0xEB, 0xC5, 0xF5, 0xA1, 0x16, - 0xA2, 0x2A, 0x2E, 0xD5, 0x78, 0xC5, 0xAD, 0x9C, 0x48, 0x76, - 0xF2, 0x58, 0xDE, 0x68, 0x19, 0x58, 0x8C, 0xEA, 0xF5, 0xD0, - 0x54, 0x4F, 0x73, 0x60, 0x92, 0x71, 0x27, 0xF7, 0x02, 0x26, - 0xC0, 0x00, 0x02, 0x24, 0xC2, 0xE1, 0xD7, 0x77, 0x1A, 0x4D, - 0x5F, 0x7B, 0xC6, 0xC7, 0x52, 0x42, 0x9C, 0x26, 0xBE, 0x75, - 0x2E, 0x37, 0x00, 0xD8, 0x2C, 0xEF, 0x37, 0xC2, 0xF8, 0x88, - 0x89, 0xBA, 0x60, 0x35, 0xCE, 0xD5, 0xC4, 0x3D, 0x00, 0x6A, - 0xF1, 0xE1, 0x66, 0x4C, 0xFF, 0x79, 0xC7, 0xDF, 0x04, 0x99, - 0x02, 0xEB, 0x0E, 0x9D, 0xBE, 0x2C, 0x06, 0xB8, 0xE1, 0xC8, - 0xAE, 0xC4, 0xE8, 0xB7, 0xE7, 0x66, 0xEF, 0x01, 0x72, 0x45, - 0xB2, 0xBF, 0x69, 0xF7, 0xA2, 0x72, 0xEC, 0x91, 0x82, 0x9D, - 0xE5, 0x91, 0x9A, 0x6D, 0x4D, 0x0D, 0x29, 0x58, 0xE3, 0xA2, - 0xBB, 0x4F, 0x7B, 0xED, 0xA6, 0xEC, 0x0D, 0x91, 0xF6, 0xE7, - 0x68, 0x61, 0xDF, 0x8A, 0x1A, 0x5A, 0x2A, 0x21, 0x51, 0x80, - 0x31, 0xD5, 0xD6, 0xFB, 0xE5, 0x0D, 0x01, 0x49, 0x22, 0x05, - 0xEE, 0xA2, 0x7A, 0xF6, 0x6C, 0xCD, 0x9D, 0x95, 0x79, 0x7E, - 0x9D, 0x22, 0x91, 0x59, 0x31, 0x80, 0x55, 0xC9, 0x66, 0xC8, - 0x33, 0x36, 0x56, 0x65, 0xCC, 0x26, 0x88, 0xE7, 0xC0, 0x01, - 0xF4, 0x22, 0xF9, 0xE6, 0xF1, 0x18, 0x69, 0xAB, 0x93, 0x80, - 0x95, 0xBF, 0xA4, 0xB7, 0x7F, 0x56, 0x7D, 0xC0, 0xEE, 0xA7, - 0x01, 0x5B, 0x9B, 0xA6, 0x80, 0x5A, 0x17, 0x31, 0xC8, 0x93, - 0xF6, 0x6F, 0xFD, 0x27, 0x9A, 0x09, 0xB8, 0x48, 0x04, 0xD5, - 0x1F, 0xBB, 0x8B, 0xED, 0xB7, 0x08, 0x43, 0xBF, 0x82, 0xB1, - 0xAF, 0xD9, 0x35, 0x03, 0xE8, 0x36, 0xB4, 0xCD, 0x74, 0x74, - 0x30, 0x85, 0x73, 0x1F, 0x51, 0xED, 0xA5, 0xFD, 0x64, 0xFC, - 0xF1, 0x22, 0x21, 0x36, 0x3C, 0x5E, 0x46, 0x74, 0x9D, 0x94, - 0x2C, 0x0F, 0xDF, 0x2B, 0x6E, 0x5E, 0xA8, 0x7C, 0x80, 0xA4, - 0x4C, 0xE4, 0x1A, 0xE2, 0x80, 0x29, 0x5F, 0x85, 0x76, 0x95, - 0xD0, 0x2D, 0x26, 0x50, 0xB2, 0x14, 0x37, 0xA3, 0x3A, 0x4E, - 0xB9, 0x68, 0xCB, 0x1D, 0x9A, 0x9B, 0x33, 0xD0, 0x3D, 0x1B, - 0x0F, 0x3F, 0xA2, 0x95, 0xE0, 0x80, 0xA1, 0x39, 0x03, 0x14, - 0x5F, 0x21, 0x27, 0x54, 0xB5, 0x4D, 0x1F, 0x7A, 0x9A, 0x1E, - 0xB1, 0xC9, 0x63, 0xBE, 0xEC, 0x0C, 0xC1, 0x16, 0x80, 0x0F, - 0xFD, 0x3B, 0x3F, 0xFD, 0x97, 0xF8, 0x4F, 0xD9, 0xFE, 0xC7, - 0x6A, 0xE5, 0x40, 0x5B, 0xB8, 0x50, 0xA8, 0x94, 0x6F, 0x9F, - 0xD8, 0x23, 0xE8, 0xBC, 0x16, 0x9B, 0xF8, 0xC5, 0x0C, 0x48, - 0x28, 0x1B, 0x51, 0x8B, 0x1C, 0x9F, 0x37, 0x97, 0x6B, 0x0B, - 0x1C, 0x2B, 0xCF, 0x7F, 0x9E, 0xC4, 0x54, 0x8F, 0x4D, 0xBF, - 0x43, 0xBB, 0x40, 0x20, 0x79, 0x1F, 0x29, 0xF2, 0x43, 0x65, - 0x0D, 0xC8, 0x16, 0xAC, 0xE4, 0xF3, 0x82, 0x67, 0x01, 0xD9, - 0x19, 0x80, 0xAD, 0x16, 0x1F, 0xF6, 0xFA, 0xD3, 0xD8, 0x74, - 0x6F, 0xE5, 0x00, 0x8E, 0x77, 0x95, 0x51, 0x83, 0xD4, 0xF2, - 0x8B, 0x79, 0x2D, 0xBA, 0xB1, 0x10, 0x0C, 0x0F, 0xCC, 0x7D, - 0x24, 0x7A, 0xF5, 0xDF, 0x54, 0x54, 0xC0, 0xAF, 0x80, 0x3D, - 0x7E, 0x9C, 0x8F, 0x27, 0xA7, 0x0A, 0xE4, 0x8C, 0xB7, 0x5C, - 0x61, 0xF4, 0xAD, 0xB3, 0xD8, 0xA9, 0x1B, 0xEC, 0x13, 0xCB, - 0xD8, 0xD3, 0x81, 0xBA, 0x9D, 0xCA, 0xD9, 0xAE, 0xC4, 0x43, - 0x69, 0xF4, 0xDE, 0xF9, 0xE0, 0xFE, 0x5D, 0x53, 0x6D, 0xDA, - 0x5F, 0xED, 0x5F, 0x30, 0x81, 0x2C, 0xDE, 0x92, 0x04, 0xDE, - 0x94, 0xBB, 0x45, 0xAF, 0x14, 0x84, 0xC9, 0xE3, 0xBD, 0xBD, - 0x7F, 0x52, 0xE9, 0x6B, 0x34, 0xCA, 0x06, 0x3A, 0xE1, 0x79, - 0x22, 0x3C, 0xA8, 0x34, 0xED, 0x7E, 0x26, 0x18, 0x84, 0xDB, - 0x92, 0x48, 0xFD, 0xD6, 0x82, 0x04, 0x1D, 0x82, 0x1A, 0xA6, - 0x28, 0x74, 0x31, 0xA5, 0x74, 0x1F, 0xD9, 0x0F, 0xF2, 0xC8, - 0x4C, 0x38, 0x8F, 0xAF, 0x2A, 0xE0, 0x5F, 0xD6, 0xA4, 0x1C, - 0xE3, 0xF8, 0x70, 0xD5, 0x4C, 0xF8, 0x3C, 0x92, 0x0A, 0x01, - 0xEF, 0xB7, 0xEA, 0x57, 0xA5, 0x88, 0x4C, 0x10, 0x68, 0x99, - 0xC8, 0x4F, 0x1D, 0x67, 0x8E, 0x43, 0x7D, 0x3D, 0x5E, 0x20, - 0x02, 0x26, 0xC0, 0x00, 0x02, 0x68, 0x4F, 0x5F, 0x8D, 0xC4, - 0x7F, 0x74, 0xCD, 0xFE, 0xFB, 0x21, 0x22, 0x03, 0x06, 0xFA, - 0x2E, 0x4C, 0xFF, 0x35, 0xBB, 0x9E, 0x93, 0x44, 0x35, 0x8A, - 0xFF, 0x97, 0x39, 0x36, 0x8D, 0x53, 0x4D, 0xFA, 0x04, 0xA8, - 0x98, 0x13, 0x9C, 0xAA, 0x87, 0x0D, 0x8B, 0x50, 0x0D, 0x9C, - 0xB1, 0xAC, 0x4C, 0x59, 0x9B, 0xA2, 0xE4, 0x4C, 0xFC, 0x46, - 0xC5, 0xA6, 0x00, 0x4A, 0xA8, 0xD3, 0x24, 0x40, 0x9E, 0x48, - 0x8F, 0xC0, 0x8C, 0x0E, 0x16, 0x02, 0x3C, 0xF5, 0x12, 0x3D, - 0x97, 0xCE, 0xDE, 0x11, 0xBE, 0x46, 0xE8, 0x8F, 0x15, 0x3B, - 0xB3, 0x1D, 0x74, 0xCB, 0xEE, 0x77, 0x2D, 0xEB, 0xAD, 0x87, - 0x39, 0x85, 0xD7, 0xBC, 0x38, 0x87, 0x2A, 0x0B, 0xB5, 0xB0, - 0xD1, 0x09, 0x7D, 0x12, 0xC6, 0x4D, 0x9A, 0xF8, 0x00, 0xC5, - 0xA2, 0xF9, 0x9A, 0xFF, 0x30, 0x5D, 0x6E, 0x79, 0xD7, 0xBA, - 0xB3, 0xCC, 0x2A, 0x43, 0x61, 0xAC, 0x38, 0x99, 0x10, 0xDF, - 0x60, 0x94, 0x7B, 0x49, 0xD9, 0xC2, 0x4C, 0x6D, 0x3F, 0xD7, - 0x38, 0x85, 0xE7, 0x91, 0x26, 0x9E, 0x7F, 0x7E, 0xA4, 0x91, - 0x9B, 0x92, 0x02, 0xC1, 0x1F, 0xAF, 0x5C, 0x6B, 0xBA, 0x27, - 0xAD, 0x33, 0xCC, 0xE6, 0x20, 0x23, 0x61, 0xBE, 0x4A, 0xDA, - 0x28, 0x63, 0xB2, 0xE2, 0xAC, 0xA9, 0x51, 0x50, 0x9A, 0xAB, - 0xCA, 0x8C, 0x5C, 0xF3, 0x0A, 0x44, 0x03, 0xA9, 0x94, 0x92, - 0x1D, 0xC5, 0xB2, 0x09, 0xF3, 0x0E, 0xB3, 0x6A, 0x1D, 0x72, - 0xDC, 0x71, 0x4A, 0xAE, 0x4E, 0x0B, 0x1B, 0xCF, 0xF3, 0xCF, - 0x4B, 0x38, 0xD1, 0xCA, 0x27, 0xC2, 0x6A, 0x41, 0x0F, 0x3A, - 0x1D, 0xCD, 0x3E, 0xB1, 0x1A, 0xF7, 0x16, 0x48, 0x4A, 0xAA, - 0xA7, 0x28, 0x16, 0x07, 0x9B, 0xE0, 0x41, 0x99, 0xF1, 0x47, - 0x8C, 0x48, 0x6C, 0x2D, 0x93, 0x9E, 0x47, 0x2B, 0x9A, 0x96, - 0x20, 0x44, 0xF4, 0x2A, 0xCB, 0xB0, 0xDA, 0xBD, 0x17, 0x38, - 0xCB, 0x45, 0x9F, 0x21, 0xA8, 0x93, 0x26, 0x67, 0x51, 0x36, - 0x6F, 0x05, 0x4A, 0x08, 0x72, 0xFB, 0xA3, 0x98, 0xBF, 0x9E, - 0x39, 0xEC, 0xAF, 0xDA, 0x8A, 0xFD, 0xC1, 0xB2, 0xC4, 0x4D, - 0xFE, 0xCD, 0xBD, 0x7F, 0xF8, 0xCE, 0x4F, 0x7E, 0x4E, 0xBA, - 0xD1, 0x87, 0x3E, 0x5F, 0x77, 0xA2, 0x96, 0x3E, 0x8B, 0x15, - 0xDE, 0xE7, 0xBF, 0x7F, 0x97, 0x0F, 0xE1, 0xE7, 0x2F, 0x58, - 0x5D, 0xEF, 0x56, 0x39, 0x66, 0x63, 0x61, 0x94, 0x3D, 0x31, - 0xC8, 0x8D, 0xA8, 0xAC, 0xB5, 0x4C, 0x20, 0x1A, 0xD4, 0x18, - 0x34, 0x61, 0xA2, 0x4F, 0x65, 0xB3, 0x12, 0xFE, 0xA9, 0x02, - 0xCC, 0x47, 0x8F, 0x1C, 0x39, 0xFD, 0xDB, 0x08, 0x62, 0xFD, - 0x74, 0x8D, 0xF9, 0xAA, 0x34, 0xCA, 0x20, 0x67, 0xE8, 0xBC, - 0xAB, 0xED, 0x8C, 0x09, 0xC1, 0xA1, 0xE2, 0x3A, 0x41, 0xB7, - 0x1D, 0x82, 0x99, 0xAA, 0x79, 0x93, 0xB5, 0x1D, 0x6A, 0xE8, - 0xFC, 0x31, 0xBF, 0x67, 0xD8, 0xE9, 0x36, 0xD4, 0xBF, 0x9E, - 0xBF, 0xAB, 0x13, 0x20, 0xE3, 0x01, 0x29, 0x60, 0x28, 0x19, - 0xD2, 0x0E, 0xBC, 0x21, 0x3E, 0xD6, 0xC0, 0xC3, 0xDD, 0x64, - 0xFC, 0x98, 0x45, 0x26, 0x9B, 0x5C, 0xCB, 0xE2, 0x76, 0x0A, - 0x0D, 0x13, 0x1A, 0x7F, 0xEF, 0xE2, 0x44, 0xA3, 0xD8, 0xCE, - 0xD6, 0x0E, 0x5A, 0xA8, 0x40, 0x7B, 0x9E, 0xA0, 0xBE, 0xD6, - 0x63, 0x56, 0x77, 0x57, 0x69, 0x2C, 0xF8, 0xB6, 0x8D, 0x08, - 0xF3, 0x80, 0xA1, 0x2F, 0x53, 0xE2, 0x2F, 0xFD, 0xE6, 0x86, - 0x91, 0x83, 0x12, 0x7E, 0x73, 0xCF, 0xC8, 0x12, 0x58, 0xCD, - 0x9B, 0x30, 0x2C, 0x1E, 0xB8, 0x1E, 0xA3, 0x66, 0x27, 0xE9, - 0x33, 0xB2, 0x57, 0x9B, 0xF7, 0xFC, 0x04, 0xE1, 0xDF, 0xA4, - 0xC5, 0x7A, 0x39, 0xCE, 0xDF, 0xEB, 0x03, 0x89, 0x37, 0xFB, - 0xB0, 0x17, 0x12, 0x55, 0x52, 0x60, 0x25, 0xD1, 0xA6, 0x54, - 0xED, 0xD2, 0xBA, 0xE9, 0x66, 0x5A, 0xCA, 0xE3, 0x71, 0xF8, - 0xE7, 0x35, 0x1C, 0xAC, 0x00, 0x2C, 0xBD, 0x52, 0x6F, 0xE0, - 0x96, 0x91, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x02, 0xB1, 0x96, - 0x3E, 0x04, 0x9B, 0x7A, 0x13, 0x3F, 0xA3, 0x05, 0x16, 0xBF, - 0x79, 0xE5, 0x67, 0x77, 0x23, 0x1E, 0x4D, 0x4C, 0x26, 0x7C, - 0x9D, 0x3E, 0xF5, 0x37, 0x49, 0xAC, 0x5C, 0xA7, 0x9F, 0xD7, - 0x8B, 0x61, 0x4B, 0x21, 0xEC, 0x27, 0x9A, 0x62, 0x75, 0xD1, - 0xCB, 0xEB, 0x58, 0x98, 0x84, 0xD1, 0xD9, 0xD8, 0x00, 0x0E, - 0x38, 0xCB, 0x40, 0xE9, 0xC0, 0x87, 0x62, 0x6D, 0xD6, 0xBE, - 0x5E, 0x47, 0x40, 0xCE, 0x39, 0xD2, 0x28, 0xFF, 0x32, 0x08, - 0xFB, 0xF1, 0x86, 0xEF, 0xF1, 0x1F, 0xC7, 0x28, 0xE0, 0x2A, - 0x9B, 0xAA, 0xA7, 0xEC, 0xBA, 0x63, 0x27, 0x98, 0xCC, 0x4C, - 0x35, 0x48, 0xE2, 0x83, 0xE2, 0xE4, 0x7E, 0xCF, 0xF2, 0x38, - 0xED, 0x1C, 0xE7, 0x17, 0xCB, 0xAC, 0xCC, 0xDA, 0xF5, 0x3B, - 0xD3, 0xC5, 0xFE, 0xB5, 0x04, 0x3A, 0xFC, 0xF7, 0x66, 0x66, - 0x89, 0xB5, 0xAD, 0x1C, 0x18, 0xFE, 0x63, 0xF6, 0x9E, 0x8D, - 0x73, 0xDC, 0x9D, 0x54, 0xDD, 0x02, 0x3B, 0x1D, 0x3F, 0x3D, - 0xD1, 0x4C, 0xCB, 0x3C, 0x09, 0x8E, 0x5A, 0x06, 0x5C, 0x03, - 0x59, 0xF4, 0x7B, 0xF6, 0x39, 0x02, 0x2B, 0xDC, 0x76, 0x82, - 0x2A, 0x33, 0x34, 0x34, 0x57, 0x9F, 0xC8, 0xF0, 0xF0, 0x14, - 0x29, 0x0C, 0x6E, 0x92, 0x36, 0x56, 0x3B, 0xA6, 0x68, 0xF0, - 0x3B, 0x3C, 0xA7, 0x8F, 0x60, 0x85, 0x5D, 0xAD, 0x14, 0xBF, - 0xA7, 0x8B, 0x8E, 0xED, 0x20, 0x0A, 0x64, 0xB2, 0x05, 0xF9, - 0x59, 0x45, 0xC0, 0x97, 0x2D, 0x0D, 0x3A, 0x77, 0xC0, 0xBD, - 0xA2, 0x9F, 0xD4, 0x21, 0xA5, 0x23, 0x7D, 0x1A, 0xE2, 0x4D, - 0x72, 0x44, 0xF6, 0x3E, 0x2A, 0x12, 0xF6, 0xB3, 0xDD, 0x15, - 0x63, 0xCC, 0x7A, 0x5E, 0x60, 0xC2, 0xB0, 0xEE, 0x2C, 0x35, - 0x08, 0x35, 0xE8, 0xA8, 0x08, 0x86, 0xA6, 0xC9, 0xA2, 0x84, - 0xBF, 0x90, 0x14, 0x92, 0x95, 0x6A, 0x08, 0x39, 0x30, 0xB2, - 0x94, 0x3E, 0x0D, 0xE9, 0x3B, 0x28, 0xC7, 0x89, 0x6F, 0xFE, - 0xB9, 0x83, 0x00, 0xE9, 0x9A, 0xA5, 0x47, 0x82, 0xEB, 0xAE, - 0xA8, 0x2F, 0xD4, 0x89, 0xDB, 0x00, 0xC0, 0xA3, 0xE8, 0x79, - 0xC8, 0x5D, 0x90, 0xA5, 0x5F, 0xB6, 0x11, 0x42, 0x99, 0x1E, - 0x7C, 0x9C, 0xB5, 0xA6, 0x90, 0x85, 0xE8, 0xED, 0x14, 0x55, - 0x99, 0x13, 0x10, 0xFD, 0x94, 0xF6, 0x48, 0x86, 0x26, 0x5A, - 0x36, 0x15, 0x53, 0xE5, 0x02, 0xD4, 0x46, 0xA4, 0x3B, 0x97, - 0xB0, 0x65, 0x25, 0xD2, 0x52, 0x08, 0x7D, 0x12, 0x28, 0xC3, - 0x0A, 0x26, 0xF1, 0xCD, 0x10, 0x90, 0xB0, 0x61, 0x6C, 0x31, - 0xEE, 0xC4, 0x79, 0x86, 0x36, 0x94, 0x38, 0x26, 0xD8, 0xA0, - 0x44, 0x90, 0x38, 0x08, 0xCA, 0xCA, 0x8A, 0xEF, 0x6D, 0xFD, - 0xBF, 0xAC, 0xE2, 0x87, 0xC4, 0xD3, 0xB6, 0x68, 0xA5, 0x02, - 0x05, 0xB4, 0xC1, 0xA3, 0x38, 0x60, 0x1B, 0x7F, 0xA5, 0xF2, - 0xA8, 0x17, 0xB0, 0x17, 0x88, 0x0F, 0xE8, 0xE1, 0x25, 0x9C, - 0x4E, 0x82, 0x37, 0x0C, 0xC3, 0xFF, 0x6D, 0x99, 0x9F, 0xB3, - 0x8B, 0x92, 0x2B, 0x96, 0x6B, 0xD3, 0xDF, 0x3F, 0x45, 0xD8, - 0xA2, 0x46, 0xAA, 0x06, 0x7D, 0xA7, 0x57, 0xEC, 0x87, 0x99, - 0xFA, 0x2F, 0x93, 0x6D, 0x65, 0x77, 0xD3, 0x72, 0x2B, 0x3D, - 0xFC, 0x9D, 0x0D, 0x2C, 0x88, 0x75, 0x37, 0x4B, 0x18, 0xA9, - 0x2D, 0xA9, 0xD6, 0xE3, 0x75, 0xFA, 0x29, 0xCE, 0x91, 0x51, - 0x74, 0xF9, 0x71, 0xFB, 0x0B, 0x1F, 0x24, 0x3D, 0xA8, 0xF3, - 0x56, 0x67, 0x7A, 0x13, 0xAA, 0xFF, 0x1C, 0x6D, 0xDD, 0x0F, - 0x14, 0xBC, 0x34, 0x35, 0xE0, 0xAF, 0x7A, 0x55, 0x8C, 0x9A, - 0xE0, 0xA6, 0x35, 0x1F, 0xAB, 0xC3, 0xF7, 0x14, 0x7E, 0xFF, - 0x13, 0x64, 0xAF, 0x1C, 0x11, 0x68, 0x25, 0x4D, 0x07, 0x05, - 0x3F, 0x76, 0x61, 0x29, 0x32, 0xB5, 0xEF, 0xF7, 0x7E, 0xE8, - 0x5C, 0xE2, 0xAA, 0x17, 0x3F, 0x5C, 0x48, 0xFA, 0x05, 0xB0, - 0xDF, 0x1F, 0x2B, 0x9B, 0x25, 0xAA, 0xA8, 0x1F, 0x80, 0xF5, - 0xE5, 0x9C, 0xC2, 0xF5, 0x02, 0x06, 0xC0, 0x00, 0x02, 0x96, - 0xA3, 0xD9, 0x49, 0x25, 0x73, 0x8B, 0x32, 0xB3, 0xD6, 0x68, - 0x6E, 0x3F, 0xDE, 0x58, 0xCB, 0xA8, 0x00, 0x34, 0xB2, 0x7D, - 0x5A, 0x88, 0x7F, 0x1B, 0x3A, 0xA7, 0xD2, 0x56, 0x5B, 0x20, - 0x6F, 0x6B, 0x43, 0x58, 0xC9, 0x48, 0x1F, 0x76, 0xE3, 0xA5, - 0x79, 0x0D, 0xD3, 0xC7, 0xBB, 0x76, 0xE8, 0xC2, 0xD5, 0x77, - 0x2B, 0x39, 0x93, 0x7F, 0x9B, 0x33, 0xB3, 0x0C, 0x12, 0x50, - 0x8A, 0x95, 0xB3, 0x27, 0xCB, 0x49, 0xDB, 0x3C, 0x6A, 0xB9, - 0x06, 0xD8, 0x31, 0x8E, 0x14, 0x6A, 0x3F, 0x5B, 0x03, 0x98, - 0xD8, 0x5C, 0xCA, 0x46, 0x14, 0xDA, 0xAB, 0x51, 0xDF, 0x72, - 0x3A, 0xAD, 0x8E, 0xDA, 0x9A, 0x44, 0x0E, 0x4C, 0xB0, 0x92, - 0xF6, 0x6A, 0x0E, 0xC8, 0x37, 0x0F, 0x93, 0x73, 0xB0, 0xB5, - 0x11, 0x12, 0x3F, 0xCF, 0x29, 0x50, 0x6B, 0xD9, 0x22, 0x2C, - 0x76, 0x71, 0x07, 0xBC, 0x00, 0x10, 0xB8, 0x54, 0x6A, 0x9A, - 0x59, 0x82, 0x4E, 0xE9, 0x02, 0x8B, 0x9C, 0xC9, 0x4B, 0xD3, - 0x7F, 0xAD, 0xA5, 0xF9, 0x7C, 0xB4, 0x00, 0xB4, 0x5A, 0xAF, - 0x23, 0x12, 0xF2, 0x5B, 0xB9, 0x2C, 0xFD, 0x73, 0xB9, 0xFC, - 0x4B, 0x4F, 0xAF, 0xD2, 0x80, 0xC2, 0xF7, 0x15, 0xEC, 0xE1, - 0x4B, 0xEF, 0xA3, 0x99, 0x59, 0x0C, 0xD5, 0x2F, 0x98, 0xF5, - 0x38, 0xD2, 0xFC, 0xF3, 0x82, 0xA7, 0xE0, 0x15, 0x35, 0x27, - 0xCD, 0xCF, 0xCE, 0xA4, 0x65, 0x92, 0x1E, 0x6C, 0x25, 0x8F, - 0xB7, 0x78, 0x15, 0x5B, 0x7A, 0x9D, 0xB0, 0xEC, 0xDE, 0x0A, - 0xF5, 0x0B, 0xCD, 0xD4, 0xF6, 0xC4, 0xD5, 0xA9, 0xC1, 0x4E, - 0xE0, 0xA2, 0x8B, 0xC4, 0x43, 0x97, 0xAC, 0xC9, 0x41, 0xF2, - 0x5A, 0x36, 0xD1, 0xD6, 0x7E, 0xC2, 0xD3, 0x06, 0xCB, 0x78, - 0x47, 0x78, 0x05, 0x35, 0x61, 0xE6, 0xD4, 0xDC, 0x65, 0x75, - 0x63, 0x5B, 0x71, 0xD7, 0x3C, 0x27, 0x9B, 0x26, 0x70, 0xAB, - 0x4D, 0x97, 0xE5, 0x83, 0x7C, 0xEB, 0x5B, 0x8F, 0xD6, 0xBC, - 0x84, 0x9D, 0xF8, 0x08, 0x65, 0x10, 0x6E, 0x48, 0xBE, 0xD2, - 0x86, 0xC0, 0xEB, 0x08, 0x27, 0x38, 0xF8, 0x6E, 0x5D, 0xBA, - 0x5B, 0xC6, 0x78, 0xED, 0xB1, 0x8D, 0x57, 0xFC, 0xA4, 0xDD, - 0xF3, 0xDF, 0xB9, 0x36, 0x92, 0xB8, 0x00, 0x06, 0x5F, 0xAD, - 0x04, 0xE3, 0x8D, 0x64, 0x64, 0x7A, 0xE0, 0x57, 0x4C, 0x68, - 0x56, 0xDC, 0x1F, 0x93, 0xA5, 0xD7, 0xEE, 0xFC, 0x8A, 0xB9, - 0x26, 0x99, 0xC5, 0x1A, 0x63, 0xD6, 0x9B, 0xBC, 0xA2, 0xF3, - 0xE1, 0x84, 0xDC, 0xFB, 0x0C, 0x4F, 0xB4, 0x0D, 0x75, 0x8B, - 0xDD, 0xB6, 0x76, 0x2C, 0x33, 0x46, 0xDD, 0x94, 0xE0, 0x8C, - 0x37, 0x03, 0x14, 0x44, 0xC2, 0x0F, 0x6C, 0x03, 0xA6, 0x39, - 0x1E, 0xB5, 0x00, 0x83, 0xC6, 0x59, 0x81, 0xD6, 0x11, 0x3A, - 0x22, 0x6F, 0x74, 0x1C, 0x8B, 0x4C, 0xF3, 0x1C, 0x59, 0x2F, - 0x19, 0x18, 0xB5, 0x20, 0x24, 0x9C, 0x14, 0x45, 0x7E, 0x98, - 0xFB, 0x71, 0xC4, 0xCC, 0x19, 0x99, 0x28, 0x9E, 0x63, 0xC2, - 0xD6, 0x0D, 0x47, 0x2A, 0x3B, 0x36, 0xB7, 0x8C, 0xF1, 0x98, - 0x33, 0x96, 0x9D, 0x09, 0x99, 0x74, 0xE3, 0x41, 0xCD, 0x67, - 0xCE, 0x11, 0xBA, 0x35, 0xE3, 0x44, 0x3D, 0xE0, 0xB9, 0x53, - 0x79, 0x58, 0x0F, 0xC5, 0x98, 0xCC, 0xAB, 0xF8, 0x37, 0x5C, - 0x96, 0xCE, 0xB5, 0xDA, 0xB5, 0x05, 0x79, 0xD6, 0x96, 0x82, - 0xCA, 0x3F, 0x2C, 0x8A, 0x44, 0xCE, 0xCE, 0x99, 0xA2, 0x77, - 0x9E, 0xE0, 0xFE, 0x58, 0x97, 0x5A, 0xDA, 0x8B, 0xB8, 0x0A, - 0xA2, 0x3F, 0x26, 0x00, 0x5C, 0xAC, 0xD8, 0x33, 0x95, 0xBF, - 0x43, 0x0D, 0x09, 0xB5, 0x9A, 0x89, 0x4C, 0x46, 0x83, 0xAF, - 0xD1, 0xD3, 0x61, 0x33, 0xA1, 0x19, 0xD3, 0xD6, 0x81, 0xB0, - 0xDA, 0x55, 0x4B, 0xD3, -}; - -const uint32_t gphDnldNfc_DlSeqSz = sizeof(gphDnldNfc_DlSequence); +/******************************************************************************************** + * + * Copyright 2021 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"),to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + ********************************************************************************************/ +#include + +const uint8_t gphDnldNfc_DlSequence[] = { + 0x01, 0x34, 0xC0, 0x00, 0xDE, 0x10, 0xAD, 0x69, 0xE0, 0x28, + 0xAC, 0xFA, 0xF2, 0x4A, 0x0F, 0x49, 0x7E, 0x6A, 0x61, 0xD1, + 0x00, 0xFD, 0x4A, 0x66, 0xDD, 0x42, 0x4D, 0xFF, 0x90, 0xA5, + 0x6C, 0x54, 0xF0, 0x53, 0x5E, 0x17, 0x1E, 0x28, 0x8B, 0xF2, + 0x56, 0x6D, 0x74, 0x7B, 0x4E, 0xBA, 0xEB, 0x8D, 0x22, 0x43, + 0x01, 0xE9, 0xC4, 0x85, 0x2B, 0xFB, 0xA7, 0xD9, 0x3C, 0x64, + 0x63, 0x2D, 0xBB, 0x63, 0x5C, 0xDB, 0x14, 0x4D, 0x86, 0xA0, + 0x73, 0xC1, 0x32, 0xA4, 0x12, 0xD0, 0xED, 0x12, 0x90, 0xCF, + 0xAF, 0x56, 0x35, 0x3D, 0x97, 0x6B, 0xAC, 0x81, 0x1B, 0xD6, + 0x77, 0x9A, 0x4F, 0x9C, 0x90, 0x7D, 0x16, 0x6E, 0xC4, 0xCD, + 0x2D, 0xD2, 0x57, 0x49, 0x99, 0x24, 0xBC, 0x06, 0x71, 0x04, + 0xA8, 0x14, 0xEF, 0x21, 0x55, 0x0D, 0xAD, 0x82, 0x88, 0x5C, + 0xEF, 0xDF, 0x03, 0x93, 0xB5, 0xE8, 0x21, 0x18, 0xE0, 0x54, + 0xB8, 0xE1, 0x7E, 0x88, 0xE9, 0xF7, 0xEE, 0x86, 0xD2, 0x36, + 0xD7, 0x4B, 0x99, 0x6C, 0x35, 0x8B, 0xE0, 0xA2, 0xA2, 0xFB, + 0xED, 0xB5, 0x9A, 0xA0, 0xEE, 0x19, 0x67, 0x66, 0x14, 0x14, + 0xEC, 0xEF, 0x3F, 0xC0, 0x25, 0x7C, 0xA8, 0x9F, 0x58, 0x11, + 0xCD, 0x99, 0x00, 0xBF, 0xB8, 0x6D, 0xD5, 0x06, 0x8A, 0x5D, + 0x40, 0xB0, 0x2C, 0x9A, 0x20, 0xA2, 0x30, 0xDA, 0xFD, 0xB0, + 0xE3, 0x05, 0x5F, 0xB7, 0x3B, 0x9C, 0xD6, 0xB8, 0x92, 0xAE, + 0x4B, 0xDC, 0xF2, 0x1D, 0xA4, 0x11, 0xCE, 0x0C, 0xFD, 0x37, + 0x6E, 0xBA, 0x8B, 0x6C, 0x84, 0x3E, 0x3A, 0x3D, 0x20, 0xBE, + 0x64, 0xA6, 0x56, 0x7F, 0x06, 0x66, 0x04, 0x38, 0x1D, 0x97, + 0xD9, 0x96, 0xE6, 0x07, 0x29, 0xE2, 0x1A, 0xC4, 0x5F, 0x0A, + 0xAC, 0x62, 0x50, 0xF8, 0xD2, 0x33, 0x3F, 0x7A, 0x50, 0x89, + 0x98, 0x44, 0xCB, 0xFD, 0x75, 0x79, 0x25, 0xB1, 0x3A, 0xDE, + 0x53, 0x86, 0x13, 0x54, 0x46, 0x0B, 0x5F, 0x94, 0xEC, 0x1B, + 0x72, 0x24, 0x35, 0x84, 0x67, 0xC8, 0xBE, 0xDB, 0xAC, 0xB2, + 0x0C, 0x94, 0x88, 0xE1, 0xC4, 0x36, 0xD1, 0x6B, 0xB9, 0x4C, + 0xAE, 0xB0, 0x55, 0xF8, 0xBE, 0xD4, 0x7D, 0x16, 0x76, 0x84, + 0x2E, 0x46, 0x0B, 0xF6, 0x0D, 0x43, 0xB6, 0xBB, 0x5F, 0x98, + 0x02, 0x26, 0xC0, 0x00, 0x02, 0x35, 0x79, 0x26, 0x91, 0x8C, + 0x34, 0x8D, 0x69, 0x6E, 0x7F, 0x6B, 0xBF, 0xBD, 0x81, 0x3F, + 0x9C, 0x94, 0x0C, 0x65, 0x47, 0xC5, 0x08, 0xA7, 0x14, 0x6F, + 0x5A, 0xAC, 0x7C, 0xAC, 0x0C, 0x15, 0xD5, 0x6F, 0xBF, 0xDC, + 0xCE, 0x97, 0xD0, 0xD5, 0xEB, 0x1D, 0x3C, 0x7A, 0xEB, 0x2A, + 0x4E, 0x76, 0x08, 0xF2, 0xEA, 0x3A, 0xA0, 0xB8, 0xFC, 0xA0, + 0x74, 0x92, 0x8F, 0x86, 0xB1, 0x15, 0x0D, 0x7D, 0x92, 0x0F, + 0x64, 0xCE, 0xCA, 0xC1, 0xC4, 0x20, 0xA2, 0x48, 0x2D, 0xB0, + 0x47, 0x24, 0xF1, 0x20, 0x77, 0xDF, 0x87, 0x0D, 0xFA, 0xC6, + 0x89, 0xEE, 0xBD, 0x5E, 0xD5, 0x85, 0x64, 0xBC, 0x40, 0x6E, + 0x86, 0x01, 0x3D, 0xB6, 0x83, 0x8C, 0xAA, 0xF3, 0x2D, 0x3A, + 0xBB, 0x0D, 0xE6, 0xA5, 0xC0, 0x64, 0x07, 0xCB, 0x57, 0x81, + 0x7E, 0xD8, 0x3C, 0x3D, 0x4A, 0x9F, 0x8E, 0xF0, 0x57, 0x2E, + 0x5E, 0x41, 0x42, 0x00, 0xB0, 0xC7, 0x4E, 0x17, 0xED, 0xC6, + 0xAB, 0x73, 0x71, 0x65, 0x1D, 0x60, 0x34, 0x2A, 0x2B, 0xAF, + 0x59, 0x82, 0x5E, 0x16, 0x48, 0x48, 0x0F, 0x86, 0x62, 0x0C, + 0x84, 0x56, 0x00, 0x03, 0x2A, 0xA6, 0x2C, 0x21, 0xD0, 0x70, + 0xF9, 0xE5, 0x37, 0x0E, 0x81, 0x20, 0x36, 0x4E, 0x86, 0x8D, + 0xCF, 0xED, 0xBD, 0x0D, 0x49, 0x75, 0x0E, 0x5B, 0x80, 0xF7, + 0xAF, 0x40, 0x56, 0x8B, 0xD8, 0xFC, 0xC6, 0xE4, 0x6D, 0xD6, + 0x2E, 0x0D, 0xD0, 0x76, 0x75, 0x39, 0x3E, 0xF0, 0xEA, 0xC5, + 0x23, 0x12, 0x06, 0x45, 0xEA, 0x04, 0x6D, 0xC1, 0xA2, 0x95, + 0x95, 0x40, 0xD6, 0x6B, 0x65, 0xD6, 0x7D, 0x62, 0xA5, 0xB4, + 0x6B, 0x6C, 0x24, 0x3E, 0xFB, 0xAB, 0x71, 0x4D, 0xFC, 0x24, + 0x9F, 0x71, 0x8C, 0x04, 0x9A, 0xEE, 0x6D, 0x72, 0x3A, 0x01, + 0x11, 0xC1, 0x01, 0xB2, 0xC2, 0xC8, 0xBA, 0x7D, 0x53, 0x56, + 0x0D, 0x3F, 0x35, 0xF6, 0x86, 0x46, 0x7C, 0x67, 0xBF, 0x83, + 0x04, 0x01, 0x98, 0xBC, 0x06, 0x08, 0xF3, 0x89, 0x88, 0x8E, + 0x93, 0xB3, 0xA9, 0x21, 0x18, 0x71, 0xFF, 0xFC, 0x4E, 0xF7, + 0xFE, 0x1A, 0x5D, 0xC9, 0x21, 0xF6, 0x3B, 0x27, 0x2C, 0x26, + 0x37, 0xE2, 0x4F, 0x8C, 0x94, 0x77, 0xC7, 0x0D, 0xB9, 0x74, + 0xCD, 0x9F, 0xE1, 0x70, 0xFD, 0x35, 0x11, 0xA2, 0xB6, 0xAC, + 0x39, 0x3D, 0xC9, 0x57, 0x94, 0x3F, 0x10, 0x89, 0x9F, 0x0F, + 0x7D, 0x49, 0x0E, 0xFE, 0x84, 0x34, 0x87, 0x5B, 0xA5, 0xA0, + 0x5E, 0x0D, 0xE4, 0x05, 0x5A, 0x45, 0x8B, 0x31, 0x28, 0xF0, + 0x80, 0x7A, 0xF9, 0x56, 0xE7, 0x60, 0xB0, 0x31, 0xBB, 0x75, + 0x7E, 0x30, 0x74, 0x53, 0x14, 0xF6, 0xDE, 0x24, 0x9E, 0xE0, + 0xB9, 0x9F, 0xE6, 0xB0, 0x5D, 0x5B, 0x7A, 0xF3, 0xFD, 0x0D, + 0x4C, 0xCA, 0xAD, 0x01, 0xE4, 0x3F, 0xFE, 0x1D, 0x03, 0xE7, + 0xD4, 0xC6, 0xC1, 0xE9, 0xF5, 0x9E, 0x72, 0x9C, 0x4A, 0x09, + 0x85, 0x2C, 0xBE, 0x46, 0x49, 0xE1, 0x0F, 0xBF, 0x27, 0xF2, + 0x81, 0xC3, 0x33, 0x95, 0xEC, 0xBE, 0x37, 0x2B, 0x65, 0xA5, + 0xEC, 0xF7, 0x69, 0x23, 0x3B, 0xA6, 0xA6, 0xC3, 0xC7, 0x9F, + 0x9B, 0x79, 0xE6, 0x37, 0xB4, 0xDB, 0x33, 0x3B, 0xC5, 0x19, + 0x50, 0x7B, 0xBB, 0x7B, 0x4B, 0xFF, 0x0A, 0x3A, 0x0F, 0xDE, + 0x9D, 0x1F, 0x70, 0xE0, 0x9C, 0x37, 0x9B, 0x61, 0x01, 0xD9, + 0xCB, 0x9F, 0xC7, 0x1F, 0x9B, 0x25, 0x7D, 0x18, 0xF0, 0x6F, + 0x12, 0x54, 0xC2, 0x17, 0x8F, 0xB2, 0x1F, 0x5D, 0x0F, 0x73, + 0xB2, 0xEE, 0xE9, 0x0E, 0xC4, 0xA1, 0x70, 0x48, 0xDF, 0x0B, + 0xB4, 0xDD, 0xFF, 0xC7, 0x01, 0xA6, 0xBC, 0x08, 0xCE, 0x0E, + 0xB4, 0x4A, 0xAE, 0xFF, 0x88, 0xA6, 0x4D, 0x60, 0xC7, 0x55, + 0x38, 0x74, 0x3C, 0x1D, 0x8F, 0x82, 0xD3, 0xD3, 0x31, 0x60, + 0xE4, 0xB2, 0x24, 0x76, 0xE7, 0xD8, 0x53, 0x05, 0x20, 0x3E, + 0x5C, 0xEF, 0x17, 0x4C, 0x20, 0x6F, 0x6A, 0x6D, 0x10, 0xA3, + 0xA4, 0xE9, 0xFB, 0x76, 0x66, 0x99, 0x5D, 0xD1, 0x34, 0x52, + 0x42, 0xBF, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x9E, 0xED, 0xAE, + 0xE5, 0x23, 0x85, 0x5C, 0xFF, 0xAD, 0x6E, 0x89, 0x02, 0x33, + 0x97, 0x74, 0x05, 0x59, 0x1E, 0x73, 0x4E, 0xD3, 0x9A, 0x97, + 0xD3, 0x85, 0x2B, 0x12, 0xFB, 0xA2, 0xF0, 0xA4, 0x4C, 0x2A, + 0x58, 0xFB, 0x56, 0x6C, 0xE9, 0xA6, 0x04, 0x07, 0x9F, 0xBC, + 0x76, 0x66, 0x01, 0x80, 0xB8, 0x1E, 0x4A, 0x8A, 0x0C, 0x76, + 0x8A, 0x3C, 0x5F, 0x25, 0xAD, 0x83, 0xF3, 0x10, 0x02, 0xE1, + 0x38, 0x4B, 0xFA, 0x81, 0xD2, 0xC5, 0x6D, 0x18, 0xA7, 0xD8, + 0x0A, 0x4E, 0xC9, 0xC7, 0xA3, 0x19, 0x52, 0x0D, 0xBB, 0xA9, + 0xDE, 0x9C, 0x90, 0x57, 0x71, 0x1A, 0x37, 0xA8, 0x70, 0x4D, + 0x75, 0x7E, 0x34, 0x90, 0x74, 0x0E, 0x02, 0xC8, 0x8A, 0x80, + 0x3D, 0x06, 0x67, 0xF4, 0xF2, 0xD4, 0x15, 0x66, 0x0D, 0x23, + 0xAE, 0x46, 0x0A, 0x23, 0x7B, 0x36, 0x96, 0x48, 0x7D, 0x99, + 0xF4, 0x09, 0xE3, 0xA9, 0x53, 0xAC, 0x94, 0xB7, 0x23, 0x7E, + 0x57, 0xCF, 0x90, 0xCD, 0x13, 0x0D, 0x50, 0xBD, 0xC9, 0xE4, + 0xC2, 0x22, 0x5F, 0x28, 0x11, 0xF8, 0x1F, 0x42, 0x33, 0xEE, + 0xF3, 0xB4, 0xED, 0x8F, 0xF4, 0xA0, 0xAE, 0xF5, 0xAE, 0x56, + 0x59, 0xC3, 0x65, 0xDB, 0xF2, 0x51, 0x6D, 0x15, 0xA3, 0xAF, + 0xA5, 0xC7, 0x9F, 0x7A, 0xE8, 0xCC, 0xB4, 0xD8, 0xCA, 0x39, + 0x3F, 0x79, 0xB3, 0x86, 0xDB, 0x37, 0x52, 0xDA, 0x5E, 0xDB, + 0x7F, 0x53, 0x60, 0x43, 0x75, 0x53, 0x93, 0xD4, 0xA2, 0xE2, + 0xE7, 0xB7, 0x42, 0xF0, 0x97, 0xA5, 0xB5, 0x52, 0xD3, 0xCF, + 0xE7, 0x70, 0x6F, 0x10, 0xD4, 0x85, 0xC4, 0x4B, 0x3D, 0x09, + 0xE1, 0x02, 0xB8, 0xED, 0xA5, 0xCC, 0x7B, 0x2D, 0x68, 0xEF, + 0xEF, 0x9E, 0x87, 0x8C, 0xB7, 0xC9, 0x85, 0xA8, 0x01, 0xC2, + 0xCF, 0x43, 0xB5, 0x6D, 0x30, 0x2A, 0x9F, 0x06, 0x96, 0xE0, + 0x43, 0xEC, 0x3F, 0xC1, 0x2F, 0x7D, 0x4D, 0x85, 0x76, 0xD3, + 0xF7, 0xFA, 0xC8, 0x84, 0x20, 0xA8, 0x3C, 0xD9, 0x3E, 0x4A, + 0xB4, 0x87, 0x05, 0xCF, 0x9B, 0x51, 0x68, 0xF9, 0x49, 0xBA, + 0x4D, 0x68, 0x97, 0x6E, 0x79, 0xDB, 0x04, 0x51, 0x66, 0x6F, + 0xF9, 0x59, 0x2D, 0x55, 0x96, 0x13, 0x59, 0x52, 0x30, 0xB8, + 0x73, 0xD1, 0x12, 0x33, 0x31, 0xEC, 0x4C, 0x0C, 0x8E, 0xD4, + 0x47, 0xE7, 0x30, 0xC6, 0x98, 0xB5, 0x5B, 0x35, 0x1B, 0xAC, + 0x51, 0xBB, 0xFA, 0xC3, 0x8D, 0x3E, 0x89, 0x83, 0x1C, 0xED, + 0xB1, 0x03, 0x9C, 0xC7, 0x5C, 0x89, 0xF9, 0xC2, 0xE3, 0x45, + 0x91, 0xDB, 0x41, 0x0A, 0x22, 0xD1, 0x90, 0x39, 0xD6, 0x9D, + 0x0A, 0xD8, 0x36, 0xDC, 0xDB, 0xDD, 0x63, 0x22, 0xF8, 0x7B, + 0x4D, 0x90, 0x4C, 0x27, 0x0F, 0xCC, 0x16, 0x0E, 0x32, 0x46, + 0xD7, 0x20, 0x5A, 0x43, 0xC4, 0xC5, 0x37, 0x2E, 0xEB, 0x3F, + 0x42, 0x2C, 0xFA, 0x99, 0xE2, 0xF9, 0x70, 0xB3, 0xC3, 0xCF, + 0x4C, 0x67, 0xEB, 0x7C, 0x9D, 0xAF, 0x96, 0x15, 0x97, 0xD2, + 0x07, 0x3B, 0xF6, 0xEF, 0x2F, 0x98, 0xAA, 0x1D, 0x45, 0xDC, + 0x11, 0xBA, 0xF6, 0x0C, 0x18, 0x64, 0x80, 0xF2, 0x6B, 0xBD, + 0x3C, 0x85, 0xC1, 0xCD, 0x78, 0xD0, 0x62, 0x79, 0x0F, 0xCD, + 0xCA, 0x3D, 0x94, 0x0A, 0x11, 0xEF, 0x11, 0x86, 0xFA, 0x3F, + 0x31, 0xB2, 0xF1, 0x2C, 0x74, 0x1B, 0x57, 0x05, 0xD4, 0x4F, + 0xAF, 0xE7, 0xCB, 0x60, 0x9E, 0x78, 0x82, 0xAD, 0xF3, 0x34, + 0x6A, 0x2F, 0xDC, 0xA1, 0xC9, 0xEA, 0x3E, 0x6E, 0x01, 0x80, + 0x17, 0x5B, 0xCC, 0xBB, 0xED, 0xD0, 0x30, 0x11, 0xBE, 0xEE, + 0x2E, 0x9F, 0xCE, 0xE1, 0xFF, 0x32, 0xB8, 0x7D, 0x40, 0xC8, + 0x46, 0x0F, 0x41, 0x16, 0xE1, 0xB3, 0x98, 0x47, 0xCE, 0xE1, + 0x41, 0xDE, 0x80, 0xA7, 0x56, 0x83, 0xA8, 0xDA, 0xC3, 0x49, + 0x33, 0x6F, 0x93, 0x68, 0xA0, 0xC6, 0x1A, 0x0B, 0x82, 0x38, + 0x56, 0xEE, 0xBB, 0x97, 0x5D, 0xBD, 0x8A, 0x32, 0x2D, 0xFE, + 0x40, 0xC7, 0x0D, 0xCA, 0x32, 0x08, 0xCC, 0xE2, 0x18, 0x57, + 0xBB, 0xC1, 0x60, 0x43, 0x02, 0x26, 0xC0, 0x00, 0x02, 0xAD, + 0x9E, 0x61, 0x0D, 0x67, 0x25, 0xE4, 0x6E, 0x8F, 0x6D, 0xEA, + 0x16, 0x98, 0xFA, 0x76, 0x6D, 0x6D, 0x3C, 0xED, 0x4B, 0x25, + 0x60, 0xC6, 0xAB, 0x59, 0x91, 0x43, 0xAA, 0xAA, 0xEC, 0x8F, + 0xA1, 0x3E, 0xB1, 0x78, 0x72, 0xEE, 0xD1, 0x91, 0xBA, 0xD9, + 0x9B, 0xE3, 0x55, 0x61, 0x98, 0x46, 0x4B, 0xC5, 0x41, 0x3B, + 0x9C, 0x88, 0x1D, 0x82, 0xD5, 0xD5, 0x99, 0x13, 0x64, 0x44, + 0x00, 0xBD, 0xBE, 0xC4, 0xF6, 0x6A, 0x2D, 0xE3, 0xD0, 0xE7, + 0x88, 0xD3, 0xA1, 0x48, 0x88, 0x84, 0x8A, 0x25, 0xAB, 0x90, + 0x43, 0xFB, 0x3D, 0x1B, 0x06, 0xB2, 0xFD, 0x24, 0x58, 0x0C, + 0xFA, 0x0A, 0xD3, 0x23, 0x73, 0xA7, 0xF8, 0x50, 0xC5, 0x1B, + 0x3A, 0x75, 0xF4, 0x24, 0xA8, 0x52, 0xFB, 0x1B, 0x61, 0xAB, + 0x79, 0x06, 0x54, 0xD9, 0x1D, 0x3A, 0x72, 0x4F, 0x8F, 0xD3, + 0xC7, 0x71, 0xA8, 0x66, 0x80, 0x49, 0x8D, 0x50, 0xD1, 0xBF, + 0xC8, 0x70, 0xAE, 0x4F, 0x64, 0x53, 0x26, 0x37, 0xDA, 0x6B, + 0x62, 0xFE, 0xF9, 0x60, 0xAD, 0xAD, 0x49, 0x51, 0x37, 0x2E, + 0x61, 0xA9, 0xAA, 0x72, 0xFD, 0x02, 0x20, 0x0B, 0xB0, 0xB0, + 0x07, 0x95, 0x0C, 0x38, 0x13, 0xB6, 0xA4, 0x33, 0xFA, 0xFA, + 0x12, 0xE1, 0x62, 0x00, 0x92, 0x46, 0x23, 0xAA, 0xD7, 0x9D, + 0xBD, 0xAF, 0x15, 0xCA, 0x8C, 0x88, 0x2A, 0x4B, 0x1B, 0xA8, + 0x06, 0xA0, 0xC2, 0x80, 0x8E, 0x98, 0x46, 0xA1, 0x84, 0x2C, + 0x4A, 0x0F, 0xEA, 0x70, 0xE6, 0xDD, 0x17, 0x30, 0x8A, 0x41, + 0x69, 0x8A, 0x1B, 0xC2, 0xC7, 0x18, 0xD5, 0xB3, 0x94, 0x4F, + 0x51, 0x15, 0xCC, 0x37, 0x9A, 0x9E, 0xFD, 0x12, 0x40, 0xC1, + 0xA3, 0x06, 0x0F, 0x36, 0xFC, 0x04, 0x18, 0x35, 0x40, 0x9C, + 0x9E, 0x46, 0x5E, 0x14, 0xB6, 0xF7, 0xBF, 0xE5, 0x21, 0x12, + 0xF2, 0xE2, 0x17, 0xB3, 0x63, 0x8C, 0xD1, 0xE3, 0xA9, 0x0A, + 0x80, 0x1B, 0x74, 0x7A, 0x58, 0x91, 0x88, 0x9D, 0xAE, 0xE6, + 0x05, 0x1D, 0x3C, 0x1E, 0xE9, 0x95, 0x08, 0x75, 0xEE, 0x20, + 0xA8, 0x4B, 0x3D, 0x36, 0xAF, 0xB0, 0xFA, 0x94, 0x62, 0x5D, + 0x9F, 0xD5, 0x50, 0x2A, 0x24, 0xFC, 0x1D, 0xDC, 0x39, 0xCB, + 0x0D, 0x5A, 0xA1, 0xDA, 0xEF, 0xC9, 0xB3, 0x62, 0xF8, 0x7D, + 0x0C, 0xE4, 0x6B, 0xEC, 0xF0, 0xF7, 0x96, 0x63, 0x58, 0x80, + 0x55, 0x22, 0x6D, 0x42, 0x38, 0xE9, 0x1D, 0x69, 0xD5, 0x2F, + 0x03, 0x3C, 0xCD, 0x27, 0x34, 0x99, 0x39, 0xF0, 0x5C, 0xE0, + 0x23, 0x70, 0x85, 0x4B, 0x30, 0xBD, 0x21, 0x01, 0xF6, 0x06, + 0x0B, 0xED, 0xBA, 0xA1, 0x6F, 0xE0, 0x6E, 0xD3, 0x78, 0xA8, + 0x56, 0x94, 0x92, 0x84, 0xA8, 0x60, 0x35, 0xA8, 0x86, 0x56, + 0x41, 0xEA, 0x12, 0x34, 0x86, 0x52, 0x18, 0x75, 0x43, 0x01, + 0x0A, 0xCE, 0xBA, 0x04, 0xF7, 0x32, 0x09, 0x2D, 0xB1, 0xAC, + 0x04, 0xB0, 0x4E, 0xEA, 0xBE, 0xDE, 0xDE, 0x95, 0x37, 0xDA, + 0x86, 0x72, 0xFE, 0x10, 0x16, 0xBB, 0xA7, 0xE9, 0x67, 0xC9, + 0x3C, 0x85, 0x18, 0xFF, 0xD7, 0x74, 0x25, 0x3A, 0x95, 0x04, + 0xD5, 0x7F, 0x99, 0x41, 0x6A, 0x6A, 0x2C, 0xF6, 0x3E, 0x3C, + 0x4B, 0xA7, 0xB9, 0xDA, 0x13, 0xFC, 0xF6, 0x46, 0xEF, 0x7E, + 0xB4, 0xA6, 0x1B, 0x36, 0x93, 0x5B, 0xDA, 0xDB, 0x6A, 0xC7, + 0x37, 0x58, 0x3C, 0x4F, 0x52, 0x7E, 0x39, 0xD7, 0xE2, 0xBA, + 0x79, 0xA7, 0x9A, 0x05, 0x8A, 0xF5, 0x65, 0x86, 0xF4, 0x52, + 0xBC, 0x79, 0x6D, 0xA9, 0xFE, 0xEE, 0xE6, 0xC5, 0x2B, 0x28, + 0x62, 0x8E, 0xF6, 0x6E, 0xD5, 0x08, 0x90, 0x96, 0x72, 0x7A, + 0x6B, 0x61, 0x8B, 0x6A, 0xE6, 0xCD, 0x05, 0x63, 0x12, 0x9A, + 0xF7, 0x01, 0xAC, 0xF7, 0x8F, 0x1F, 0xE0, 0xCA, 0x1E, 0xF9, + 0x86, 0xC1, 0xF6, 0x0D, 0x2D, 0x9F, 0x8A, 0x2C, 0x8B, 0x3C, + 0xE4, 0x89, 0xDF, 0x72, 0x86, 0x17, 0xA8, 0x7F, 0x9D, 0x8B, + 0x0D, 0x87, 0xCB, 0xC5, 0xAE, 0xE3, 0x90, 0xB1, 0xD9, 0x8B, + 0x5E, 0x04, 0x97, 0xAA, 0x19, 0x85, 0x02, 0x26, 0xC0, 0x00, + 0x02, 0x26, 0xDA, 0x00, 0x7E, 0x08, 0xC0, 0x08, 0x12, 0x9A, + 0x78, 0x4E, 0x9D, 0xA7, 0xB0, 0x5E, 0x0D, 0x76, 0x6D, 0x4D, + 0xC7, 0x89, 0x35, 0xDD, 0xB5, 0x58, 0x9F, 0x20, 0x3C, 0x41, + 0x77, 0x9B, 0x85, 0x06, 0x21, 0xA4, 0x99, 0x56, 0xF9, 0x5B, + 0x07, 0x01, 0x06, 0x1A, 0xE1, 0x1B, 0xC7, 0x9F, 0x46, 0x5D, + 0x1F, 0xB8, 0xB2, 0x91, 0xA5, 0xC2, 0x01, 0x94, 0xFA, 0x53, + 0x74, 0xFA, 0x6A, 0x5B, 0x63, 0x08, 0x2E, 0x24, 0xB0, 0xCF, + 0x03, 0x40, 0x9C, 0xA1, 0xF2, 0xDB, 0xA2, 0x35, 0xD7, 0xCA, + 0x78, 0x4E, 0x9D, 0x8B, 0x92, 0x4A, 0xD1, 0xEA, 0xF8, 0x14, + 0xCA, 0xA0, 0x32, 0x55, 0x95, 0xA0, 0x1F, 0xB7, 0x1D, 0x8B, + 0x8E, 0x8E, 0xA6, 0xF0, 0x2A, 0x30, 0x76, 0xB4, 0x9B, 0x6F, + 0xAB, 0xBC, 0xC7, 0xA8, 0xF6, 0x2B, 0x9D, 0x1D, 0xC2, 0x24, + 0x06, 0x10, 0x06, 0xE7, 0x59, 0x34, 0xE9, 0x30, 0xA8, 0xF5, + 0x61, 0x55, 0xEC, 0xFB, 0xA1, 0x43, 0x17, 0x10, 0x08, 0xFF, + 0x3C, 0x93, 0x03, 0xFF, 0x83, 0x35, 0x81, 0x77, 0x7E, 0x97, + 0xC2, 0xA0, 0x53, 0x2A, 0x26, 0xD4, 0xDF, 0xC0, 0xA3, 0x21, + 0x07, 0x14, 0x41, 0xD3, 0x7C, 0xE5, 0x40, 0x00, 0xDE, 0x32, + 0xF5, 0xB9, 0xBB, 0x61, 0x44, 0xBC, 0xA4, 0xFD, 0x67, 0xAA, + 0x69, 0xF4, 0x96, 0x93, 0xD2, 0xAF, 0xEA, 0xC5, 0x72, 0xDB, + 0xEA, 0x88, 0x2A, 0x5F, 0xC5, 0xAB, 0x00, 0xFA, 0xA9, 0x32, + 0x61, 0x58, 0xBE, 0xC0, 0x42, 0xA9, 0xFA, 0xB6, 0x44, 0xD6, + 0x59, 0xF8, 0x26, 0x8B, 0xB9, 0x0A, 0xD9, 0xE2, 0x5B, 0x1B, + 0x20, 0xD1, 0x34, 0x91, 0x81, 0xF3, 0xFF, 0xED, 0x6D, 0x81, + 0xF9, 0x7D, 0xE3, 0x73, 0x37, 0xC1, 0x01, 0x12, 0x28, 0x9B, + 0xEA, 0xDA, 0x0E, 0x3D, 0x68, 0x16, 0x23, 0xE1, 0x68, 0xFF, + 0x1A, 0x59, 0xCC, 0x89, 0xF8, 0x44, 0x70, 0x13, 0xB2, 0x98, + 0xB1, 0x31, 0xEA, 0xEC, 0x65, 0x21, 0x36, 0xEF, 0xCC, 0x85, + 0x62, 0xC3, 0xEC, 0x62, 0xE9, 0x06, 0xEC, 0xB3, 0x47, 0x94, + 0xE5, 0xF2, 0x6F, 0xFD, 0x80, 0xEE, 0x70, 0xB0, 0x06, 0x56, + 0x8B, 0xF2, 0xDC, 0x7A, 0x52, 0x90, 0xC2, 0xE4, 0x77, 0xDD, + 0xF7, 0xC2, 0x0C, 0x9C, 0xBE, 0x5A, 0x0F, 0xC6, 0x45, 0xB1, + 0x3A, 0x63, 0x38, 0x2C, 0xD9, 0xC4, 0x45, 0x08, 0x44, 0x90, + 0xE2, 0xBC, 0xA2, 0x5A, 0xE6, 0x2E, 0xFD, 0xCB, 0x36, 0x7F, + 0xA9, 0xAC, 0x8C, 0x34, 0x1A, 0x3C, 0xE2, 0x9B, 0x24, 0x45, + 0xE3, 0x9C, 0xCF, 0xF9, 0x96, 0xFE, 0x58, 0xB5, 0x29, 0x20, + 0x0B, 0xC9, 0x5C, 0xAF, 0xCF, 0x7F, 0xCB, 0x8A, 0x14, 0xE1, + 0xCD, 0xF7, 0x5B, 0x93, 0xBC, 0x7D, 0x7A, 0x3B, 0xD2, 0xF2, + 0xFA, 0x2B, 0x57, 0x02, 0x9C, 0xAC, 0xA2, 0x16, 0x11, 0x2D, + 0xDB, 0x3D, 0x42, 0x26, 0x87, 0xBE, 0x9F, 0x8B, 0x7B, 0x00, + 0x20, 0x09, 0x41, 0x05, 0xB0, 0x42, 0x98, 0x44, 0xD6, 0xCC, + 0x08, 0xA2, 0x20, 0x1F, 0x2A, 0x59, 0xB3, 0x05, 0x4F, 0xB4, + 0xA6, 0xF8, 0xF8, 0xFD, 0x27, 0xBB, 0xC5, 0xC3, 0x52, 0x4D, + 0x63, 0x37, 0xCF, 0xAE, 0x4C, 0x60, 0x1E, 0x98, 0x26, 0x12, + 0x3D, 0xB9, 0xE6, 0x87, 0x09, 0x17, 0xB1, 0xE4, 0x81, 0x2C, + 0x8E, 0x73, 0xA1, 0x40, 0x53, 0x96, 0xD8, 0x17, 0x7F, 0x39, + 0xA8, 0x4F, 0xE9, 0xEF, 0x30, 0xE2, 0x5E, 0xEF, 0x9C, 0x13, + 0x70, 0x21, 0x14, 0xA3, 0x5D, 0xEA, 0x43, 0xFB, 0xA6, 0x80, + 0x70, 0xB9, 0x4B, 0x68, 0x9C, 0x5A, 0x82, 0x59, 0x00, 0xFA, + 0x5E, 0x4C, 0x4F, 0x76, 0xB1, 0xF4, 0x45, 0xCD, 0xE6, 0x18, + 0x09, 0xE2, 0x36, 0x8A, 0x60, 0x4B, 0xF4, 0x61, 0x55, 0xC4, + 0xE9, 0x69, 0xC1, 0x03, 0x9E, 0x9C, 0xAF, 0x1C, 0xE5, 0xD1, + 0xFF, 0x45, 0x16, 0x43, 0xD7, 0xE5, 0x4B, 0xCC, 0xEA, 0x24, + 0x2E, 0xCE, 0xE3, 0x90, 0x17, 0xDB, 0xC4, 0x57, 0x4D, 0xF9, + 0xCB, 0xEC, 0x09, 0x62, 0xBD, 0xD8, 0x7A, 0x89, 0x55, 0x92, + 0x90, 0x7B, 0x22, 0x20, 0xD9, 0x9A, 0xC9, 0x19, 0x02, 0x26, + 0xC0, 0x00, 0x02, 0x2E, 0xA2, 0xCF, 0xDE, 0xE3, 0xDE, 0xA9, + 0x10, 0x3D, 0xEB, 0xD9, 0x4B, 0x51, 0x68, 0x41, 0x57, 0xCD, + 0x7C, 0xF4, 0x28, 0x84, 0x22, 0x1C, 0xA7, 0xA6, 0x8A, 0xDD, + 0x97, 0x5B, 0x8A, 0x07, 0x01, 0x97, 0x13, 0x20, 0x06, 0x12, + 0xC9, 0xBB, 0x6D, 0x12, 0x25, 0x6D, 0x08, 0x13, 0x3C, 0x32, + 0x48, 0xFE, 0x49, 0xD9, 0xC1, 0x3E, 0x00, 0x1C, 0xD9, 0xF0, + 0xE2, 0xB3, 0xE0, 0x07, 0xE1, 0x8F, 0xDF, 0x75, 0xE0, 0xB9, + 0x61, 0x1A, 0xBF, 0xAF, 0x66, 0xE0, 0xAB, 0x8A, 0x4B, 0x71, + 0xCB, 0x4F, 0xB7, 0x4C, 0x30, 0xC8, 0xB0, 0xC4, 0xC0, 0x38, + 0x73, 0xDD, 0x3C, 0xDC, 0x5D, 0x81, 0x40, 0x14, 0x23, 0x9C, + 0xD2, 0x48, 0xF9, 0xCB, 0xC4, 0x1B, 0xD5, 0xC7, 0x85, 0xB0, + 0x57, 0xC1, 0xF5, 0x41, 0x7A, 0x2E, 0xC6, 0x03, 0x86, 0x8C, + 0x4E, 0xAF, 0x24, 0x21, 0xB9, 0x0B, 0xE9, 0x24, 0x12, 0x02, + 0x3E, 0x35, 0x7C, 0x1D, 0x9A, 0x2D, 0x5E, 0xB7, 0xEE, 0x08, + 0x34, 0x2C, 0x2B, 0xAD, 0x8D, 0x02, 0xF6, 0xFE, 0x06, 0x88, + 0xD0, 0xA5, 0xA2, 0x1E, 0x5B, 0xD2, 0x88, 0x09, 0x9F, 0x43, + 0xDF, 0xC4, 0x85, 0x59, 0x50, 0x7B, 0x94, 0xD9, 0xBB, 0xBE, + 0xF5, 0x1D, 0x60, 0xD0, 0x90, 0x6F, 0xD5, 0x1E, 0x49, 0xF1, + 0x76, 0x04, 0x96, 0xCA, 0x3F, 0x44, 0x64, 0xBE, 0x41, 0xE7, + 0x4A, 0x6E, 0xA8, 0x11, 0x14, 0x21, 0xEA, 0x9E, 0x43, 0x6D, + 0x2E, 0xF6, 0x49, 0x7A, 0x8C, 0xD6, 0xF1, 0x4A, 0xC3, 0x17, + 0x16, 0x23, 0x3B, 0x02, 0x6A, 0xA7, 0x90, 0x1D, 0x8C, 0xBF, + 0xB4, 0x25, 0xDA, 0xB6, 0x0F, 0x2A, 0x60, 0xF5, 0xC1, 0x7F, + 0xFA, 0x1D, 0x0B, 0xAF, 0x28, 0x8A, 0x00, 0x8A, 0xBE, 0xA8, + 0x72, 0x20, 0x5F, 0xEC, 0x3F, 0x16, 0x6E, 0xAB, 0xC4, 0xFC, + 0x6B, 0x75, 0xD7, 0xFB, 0x73, 0x60, 0x7E, 0x25, 0xE5, 0xA3, + 0x91, 0x6A, 0x33, 0xD3, 0x9E, 0xAC, 0xFB, 0x8C, 0xD1, 0xC6, + 0x63, 0xF4, 0x3F, 0xB7, 0xD1, 0xD3, 0x88, 0x90, 0x4C, 0xA2, + 0x7E, 0x6B, 0x19, 0x61, 0xCC, 0xAB, 0x48, 0xDD, 0x8D, 0xE2, + 0x1B, 0xB7, 0x9E, 0x2F, 0x58, 0x10, 0x78, 0xAC, 0x94, 0xF6, + 0xD6, 0x62, 0x4D, 0x66, 0x78, 0x67, 0x9F, 0x1B, 0x3A, 0x78, + 0x4E, 0xA0, 0xDB, 0x47, 0x92, 0xC4, 0x43, 0x1A, 0x22, 0xFC, + 0x26, 0x38, 0xA4, 0xF2, 0x7A, 0x52, 0x31, 0x71, 0x63, 0x16, + 0x58, 0xF5, 0xA4, 0x4A, 0xCA, 0x73, 0xD5, 0x90, 0x39, 0x55, + 0x8F, 0xB2, 0xC0, 0x3F, 0x3A, 0xEC, 0x69, 0xC4, 0x42, 0xCE, + 0xB9, 0x1B, 0xA4, 0x32, 0x52, 0x14, 0x7C, 0xBB, 0xF6, 0xB3, + 0x5A, 0x7C, 0xF1, 0x75, 0x1E, 0x4B, 0xB8, 0xB0, 0xB3, 0x8E, + 0x13, 0x63, 0x7B, 0xF5, 0xB9, 0x93, 0x22, 0x98, 0xDF, 0x6C, + 0xEC, 0x51, 0x4F, 0xC8, 0x0B, 0xA0, 0x14, 0x57, 0x75, 0x1B, + 0xF6, 0xE9, 0x5D, 0xC2, 0x47, 0x65, 0xDF, 0x79, 0x0D, 0x48, + 0xBE, 0x4F, 0x46, 0xF0, 0x37, 0xA5, 0x7C, 0xA3, 0x6B, 0x3E, + 0xE6, 0xA2, 0x0E, 0x69, 0xAF, 0x3C, 0x46, 0x8A, 0x77, 0xD2, + 0xBF, 0x2A, 0x16, 0x00, 0x17, 0x2F, 0x9C, 0x4E, 0xD8, 0xA8, + 0x48, 0xD4, 0xCC, 0x0C, 0x29, 0xD1, 0x7A, 0xAE, 0x81, 0x4F, + 0x04, 0x76, 0x53, 0xCF, 0x22, 0x76, 0x39, 0x61, 0xB6, 0x76, + 0x42, 0xE6, 0x4E, 0x71, 0xB3, 0x06, 0xB9, 0x31, 0x04, 0x60, + 0x88, 0x04, 0x02, 0x89, 0x72, 0x13, 0xD8, 0x8E, 0xD7, 0xE7, + 0x88, 0xCC, 0x3B, 0x88, 0x4A, 0xC7, 0x96, 0x58, 0x12, 0xDA, + 0x75, 0x15, 0xE2, 0x9A, 0xFA, 0x9E, 0x7C, 0x0E, 0xD6, 0x86, + 0x64, 0x7F, 0x31, 0xE3, 0x5C, 0xD8, 0xCF, 0xC0, 0x6D, 0x9B, + 0x1A, 0x1D, 0x8E, 0x90, 0xED, 0x8E, 0x7B, 0xFD, 0xAF, 0xE0, + 0x85, 0xE2, 0x51, 0x49, 0xAE, 0xE6, 0x03, 0x78, 0x41, 0xB9, + 0x05, 0xA0, 0xB8, 0x25, 0x03, 0x51, 0xD1, 0x93, 0x05, 0xE1, + 0xAA, 0x19, 0x0F, 0x1A, 0xF0, 0xD6, 0x18, 0xB6, 0x23, 0xFD, + 0xBC, 0x6E, 0x10, 0xA5, 0x18, 0xE9, 0x3B, 0xE5, 0xA4, 0x22, + 0x02, 0x26, 0xC0, 0x00, 0x02, 0x55, 0x43, 0x38, 0x66, 0x6B, + 0x96, 0x00, 0x6F, 0x33, 0xEE, 0x72, 0x7A, 0x9E, 0xD2, 0x5C, + 0x1F, 0x87, 0x4C, 0xFC, 0xE9, 0x3C, 0xAB, 0xC7, 0x5E, 0x55, + 0xD6, 0xEF, 0x78, 0xB1, 0x4D, 0xA7, 0x92, 0x3F, 0x57, 0x3B, + 0xF5, 0x7F, 0xE0, 0xD6, 0xE0, 0xD0, 0x8D, 0xE5, 0xE1, 0xAE, + 0x48, 0xC1, 0xF7, 0xF3, 0xC3, 0xA4, 0xF7, 0x8F, 0xE7, 0x6F, + 0xB2, 0xB1, 0xA5, 0x6F, 0x6A, 0xCF, 0x5F, 0x3C, 0xF2, 0x50, + 0x31, 0x19, 0x89, 0xF1, 0x74, 0x55, 0xA2, 0xFF, 0x7A, 0x5D, + 0xCB, 0x96, 0xED, 0xE4, 0xEA, 0x28, 0x4B, 0xF7, 0xE4, 0x45, + 0x7D, 0x99, 0xAF, 0xC5, 0xDB, 0xC1, 0x2D, 0xE8, 0xE9, 0xEA, + 0x2B, 0xAD, 0x7E, 0x8E, 0x96, 0x25, 0xA0, 0x9E, 0xDA, 0x31, + 0xE4, 0xCD, 0xC6, 0x8D, 0x69, 0x39, 0x04, 0x53, 0x1B, 0xCA, + 0xEF, 0x96, 0x8E, 0xEF, 0xFB, 0x4E, 0xC8, 0x11, 0x8E, 0x42, + 0x03, 0xC2, 0x96, 0x1A, 0x2C, 0xD8, 0xCF, 0x17, 0x05, 0x36, + 0xF7, 0x02, 0xAB, 0xBD, 0x1A, 0xF3, 0x51, 0xC0, 0xE2, 0x1E, + 0x0D, 0x8D, 0xE9, 0x81, 0x57, 0xD1, 0xA1, 0x9A, 0x2C, 0x7D, + 0x43, 0xBD, 0x23, 0x50, 0xA9, 0x3D, 0x77, 0xC1, 0x5F, 0x2D, + 0x3A, 0x61, 0x56, 0xE1, 0x47, 0xB4, 0x6C, 0xB1, 0xDF, 0xD7, + 0x1E, 0x95, 0x00, 0x02, 0x5B, 0xDA, 0xBD, 0x39, 0x2A, 0x06, + 0x98, 0x2B, 0x54, 0x63, 0xC9, 0xDB, 0x30, 0xF2, 0xB6, 0xB6, + 0xC8, 0x22, 0xAB, 0xB5, 0x68, 0xA3, 0xB7, 0x94, 0x6C, 0x97, + 0x5B, 0xC0, 0x6F, 0xA5, 0x11, 0xFD, 0x9A, 0x52, 0x5A, 0xB5, + 0x3D, 0xEA, 0xC3, 0x23, 0xD1, 0xA7, 0x31, 0xA1, 0xCE, 0xA8, + 0x4A, 0x7C, 0x5D, 0xF6, 0x21, 0xC1, 0x38, 0x73, 0xA3, 0x83, + 0x00, 0x28, 0x9D, 0x76, 0x5A, 0xC5, 0x63, 0xDB, 0x47, 0x25, + 0xAB, 0xD7, 0x25, 0xAE, 0x7D, 0x87, 0xF1, 0xA1, 0xE6, 0x9C, + 0x83, 0x33, 0x30, 0xE1, 0xAD, 0x65, 0xFD, 0x0F, 0xBB, 0xD0, + 0xEF, 0xF5, 0xC3, 0x19, 0x9B, 0x9D, 0x13, 0xBA, 0xEF, 0x9F, + 0x13, 0x2F, 0x76, 0x55, 0x2C, 0x2A, 0xC3, 0x8B, 0x40, 0x79, + 0x49, 0x02, 0x88, 0xE7, 0x4B, 0x57, 0xF5, 0xC5, 0x56, 0x30, + 0xF2, 0xB8, 0x2D, 0x83, 0x6F, 0xB6, 0xBF, 0xE2, 0x7E, 0xFF, + 0x18, 0x61, 0x11, 0x6B, 0x77, 0xCC, 0x04, 0x8B, 0xE4, 0x7C, + 0xF9, 0x48, 0x9C, 0xE0, 0x10, 0x7F, 0x68, 0xFE, 0x40, 0xF0, + 0x23, 0x5C, 0x13, 0x56, 0xD7, 0xCC, 0xDA, 0x83, 0xD6, 0x5C, + 0xB2, 0xED, 0x3F, 0x4C, 0x1E, 0x0A, 0x2F, 0x9D, 0xA2, 0x08, + 0x95, 0xB1, 0x80, 0xFB, 0x04, 0xAC, 0xED, 0x88, 0x01, 0xDC, + 0x69, 0xC7, 0x2D, 0xE8, 0xEB, 0xD1, 0xCE, 0x8E, 0x32, 0x04, + 0x0B, 0xA5, 0x1E, 0xFA, 0x47, 0xA2, 0x8F, 0xB6, 0xF4, 0xC8, + 0xFE, 0x81, 0xFC, 0x68, 0xFF, 0x82, 0x9A, 0x9A, 0xB6, 0x2C, + 0x58, 0x55, 0xEE, 0xFC, 0xBB, 0x23, 0x47, 0xA4, 0xEB, 0xF8, + 0x08, 0xB1, 0xF0, 0xAA, 0xE3, 0x7A, 0xDC, 0xEF, 0xD6, 0xB4, + 0x60, 0x39, 0x6F, 0x0F, 0x8A, 0x4C, 0x65, 0x48, 0x65, 0x78, + 0x6D, 0xF8, 0x44, 0x13, 0xA2, 0x9A, 0x76, 0xE8, 0xA7, 0x06, + 0x33, 0x54, 0x74, 0x73, 0xE4, 0x69, 0x66, 0x27, 0xA0, 0x66, + 0xA0, 0x5A, 0x9E, 0x26, 0xF2, 0xA4, 0x3C, 0xA6, 0xCF, 0x86, + 0x0F, 0x9D, 0x0A, 0x75, 0xC1, 0x9C, 0x34, 0xD1, 0x40, 0x21, + 0x64, 0x62, 0x7B, 0xBF, 0xAE, 0xCD, 0x44, 0x17, 0x6D, 0x5F, + 0x21, 0x02, 0x17, 0x1A, 0x2C, 0xA4, 0x18, 0x1D, 0x4F, 0x2E, + 0xC8, 0xE2, 0xCF, 0xAE, 0x25, 0x4A, 0xC4, 0xA2, 0x5A, 0x2E, + 0x10, 0x09, 0x69, 0xB2, 0xEA, 0xF9, 0xB9, 0x4C, 0x36, 0xA4, + 0xD6, 0xCB, 0x03, 0x6E, 0x7B, 0xC1, 0xA4, 0x28, 0x1A, 0x09, + 0xBF, 0xF1, 0xA1, 0x3F, 0x75, 0xB8, 0x5A, 0xF3, 0x9F, 0x12, + 0x35, 0x4B, 0x16, 0x21, 0x3B, 0x8D, 0xF9, 0x87, 0xCB, 0x8A, + 0xEC, 0x29, 0x1B, 0xF0, 0xB3, 0x96, 0x77, 0xB7, 0x7B, 0xA8, + 0x6A, 0x98, 0xE4, 0x8B, 0x61, 0xB6, 0x47, 0xD7, 0x92, 0xB4, + 0x0B, 0x47, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x4B, 0x86, 0xD9, + 0x89, 0x5B, 0x11, 0x29, 0x1D, 0x8E, 0x56, 0xC4, 0x4A, 0x0D, + 0xD4, 0x9F, 0x43, 0x9F, 0xA2, 0x55, 0x58, 0xE1, 0xF6, 0xF6, + 0x58, 0xFB, 0xCD, 0x3F, 0x06, 0x4C, 0xC2, 0x60, 0x6D, 0xB7, + 0xB2, 0xFF, 0xFE, 0x89, 0x77, 0x7A, 0x1E, 0xA0, 0xC8, 0xDD, + 0x7F, 0x3E, 0x6B, 0x38, 0x2F, 0x41, 0x2B, 0xDF, 0x42, 0x14, + 0x50, 0x28, 0xEE, 0xDE, 0x3F, 0xD8, 0xFF, 0x09, 0x43, 0x7A, + 0x22, 0x4F, 0xF3, 0xFC, 0x60, 0x7E, 0x2C, 0x1A, 0xB6, 0x9E, + 0x21, 0x40, 0x76, 0x3B, 0x42, 0xFC, 0xBC, 0x1D, 0x00, 0xA4, + 0x55, 0x95, 0x47, 0xBD, 0x6E, 0x31, 0xAB, 0x05, 0xAD, 0x38, + 0x53, 0xB0, 0x24, 0x83, 0x7D, 0x0E, 0xA8, 0x40, 0xE6, 0x33, + 0x6D, 0xEF, 0x72, 0x35, 0xCF, 0x3C, 0x11, 0x67, 0x1D, 0x28, + 0xEF, 0x7B, 0x7A, 0x7A, 0x0E, 0xD2, 0x7F, 0xBA, 0xEB, 0xA0, + 0x49, 0x46, 0x29, 0x40, 0x5B, 0x62, 0xA9, 0xED, 0xC9, 0xAC, + 0xDD, 0xAF, 0xE9, 0xAF, 0xF9, 0x75, 0x70, 0xC7, 0xAD, 0xB2, + 0xB6, 0x51, 0x08, 0x23, 0x89, 0x1F, 0xCC, 0xDE, 0xB7, 0x6B, + 0x25, 0xC4, 0x77, 0x90, 0x01, 0xBA, 0x80, 0x62, 0x3E, 0xFF, + 0x93, 0x00, 0x15, 0x43, 0x7D, 0xBE, 0x80, 0x83, 0xBB, 0xB0, + 0xAA, 0x3B, 0xF2, 0x0A, 0x9D, 0x86, 0x23, 0xA4, 0xB7, 0xB7, + 0x44, 0x30, 0xA7, 0x17, 0x66, 0x70, 0xEE, 0x2D, 0x1F, 0xDF, + 0xBD, 0xD9, 0x14, 0x3E, 0x55, 0xC6, 0xC9, 0x5B, 0xC3, 0xF2, + 0xE5, 0x10, 0xD5, 0x1A, 0x93, 0xF6, 0x76, 0xAB, 0x71, 0x87, + 0xDE, 0xD5, 0x51, 0x99, 0x37, 0x6F, 0xEE, 0xB1, 0x63, 0xDA, + 0x7F, 0x3B, 0xAC, 0x77, 0x1B, 0x4B, 0xA3, 0xE3, 0x77, 0x41, + 0xEA, 0x23, 0xF3, 0xB9, 0x22, 0x75, 0x07, 0x8E, 0x64, 0x3E, + 0x32, 0xA9, 0x28, 0xAA, 0x93, 0x8F, 0xE8, 0xDA, 0x60, 0xE9, + 0xD7, 0x35, 0x7F, 0xD7, 0x8F, 0xC8, 0xE5, 0x5B, 0x61, 0x47, + 0xD6, 0xD4, 0xA7, 0xFF, 0x25, 0x8F, 0x03, 0xC3, 0x03, 0x07, + 0xED, 0x30, 0x45, 0x86, 0x73, 0x1E, 0x8F, 0x2F, 0x3D, 0xB4, + 0xC0, 0x37, 0x7A, 0xE7, 0x80, 0xEA, 0xA0, 0xDB, 0x98, 0xAE, + 0xF9, 0x24, 0x0C, 0x74, 0x36, 0x54, 0x13, 0x34, 0x30, 0xCF, + 0x0E, 0xC8, 0x9D, 0x94, 0xE7, 0xAF, 0x6A, 0xC0, 0x32, 0x32, + 0xA3, 0xDE, 0x3A, 0x5B, 0x72, 0x72, 0xE3, 0x8F, 0x91, 0xC5, + 0x44, 0xAB, 0x86, 0x7B, 0xE0, 0x6C, 0x80, 0x84, 0x64, 0x1D, + 0xC0, 0xF1, 0x28, 0x7C, 0x6A, 0x35, 0x76, 0xCF, 0x12, 0x56, + 0x84, 0x1C, 0x21, 0x51, 0x33, 0x00, 0xFF, 0xB2, 0x64, 0x30, + 0x44, 0x1C, 0xA5, 0x05, 0x09, 0xE2, 0x14, 0x8E, 0xF3, 0xD8, + 0x91, 0x21, 0x60, 0xC0, 0x51, 0x68, 0x62, 0xF5, 0x7E, 0x06, + 0xD5, 0xC0, 0xEE, 0xB8, 0x91, 0xF1, 0x52, 0x14, 0x6C, 0x27, + 0xB6, 0x6A, 0x1C, 0x64, 0xBF, 0x59, 0x47, 0x64, 0x03, 0x8D, + 0x4E, 0xEB, 0xA3, 0x73, 0x10, 0xE2, 0xBC, 0xA0, 0x30, 0x29, + 0xE6, 0xF5, 0xED, 0x04, 0xCA, 0xAA, 0xC2, 0xBA, 0xDB, 0x8E, + 0xBC, 0x00, 0x34, 0x3D, 0xB6, 0x12, 0xCB, 0xAF, 0xC0, 0x3D, + 0x97, 0xF7, 0x5A, 0x1B, 0x83, 0x90, 0x91, 0xD0, 0xE2, 0xCF, + 0xE6, 0x21, 0x07, 0xCF, 0x2E, 0xFD, 0x71, 0xA1, 0x10, 0x18, + 0x67, 0x3F, 0x8F, 0xE2, 0x86, 0xFA, 0xA6, 0xDF, 0x6D, 0xE4, + 0x31, 0x7D, 0x75, 0x12, 0x99, 0x23, 0xC7, 0xFB, 0xF2, 0x04, + 0x76, 0x4C, 0x93, 0x9B, 0xB9, 0x89, 0x1D, 0x88, 0x5A, 0x0E, + 0xDE, 0x5A, 0x27, 0x35, 0x88, 0xE7, 0x80, 0x14, 0x87, 0xCA, + 0x23, 0xE6, 0xEF, 0xA8, 0xEA, 0x73, 0x7D, 0x93, 0x0C, 0x61, + 0x81, 0x2E, 0x10, 0xDF, 0x13, 0x57, 0x96, 0xD9, 0x36, 0x68, + 0x93, 0x42, 0x7A, 0x67, 0x60, 0x44, 0x57, 0xD8, 0x6C, 0x4B, + 0xD4, 0xCC, 0x7E, 0x70, 0xE2, 0xCD, 0xC7, 0x14, 0x4A, 0xDE, + 0x32, 0x35, 0x8B, 0x4B, 0x14, 0xE0, 0x8D, 0x5C, 0x33, 0x72, + 0xC9, 0x5D, 0x1F, 0xF6, 0xD7, 0xC3, 0xCF, 0x72, 0xA1, 0x2C, + 0x98, 0x2C, 0x0E, 0xEA, 0x02, 0x26, 0xC0, 0x00, 0x02, 0xEC, + 0xFC, 0x5D, 0x99, 0x61, 0x74, 0x77, 0x64, 0xF2, 0x70, 0x18, + 0x1A, 0x0B, 0x9F, 0x5A, 0x64, 0xE4, 0xCE, 0xA9, 0xCE, 0xCF, + 0x15, 0x35, 0x0E, 0x90, 0x95, 0xD1, 0x78, 0xBC, 0x36, 0xDD, + 0x32, 0xB0, 0x72, 0xCF, 0xCE, 0xFE, 0x8D, 0xAA, 0xF4, 0x19, + 0x73, 0x80, 0x37, 0xB6, 0x7B, 0x88, 0xB5, 0x7F, 0x5B, 0x7E, + 0xC7, 0x1F, 0x40, 0x5E, 0xCF, 0xC5, 0xE3, 0x75, 0x43, 0xCA, + 0x9D, 0x7C, 0xA1, 0x5D, 0x12, 0xBE, 0x30, 0x0E, 0x2C, 0x6D, + 0xE1, 0xD4, 0xD9, 0xC0, 0x90, 0x9F, 0x13, 0x6C, 0x00, 0x75, + 0xC9, 0x98, 0xE8, 0x4A, 0x1E, 0x43, 0x27, 0xB2, 0x3D, 0x16, + 0x5D, 0xF7, 0x18, 0xF6, 0xF2, 0x57, 0xA8, 0x54, 0x57, 0x50, + 0xFD, 0x98, 0x0F, 0x99, 0x63, 0x9E, 0x94, 0x71, 0x8B, 0x6B, + 0x6A, 0xAC, 0x27, 0x7A, 0xE5, 0xFE, 0x49, 0x5F, 0xA9, 0x3F, + 0x72, 0x32, 0xE5, 0x67, 0x87, 0xE9, 0xCC, 0xBC, 0x64, 0xE9, + 0x6B, 0x15, 0x06, 0x60, 0x32, 0x43, 0x49, 0x53, 0x47, 0xB2, + 0x56, 0xCE, 0xBF, 0x5F, 0x9B, 0x16, 0x40, 0x7D, 0x90, 0x0E, + 0xFB, 0xFE, 0x66, 0x58, 0xB3, 0xFC, 0x42, 0xB5, 0x90, 0xE6, + 0xCA, 0x6C, 0xD0, 0x3C, 0xA0, 0x2D, 0x84, 0x5E, 0xA0, 0xE7, + 0xD7, 0x8B, 0xB0, 0x42, 0x56, 0x3D, 0x48, 0xAF, 0x18, 0xEF, + 0xAF, 0x27, 0x76, 0xE3, 0x26, 0x0B, 0xCA, 0xA0, 0x01, 0x4B, + 0x79, 0xD1, 0xAC, 0xD5, 0x8B, 0xCD, 0x70, 0x9F, 0x6E, 0xFB, + 0x72, 0xBB, 0x9B, 0xDA, 0x4A, 0xFA, 0x96, 0x45, 0x29, 0x59, + 0x16, 0x4B, 0x57, 0xC1, 0x7B, 0x5D, 0x94, 0x5E, 0xDA, 0xC1, + 0x2B, 0x3C, 0xD9, 0xD5, 0x6B, 0x23, 0xE7, 0x53, 0x9C, 0xAA, + 0x89, 0x07, 0xFC, 0x66, 0xBC, 0xBC, 0xDD, 0x5D, 0xC7, 0xC0, + 0x46, 0xAF, 0xF6, 0xCB, 0xBB, 0xD3, 0x37, 0xC1, 0x7F, 0xCD, + 0xAE, 0x69, 0x1F, 0xCA, 0x20, 0x07, 0x76, 0x3F, 0xD0, 0x71, + 0x4F, 0x19, 0x6A, 0x92, 0xA2, 0xD8, 0x81, 0xE7, 0x84, 0xC3, + 0x24, 0x55, 0xF3, 0x1F, 0xA6, 0x8B, 0xAF, 0x11, 0xA6, 0xAC, + 0x9B, 0x2D, 0x12, 0xD0, 0x0D, 0xBC, 0x20, 0x26, 0x01, 0x76, + 0x39, 0xBF, 0xAB, 0x52, 0xD6, 0x93, 0x76, 0x29, 0x4C, 0xD8, + 0x8F, 0xBA, 0xA9, 0xA1, 0xCE, 0x09, 0xCC, 0xB7, 0xC5, 0x34, + 0xCC, 0xC1, 0x27, 0xE9, 0x47, 0xFB, 0x02, 0xC0, 0x0B, 0xB7, + 0xE2, 0x1B, 0x9A, 0x05, 0x32, 0x99, 0x7E, 0xEF, 0xDA, 0xC3, + 0xE2, 0xB3, 0x0D, 0x2F, 0xD7, 0x32, 0x14, 0xAA, 0x90, 0x00, + 0x5B, 0x8F, 0xA9, 0x6D, 0xBD, 0x54, 0xAF, 0xE2, 0x47, 0x8C, + 0x20, 0xD4, 0x14, 0x34, 0x13, 0x08, 0x17, 0x1B, 0xA2, 0x3B, + 0xDC, 0x6D, 0x5A, 0x08, 0x04, 0x58, 0x38, 0xAC, 0x84, 0xBB, + 0x22, 0x64, 0x6B, 0xE6, 0xB9, 0x46, 0x4A, 0xB6, 0x39, 0xD2, + 0xF4, 0x6D, 0x13, 0x63, 0x7F, 0x79, 0x6F, 0x54, 0x38, 0x72, + 0x1A, 0x3D, 0x45, 0x28, 0x14, 0x8F, 0x9D, 0xFE, 0x51, 0x02, + 0x3F, 0x0C, 0xFD, 0xE4, 0x7A, 0xC4, 0xFC, 0x00, 0xF0, 0xF6, + 0x7E, 0x98, 0x36, 0x40, 0x35, 0x92, 0x3A, 0x42, 0xBE, 0xA6, + 0xAE, 0x3C, 0x55, 0xF5, 0x4E, 0x41, 0xF4, 0x22, 0x63, 0x80, + 0x2E, 0xC9, 0x65, 0x73, 0x43, 0x2F, 0xE7, 0xF9, 0xC5, 0x5C, + 0x21, 0xDD, 0xF5, 0x15, 0x38, 0xE4, 0xDD, 0x92, 0x08, 0x9D, + 0x75, 0x65, 0x13, 0x28, 0xA5, 0xF9, 0x45, 0x13, 0xE0, 0x8F, + 0xB2, 0x36, 0x91, 0xAA, 0xBE, 0x87, 0xD2, 0x78, 0x3F, 0xB0, + 0xEE, 0x0C, 0x4C, 0x8C, 0xD7, 0x56, 0x85, 0x21, 0x43, 0x40, + 0xC4, 0x26, 0x90, 0xC2, 0x63, 0xF0, 0xC3, 0x49, 0xA0, 0xF0, + 0x2A, 0xCA, 0xA3, 0x9A, 0x39, 0xA6, 0xAA, 0x98, 0x2B, 0x8E, + 0xBA, 0x0B, 0xD9, 0x21, 0xC4, 0xC9, 0x97, 0x1B, 0x57, 0x80, + 0x49, 0x3E, 0xC4, 0x4B, 0xD8, 0x5E, 0xE2, 0x43, 0xC2, 0x13, + 0x8D, 0x51, 0x28, 0x8B, 0x30, 0x7C, 0x17, 0xB0, 0x58, 0x15, + 0x5F, 0x56, 0xF8, 0xF3, 0x8F, 0x9A, 0xC0, 0x9B, 0x27, 0x90, + 0x23, 0x48, 0xED, 0x5E, 0x50, 0xE2, 0x02, 0x26, 0xC0, 0x00, + 0x02, 0x02, 0xCA, 0xFA, 0x0D, 0x3A, 0xC4, 0xBF, 0x20, 0x04, + 0xD3, 0xA1, 0x4F, 0xED, 0x80, 0x40, 0x81, 0x15, 0x67, 0x0D, + 0x65, 0x3E, 0x52, 0x9C, 0x30, 0x20, 0xD2, 0xD8, 0xAC, 0xAF, + 0x06, 0xE5, 0xDA, 0x8B, 0x8B, 0x3A, 0xCA, 0xDC, 0x59, 0x8F, + 0x2F, 0x93, 0x53, 0x5B, 0xAC, 0xCE, 0x1F, 0xDF, 0x3B, 0x50, + 0xBF, 0x70, 0xF1, 0x7A, 0xCC, 0xA2, 0x25, 0x88, 0xD1, 0xA0, + 0xBC, 0x9D, 0x41, 0x1F, 0x9C, 0x0A, 0x95, 0x27, 0xE2, 0x71, + 0x4C, 0x1C, 0x14, 0xDB, 0xEA, 0xCD, 0xA3, 0x7C, 0x39, 0x57, + 0x69, 0x95, 0xA5, 0x04, 0x4F, 0xA3, 0xC0, 0x24, 0xC1, 0x5B, + 0x39, 0xF4, 0x9F, 0xBC, 0xB2, 0xC3, 0x37, 0x28, 0x1F, 0xFA, + 0xB9, 0xD7, 0xFF, 0x7A, 0xA2, 0x52, 0x03, 0x1F, 0x96, 0x5B, + 0xC4, 0x83, 0x08, 0x75, 0xFF, 0xF6, 0xF2, 0xF9, 0x7C, 0x1D, + 0x09, 0xB4, 0x3B, 0xAE, 0xCD, 0x2E, 0xF2, 0x6F, 0x2F, 0x4F, + 0xBC, 0x2B, 0x5B, 0x6D, 0x9A, 0x1B, 0xE6, 0x5E, 0xF5, 0xA8, + 0x93, 0x98, 0xDC, 0x6E, 0x5E, 0x17, 0xCA, 0xAB, 0x90, 0xFD, + 0xFB, 0x68, 0x1F, 0x67, 0x88, 0x58, 0x85, 0x4F, 0xAA, 0xC3, + 0x68, 0x40, 0xD5, 0xBC, 0xAC, 0x1D, 0x94, 0xC5, 0xB6, 0x01, + 0x2A, 0xE8, 0xBD, 0xDD, 0xBB, 0x17, 0x9D, 0x0E, 0x55, 0x62, + 0x45, 0xFB, 0x21, 0xB6, 0x71, 0x76, 0xEB, 0xCC, 0xF5, 0xE7, + 0xF1, 0xCD, 0xB7, 0xCA, 0xBD, 0xFF, 0xA9, 0xF7, 0x1A, 0xAA, + 0x1A, 0xCD, 0xC1, 0x71, 0x62, 0xE3, 0xDD, 0x09, 0x06, 0xAA, + 0x23, 0xFD, 0xEF, 0x6B, 0xA7, 0x83, 0xD8, 0xE6, 0x70, 0x01, + 0xF0, 0xEF, 0x69, 0xA9, 0x4B, 0x9B, 0x83, 0x57, 0x77, 0xAD, + 0x51, 0xBE, 0xBA, 0xF6, 0x2A, 0x6F, 0x1F, 0x97, 0x9A, 0xFE, + 0xA8, 0xE2, 0xAA, 0x20, 0x51, 0x95, 0xBA, 0xAE, 0x66, 0xB3, + 0xA8, 0x61, 0xCF, 0x8B, 0xFA, 0x6B, 0x48, 0xC4, 0x22, 0xE1, + 0xDF, 0x3A, 0x0D, 0xA9, 0x09, 0xF1, 0x66, 0x0C, 0x46, 0x74, + 0x90, 0x8B, 0x68, 0x00, 0x4F, 0x4F, 0x3A, 0x90, 0x58, 0x56, + 0xF4, 0x8A, 0x71, 0xB6, 0x1A, 0x91, 0x59, 0x17, 0x5C, 0xC0, + 0x87, 0x82, 0x7E, 0xB0, 0x81, 0x90, 0xF1, 0x6A, 0x03, 0xB8, + 0xA0, 0xAB, 0xDD, 0x63, 0x96, 0x48, 0x19, 0x37, 0x1F, 0x0F, + 0x24, 0x7A, 0x70, 0x48, 0x7D, 0x28, 0x1F, 0xB3, 0xCD, 0x76, + 0x53, 0x83, 0xC5, 0x53, 0xE8, 0xAB, 0x3A, 0xFC, 0x5B, 0x8A, + 0xF0, 0x5A, 0x0F, 0xEF, 0xFF, 0xB0, 0xC1, 0x61, 0x61, 0x58, + 0x4A, 0x8C, 0x1C, 0x20, 0xFC, 0x46, 0x07, 0x58, 0xF0, 0x20, + 0x81, 0x66, 0x28, 0x0E, 0xC2, 0x16, 0xAB, 0x98, 0xFF, 0x6E, + 0x24, 0xAC, 0x78, 0x42, 0xAE, 0x7D, 0xAB, 0x6F, 0xB4, 0x11, + 0x1C, 0x0C, 0x40, 0xF8, 0xF4, 0x93, 0x63, 0xE4, 0x6A, 0xEB, + 0xC5, 0xD9, 0x6E, 0x35, 0xC9, 0xA7, 0x2D, 0x49, 0xEA, 0x5D, + 0x69, 0x73, 0x06, 0x1C, 0xC4, 0x7E, 0x46, 0xFD, 0x09, 0x88, + 0x77, 0x77, 0xE7, 0xEB, 0x31, 0x34, 0x16, 0x72, 0x76, 0x1B, + 0x4E, 0xF8, 0x67, 0x9F, 0xCA, 0x1C, 0x67, 0x4E, 0xD8, 0x88, + 0xAA, 0x01, 0x27, 0x8E, 0x08, 0x70, 0xF8, 0x0B, 0x23, 0xF6, + 0x84, 0x47, 0x2F, 0x4E, 0x5F, 0xB7, 0x2C, 0x39, 0xBF, 0x61, + 0xEC, 0x6D, 0x24, 0x5C, 0x57, 0xBE, 0xAE, 0x19, 0x20, 0xBE, + 0x55, 0x40, 0x1D, 0xB7, 0x5F, 0xC3, 0xF6, 0x5B, 0x19, 0xC6, + 0x8A, 0x94, 0x23, 0x5C, 0x95, 0x33, 0x4C, 0x90, 0xE0, 0x46, + 0xAC, 0x0A, 0x1D, 0x50, 0xFB, 0x0A, 0xAB, 0xA2, 0xEB, 0x2A, + 0x21, 0xBF, 0x15, 0xD5, 0x9E, 0x80, 0x3B, 0x16, 0xB0, 0x3F, + 0x6F, 0x6F, 0xF6, 0xBE, 0x92, 0xA1, 0x2F, 0x83, 0xA8, 0x3C, + 0xA6, 0xE7, 0x86, 0xCD, 0x3B, 0x96, 0xCE, 0xF1, 0x36, 0x7C, + 0x69, 0xD9, 0xD5, 0x0F, 0xC1, 0x4C, 0x7A, 0xE5, 0xAF, 0xAC, + 0x86, 0x90, 0x98, 0x3D, 0x2B, 0x94, 0xA2, 0x7C, 0x5B, 0xF7, + 0x27, 0xCD, 0xE5, 0x93, 0x60, 0x2C, 0x47, 0xE3, 0xFA, 0x18, + 0xCB, 0xEB, 0xDB, 0x0A, 0x49, 0x99, 0x0F, 0xAE, 0x02, 0x26, + 0xC0, 0x00, 0x02, 0xF3, 0x51, 0xA3, 0x96, 0x54, 0xDA, 0xE9, + 0x09, 0x47, 0x82, 0x50, 0xB8, 0x82, 0x39, 0x98, 0x54, 0x81, + 0x54, 0x91, 0x2C, 0xE6, 0xBC, 0x84, 0x03, 0x07, 0x26, 0x6D, + 0x0F, 0x5E, 0x2B, 0x45, 0xF5, 0x1D, 0x7B, 0xD6, 0x14, 0x03, + 0xD7, 0x09, 0x64, 0xEE, 0x05, 0xBA, 0xE0, 0x74, 0x67, 0x02, + 0xF5, 0x7E, 0x42, 0x42, 0xEC, 0x56, 0xE0, 0x9E, 0x82, 0x88, + 0x58, 0x3C, 0x96, 0xAF, 0x37, 0x95, 0x49, 0xC8, 0x87, 0xBD, + 0xFE, 0x7A, 0x6B, 0x4D, 0x37, 0xEE, 0x7C, 0xAA, 0x18, 0x5F, + 0x7E, 0x0B, 0x28, 0xA3, 0x95, 0x23, 0x42, 0xAB, 0xC1, 0xFA, + 0x41, 0xAE, 0xD5, 0xBD, 0x67, 0xA6, 0xC4, 0x7C, 0xAC, 0x2D, + 0xEF, 0x64, 0xC2, 0x5D, 0x30, 0x94, 0xF3, 0x97, 0x49, 0x00, + 0x39, 0x28, 0x57, 0x5D, 0x31, 0xBB, 0x1D, 0x10, 0x17, 0xE7, + 0x56, 0x55, 0xDF, 0x4C, 0xDD, 0xA6, 0x64, 0x02, 0xBC, 0x1C, + 0x2B, 0x4C, 0x30, 0xBF, 0x89, 0x7C, 0xFC, 0x7E, 0x84, 0xBC, + 0x51, 0x97, 0x6C, 0x74, 0x5B, 0x08, 0xE0, 0x96, 0x84, 0x81, + 0xF3, 0x17, 0x6B, 0xD6, 0xF6, 0x66, 0x06, 0x1B, 0x33, 0x4D, + 0xF8, 0xED, 0xC0, 0x53, 0x8B, 0x35, 0x6B, 0x85, 0x4F, 0x37, + 0x0F, 0x87, 0xF3, 0x85, 0x72, 0xAE, 0xCB, 0x3A, 0x23, 0x97, + 0xC0, 0xF6, 0xE7, 0x53, 0xDF, 0x57, 0x0E, 0x8E, 0x0B, 0x66, + 0x2A, 0xA2, 0x9D, 0xA8, 0xE2, 0x60, 0x57, 0xCA, 0x27, 0x7E, + 0xB1, 0xDB, 0x7B, 0x6A, 0xB0, 0xBE, 0xB5, 0x47, 0xEE, 0xE6, + 0xBA, 0x0E, 0xB2, 0x71, 0x0B, 0xF7, 0xE4, 0x27, 0x9D, 0x25, + 0xAA, 0x3F, 0xA9, 0x1A, 0x5B, 0xD9, 0x9D, 0xBB, 0x20, 0x32, + 0x37, 0xE1, 0xD3, 0x4A, 0xBA, 0x45, 0x9E, 0x00, 0x10, 0x3F, + 0x21, 0x6E, 0xA2, 0xCE, 0x30, 0xA0, 0x2A, 0x5B, 0x31, 0x51, + 0x05, 0xA1, 0x51, 0xED, 0x89, 0x5E, 0xB1, 0x09, 0xE6, 0x71, + 0xD8, 0x42, 0xFD, 0xA1, 0x04, 0x83, 0xFB, 0x09, 0x4F, 0x90, + 0x4D, 0x7E, 0x5A, 0xB9, 0x4C, 0xC9, 0xA3, 0x57, 0x4E, 0x54, + 0x98, 0xB3, 0xBD, 0xB7, 0x52, 0x9D, 0xDE, 0xF3, 0xD3, 0xE0, + 0x9C, 0x2D, 0x97, 0x46, 0x1B, 0xF9, 0x75, 0x37, 0x5D, 0x0A, + 0xA3, 0x4A, 0x18, 0x35, 0x80, 0xC5, 0x08, 0xA8, 0x37, 0x09, + 0x44, 0x92, 0xB1, 0x74, 0xFE, 0x28, 0x95, 0x55, 0xB6, 0x08, + 0xA0, 0x75, 0xE9, 0xA0, 0x4B, 0x8E, 0xE6, 0x61, 0x17, 0x2A, + 0xED, 0x15, 0x0B, 0x6C, 0x7C, 0xC3, 0x82, 0x57, 0x90, 0xC5, + 0xFF, 0xD8, 0xA5, 0xBF, 0xAA, 0xBE, 0xCF, 0x8E, 0x06, 0xFF, + 0x27, 0xDA, 0x40, 0x24, 0xDD, 0xC0, 0xBE, 0x4E, 0x19, 0x9D, + 0x23, 0xA2, 0x3A, 0x70, 0x64, 0xEB, 0xF6, 0xA7, 0xE9, 0x71, + 0x57, 0xE9, 0x63, 0x03, 0xAE, 0xEC, 0x73, 0x21, 0x23, 0x8D, + 0x61, 0x5A, 0x10, 0x54, 0xF9, 0x80, 0xE7, 0x47, 0x45, 0xD4, + 0x8B, 0x16, 0xEE, 0x2B, 0xD8, 0xC1, 0xEE, 0x0F, 0x4F, 0x78, + 0x40, 0x00, 0xB6, 0x25, 0x81, 0x2A, 0x37, 0x4D, 0x71, 0x92, + 0xFA, 0x56, 0x3F, 0xDC, 0x91, 0x01, 0x27, 0xC7, 0x17, 0xFD, + 0x27, 0x55, 0x6F, 0x32, 0x14, 0xE7, 0xEA, 0x18, 0xDA, 0x4A, + 0x70, 0x10, 0xF8, 0x72, 0x78, 0xA1, 0xC1, 0x13, 0x5F, 0x1B, + 0x98, 0x93, 0xC2, 0xBF, 0x29, 0xA3, 0x59, 0x79, 0x15, 0x57, + 0x17, 0xE5, 0x66, 0x7A, 0x3B, 0x8E, 0xB3, 0x3B, 0x9E, 0xC0, + 0x77, 0xBD, 0x2D, 0x95, 0x26, 0xF0, 0xD5, 0xB4, 0x30, 0xC8, + 0x0D, 0xCA, 0xB5, 0xDE, 0xB2, 0x21, 0x27, 0x9A, 0x27, 0xAF, + 0x89, 0xB4, 0x0D, 0x1B, 0x5A, 0x43, 0x3E, 0x69, 0x76, 0x25, + 0xAC, 0x42, 0x23, 0x5F, 0x5A, 0xA6, 0xDB, 0xE6, 0x77, 0x9D, + 0x2A, 0x99, 0x1B, 0xE7, 0x47, 0x05, 0x06, 0x47, 0x01, 0x14, + 0x0D, 0xEA, 0xF5, 0x28, 0x3A, 0x5B, 0x87, 0xF0, 0xFB, 0x7C, + 0x96, 0x39, 0x6C, 0x4A, 0x48, 0xA5, 0x7A, 0x94, 0xB0, 0xB8, + 0xBB, 0x03, 0xDA, 0xEA, 0x4F, 0xD1, 0x5B, 0x8B, 0x9D, 0x0A, + 0x5E, 0xAB, 0xD8, 0x89, 0x5C, 0x4D, 0xD1, 0xA7, 0xC4, 0x8A, + 0x02, 0x26, 0xC0, 0x00, 0x02, 0x14, 0x04, 0xA6, 0x12, 0xC1, + 0x4E, 0x67, 0x67, 0x6C, 0xEE, 0x9E, 0x7A, 0x55, 0x00, 0xCB, + 0x12, 0x7B, 0x69, 0x4C, 0x94, 0x57, 0x73, 0x71, 0xC8, 0x45, + 0xAA, 0x04, 0x75, 0x85, 0xED, 0x68, 0x7D, 0x09, 0xD5, 0x4A, + 0xD0, 0x86, 0xDB, 0x0B, 0xC3, 0x80, 0xD1, 0x11, 0xB3, 0x59, + 0xCF, 0xBD, 0x13, 0x7B, 0xD2, 0x30, 0xDF, 0xDD, 0x41, 0xD7, + 0xBC, 0x34, 0x11, 0x85, 0x58, 0x2A, 0x8E, 0x2B, 0xDC, 0x00, + 0x78, 0x94, 0x28, 0x52, 0xD9, 0x0C, 0x70, 0xCB, 0x7D, 0xE9, + 0xCF, 0x7C, 0x11, 0x91, 0x09, 0xA8, 0xD7, 0xBC, 0xC8, 0xA1, + 0xDF, 0xF3, 0xB4, 0x25, 0x3A, 0x88, 0x02, 0xF0, 0xBE, 0x8E, + 0x89, 0x2B, 0xA6, 0x43, 0x88, 0xD0, 0xCC, 0x27, 0x91, 0x77, + 0x8D, 0x01, 0x32, 0xA6, 0x0C, 0x3D, 0x86, 0x76, 0x03, 0x4F, + 0x01, 0xF6, 0x02, 0xB3, 0xD0, 0x7A, 0x39, 0x78, 0x1E, 0xF2, + 0x35, 0xB6, 0xB3, 0xC9, 0x50, 0xE7, 0x0A, 0xD1, 0x3C, 0xB4, + 0xE2, 0x02, 0x60, 0x13, 0x8A, 0x0F, 0x15, 0xEE, 0x48, 0x67, + 0x84, 0x9E, 0x8E, 0x56, 0x22, 0xB9, 0x0A, 0xE2, 0x36, 0xDE, + 0x97, 0x4E, 0x9F, 0x0A, 0xE0, 0xB8, 0x2A, 0x0D, 0x07, 0x7F, + 0xCE, 0x76, 0xEA, 0x58, 0x54, 0xBC, 0x7A, 0xA1, 0x87, 0x15, + 0x3F, 0xCE, 0xDA, 0x58, 0xA4, 0x51, 0x36, 0x49, 0xB0, 0x23, + 0xC0, 0x55, 0xFB, 0xE2, 0x47, 0xB6, 0xD6, 0x31, 0x90, 0xA9, + 0x99, 0x2A, 0xC3, 0x59, 0xAE, 0x60, 0x03, 0xC2, 0x56, 0xC0, + 0x03, 0xA9, 0x3E, 0xF0, 0xE9, 0x59, 0x30, 0xD5, 0x90, 0x15, + 0x72, 0x32, 0x30, 0xD1, 0xFA, 0xDD, 0xB3, 0x09, 0xF0, 0x1A, + 0xA3, 0x6E, 0x5E, 0xBB, 0xDE, 0x58, 0x08, 0x91, 0xFB, 0xA0, + 0xEC, 0x45, 0x7F, 0x05, 0x90, 0x78, 0xCF, 0x6F, 0x66, 0xF4, + 0x2A, 0x79, 0x93, 0x33, 0x17, 0x07, 0x86, 0xE6, 0xEC, 0xFD, + 0xEC, 0x07, 0x74, 0x17, 0x26, 0x84, 0x52, 0x54, 0x9A, 0xBC, + 0xDE, 0xEE, 0xD7, 0xE9, 0x2F, 0xA7, 0x60, 0xA6, 0x54, 0x74, + 0xB9, 0x83, 0x6D, 0xE6, 0xB7, 0x46, 0xDC, 0xC8, 0x09, 0x36, + 0x25, 0x1E, 0x8B, 0x61, 0x94, 0x2D, 0xBA, 0xE2, 0xAB, 0xE6, + 0xD0, 0xDB, 0x9C, 0x13, 0x74, 0x25, 0xDA, 0xD7, 0x69, 0x69, + 0xFA, 0x52, 0x3C, 0x15, 0xBB, 0xFC, 0x5D, 0xE2, 0x6E, 0xA5, + 0x26, 0x35, 0x65, 0xF4, 0xE0, 0x29, 0x77, 0xCF, 0xAB, 0xF9, + 0xAB, 0x8C, 0x9D, 0x7D, 0x60, 0xA4, 0xA0, 0x3D, 0x43, 0xB6, + 0x9D, 0xAE, 0x04, 0x46, 0x8A, 0xE2, 0x3B, 0x4C, 0xC8, 0xA4, + 0x5D, 0x61, 0xB4, 0x5B, 0x8B, 0x2E, 0xD5, 0x2A, 0x07, 0x27, + 0x6A, 0x34, 0x04, 0xBA, 0xF8, 0x72, 0x32, 0x99, 0x97, 0x8C, + 0xC0, 0xCD, 0x35, 0x68, 0xB8, 0xA9, 0x45, 0x76, 0xA5, 0xD4, + 0x17, 0x36, 0xB1, 0x25, 0xF7, 0x47, 0x69, 0x30, 0x68, 0x14, + 0x0B, 0x9C, 0x38, 0xB1, 0x29, 0x16, 0x88, 0xAD, 0xDF, 0x31, + 0x7E, 0x3C, 0x5F, 0xA4, 0x0D, 0x86, 0x5A, 0x29, 0x37, 0xA9, + 0x1B, 0xD5, 0x68, 0x9F, 0xE0, 0xE6, 0x32, 0x42, 0x12, 0x37, + 0x99, 0xC5, 0xB8, 0xA1, 0xD3, 0x5B, 0x90, 0x9C, 0xAD, 0x86, + 0x6B, 0x03, 0x82, 0x91, 0xD9, 0xF9, 0xDC, 0xD5, 0x41, 0x7B, + 0xF3, 0xE4, 0x08, 0x92, 0xCA, 0x6A, 0xAA, 0xBD, 0xFE, 0x25, + 0x50, 0xDC, 0x2C, 0x00, 0x65, 0x59, 0x9B, 0xD3, 0x30, 0xD2, + 0x39, 0xC0, 0x4D, 0xFD, 0x8C, 0x9D, 0x88, 0xD3, 0x52, 0xD6, + 0xC0, 0xA0, 0x1C, 0x08, 0x0B, 0x1F, 0x91, 0xAF, 0x60, 0x56, + 0xED, 0x8B, 0x37, 0xD3, 0x15, 0x08, 0x5C, 0xEA, 0xFA, 0x03, + 0x0A, 0x54, 0x92, 0x96, 0x34, 0x4F, 0x14, 0x0E, 0xD5, 0xB4, + 0xA0, 0x2E, 0xC0, 0xEC, 0x93, 0x8F, 0xA5, 0xF3, 0x82, 0x5F, + 0x0D, 0xA8, 0xBD, 0x28, 0x4B, 0x1C, 0x65, 0xC1, 0x97, 0x5B, + 0xEE, 0x99, 0xC5, 0xC2, 0xB9, 0x34, 0x4D, 0xDB, 0x6E, 0x42, + 0x26, 0x93, 0x49, 0x83, 0x36, 0x25, 0x72, 0x03, 0x08, 0xE2, + 0xE6, 0x67, 0x01, 0xBC, 0x7A, 0x10, 0x7A, 0xBC, 0x6B, 0x0B, + 0x4A, 0x94, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x72, 0x08, 0xBA, + 0x77, 0xE2, 0x2F, 0x48, 0xD4, 0x9E, 0xC4, 0x23, 0x45, 0x55, + 0xF1, 0x0B, 0x1B, 0x50, 0x47, 0x8C, 0x40, 0x7C, 0xF7, 0xE4, + 0xCF, 0xD6, 0x0A, 0x0A, 0xD3, 0x7F, 0x35, 0x85, 0x84, 0x78, + 0xF2, 0x28, 0xEA, 0x14, 0x06, 0x2A, 0xC0, 0x53, 0x22, 0x45, + 0x9B, 0xDA, 0xE9, 0xEE, 0x98, 0x5D, 0xEC, 0xEC, 0xEF, 0xA1, + 0x1A, 0xDD, 0x7C, 0xE2, 0x29, 0xFF, 0x2B, 0x8A, 0x00, 0x49, + 0xD6, 0x2E, 0x7C, 0x50, 0x26, 0x29, 0x65, 0x97, 0xB4, 0xA8, + 0x6B, 0x38, 0x95, 0xC0, 0x7F, 0x41, 0xAD, 0xD5, 0xA2, 0x54, + 0x37, 0xE1, 0x72, 0x3A, 0x28, 0x58, 0xCA, 0x88, 0xB4, 0xF8, + 0x34, 0x43, 0xFF, 0xE4, 0xE4, 0xC2, 0x37, 0x0B, 0x72, 0x77, + 0x2B, 0x94, 0x8C, 0xB8, 0xCD, 0x72, 0x1E, 0xDB, 0x0A, 0xFA, + 0x86, 0x0E, 0xBC, 0x76, 0xDE, 0x89, 0x20, 0xBB, 0x1A, 0xC3, + 0x07, 0xAA, 0x0F, 0x0D, 0xED, 0x58, 0x42, 0x74, 0x44, 0xD0, + 0x89, 0x61, 0x25, 0xAF, 0xC0, 0x18, 0xFE, 0x16, 0xC9, 0x37, + 0x03, 0x11, 0x11, 0xEC, 0x9F, 0xFF, 0x2B, 0x00, 0x4F, 0x37, + 0xB6, 0xEC, 0x54, 0x0A, 0xA1, 0x68, 0xE5, 0x69, 0x38, 0xD5, + 0x55, 0x9E, 0x94, 0xAF, 0x3D, 0x67, 0xFF, 0x4D, 0x5D, 0x66, + 0x1D, 0xD0, 0x45, 0x1B, 0xF9, 0x23, 0x5F, 0xCF, 0x18, 0xFB, + 0x3F, 0x13, 0x0A, 0x2E, 0x86, 0xC4, 0x44, 0x28, 0xAB, 0x72, + 0x78, 0x77, 0x14, 0xCA, 0x70, 0xBF, 0x3E, 0x79, 0x47, 0xAB, + 0x3D, 0x22, 0xB9, 0x57, 0xB8, 0x04, 0x4B, 0x62, 0x2A, 0x26, + 0x4C, 0xEE, 0x80, 0xF4, 0x1C, 0x5C, 0xE3, 0xFF, 0x23, 0xC8, + 0x7C, 0x27, 0x90, 0xC8, 0x61, 0xC3, 0x7C, 0xC8, 0x5B, 0x46, + 0xB8, 0xCC, 0x8A, 0x67, 0xFC, 0xB9, 0xF1, 0xE7, 0x21, 0x68, + 0x47, 0x37, 0x9D, 0xEB, 0x14, 0xC4, 0x55, 0x02, 0x43, 0xA6, + 0xAA, 0x50, 0xE2, 0x78, 0x66, 0xE9, 0x55, 0x2D, 0x4C, 0x84, + 0xDF, 0x81, 0xCF, 0x0C, 0xD4, 0x36, 0xCA, 0x3D, 0xF7, 0xEE, + 0x2A, 0x5D, 0x10, 0xC9, 0xEA, 0x19, 0xF2, 0xF3, 0xBD, 0x42, + 0xA9, 0xE1, 0xA6, 0xD1, 0x84, 0xE9, 0x1A, 0x26, 0xDC, 0xBE, + 0x72, 0x43, 0xC7, 0x79, 0x92, 0xD9, 0x5F, 0x7C, 0x42, 0xCD, + 0xFF, 0x76, 0xBE, 0xB9, 0x99, 0x60, 0x6B, 0x5E, 0xAD, 0xAC, + 0x62, 0xAD, 0xFD, 0x58, 0x1C, 0x4E, 0xC6, 0x6D, 0xE7, 0xF9, + 0x2E, 0xD1, 0xEC, 0x9F, 0x98, 0xAE, 0x4F, 0xB6, 0xE1, 0xB3, + 0x77, 0xDD, 0xA4, 0x5D, 0x24, 0x76, 0xF0, 0xED, 0xBE, 0x19, + 0xB1, 0x98, 0x85, 0x08, 0xAB, 0xF0, 0x39, 0x94, 0x1D, 0x12, + 0xCA, 0x8B, 0xD2, 0xCC, 0x97, 0x44, 0xCB, 0x89, 0x9B, 0x66, + 0x50, 0x51, 0x64, 0x9E, 0xB1, 0x9E, 0x2C, 0xAA, 0xE5, 0x91, + 0x59, 0x53, 0xB1, 0x5E, 0xB3, 0xBB, 0x99, 0x00, 0x53, 0xA9, + 0xC1, 0x6C, 0x59, 0x46, 0xFD, 0xCB, 0x53, 0x83, 0xDD, 0x37, + 0xA1, 0xA3, 0x65, 0x26, 0xC6, 0x48, 0x6D, 0x15, 0xE8, 0xC1, + 0xE3, 0x45, 0x10, 0x6E, 0x8A, 0xE1, 0xDB, 0x10, 0xDB, 0x58, + 0x16, 0x5C, 0x31, 0x2E, 0x06, 0xA8, 0xAE, 0xD7, 0xB2, 0x11, + 0x55, 0x07, 0x2E, 0x57, 0x57, 0x02, 0x48, 0xC0, 0x8B, 0x59, + 0x8C, 0xBE, 0x1A, 0x47, 0x52, 0x3E, 0xD0, 0x05, 0xEA, 0xBC, + 0x86, 0xEA, 0x31, 0xD9, 0x58, 0x52, 0xCF, 0x7D, 0xD2, 0x30, + 0x4E, 0x0D, 0x24, 0x6F, 0x39, 0xF6, 0xEB, 0xC8, 0x5D, 0xE4, + 0xFF, 0x8D, 0xB9, 0x71, 0x02, 0x71, 0x67, 0x89, 0xFA, 0xB8, + 0x4F, 0xC9, 0x77, 0x78, 0x60, 0x36, 0xDF, 0x0E, 0x96, 0xAC, + 0x4F, 0x44, 0x8A, 0x2C, 0xE5, 0x8C, 0xC3, 0x96, 0x79, 0xE2, + 0x43, 0x75, 0xF5, 0x59, 0xC0, 0x81, 0x0A, 0x54, 0xC2, 0xA3, + 0x28, 0x8A, 0x32, 0xCE, 0x91, 0x5A, 0x91, 0x06, 0x45, 0xEB, + 0x34, 0x1A, 0x87, 0xF9, 0x57, 0x91, 0x0D, 0x34, 0x7F, 0x82, + 0x91, 0x82, 0xC5, 0x26, 0xCB, 0xB3, 0x4F, 0xF2, 0x20, 0x6A, + 0x02, 0x95, 0x73, 0x7B, 0x4F, 0x4E, 0xAF, 0x8A, 0x40, 0x83, + 0xFE, 0xF9, 0xD2, 0xFD, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x0E, + 0xA2, 0xA8, 0x59, 0xF0, 0x82, 0x17, 0x4C, 0x0E, 0xF3, 0x83, + 0xA1, 0xB6, 0x36, 0x83, 0xCB, 0xFB, 0xA2, 0x66, 0x53, 0x65, + 0x40, 0x40, 0xAA, 0x3D, 0x82, 0x62, 0x54, 0x0A, 0x27, 0x6A, + 0xD6, 0x07, 0xAF, 0x91, 0xCF, 0x9B, 0x89, 0x58, 0xBC, 0xCE, + 0x74, 0x87, 0x9C, 0x7E, 0x30, 0xF3, 0x06, 0x2B, 0xF1, 0xB4, + 0x70, 0x9D, 0xAA, 0x41, 0xD7, 0x25, 0x75, 0xE5, 0x72, 0x25, + 0x00, 0xC7, 0x21, 0x9D, 0xEE, 0xD1, 0x24, 0x16, 0x0B, 0x12, + 0x22, 0x88, 0xB8, 0x9D, 0xA5, 0x38, 0xA0, 0x50, 0x39, 0x27, + 0xAE, 0x10, 0xF6, 0x9A, 0x0B, 0x77, 0x56, 0x3F, 0x96, 0xDF, + 0x22, 0xE5, 0xEA, 0xAC, 0x8F, 0xDF, 0xDD, 0x78, 0xEF, 0x5A, + 0x7B, 0x50, 0x72, 0x98, 0x92, 0xDD, 0x94, 0xB5, 0xDB, 0x99, + 0xCE, 0xF2, 0x7A, 0xF3, 0xFA, 0x80, 0xD3, 0xCD, 0x1F, 0xCA, + 0xA2, 0x2E, 0x21, 0x94, 0xF2, 0xB3, 0x71, 0x7C, 0x07, 0xE6, + 0xB9, 0x68, 0x1E, 0x13, 0x02, 0x15, 0xC8, 0x34, 0xA0, 0xB5, + 0xD9, 0x95, 0x1A, 0x9B, 0x57, 0xE7, 0xAF, 0xB0, 0xE1, 0xA7, + 0x95, 0xF2, 0x36, 0xA3, 0xF9, 0xC5, 0x2C, 0xF0, 0xC3, 0xE1, + 0xD1, 0x26, 0xA1, 0x8F, 0xE6, 0x07, 0xFB, 0x1F, 0x03, 0xFF, + 0xA5, 0x81, 0xF5, 0x5D, 0x21, 0x3B, 0x93, 0x66, 0x1A, 0x78, + 0x6F, 0xD4, 0x77, 0xB3, 0x91, 0x26, 0x6F, 0x1F, 0x5A, 0x8B, + 0x0F, 0x07, 0xEA, 0x24, 0x5F, 0x5E, 0x68, 0x9F, 0x89, 0x75, + 0x00, 0x23, 0x1C, 0x80, 0x55, 0x86, 0x93, 0x58, 0x94, 0x41, + 0x37, 0x0D, 0x23, 0xD3, 0x09, 0x72, 0x40, 0x79, 0xA2, 0x52, + 0x0D, 0xA3, 0x40, 0x3F, 0x54, 0x7E, 0x59, 0x55, 0x5B, 0x7D, + 0x0C, 0x52, 0xAA, 0x97, 0x0C, 0xC6, 0xCB, 0x0B, 0x6C, 0x83, + 0x45, 0x28, 0x62, 0x09, 0x0A, 0x74, 0x27, 0x1D, 0x4D, 0x02, + 0x07, 0xB3, 0xA5, 0x83, 0x9A, 0x43, 0xB3, 0x68, 0xF7, 0x97, + 0x3E, 0xD7, 0x34, 0x04, 0x83, 0xC7, 0x6F, 0x64, 0xB8, 0x0B, + 0xB9, 0xE9, 0x94, 0x46, 0xB9, 0x4D, 0xA7, 0xB4, 0x26, 0xF7, + 0x9C, 0x05, 0x94, 0x8B, 0xBE, 0x93, 0x03, 0xA7, 0x73, 0x65, + 0xAB, 0xC5, 0xE1, 0x2B, 0x3B, 0x4C, 0x56, 0x1F, 0x11, 0x7B, + 0xD3, 0xC0, 0x77, 0x48, 0x42, 0x27, 0x8D, 0x2A, 0xAA, 0x1E, + 0x18, 0x41, 0x76, 0xA1, 0x80, 0x99, 0x52, 0x50, 0x66, 0x7B, + 0x27, 0x4B, 0x49, 0xA1, 0xE8, 0xCA, 0xF1, 0x3E, 0x60, 0x2E, + 0x93, 0xEF, 0x4A, 0x20, 0x3C, 0xC4, 0xBB, 0x14, 0xD3, 0x8F, + 0x14, 0xAF, 0xC0, 0xF8, 0x4B, 0xC6, 0x49, 0x1A, 0x3B, 0x17, + 0x43, 0xC2, 0xAB, 0xF0, 0x01, 0xFC, 0x6E, 0x67, 0x86, 0xAC, + 0xE4, 0x6F, 0xF2, 0x26, 0xF2, 0xEC, 0x15, 0xA1, 0x96, 0x81, + 0xDD, 0xCF, 0xCA, 0xB4, 0xE1, 0x5A, 0xA0, 0xF5, 0xBB, 0x70, + 0xEB, 0xF9, 0xA6, 0x28, 0x66, 0xC3, 0xBE, 0xB9, 0xBD, 0xDD, + 0xEF, 0x8E, 0x9E, 0x3C, 0x91, 0x50, 0x38, 0x61, 0x40, 0x25, + 0x4D, 0xCD, 0xA0, 0xAF, 0xFE, 0x57, 0xB8, 0x96, 0xDD, 0x2B, + 0x52, 0x29, 0x91, 0x7A, 0x31, 0xE8, 0x9A, 0xBB, 0xC9, 0x70, + 0x2B, 0xE1, 0x40, 0x3A, 0x9F, 0xB7, 0x31, 0xBE, 0xE5, 0x46, + 0xDA, 0x8A, 0xDE, 0x13, 0x22, 0x87, 0x70, 0xFE, 0x96, 0x40, + 0x9F, 0xC1, 0x2B, 0xFE, 0x83, 0x31, 0xE9, 0xA5, 0x4C, 0x37, + 0xEB, 0xFD, 0xFB, 0x2C, 0xBD, 0x0C, 0x1F, 0xB2, 0x62, 0x32, + 0x0E, 0x76, 0x9A, 0x2C, 0xC2, 0x84, 0x34, 0xA0, 0x6D, 0x72, + 0x21, 0x47, 0xF9, 0x3E, 0xC6, 0x5C, 0xEE, 0xB6, 0xE1, 0xD9, + 0x2E, 0xDF, 0x50, 0xD6, 0x2C, 0x9B, 0x44, 0xBE, 0xF0, 0x01, + 0x8E, 0xB4, 0x34, 0x38, 0x9C, 0x6C, 0x3E, 0x26, 0xB2, 0x4C, + 0x8E, 0xF0, 0x41, 0x2F, 0x07, 0x0E, 0xE9, 0x69, 0x1C, 0x0A, + 0x00, 0x05, 0xB0, 0x09, 0xA7, 0x07, 0x18, 0x41, 0xD1, 0xF7, + 0x22, 0xE4, 0x85, 0x64, 0xB7, 0x83, 0xF7, 0xB1, 0xE2, 0xAC, + 0x2E, 0xD9, 0x83, 0x81, 0x18, 0xCB, 0xBD, 0xEE, 0xD9, 0x09, + 0x99, 0xBA, 0x95, 0x66, 0x1F, 0xBA, 0x02, 0x26, 0xC0, 0x00, + 0x02, 0x67, 0x72, 0x24, 0xB5, 0xFE, 0x8C, 0x50, 0x84, 0x47, + 0x41, 0x6A, 0x29, 0x1F, 0x17, 0xB2, 0x9E, 0x02, 0x67, 0x70, + 0x55, 0x03, 0x3F, 0x8F, 0x07, 0x20, 0x91, 0x6B, 0x22, 0x7F, + 0x06, 0xC3, 0xC9, 0x0A, 0xB5, 0x07, 0x0D, 0x91, 0x5F, 0x87, + 0x6D, 0xE2, 0xEE, 0x2B, 0x01, 0xE7, 0x45, 0x3F, 0x89, 0x1C, + 0x8B, 0x12, 0x33, 0x23, 0x61, 0x64, 0x3F, 0x4B, 0xF1, 0x27, + 0x0E, 0x8B, 0x7B, 0x7E, 0x64, 0x2E, 0xDE, 0xE0, 0x3F, 0x3E, + 0x5C, 0xAE, 0x8C, 0x73, 0xB2, 0x8B, 0x62, 0x0F, 0xF9, 0xEB, + 0xF0, 0x74, 0xBD, 0xB9, 0xCC, 0x43, 0x80, 0xC3, 0x05, 0x31, + 0x53, 0x6F, 0x72, 0x42, 0x8E, 0x14, 0xAD, 0xF0, 0x45, 0x36, + 0x88, 0xE4, 0xF9, 0x0F, 0xD9, 0xCA, 0x1E, 0x82, 0xC2, 0x89, + 0x44, 0xC3, 0x69, 0xC6, 0xDD, 0x27, 0xB5, 0xCA, 0xCF, 0x56, + 0x23, 0x5D, 0x50, 0xF9, 0x69, 0x87, 0xCF, 0x4D, 0x2F, 0xA8, + 0xEE, 0xD4, 0x55, 0x2A, 0xC7, 0x3A, 0x2D, 0x03, 0xCD, 0x38, + 0xDE, 0x4F, 0x29, 0x91, 0x14, 0xAD, 0x39, 0x05, 0x77, 0x5F, + 0x41, 0x48, 0x30, 0x63, 0xE6, 0x81, 0x40, 0x68, 0x75, 0x8D, + 0xC5, 0x70, 0x2D, 0xC9, 0xB9, 0x10, 0x75, 0xF3, 0x28, 0x91, + 0x99, 0x97, 0x16, 0x2E, 0x7C, 0xAD, 0x50, 0x80, 0x40, 0x00, + 0xEE, 0x8F, 0x59, 0xA1, 0x8F, 0x82, 0xDE, 0x1E, 0xDB, 0x56, + 0xA1, 0xD6, 0x2E, 0x06, 0x9D, 0x42, 0xCF, 0xA0, 0xB7, 0x1F, + 0x37, 0x22, 0x02, 0x2E, 0x33, 0xAE, 0xE4, 0x7B, 0x7C, 0xC6, + 0x11, 0x5E, 0xF6, 0xA5, 0x5B, 0x54, 0x8B, 0x28, 0x54, 0x01, + 0x4C, 0x41, 0x49, 0x8E, 0xAD, 0x22, 0xBB, 0x67, 0x7A, 0xF3, + 0xEC, 0xE3, 0x93, 0xE4, 0x3A, 0x71, 0xB2, 0x82, 0xC4, 0x8A, + 0x7B, 0x99, 0xA7, 0x6B, 0x69, 0x28, 0xE3, 0xC5, 0x89, 0xF7, + 0x3E, 0xF3, 0xC5, 0xB2, 0x40, 0x91, 0xF8, 0x6A, 0xE3, 0x63, + 0xB1, 0x5C, 0xE3, 0x79, 0xFF, 0x41, 0xE8, 0x2F, 0xCA, 0x11, + 0xA2, 0xED, 0x86, 0x59, 0x53, 0x9D, 0xF9, 0xE1, 0x15, 0x5D, + 0x38, 0x32, 0x69, 0x60, 0x45, 0x20, 0x74, 0xF5, 0xF6, 0x24, + 0xA2, 0x4E, 0xAE, 0xB5, 0x2F, 0xE2, 0xEE, 0xBD, 0xD3, 0x27, + 0xE1, 0x90, 0x89, 0x89, 0xA3, 0x7E, 0x2B, 0x73, 0x63, 0xB8, + 0x36, 0xFA, 0x17, 0x0C, 0x8F, 0x0F, 0xE8, 0xBE, 0xDC, 0x8D, + 0x52, 0x34, 0xB3, 0x52, 0x0E, 0xB1, 0x97, 0x8D, 0x69, 0xC8, + 0x27, 0x2E, 0xBC, 0xFC, 0xDB, 0x6C, 0x98, 0xE8, 0x50, 0xF1, + 0x7A, 0x14, 0xE7, 0xA4, 0x11, 0xD2, 0xDA, 0x71, 0xCB, 0x77, + 0x88, 0x7B, 0xEE, 0x24, 0x52, 0xF4, 0x83, 0x2F, 0x1B, 0x25, + 0x73, 0x7D, 0x57, 0xAE, 0x78, 0x42, 0xC7, 0x7F, 0x84, 0xDB, + 0x67, 0x7A, 0x81, 0xAB, 0xB5, 0xC4, 0x41, 0x38, 0xA0, 0x8D, + 0x8C, 0x50, 0x1F, 0x56, 0xF6, 0x9A, 0x2B, 0x57, 0x89, 0x20, + 0xA9, 0xE9, 0x1E, 0x55, 0x22, 0xD7, 0x88, 0xFA, 0x5D, 0x5F, + 0x51, 0x5C, 0x7C, 0x17, 0x6E, 0x1D, 0x1A, 0xE3, 0xE6, 0x24, + 0x67, 0xFE, 0xAA, 0xEF, 0x28, 0x25, 0xCA, 0xD7, 0x9B, 0x44, + 0x3A, 0x55, 0x6B, 0x2E, 0xDE, 0x7D, 0xD0, 0x1E, 0x16, 0xD6, + 0xA5, 0xA6, 0x97, 0xE0, 0x35, 0x90, 0x13, 0xD4, 0x16, 0x53, + 0xA2, 0x66, 0xCB, 0x12, 0xEE, 0xED, 0xA1, 0x42, 0x2C, 0x6A, + 0xF5, 0x13, 0x63, 0x5B, 0x2A, 0x0C, 0x8C, 0x3A, 0xC4, 0xAA, + 0x77, 0xFD, 0x03, 0x29, 0x47, 0x2E, 0x4E, 0xCE, 0x26, 0x2E, + 0xE2, 0x87, 0xD5, 0x49, 0xBE, 0xCE, 0x07, 0x71, 0x8F, 0xBB, + 0xDF, 0x5E, 0x73, 0x17, 0x28, 0x1B, 0x34, 0x55, 0xA2, 0xB1, + 0x99, 0x72, 0x90, 0xFD, 0xDF, 0xB3, 0xC7, 0x63, 0xFE, 0x1B, + 0x75, 0x6B, 0x6D, 0x73, 0xDE, 0x21, 0xD0, 0x18, 0xBE, 0x87, + 0xE8, 0xDA, 0x74, 0x1E, 0x78, 0x65, 0x6D, 0x30, 0x3B, 0xF1, + 0xEF, 0xE3, 0x32, 0xD6, 0xF8, 0x77, 0x31, 0xAB, 0x72, 0x72, + 0xF1, 0x43, 0x5C, 0x9F, 0xF1, 0x99, 0xA9, 0xB7, 0xD6, 0xEA, + 0x12, 0x4C, 0x96, 0x7E, 0x87, 0x76, 0xD2, 0xAB, 0x02, 0x26, + 0xC0, 0x00, 0x02, 0x91, 0x0F, 0xB9, 0x72, 0xF7, 0x06, 0x0A, + 0x2A, 0x92, 0x77, 0x84, 0x0C, 0xBE, 0x44, 0x6D, 0x58, 0x6C, + 0xBC, 0xE0, 0x19, 0x8A, 0xFC, 0x4C, 0x93, 0xDD, 0xB7, 0xC5, + 0x45, 0xBF, 0x0A, 0x66, 0x29, 0xEF, 0x95, 0x78, 0x07, 0x6D, + 0xD0, 0xAA, 0x6C, 0x32, 0xE9, 0xF8, 0xEA, 0x1A, 0x74, 0x79, + 0x51, 0x39, 0x25, 0xCB, 0x00, 0x7C, 0xD0, 0xE7, 0xBB, 0xC4, + 0x09, 0xC2, 0xFC, 0x0F, 0xA2, 0x29, 0x45, 0x30, 0x3F, 0x89, + 0x76, 0x36, 0xF2, 0x92, 0xAF, 0xAF, 0x60, 0xC3, 0x93, 0x3E, + 0x55, 0x6B, 0x87, 0xAE, 0xBF, 0x6E, 0x2C, 0x54, 0xFD, 0xAF, + 0x74, 0x4F, 0x0F, 0xAA, 0xC7, 0x4F, 0x4C, 0x6B, 0x18, 0xFE, + 0xC6, 0x84, 0x27, 0xC0, 0x78, 0xD2, 0xD9, 0xE3, 0x7B, 0x41, + 0x1C, 0x1C, 0xBF, 0xDA, 0xDF, 0xCC, 0x49, 0x41, 0xC0, 0xC0, + 0x65, 0xE0, 0x8F, 0x44, 0x19, 0xE4, 0x78, 0xAD, 0xCD, 0xC5, + 0x5A, 0x9D, 0x11, 0x22, 0x43, 0xD7, 0x6E, 0x39, 0xD5, 0x2B, + 0xA7, 0x73, 0x3F, 0x99, 0xA8, 0xA3, 0x02, 0x73, 0x99, 0xF0, + 0x62, 0x87, 0xF4, 0x8B, 0xD7, 0x4F, 0x47, 0x9C, 0x18, 0x72, + 0x98, 0xB0, 0x33, 0x1B, 0x5E, 0x29, 0x04, 0xEA, 0x71, 0x6B, + 0x45, 0xCB, 0xC0, 0x9E, 0x15, 0x6E, 0x92, 0xDA, 0x50, 0xC3, + 0x58, 0x07, 0x29, 0x5E, 0xC5, 0xBD, 0x3B, 0xCE, 0xAC, 0x11, + 0xE5, 0xBB, 0x3D, 0x7E, 0xB8, 0xC3, 0x1F, 0x94, 0x9F, 0xD9, + 0x63, 0x35, 0x56, 0x23, 0x45, 0xAF, 0x23, 0xF0, 0x0B, 0x7B, + 0xE3, 0xFB, 0x81, 0x2E, 0xD3, 0x20, 0xE3, 0x1D, 0x97, 0x84, + 0xC1, 0x88, 0x77, 0x87, 0x3C, 0xAB, 0xE9, 0x1E, 0x69, 0x04, + 0x7D, 0x7B, 0xE6, 0x6B, 0xDB, 0xE9, 0xF2, 0xB6, 0x66, 0x10, + 0x0F, 0x4D, 0x57, 0x3F, 0xF5, 0x3E, 0xDA, 0xEA, 0xBC, 0xD4, + 0x5B, 0xA1, 0x20, 0xB0, 0x69, 0xC0, 0x8A, 0xA1, 0x28, 0xC0, + 0xEF, 0xFE, 0x2D, 0x0B, 0xF8, 0x06, 0x23, 0x4B, 0x1C, 0x77, + 0x0A, 0x10, 0xBF, 0xA7, 0xD9, 0x24, 0x9E, 0xA2, 0x1B, 0x90, + 0x6C, 0xFD, 0x85, 0x3A, 0xD3, 0xC6, 0x39, 0xA7, 0xA2, 0x28, + 0xC5, 0xC1, 0x2F, 0xD2, 0x28, 0xDC, 0x4F, 0x63, 0x0D, 0x6B, + 0x54, 0xB4, 0x27, 0x95, 0xC3, 0xC1, 0xE0, 0x08, 0xB0, 0x9D, + 0x7F, 0x6C, 0xFE, 0xF5, 0x65, 0xCE, 0x0E, 0xCE, 0x24, 0xCD, + 0xAE, 0x4C, 0x0F, 0x82, 0x54, 0x48, 0xAF, 0x37, 0xAE, 0x64, + 0x31, 0x07, 0xEE, 0xE6, 0x6B, 0xEF, 0xAF, 0x7F, 0x2A, 0x07, + 0x2E, 0xB6, 0xD0, 0xAC, 0x70, 0x87, 0x19, 0x9E, 0xD3, 0xFB, + 0x89, 0xBD, 0xBA, 0xFF, 0xB9, 0x92, 0x4B, 0x25, 0x65, 0xA3, + 0x09, 0xCD, 0xFE, 0x32, 0x19, 0xF3, 0xF4, 0x05, 0xA4, 0x13, + 0xDF, 0x65, 0xA3, 0x4C, 0xE8, 0xF3, 0x3C, 0xA3, 0x11, 0x95, + 0xEA, 0xC3, 0x34, 0xCA, 0xC6, 0xB9, 0x34, 0x6B, 0x53, 0x18, + 0xCC, 0xF9, 0x44, 0x28, 0x1E, 0x90, 0x74, 0xA6, 0xB1, 0x59, + 0x4D, 0xAE, 0x18, 0x53, 0x1D, 0x60, 0xCF, 0xCC, 0x15, 0xDA, + 0x4E, 0x2B, 0x6F, 0x8F, 0x4E, 0x39, 0x89, 0xE3, 0x67, 0x05, + 0xB5, 0x9C, 0x36, 0x5B, 0x3C, 0xA0, 0x9F, 0x46, 0x24, 0xE7, + 0x61, 0x42, 0x1C, 0xA7, 0xD7, 0x27, 0x5B, 0x5C, 0xF5, 0xFD, + 0x5F, 0x03, 0x79, 0x5F, 0x36, 0xA0, 0x85, 0x13, 0x40, 0x48, + 0x8C, 0x44, 0xB4, 0x64, 0x54, 0x83, 0xD8, 0xB6, 0x83, 0xB8, + 0x4E, 0x46, 0xCF, 0x98, 0xA5, 0x1C, 0xAA, 0xF0, 0x03, 0xD6, + 0x26, 0x80, 0x0F, 0x2A, 0xC5, 0xF4, 0xD1, 0x28, 0x0C, 0x5F, + 0xF8, 0x63, 0x8D, 0x68, 0x26, 0x3A, 0xE5, 0x5D, 0xAE, 0x17, + 0x64, 0xF2, 0x60, 0x73, 0x6D, 0xBD, 0x75, 0x90, 0xD2, 0x50, + 0xC4, 0x9A, 0x4C, 0x3E, 0x4B, 0xAE, 0x57, 0xBE, 0xCD, 0x42, + 0xC1, 0xA7, 0xCB, 0xAD, 0x73, 0x15, 0xF6, 0x69, 0x36, 0xB5, + 0xC3, 0x15, 0x1D, 0xC0, 0x09, 0x4B, 0x6B, 0x4F, 0xA3, 0xD2, + 0xAF, 0x9E, 0xF4, 0x9A, 0xC1, 0x5F, 0xF5, 0x0A, 0x95, 0x93, + 0xA4, 0x57, 0xA9, 0x61, 0x8D, 0x98, 0xB1, 0x19, 0xCC, 0x95, + 0x02, 0x26, 0xC0, 0x00, 0x02, 0x6E, 0x4C, 0x0F, 0xB4, 0x2D, + 0xBC, 0x3A, 0x51, 0xAE, 0x16, 0xBA, 0xEC, 0x72, 0x04, 0x3E, + 0x8D, 0x3D, 0x4E, 0x0E, 0x29, 0x4B, 0x6F, 0x00, 0xF5, 0xE2, + 0x12, 0x0B, 0xAC, 0x73, 0x7E, 0xA5, 0x12, 0x8D, 0x59, 0x45, + 0x73, 0xC8, 0xB9, 0x57, 0xCB, 0x78, 0xAD, 0xA3, 0xBD, 0x95, + 0x18, 0x04, 0x86, 0xB9, 0xFE, 0x9F, 0xBF, 0x67, 0x03, 0x08, + 0xA9, 0x91, 0xF3, 0x71, 0x1A, 0x6C, 0xD2, 0x74, 0xAA, 0x40, + 0xCC, 0x30, 0x7D, 0x0B, 0x78, 0xEF, 0xC7, 0xDC, 0x95, 0xC3, + 0x29, 0x5D, 0x18, 0xBC, 0x38, 0x7C, 0xFE, 0x65, 0xEF, 0x44, + 0xF0, 0x61, 0x91, 0x3E, 0x59, 0x75, 0x96, 0x84, 0x75, 0xD9, + 0xA2, 0x99, 0xDB, 0xFA, 0x9B, 0x7D, 0x09, 0x06, 0x8D, 0xDA, + 0xCC, 0xA1, 0x6E, 0x2E, 0xDB, 0x12, 0x83, 0xA6, 0x2E, 0x9C, + 0xC8, 0x5A, 0xE9, 0xBB, 0xC3, 0x70, 0x16, 0x0C, 0x6E, 0x2A, + 0xDA, 0xD0, 0xDF, 0xF4, 0xAF, 0xAA, 0x42, 0x0A, 0x16, 0x8C, + 0x73, 0xAA, 0xAD, 0x75, 0x7B, 0xCC, 0x29, 0xB5, 0x18, 0xB9, + 0x58, 0xBF, 0xDB, 0x91, 0x44, 0x74, 0x25, 0x3E, 0x54, 0xC3, + 0x2D, 0x8A, 0x2E, 0x85, 0xD0, 0x92, 0x02, 0xAE, 0xA1, 0xF9, + 0x70, 0xC5, 0x33, 0x49, 0x57, 0xE1, 0x90, 0x48, 0x54, 0x73, + 0x04, 0xAD, 0x1E, 0x41, 0xE8, 0xD7, 0x24, 0xFE, 0x85, 0x83, + 0x47, 0x0F, 0x9C, 0x33, 0xF9, 0xF5, 0x10, 0xAD, 0x42, 0xFA, + 0x7B, 0xE7, 0x1C, 0x35, 0xB3, 0x8D, 0x0E, 0x2E, 0xD7, 0xCB, + 0x40, 0x32, 0x9C, 0x64, 0x3A, 0x68, 0x33, 0xF3, 0xBE, 0xD9, + 0xCD, 0xC9, 0x73, 0xEB, 0x67, 0x6E, 0x52, 0x25, 0x2F, 0xD9, + 0x7A, 0x93, 0x8B, 0x1D, 0x9D, 0xB2, 0xAF, 0xF3, 0xEE, 0x6F, + 0xB5, 0xC7, 0x8F, 0xD5, 0x4F, 0xC9, 0x7C, 0xAC, 0x05, 0x9A, + 0x16, 0x82, 0x04, 0xC4, 0xF5, 0x47, 0xD7, 0x61, 0xC7, 0xBC, + 0x8D, 0x76, 0xA9, 0xFA, 0xA6, 0x17, 0x32, 0x3A, 0x2C, 0x93, + 0x4D, 0x0B, 0x57, 0x50, 0xF5, 0xD8, 0xE6, 0xB2, 0x52, 0x4F, + 0xE5, 0x1F, 0xDB, 0xA0, 0x17, 0xEF, 0x44, 0x9A, 0x8D, 0xBF, + 0x8D, 0xB4, 0x66, 0x11, 0xF2, 0xB1, 0x51, 0x50, 0xB4, 0xDE, + 0xE0, 0x30, 0x5B, 0x1F, 0x92, 0xAC, 0x30, 0x43, 0xB3, 0x1F, + 0x32, 0xDC, 0x84, 0x2F, 0x29, 0xE9, 0x78, 0xBC, 0x5A, 0xA2, + 0x9A, 0xA8, 0xFC, 0xE2, 0xB4, 0xE7, 0x8C, 0xCC, 0x65, 0xA9, + 0x37, 0x85, 0xD8, 0x0B, 0xB3, 0xA3, 0x4F, 0x28, 0xBE, 0x4D, + 0x45, 0x97, 0xAA, 0x2E, 0xEC, 0x6D, 0x4C, 0x9E, 0x19, 0x5F, + 0xD1, 0x47, 0x87, 0x8A, 0x76, 0xCF, 0x20, 0xCC, 0xDC, 0xC5, + 0x37, 0xDD, 0x45, 0xE8, 0x13, 0xFD, 0x72, 0x92, 0x7E, 0x97, + 0xA4, 0xA7, 0x58, 0xC1, 0x0E, 0xB6, 0x9E, 0x20, 0xCC, 0xD3, + 0x5F, 0x94, 0x25, 0xD3, 0xB8, 0xB0, 0x51, 0x82, 0x45, 0x64, + 0x4B, 0x6D, 0xCB, 0x9F, 0xC6, 0x5F, 0xDD, 0x1D, 0x1B, 0xB0, + 0x7D, 0xEB, 0xEC, 0x85, 0xB0, 0x90, 0x36, 0xE0, 0xE5, 0x5F, + 0x66, 0xA3, 0x69, 0x72, 0x2C, 0x35, 0x52, 0x45, 0x8A, 0xD9, + 0x31, 0xCB, 0xD9, 0xDD, 0xF0, 0x62, 0x6A, 0x4B, 0x47, 0xEF, + 0x13, 0xD7, 0x65, 0x17, 0xC4, 0xE9, 0xD1, 0xA3, 0xF4, 0x5E, + 0x17, 0x73, 0x4C, 0xA5, 0x81, 0xD7, 0xBD, 0xB3, 0x34, 0x98, + 0x61, 0x01, 0x50, 0x1D, 0x7D, 0x7A, 0x82, 0x38, 0x93, 0x9F, + 0x0A, 0xAC, 0x42, 0x5B, 0x10, 0x4C, 0x57, 0x10, 0x4A, 0x97, + 0xD3, 0xCC, 0x8F, 0x23, 0xD1, 0xA6, 0xCB, 0xAD, 0x47, 0x8F, + 0x41, 0x24, 0x2B, 0xEB, 0xB9, 0x0B, 0x71, 0x1C, 0x27, 0x31, + 0x91, 0x21, 0x77, 0xA2, 0x01, 0x2D, 0x6F, 0x9B, 0x99, 0x5F, + 0xAC, 0xD4, 0x8E, 0x1D, 0xBB, 0x2C, 0xA3, 0xA1, 0xA2, 0xC3, + 0x2A, 0xAD, 0x6B, 0xA4, 0x62, 0xAA, 0xAE, 0xEA, 0xEE, 0x10, + 0x30, 0xB3, 0x9E, 0x2A, 0x13, 0x09, 0xF8, 0xC4, 0x2B, 0x8C, + 0xE1, 0x51, 0x62, 0xE7, 0x5D, 0xE8, 0x00, 0x50, 0x46, 0x7E, + 0xC7, 0x9A, 0x3F, 0x21, 0xD9, 0x0C, 0xB3, 0xA7, 0x2E, 0x5F, + 0x4B, 0x42, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x12, 0xA7, 0x07, + 0x49, 0x33, 0x98, 0x05, 0x3D, 0xD0, 0x14, 0xD2, 0x03, 0xA9, + 0xA5, 0x66, 0x6B, 0x53, 0x43, 0x97, 0x83, 0x21, 0x8F, 0x46, + 0x67, 0x3C, 0x86, 0xDB, 0x7B, 0xBA, 0xD2, 0xC5, 0xB4, 0x09, + 0x0F, 0x2D, 0xD3, 0x4E, 0xD2, 0xB7, 0xFC, 0x75, 0x52, 0x16, + 0x8A, 0x56, 0x5A, 0xCC, 0xE6, 0xFE, 0x5C, 0xE8, 0xAE, 0x48, + 0x7F, 0x81, 0xF2, 0x46, 0x00, 0xE5, 0x53, 0xAF, 0xC7, 0x01, + 0x12, 0x9A, 0xF9, 0xDC, 0x96, 0x79, 0xC6, 0x61, 0xC6, 0xAC, + 0xCE, 0x0B, 0x6C, 0x9F, 0xFD, 0x16, 0xCA, 0xD1, 0xD6, 0xAB, + 0xE4, 0xCB, 0x64, 0x88, 0xF7, 0x17, 0x7F, 0xCD, 0xBB, 0x8F, + 0xF9, 0x5C, 0x75, 0x7C, 0x3D, 0xBE, 0x03, 0x68, 0x30, 0xA8, + 0xC7, 0x82, 0x62, 0xDD, 0x5A, 0x42, 0x3D, 0x8D, 0x02, 0xD1, + 0x68, 0xF2, 0x04, 0x0B, 0xFA, 0xC2, 0x23, 0xB9, 0x26, 0xAA, + 0x5F, 0x43, 0x7D, 0xE5, 0xD2, 0x97, 0xB8, 0xD5, 0x6F, 0xBE, + 0x56, 0xC6, 0xCA, 0xE7, 0x56, 0xDA, 0x14, 0x4A, 0xA6, 0x35, + 0x3F, 0xBF, 0xBC, 0x9D, 0xCD, 0x51, 0x55, 0x98, 0xAB, 0xC0, + 0x42, 0xC8, 0x7D, 0x67, 0xB3, 0xDD, 0x2B, 0x6B, 0xA0, 0x06, + 0x9F, 0x13, 0x79, 0xBC, 0xE2, 0xC8, 0x9E, 0xC3, 0xFF, 0x94, + 0x9E, 0x3D, 0x60, 0xAE, 0xB3, 0x28, 0x44, 0xC5, 0xE1, 0xD8, + 0x40, 0x7F, 0xC0, 0x8F, 0x93, 0xFC, 0xDA, 0xEC, 0x70, 0x14, + 0xB1, 0x07, 0xA1, 0x21, 0x6D, 0xA2, 0xA3, 0xEF, 0x80, 0xF1, + 0xC4, 0xCC, 0xA1, 0x77, 0xD9, 0xA3, 0xD9, 0x31, 0xFB, 0xC5, + 0xE5, 0xDE, 0xC1, 0xF2, 0x6F, 0xFC, 0x73, 0x35, 0xC4, 0x1D, + 0x2C, 0x15, 0x57, 0x64, 0x57, 0x4A, 0x0D, 0x4F, 0xCB, 0xD3, + 0x3E, 0x12, 0x82, 0x5C, 0xFC, 0xED, 0x7B, 0xA1, 0x3F, 0x72, + 0x1E, 0x6B, 0x12, 0x6A, 0xB9, 0x55, 0xD2, 0xC3, 0x04, 0x52, + 0x01, 0xBB, 0x54, 0x20, 0x0A, 0xA5, 0xDA, 0xDD, 0x2D, 0x56, + 0xF4, 0xD0, 0x08, 0x62, 0x1E, 0x68, 0x30, 0x40, 0x57, 0x8A, + 0xC2, 0xDD, 0xBF, 0x0D, 0x7B, 0x28, 0xE0, 0x82, 0x1A, 0x3F, + 0xDC, 0xEA, 0x07, 0xC4, 0x32, 0x74, 0x14, 0x18, 0x9C, 0x00, + 0x9C, 0x91, 0xC0, 0x7A, 0x0A, 0x18, 0x89, 0xAD, 0xA8, 0x3D, + 0x42, 0x21, 0x0F, 0x08, 0x8D, 0xA4, 0xD5, 0xA7, 0x08, 0x09, + 0x3C, 0x21, 0x7E, 0x4E, 0x17, 0xB9, 0x1A, 0x80, 0x22, 0x45, + 0x33, 0x43, 0x24, 0xDD, 0xC4, 0x66, 0xD2, 0xB4, 0x4E, 0x40, + 0xD5, 0x5F, 0xEA, 0x86, 0x9F, 0x8B, 0x41, 0x9D, 0xD0, 0x96, + 0xC9, 0x64, 0x32, 0x39, 0xA1, 0x89, 0x56, 0x7E, 0x1D, 0x22, + 0x08, 0x08, 0xB5, 0x60, 0x1F, 0x52, 0x41, 0xA4, 0x8F, 0xC0, + 0x52, 0x6B, 0xA7, 0xBB, 0x52, 0x0E, 0x96, 0xEE, 0x62, 0x62, + 0x1A, 0xCF, 0x4C, 0x65, 0x59, 0x32, 0x2D, 0x3C, 0x1D, 0x40, + 0x57, 0xB0, 0xE9, 0xF2, 0xBA, 0x04, 0xD2, 0xBE, 0x22, 0xA9, + 0x93, 0x8E, 0xC2, 0x32, 0x06, 0x20, 0xDC, 0x9F, 0xE5, 0xC2, + 0x57, 0xFC, 0xC5, 0xDE, 0xE7, 0xD3, 0xCA, 0xB6, 0xD8, 0x85, + 0xB2, 0xE1, 0xAD, 0x23, 0x47, 0x02, 0x3F, 0xD7, 0xBD, 0x51, + 0x2A, 0x6B, 0x33, 0x2D, 0x23, 0x6D, 0xD5, 0x72, 0x1F, 0xEC, + 0x8F, 0x7F, 0x1B, 0x22, 0x2D, 0x9E, 0x44, 0x58, 0xE0, 0xA3, + 0x50, 0x54, 0xCF, 0x6B, 0x5E, 0x59, 0x7A, 0xF0, 0xDA, 0x2E, + 0x9C, 0xC4, 0xD3, 0xD9, 0x83, 0x56, 0xBB, 0x09, 0x58, 0xFF, + 0x00, 0xDD, 0xDA, 0x57, 0x5C, 0xC3, 0xED, 0x10, 0x6E, 0xD6, + 0xD0, 0xF0, 0xB9, 0xD1, 0x2C, 0x1E, 0x4E, 0x33, 0xA7, 0x44, + 0x9C, 0x87, 0xB2, 0x91, 0x16, 0x2C, 0x44, 0x1E, 0x66, 0x79, + 0x06, 0x12, 0x26, 0xB6, 0x36, 0x1F, 0xBA, 0x56, 0x9F, 0xAB, + 0x64, 0x63, 0xE4, 0x90, 0x75, 0x72, 0xF9, 0x35, 0x77, 0x2B, + 0x38, 0xE5, 0x4F, 0x29, 0xF1, 0x4C, 0xD8, 0xBD, 0x20, 0x60, + 0x65, 0x26, 0x57, 0xCE, 0x52, 0x4B, 0x18, 0xD4, 0xDF, 0xCE, + 0xC0, 0x78, 0x60, 0x83, 0xD4, 0xDF, 0xE9, 0xA2, 0x61, 0x37, + 0x78, 0x7D, 0xEB, 0xE5, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x47, + 0xA5, 0x8E, 0xA4, 0x38, 0x2C, 0xDC, 0x61, 0xFB, 0xD1, 0x29, + 0xFD, 0x30, 0xA5, 0xEE, 0xB0, 0x2F, 0xF6, 0x53, 0x4B, 0x4E, + 0xE9, 0x26, 0x67, 0x28, 0xC0, 0x06, 0x59, 0x13, 0x88, 0xF8, + 0x9B, 0xE8, 0x6B, 0x9E, 0x5A, 0xCF, 0x8D, 0x8D, 0xE1, 0x80, + 0x1A, 0xE1, 0x4A, 0x59, 0x92, 0x6A, 0x57, 0x38, 0x79, 0x1E, + 0x5D, 0xA4, 0x35, 0xA5, 0xD3, 0x80, 0x41, 0x97, 0x69, 0xB7, + 0xDF, 0xE8, 0x07, 0xFA, 0xA6, 0x64, 0xFD, 0xB2, 0xD0, 0x66, + 0xB4, 0x35, 0x52, 0xCC, 0xC9, 0x82, 0xCF, 0xFA, 0xB3, 0xE0, + 0xE6, 0x96, 0x35, 0xEF, 0xD5, 0xF6, 0xA1, 0x0B, 0xAD, 0xE0, + 0x50, 0x7D, 0x9B, 0x36, 0x8D, 0xD2, 0x6E, 0x27, 0x14, 0x2D, + 0x6D, 0xCE, 0xC2, 0xF8, 0xDA, 0x64, 0xDC, 0xFD, 0xC8, 0x79, + 0x72, 0x00, 0xE3, 0xF9, 0x3F, 0x40, 0x0D, 0x0F, 0x40, 0x3A, + 0xE3, 0xFE, 0xEA, 0x93, 0x18, 0x7F, 0x2D, 0xFA, 0x7C, 0x6B, + 0xCB, 0x45, 0x8C, 0xD5, 0x8E, 0xE3, 0x95, 0x4C, 0xF9, 0x60, + 0x83, 0x8E, 0x07, 0xC0, 0x17, 0xE9, 0x6C, 0xAF, 0x2C, 0x08, + 0x04, 0xF5, 0x8B, 0xB7, 0xB8, 0x09, 0xAD, 0x91, 0x02, 0x9A, + 0x28, 0x25, 0xE7, 0x80, 0x5C, 0xCB, 0x69, 0xA0, 0xDA, 0x43, + 0x4F, 0x4C, 0x4A, 0xA1, 0xCB, 0x45, 0x0E, 0x2F, 0x87, 0x77, + 0x43, 0x7E, 0x0E, 0x42, 0xE7, 0x21, 0x2B, 0x73, 0x90, 0x21, + 0x7B, 0x9B, 0x87, 0xEC, 0x27, 0x76, 0xFF, 0x9F, 0xEB, 0x79, + 0xF9, 0x70, 0xE6, 0x73, 0x51, 0x4B, 0x8D, 0xE4, 0xB6, 0x76, + 0xFF, 0x23, 0x71, 0xD9, 0x87, 0x43, 0x29, 0xE4, 0xA0, 0xDE, + 0xB7, 0xCF, 0x92, 0x03, 0x84, 0x07, 0x17, 0xA1, 0xE6, 0x7B, + 0x43, 0x14, 0xA3, 0x30, 0xC0, 0x1B, 0x44, 0x91, 0xCF, 0x80, + 0x48, 0x92, 0x2B, 0x6D, 0x59, 0x8E, 0x63, 0x8C, 0xE8, 0xC3, + 0xA9, 0x04, 0x33, 0x3F, 0x75, 0x6A, 0x2B, 0x7B, 0xEC, 0x74, + 0x26, 0xAD, 0x34, 0x68, 0xB9, 0x9F, 0x63, 0xEE, 0xEA, 0x42, + 0x0D, 0xC7, 0x24, 0x7B, 0xD4, 0x5E, 0x5A, 0x91, 0xF1, 0x41, + 0x2E, 0x6B, 0x0D, 0xB9, 0x75, 0xCE, 0x51, 0x1E, 0x6E, 0xF2, + 0x6B, 0x9C, 0xD4, 0xBD, 0xAF, 0x54, 0x63, 0x1A, 0xA0, 0x29, + 0x65, 0x22, 0x04, 0x9D, 0xE2, 0x6F, 0x37, 0x4B, 0xC2, 0xC2, + 0x62, 0x1B, 0x94, 0xE0, 0xF9, 0xC8, 0xB0, 0x94, 0x43, 0x29, + 0x0D, 0x4F, 0x23, 0x4A, 0xBA, 0x83, 0x15, 0x97, 0x96, 0xC8, + 0x0A, 0x85, 0xD2, 0x80, 0x8B, 0x0C, 0x16, 0x57, 0x32, 0xCA, + 0xA4, 0xF6, 0x20, 0xB5, 0x49, 0x30, 0xCC, 0xD3, 0x1C, 0xAB, + 0xE0, 0xAE, 0x52, 0x7B, 0x71, 0x40, 0x80, 0xAC, 0x30, 0x78, + 0xEE, 0x5A, 0xD3, 0x82, 0x3F, 0x51, 0x34, 0xE8, 0x38, 0xD4, + 0x8D, 0x09, 0xEB, 0xDC, 0x9E, 0x82, 0xF7, 0xE2, 0xAA, 0xCD, + 0x2D, 0x17, 0x0C, 0x08, 0x22, 0xAF, 0xED, 0xE4, 0xC0, 0xC1, + 0xBB, 0x9C, 0x47, 0xC1, 0x23, 0x81, 0x03, 0x85, 0xDD, 0x00, + 0x5C, 0x4D, 0x7F, 0xF1, 0x02, 0xF8, 0xA9, 0xA1, 0x8E, 0xB1, + 0xCD, 0xFC, 0x6F, 0xC5, 0x0D, 0x37, 0xD9, 0x83, 0x15, 0x23, + 0x14, 0x03, 0x54, 0x37, 0xFC, 0xAC, 0xB6, 0xC8, 0x0A, 0x47, + 0x3F, 0x22, 0x6F, 0xD7, 0xFA, 0xBB, 0x8D, 0x17, 0xB2, 0x7C, + 0x0F, 0x65, 0xB4, 0xA2, 0x3A, 0x5F, 0x55, 0x34, 0xEC, 0xCA, + 0x89, 0xDD, 0xD4, 0x44, 0x77, 0x30, 0x9A, 0x20, 0x6A, 0x1A, + 0x9D, 0xBE, 0x39, 0x25, 0x2E, 0xE2, 0x0C, 0xDD, 0xE0, 0x50, + 0x8F, 0xD7, 0x38, 0x01, 0xB1, 0x25, 0xC1, 0xFD, 0x06, 0xD0, + 0x60, 0xC9, 0xEB, 0x1D, 0x77, 0x6D, 0xA2, 0x18, 0xB2, 0x0B, + 0x03, 0xE6, 0xF7, 0x07, 0x51, 0xFC, 0xAF, 0xE9, 0xD4, 0xFC, + 0x80, 0x69, 0x1C, 0xE1, 0x82, 0x96, 0x39, 0x37, 0xC1, 0xD3, + 0xB1, 0x81, 0x62, 0xB7, 0x20, 0x7F, 0xDF, 0xB7, 0x84, 0xD2, + 0xCC, 0xFB, 0x7E, 0x90, 0xBB, 0x05, 0x1B, 0x81, 0xA2, 0xE0, + 0x66, 0x11, 0x8A, 0x37, 0x93, 0x0F, 0x67, 0x81, 0x77, 0x03, + 0xA6, 0xE2, 0x52, 0xB6, 0x0F, 0x9A, 0x02, 0x26, 0xC0, 0x00, + 0x02, 0x1D, 0x9D, 0x63, 0xD2, 0x5B, 0xB0, 0x79, 0x8A, 0xF4, + 0x7F, 0x08, 0x9B, 0x5E, 0xAB, 0x6E, 0xD1, 0xCC, 0x2B, 0x7C, + 0xFF, 0x0D, 0x0E, 0xDD, 0x5F, 0xAA, 0x4C, 0x53, 0x45, 0x53, + 0x48, 0xCD, 0xCD, 0xF7, 0xBA, 0x5B, 0xB9, 0x84, 0xBB, 0x00, + 0xC2, 0xF0, 0xFB, 0x30, 0x5F, 0x04, 0x4E, 0x25, 0x4C, 0x06, + 0x03, 0x8D, 0xC5, 0x37, 0xA6, 0x9D, 0x1C, 0xD8, 0x13, 0xA7, + 0x96, 0xBE, 0xED, 0x22, 0xD7, 0xBA, 0x9F, 0x4C, 0x2E, 0xF9, + 0xD0, 0x5B, 0xBB, 0xF8, 0xB8, 0x0A, 0xF3, 0xEC, 0x31, 0x3F, + 0x84, 0x6E, 0x3A, 0x12, 0x8B, 0x6A, 0x2E, 0x28, 0xCE, 0xB8, + 0x1A, 0xC6, 0xE6, 0x4A, 0xD9, 0x74, 0x04, 0x24, 0xD8, 0x79, + 0x8D, 0x62, 0x0C, 0xB0, 0xAE, 0xAF, 0x67, 0xB4, 0xA1, 0x3D, + 0x93, 0x1D, 0xA2, 0x52, 0x98, 0x3F, 0x57, 0x73, 0x94, 0xB6, + 0x94, 0xBD, 0x0F, 0x42, 0x6A, 0x64, 0x7B, 0x17, 0xAC, 0x8D, + 0x46, 0xD0, 0xE4, 0x1B, 0x8C, 0x56, 0xB6, 0x47, 0xCB, 0xFD, + 0x56, 0x61, 0x6E, 0xA0, 0xBF, 0x6B, 0x8E, 0x68, 0x05, 0x55, + 0xA4, 0xB3, 0x8C, 0x76, 0x48, 0x73, 0x4C, 0x8D, 0x9D, 0xA2, + 0xA0, 0xA1, 0xFB, 0xD0, 0x33, 0x32, 0x39, 0xD2, 0x10, 0x1C, + 0x3C, 0x93, 0xC9, 0xCA, 0x6A, 0x6E, 0x7C, 0xB6, 0xF1, 0x03, + 0xF3, 0x45, 0x51, 0x05, 0x48, 0x30, 0xF0, 0xC6, 0x84, 0xFD, + 0x4E, 0x3B, 0x03, 0xE0, 0x62, 0xB8, 0x53, 0x55, 0xB6, 0xB8, + 0x02, 0x7C, 0xB9, 0xD5, 0x5C, 0xA2, 0x9B, 0x97, 0x8A, 0xA4, + 0xDF, 0x42, 0xEB, 0x91, 0x2C, 0x98, 0x82, 0xA9, 0xAE, 0xB0, + 0x13, 0xF6, 0x6E, 0x90, 0x42, 0xFE, 0xD3, 0xAA, 0x1E, 0xBA, + 0x69, 0xFC, 0xF8, 0x20, 0xEA, 0x5D, 0xA8, 0xFE, 0x64, 0x56, + 0x26, 0x4C, 0x6C, 0x69, 0x8F, 0xAC, 0x30, 0xCF, 0xAE, 0x8B, + 0xD5, 0x63, 0x10, 0xDD, 0xCE, 0x6E, 0x0C, 0xAB, 0x31, 0x46, + 0xDF, 0x8A, 0x33, 0x28, 0x8A, 0x1C, 0xEB, 0xBE, 0xAA, 0x71, + 0x44, 0x5C, 0x89, 0xEA, 0x00, 0x34, 0x23, 0xEB, 0x18, 0x83, + 0x7F, 0xB1, 0x9B, 0x3A, 0xBF, 0x08, 0x68, 0xB6, 0xC8, 0xE2, + 0xD8, 0x2D, 0x5E, 0xA2, 0x99, 0xB9, 0xBC, 0xF8, 0x31, 0xD1, + 0xFD, 0x31, 0xD4, 0x32, 0x05, 0x58, 0x5C, 0xFB, 0xCD, 0x8C, + 0xFF, 0x75, 0x99, 0x93, 0xC8, 0x0C, 0xE8, 0xE8, 0x60, 0x11, + 0xB8, 0x5F, 0x15, 0xB5, 0x89, 0x47, 0xE1, 0x1C, 0x23, 0x1B, + 0x8E, 0x56, 0x02, 0xD3, 0x5F, 0xBD, 0xA9, 0x9F, 0x67, 0x06, + 0xCA, 0x0C, 0x6E, 0x9C, 0xFB, 0x2D, 0x3A, 0xE3, 0xF6, 0x2C, + 0x72, 0x86, 0xCD, 0x68, 0xAC, 0x7B, 0x22, 0xA3, 0x01, 0x15, + 0x50, 0xB7, 0xA0, 0x05, 0x88, 0xD0, 0xDF, 0xBD, 0xDA, 0x3B, + 0xC4, 0xFF, 0x40, 0xA1, 0x46, 0x55, 0x28, 0xB3, 0x0C, 0x1E, + 0xF8, 0xE9, 0x0A, 0x39, 0xD1, 0x66, 0xDF, 0x5B, 0x2B, 0x2C, + 0xCA, 0xA5, 0x36, 0x32, 0x0D, 0xAC, 0x8E, 0xDF, 0x75, 0x9A, + 0xE5, 0x8B, 0xE5, 0x99, 0x6B, 0xD6, 0xB7, 0x83, 0x6B, 0xFE, + 0xEA, 0xC9, 0x71, 0xB5, 0xB9, 0xAE, 0xBE, 0x74, 0xB6, 0x58, + 0x28, 0x06, 0x23, 0xCF, 0x8D, 0x09, 0xBC, 0xE3, 0x18, 0x6C, + 0xFA, 0x53, 0x02, 0xE8, 0x3D, 0x44, 0xB3, 0xFE, 0xB3, 0x11, + 0x70, 0x10, 0xDF, 0xC3, 0x93, 0x64, 0x0F, 0x19, 0x35, 0xF0, + 0x82, 0x3A, 0xE3, 0x04, 0xE3, 0x1D, 0xFE, 0x52, 0xE8, 0x52, + 0xA1, 0x7B, 0x19, 0x23, 0x8E, 0x3F, 0x5D, 0x16, 0x60, 0xCB, + 0x13, 0x1A, 0x26, 0x6D, 0xDB, 0x82, 0xEB, 0x72, 0xEE, 0x76, + 0x77, 0x36, 0xEC, 0xEE, 0x09, 0x90, 0xAF, 0x35, 0x25, 0x5A, + 0x29, 0x61, 0x7A, 0xE6, 0x8C, 0x6C, 0x2A, 0x3B, 0x3B, 0xC4, + 0xC5, 0xD4, 0xCF, 0x41, 0x40, 0x04, 0xF3, 0x0F, 0x4B, 0x1B, + 0x99, 0x7D, 0xCF, 0x1F, 0xC5, 0xEB, 0xC5, 0xF5, 0xA1, 0x16, + 0xA2, 0x2A, 0x2E, 0xD5, 0x78, 0xC5, 0xAD, 0x9C, 0x48, 0x76, + 0xF2, 0x58, 0xDE, 0x68, 0x19, 0x58, 0x8C, 0xEA, 0xF5, 0xD0, + 0x54, 0x4F, 0x73, 0x60, 0x92, 0x71, 0x27, 0xF7, 0x02, 0x26, + 0xC0, 0x00, 0x02, 0x24, 0xC2, 0xE1, 0xD7, 0x77, 0x1A, 0x4D, + 0x5F, 0x7B, 0xC6, 0xC7, 0x52, 0x42, 0x9C, 0x26, 0xBE, 0x75, + 0x2E, 0x37, 0x00, 0xD8, 0x2C, 0xEF, 0x37, 0xC2, 0xF8, 0x88, + 0x89, 0xBA, 0x60, 0x35, 0xCE, 0xD5, 0xC4, 0x3D, 0x00, 0x6A, + 0xF1, 0xE1, 0x66, 0x4C, 0xFF, 0x79, 0xC7, 0xDF, 0x04, 0x99, + 0x02, 0xEB, 0x0E, 0x9D, 0xBE, 0x2C, 0x06, 0xB8, 0xE1, 0xC8, + 0xAE, 0xC4, 0xE8, 0xB7, 0xE7, 0x66, 0xEF, 0x01, 0x72, 0x45, + 0xB2, 0xBF, 0x69, 0xF7, 0xA2, 0x72, 0xEC, 0x91, 0x82, 0x9D, + 0xE5, 0x91, 0x9A, 0x6D, 0x4D, 0x0D, 0x29, 0x58, 0xE3, 0xA2, + 0xBB, 0x4F, 0x7B, 0xED, 0xA6, 0xEC, 0x0D, 0x91, 0xF6, 0xE7, + 0x68, 0x61, 0xDF, 0x8A, 0x1A, 0x5A, 0x2A, 0x21, 0x51, 0x80, + 0x31, 0xD5, 0xD6, 0xFB, 0xE5, 0x0D, 0x01, 0x49, 0x22, 0x05, + 0xEE, 0xA2, 0x7A, 0xF6, 0x6C, 0xCD, 0x9D, 0x95, 0x79, 0x7E, + 0x9D, 0x22, 0x91, 0x59, 0x31, 0x80, 0x55, 0xC9, 0x66, 0xC8, + 0x33, 0x36, 0x56, 0x65, 0xCC, 0x26, 0x88, 0xE7, 0xC0, 0x01, + 0xF4, 0x22, 0xF9, 0xE6, 0xF1, 0x18, 0x69, 0xAB, 0x93, 0x80, + 0x95, 0xBF, 0xA4, 0xB7, 0x7F, 0x56, 0x7D, 0xC0, 0xEE, 0xA7, + 0x01, 0x5B, 0x9B, 0xA6, 0x80, 0x5A, 0x17, 0x31, 0xC8, 0x93, + 0xF6, 0x6F, 0xFD, 0x27, 0x9A, 0x09, 0xB8, 0x48, 0x04, 0xD5, + 0x1F, 0xBB, 0x8B, 0xED, 0xB7, 0x08, 0x43, 0xBF, 0x82, 0xB1, + 0xAF, 0xD9, 0x35, 0x03, 0xE8, 0x36, 0xB4, 0xCD, 0x74, 0x74, + 0x30, 0x85, 0x73, 0x1F, 0x51, 0xED, 0xA5, 0xFD, 0x64, 0xFC, + 0xF1, 0x22, 0x21, 0x36, 0x3C, 0x5E, 0x46, 0x74, 0x9D, 0x94, + 0x2C, 0x0F, 0xDF, 0x2B, 0x6E, 0x5E, 0xA8, 0x7C, 0x80, 0xA4, + 0x4C, 0xE4, 0x1A, 0xE2, 0x80, 0x29, 0x5F, 0x85, 0x76, 0x95, + 0xD0, 0x2D, 0x26, 0x50, 0xB2, 0x14, 0x37, 0xA3, 0x3A, 0x4E, + 0xB9, 0x68, 0xCB, 0x1D, 0x9A, 0x9B, 0x33, 0xD0, 0x3D, 0x1B, + 0x0F, 0x3F, 0xA2, 0x95, 0xE0, 0x80, 0xA1, 0x39, 0x03, 0x14, + 0x5F, 0x21, 0x27, 0x54, 0xB5, 0x4D, 0x1F, 0x7A, 0x9A, 0x1E, + 0xB1, 0xC9, 0x63, 0xBE, 0xEC, 0x0C, 0xC1, 0x16, 0x80, 0x0F, + 0xFD, 0x3B, 0x3F, 0xFD, 0x97, 0xF8, 0x4F, 0xD9, 0xFE, 0xC7, + 0x6A, 0xE5, 0x40, 0x5B, 0xB8, 0x50, 0xA8, 0x94, 0x6F, 0x9F, + 0xD8, 0x23, 0xE8, 0xBC, 0x16, 0x9B, 0xF8, 0xC5, 0x0C, 0x48, + 0x28, 0x1B, 0x51, 0x8B, 0x1C, 0x9F, 0x37, 0x97, 0x6B, 0x0B, + 0x1C, 0x2B, 0xCF, 0x7F, 0x9E, 0xC4, 0x54, 0x8F, 0x4D, 0xBF, + 0x43, 0xBB, 0x40, 0x20, 0x79, 0x1F, 0x29, 0xF2, 0x43, 0x65, + 0x0D, 0xC8, 0x16, 0xAC, 0xE4, 0xF3, 0x82, 0x67, 0x01, 0xD9, + 0x19, 0x80, 0xAD, 0x16, 0x1F, 0xF6, 0xFA, 0xD3, 0xD8, 0x74, + 0x6F, 0xE5, 0x00, 0x8E, 0x77, 0x95, 0x51, 0x83, 0xD4, 0xF2, + 0x8B, 0x79, 0x2D, 0xBA, 0xB1, 0x10, 0x0C, 0x0F, 0xCC, 0x7D, + 0x24, 0x7A, 0xF5, 0xDF, 0x54, 0x54, 0xC0, 0xAF, 0x80, 0x3D, + 0x7E, 0x9C, 0x8F, 0x27, 0xA7, 0x0A, 0xE4, 0x8C, 0xB7, 0x5C, + 0x61, 0xF4, 0xAD, 0xB3, 0xD8, 0xA9, 0x1B, 0xEC, 0x13, 0xCB, + 0xD8, 0xD3, 0x81, 0xBA, 0x9D, 0xCA, 0xD9, 0xAE, 0xC4, 0x43, + 0x69, 0xF4, 0xDE, 0xF9, 0xE0, 0xFE, 0x5D, 0x53, 0x6D, 0xDA, + 0x5F, 0xED, 0x5F, 0x30, 0x81, 0x2C, 0xDE, 0x92, 0x04, 0xDE, + 0x94, 0xBB, 0x45, 0xAF, 0x14, 0x84, 0xC9, 0xE3, 0xBD, 0xBD, + 0x7F, 0x52, 0xE9, 0x6B, 0x34, 0xCA, 0x06, 0x3A, 0xE1, 0x79, + 0x22, 0x3C, 0xA8, 0x34, 0xED, 0x7E, 0x26, 0x18, 0x84, 0xDB, + 0x92, 0x48, 0xFD, 0xD6, 0x82, 0x04, 0x1D, 0x82, 0x1A, 0xA6, + 0x28, 0x74, 0x31, 0xA5, 0x74, 0x1F, 0xD9, 0x0F, 0xF2, 0xC8, + 0x4C, 0x38, 0x8F, 0xAF, 0x2A, 0xE0, 0x5F, 0xD6, 0xA4, 0x1C, + 0xE3, 0xF8, 0x70, 0xD5, 0x4C, 0xF8, 0x3C, 0x92, 0x0A, 0x01, + 0xEF, 0xB7, 0xEA, 0x57, 0xA5, 0x88, 0x4C, 0x10, 0x68, 0x99, + 0xC8, 0x4F, 0x1D, 0x67, 0x8E, 0x43, 0x7D, 0x3D, 0x5E, 0x20, + 0x02, 0x26, 0xC0, 0x00, 0x02, 0x68, 0x4F, 0x5F, 0x8D, 0xC4, + 0x7F, 0x74, 0xCD, 0xFE, 0xFB, 0x21, 0x22, 0x03, 0x06, 0xFA, + 0x2E, 0x4C, 0xFF, 0x35, 0xBB, 0x9E, 0x93, 0x44, 0x35, 0x8A, + 0xFF, 0x97, 0x39, 0x36, 0x8D, 0x53, 0x4D, 0xFA, 0x04, 0xA8, + 0x98, 0x13, 0x9C, 0xAA, 0x87, 0x0D, 0x8B, 0x50, 0x0D, 0x9C, + 0xB1, 0xAC, 0x4C, 0x59, 0x9B, 0xA2, 0xE4, 0x4C, 0xFC, 0x46, + 0xC5, 0xA6, 0x00, 0x4A, 0xA8, 0xD3, 0x24, 0x40, 0x9E, 0x48, + 0x8F, 0xC0, 0x8C, 0x0E, 0x16, 0x02, 0x3C, 0xF5, 0x12, 0x3D, + 0x97, 0xCE, 0xDE, 0x11, 0xBE, 0x46, 0xE8, 0x8F, 0x15, 0x3B, + 0xB3, 0x1D, 0x74, 0xCB, 0xEE, 0x77, 0x2D, 0xEB, 0xAD, 0x87, + 0x39, 0x85, 0xD7, 0xBC, 0x38, 0x87, 0x2A, 0x0B, 0xB5, 0xB0, + 0xD1, 0x09, 0x7D, 0x12, 0xC6, 0x4D, 0x9A, 0xF8, 0x00, 0xC5, + 0xA2, 0xF9, 0x9A, 0xFF, 0x30, 0x5D, 0x6E, 0x79, 0xD7, 0xBA, + 0xB3, 0xCC, 0x2A, 0x43, 0x61, 0xAC, 0x38, 0x99, 0x10, 0xDF, + 0x60, 0x94, 0x7B, 0x49, 0xD9, 0xC2, 0x4C, 0x6D, 0x3F, 0xD7, + 0x38, 0x85, 0xE7, 0x91, 0x26, 0x9E, 0x7F, 0x7E, 0xA4, 0x91, + 0x9B, 0x92, 0x02, 0xC1, 0x1F, 0xAF, 0x5C, 0x6B, 0xBA, 0x27, + 0xAD, 0x33, 0xCC, 0xE6, 0x20, 0x23, 0x61, 0xBE, 0x4A, 0xDA, + 0x28, 0x63, 0xB2, 0xE2, 0xAC, 0xA9, 0x51, 0x50, 0x9A, 0xAB, + 0xCA, 0x8C, 0x5C, 0xF3, 0x0A, 0x44, 0x03, 0xA9, 0x94, 0x92, + 0x1D, 0xC5, 0xB2, 0x09, 0xF3, 0x0E, 0xB3, 0x6A, 0x1D, 0x72, + 0xDC, 0x71, 0x4A, 0xAE, 0x4E, 0x0B, 0x1B, 0xCF, 0xF3, 0xCF, + 0x4B, 0x38, 0xD1, 0xCA, 0x27, 0xC2, 0x6A, 0x41, 0x0F, 0x3A, + 0x1D, 0xCD, 0x3E, 0xB1, 0x1A, 0xF7, 0x16, 0x48, 0x4A, 0xAA, + 0xA7, 0x28, 0x16, 0x07, 0x9B, 0xE0, 0x41, 0x99, 0xF1, 0x47, + 0x8C, 0x48, 0x6C, 0x2D, 0x93, 0x9E, 0x47, 0x2B, 0x9A, 0x96, + 0x20, 0x44, 0xF4, 0x2A, 0xCB, 0xB0, 0xDA, 0xBD, 0x17, 0x38, + 0xCB, 0x45, 0x9F, 0x21, 0xA8, 0x93, 0x26, 0x67, 0x51, 0x36, + 0x6F, 0x05, 0x4A, 0x08, 0x72, 0xFB, 0xA3, 0x98, 0xBF, 0x9E, + 0x39, 0xEC, 0xAF, 0xDA, 0x8A, 0xFD, 0xC1, 0xB2, 0xC4, 0x4D, + 0xFE, 0xCD, 0xBD, 0x7F, 0xF8, 0xCE, 0x4F, 0x7E, 0x4E, 0xBA, + 0xD1, 0x87, 0x3E, 0x5F, 0x77, 0xA2, 0x96, 0x3E, 0x8B, 0x15, + 0xDE, 0xE7, 0xBF, 0x7F, 0x97, 0x0F, 0xE1, 0xE7, 0x2F, 0x58, + 0x5D, 0xEF, 0x56, 0x39, 0x66, 0x63, 0x61, 0x94, 0x3D, 0x31, + 0xC8, 0x8D, 0xA8, 0xAC, 0xB5, 0x4C, 0x20, 0x1A, 0xD4, 0x18, + 0x34, 0x61, 0xA2, 0x4F, 0x65, 0xB3, 0x12, 0xFE, 0xA9, 0x02, + 0xCC, 0x47, 0x8F, 0x1C, 0x39, 0xFD, 0xDB, 0x08, 0x62, 0xFD, + 0x74, 0x8D, 0xF9, 0xAA, 0x34, 0xCA, 0x20, 0x67, 0xE8, 0xBC, + 0xAB, 0xED, 0x8C, 0x09, 0xC1, 0xA1, 0xE2, 0x3A, 0x41, 0xB7, + 0x1D, 0x82, 0x99, 0xAA, 0x79, 0x93, 0xB5, 0x1D, 0x6A, 0xE8, + 0xFC, 0x31, 0xBF, 0x67, 0xD8, 0xE9, 0x36, 0xD4, 0xBF, 0x9E, + 0xBF, 0xAB, 0x13, 0x20, 0xE3, 0x01, 0x29, 0x60, 0x28, 0x19, + 0xD2, 0x0E, 0xBC, 0x21, 0x3E, 0xD6, 0xC0, 0xC3, 0xDD, 0x64, + 0xFC, 0x98, 0x45, 0x26, 0x9B, 0x5C, 0xCB, 0xE2, 0x76, 0x0A, + 0x0D, 0x13, 0x1A, 0x7F, 0xEF, 0xE2, 0x44, 0xA3, 0xD8, 0xCE, + 0xD6, 0x0E, 0x5A, 0xA8, 0x40, 0x7B, 0x9E, 0xA0, 0xBE, 0xD6, + 0x63, 0x56, 0x77, 0x57, 0x69, 0x2C, 0xF8, 0xB6, 0x8D, 0x08, + 0xF3, 0x80, 0xA1, 0x2F, 0x53, 0xE2, 0x2F, 0xFD, 0xE6, 0x86, + 0x91, 0x83, 0x12, 0x7E, 0x73, 0xCF, 0xC8, 0x12, 0x58, 0xCD, + 0x9B, 0x30, 0x2C, 0x1E, 0xB8, 0x1E, 0xA3, 0x66, 0x27, 0xE9, + 0x33, 0xB2, 0x57, 0x9B, 0xF7, 0xFC, 0x04, 0xE1, 0xDF, 0xA4, + 0xC5, 0x7A, 0x39, 0xCE, 0xDF, 0xEB, 0x03, 0x89, 0x37, 0xFB, + 0xB0, 0x17, 0x12, 0x55, 0x52, 0x60, 0x25, 0xD1, 0xA6, 0x54, + 0xED, 0xD2, 0xBA, 0xE9, 0x66, 0x5A, 0xCA, 0xE3, 0x71, 0xF8, + 0xE7, 0x35, 0x1C, 0xAC, 0x00, 0x2C, 0xBD, 0x52, 0x6F, 0xE0, + 0x96, 0x91, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x02, 0xB1, 0x96, + 0x3E, 0x04, 0x9B, 0x7A, 0x13, 0x3F, 0xA3, 0x05, 0x16, 0xBF, + 0x79, 0xE5, 0x67, 0x77, 0x23, 0x1E, 0x4D, 0x4C, 0x26, 0x7C, + 0x9D, 0x3E, 0xF5, 0x37, 0x49, 0xAC, 0x5C, 0xA7, 0x9F, 0xD7, + 0x8B, 0x61, 0x4B, 0x21, 0xEC, 0x27, 0x9A, 0x62, 0x75, 0xD1, + 0xCB, 0xEB, 0x58, 0x98, 0x84, 0xD1, 0xD9, 0xD8, 0x00, 0x0E, + 0x38, 0xCB, 0x40, 0xE9, 0xC0, 0x87, 0x62, 0x6D, 0xD6, 0xBE, + 0x5E, 0x47, 0x40, 0xCE, 0x39, 0xD2, 0x28, 0xFF, 0x32, 0x08, + 0xFB, 0xF1, 0x86, 0xEF, 0xF1, 0x1F, 0xC7, 0x28, 0xE0, 0x2A, + 0x9B, 0xAA, 0xA7, 0xEC, 0xBA, 0x63, 0x27, 0x98, 0xCC, 0x4C, + 0x35, 0x48, 0xE2, 0x83, 0xE2, 0xE4, 0x7E, 0xCF, 0xF2, 0x38, + 0xED, 0x1C, 0xE7, 0x17, 0xCB, 0xAC, 0xCC, 0xDA, 0xF5, 0x3B, + 0xD3, 0xC5, 0xFE, 0xB5, 0x04, 0x3A, 0xFC, 0xF7, 0x66, 0x66, + 0x89, 0xB5, 0xAD, 0x1C, 0x18, 0xFE, 0x63, 0xF6, 0x9E, 0x8D, + 0x73, 0xDC, 0x9D, 0x54, 0xDD, 0x02, 0x3B, 0x1D, 0x3F, 0x3D, + 0xD1, 0x4C, 0xCB, 0x3C, 0x09, 0x8E, 0x5A, 0x06, 0x5C, 0x03, + 0x59, 0xF4, 0x7B, 0xF6, 0x39, 0x02, 0x2B, 0xDC, 0x76, 0x82, + 0x2A, 0x33, 0x34, 0x34, 0x57, 0x9F, 0xC8, 0xF0, 0xF0, 0x14, + 0x29, 0x0C, 0x6E, 0x92, 0x36, 0x56, 0x3B, 0xA6, 0x68, 0xF0, + 0x3B, 0x3C, 0xA7, 0x8F, 0x60, 0x85, 0x5D, 0xAD, 0x14, 0xBF, + 0xA7, 0x8B, 0x8E, 0xED, 0x20, 0x0A, 0x64, 0xB2, 0x05, 0xF9, + 0x59, 0x45, 0xC0, 0x97, 0x2D, 0x0D, 0x3A, 0x77, 0xC0, 0xBD, + 0xA2, 0x9F, 0xD4, 0x21, 0xA5, 0x23, 0x7D, 0x1A, 0xE2, 0x4D, + 0x72, 0x44, 0xF6, 0x3E, 0x2A, 0x12, 0xF6, 0xB3, 0xDD, 0x15, + 0x63, 0xCC, 0x7A, 0x5E, 0x60, 0xC2, 0xB0, 0xEE, 0x2C, 0x35, + 0x08, 0x35, 0xE8, 0xA8, 0x08, 0x86, 0xA6, 0xC9, 0xA2, 0x84, + 0xBF, 0x90, 0x14, 0x92, 0x95, 0x6A, 0x08, 0x39, 0x30, 0xB2, + 0x94, 0x3E, 0x0D, 0xE9, 0x3B, 0x28, 0xC7, 0x89, 0x6F, 0xFE, + 0xB9, 0x83, 0x00, 0xE9, 0x9A, 0xA5, 0x47, 0x82, 0xEB, 0xAE, + 0xA8, 0x2F, 0xD4, 0x89, 0xDB, 0x00, 0xC0, 0xA3, 0xE8, 0x79, + 0xC8, 0x5D, 0x90, 0xA5, 0x5F, 0xB6, 0x11, 0x42, 0x99, 0x1E, + 0x7C, 0x9C, 0xB5, 0xA6, 0x90, 0x85, 0xE8, 0xED, 0x14, 0x55, + 0x99, 0x13, 0x10, 0xFD, 0x94, 0xF6, 0x48, 0x86, 0x26, 0x5A, + 0x36, 0x15, 0x53, 0xE5, 0x02, 0xD4, 0x46, 0xA4, 0x3B, 0x97, + 0xB0, 0x65, 0x25, 0xD2, 0x52, 0x08, 0x7D, 0x12, 0x28, 0xC3, + 0x0A, 0x26, 0xF1, 0xCD, 0x10, 0x90, 0xB0, 0x61, 0x6C, 0x31, + 0xEE, 0xC4, 0x79, 0x86, 0x36, 0x94, 0x38, 0x26, 0xD8, 0xA0, + 0x44, 0x90, 0x38, 0x08, 0xCA, 0xCA, 0x8A, 0xEF, 0x6D, 0xFD, + 0xBF, 0xAC, 0xE2, 0x87, 0xC4, 0xD3, 0xB6, 0x68, 0xA5, 0x02, + 0x05, 0xB4, 0xC1, 0xA3, 0x38, 0x60, 0x1B, 0x7F, 0xA5, 0xF2, + 0xA8, 0x17, 0xB0, 0x17, 0x88, 0x0F, 0xE8, 0xE1, 0x25, 0x9C, + 0x4E, 0x82, 0x37, 0x0C, 0xC3, 0xFF, 0x6D, 0x99, 0x9F, 0xB3, + 0x8B, 0x92, 0x2B, 0x96, 0x6B, 0xD3, 0xDF, 0x3F, 0x45, 0xD8, + 0xA2, 0x46, 0xAA, 0x06, 0x7D, 0xA7, 0x57, 0xEC, 0x87, 0x99, + 0xFA, 0x2F, 0x93, 0x6D, 0x65, 0x77, 0xD3, 0x72, 0x2B, 0x3D, + 0xFC, 0x9D, 0x0D, 0x2C, 0x88, 0x75, 0x37, 0x4B, 0x18, 0xA9, + 0x2D, 0xA9, 0xD6, 0xE3, 0x75, 0xFA, 0x29, 0xCE, 0x91, 0x51, + 0x74, 0xF9, 0x71, 0xFB, 0x0B, 0x1F, 0x24, 0x3D, 0xA8, 0xF3, + 0x56, 0x67, 0x7A, 0x13, 0xAA, 0xFF, 0x1C, 0x6D, 0xDD, 0x0F, + 0x14, 0xBC, 0x34, 0x35, 0xE0, 0xAF, 0x7A, 0x55, 0x8C, 0x9A, + 0xE0, 0xA6, 0x35, 0x1F, 0xAB, 0xC3, 0xF7, 0x14, 0x7E, 0xFF, + 0x13, 0x64, 0xAF, 0x1C, 0x11, 0x68, 0x25, 0x4D, 0x07, 0x05, + 0x3F, 0x76, 0x61, 0x29, 0x32, 0xB5, 0xEF, 0xF7, 0x7E, 0xE8, + 0x5C, 0xE2, 0xAA, 0x17, 0x3F, 0x5C, 0x48, 0xFA, 0x05, 0xB0, + 0xDF, 0x1F, 0x2B, 0x9B, 0x25, 0xAA, 0xA8, 0x1F, 0x80, 0xF5, + 0xE5, 0x9C, 0xC2, 0xF5, 0x02, 0x06, 0xC0, 0x00, 0x02, 0x96, + 0xA3, 0xD9, 0x49, 0x25, 0x73, 0x8B, 0x32, 0xB3, 0xD6, 0x68, + 0x6E, 0x3F, 0xDE, 0x58, 0xCB, 0xA8, 0x00, 0x34, 0xB2, 0x7D, + 0x5A, 0x88, 0x7F, 0x1B, 0x3A, 0xA7, 0xD2, 0x56, 0x5B, 0x20, + 0x6F, 0x6B, 0x43, 0x58, 0xC9, 0x48, 0x1F, 0x76, 0xE3, 0xA5, + 0x79, 0x0D, 0xD3, 0xC7, 0xBB, 0x76, 0xE8, 0xC2, 0xD5, 0x77, + 0x2B, 0x39, 0x93, 0x7F, 0x9B, 0x33, 0xB3, 0x0C, 0x12, 0x50, + 0x8A, 0x95, 0xB3, 0x27, 0xCB, 0x49, 0xDB, 0x3C, 0x6A, 0xB9, + 0x06, 0xD8, 0x31, 0x8E, 0x14, 0x6A, 0x3F, 0x5B, 0x03, 0x98, + 0xD8, 0x5C, 0xCA, 0x46, 0x14, 0xDA, 0xAB, 0x51, 0xDF, 0x72, + 0x3A, 0xAD, 0x8E, 0xDA, 0x9A, 0x44, 0x0E, 0x4C, 0xB0, 0x92, + 0xF6, 0x6A, 0x0E, 0xC8, 0x37, 0x0F, 0x93, 0x73, 0xB0, 0xB5, + 0x11, 0x12, 0x3F, 0xCF, 0x29, 0x50, 0x6B, 0xD9, 0x22, 0x2C, + 0x76, 0x71, 0x07, 0xBC, 0x00, 0x10, 0xB8, 0x54, 0x6A, 0x9A, + 0x59, 0x82, 0x4E, 0xE9, 0x02, 0x8B, 0x9C, 0xC9, 0x4B, 0xD3, + 0x7F, 0xAD, 0xA5, 0xF9, 0x7C, 0xB4, 0x00, 0xB4, 0x5A, 0xAF, + 0x23, 0x12, 0xF2, 0x5B, 0xB9, 0x2C, 0xFD, 0x73, 0xB9, 0xFC, + 0x4B, 0x4F, 0xAF, 0xD2, 0x80, 0xC2, 0xF7, 0x15, 0xEC, 0xE1, + 0x4B, 0xEF, 0xA3, 0x99, 0x59, 0x0C, 0xD5, 0x2F, 0x98, 0xF5, + 0x38, 0xD2, 0xFC, 0xF3, 0x82, 0xA7, 0xE0, 0x15, 0x35, 0x27, + 0xCD, 0xCF, 0xCE, 0xA4, 0x65, 0x92, 0x1E, 0x6C, 0x25, 0x8F, + 0xB7, 0x78, 0x15, 0x5B, 0x7A, 0x9D, 0xB0, 0xEC, 0xDE, 0x0A, + 0xF5, 0x0B, 0xCD, 0xD4, 0xF6, 0xC4, 0xD5, 0xA9, 0xC1, 0x4E, + 0xE0, 0xA2, 0x8B, 0xC4, 0x43, 0x97, 0xAC, 0xC9, 0x41, 0xF2, + 0x5A, 0x36, 0xD1, 0xD6, 0x7E, 0xC2, 0xD3, 0x06, 0xCB, 0x78, + 0x47, 0x78, 0x05, 0x35, 0x61, 0xE6, 0xD4, 0xDC, 0x65, 0x75, + 0x63, 0x5B, 0x71, 0xD7, 0x3C, 0x27, 0x9B, 0x26, 0x70, 0xAB, + 0x4D, 0x97, 0xE5, 0x83, 0x7C, 0xEB, 0x5B, 0x8F, 0xD6, 0xBC, + 0x84, 0x9D, 0xF8, 0x08, 0x65, 0x10, 0x6E, 0x48, 0xBE, 0xD2, + 0x86, 0xC0, 0xEB, 0x08, 0x27, 0x38, 0xF8, 0x6E, 0x5D, 0xBA, + 0x5B, 0xC6, 0x78, 0xED, 0xB1, 0x8D, 0x57, 0xFC, 0xA4, 0xDD, + 0xF3, 0xDF, 0xB9, 0x36, 0x92, 0xB8, 0x00, 0x06, 0x5F, 0xAD, + 0x04, 0xE3, 0x8D, 0x64, 0x64, 0x7A, 0xE0, 0x57, 0x4C, 0x68, + 0x56, 0xDC, 0x1F, 0x93, 0xA5, 0xD7, 0xEE, 0xFC, 0x8A, 0xB9, + 0x26, 0x99, 0xC5, 0x1A, 0x63, 0xD6, 0x9B, 0xBC, 0xA2, 0xF3, + 0xE1, 0x84, 0xDC, 0xFB, 0x0C, 0x4F, 0xB4, 0x0D, 0x75, 0x8B, + 0xDD, 0xB6, 0x76, 0x2C, 0x33, 0x46, 0xDD, 0x94, 0xE0, 0x8C, + 0x37, 0x03, 0x14, 0x44, 0xC2, 0x0F, 0x6C, 0x03, 0xA6, 0x39, + 0x1E, 0xB5, 0x00, 0x83, 0xC6, 0x59, 0x81, 0xD6, 0x11, 0x3A, + 0x22, 0x6F, 0x74, 0x1C, 0x8B, 0x4C, 0xF3, 0x1C, 0x59, 0x2F, + 0x19, 0x18, 0xB5, 0x20, 0x24, 0x9C, 0x14, 0x45, 0x7E, 0x98, + 0xFB, 0x71, 0xC4, 0xCC, 0x19, 0x99, 0x28, 0x9E, 0x63, 0xC2, + 0xD6, 0x0D, 0x47, 0x2A, 0x3B, 0x36, 0xB7, 0x8C, 0xF1, 0x98, + 0x33, 0x96, 0x9D, 0x09, 0x99, 0x74, 0xE3, 0x41, 0xCD, 0x67, + 0xCE, 0x11, 0xBA, 0x35, 0xE3, 0x44, 0x3D, 0xE0, 0xB9, 0x53, + 0x79, 0x58, 0x0F, 0xC5, 0x98, 0xCC, 0xAB, 0xF8, 0x37, 0x5C, + 0x96, 0xCE, 0xB5, 0xDA, 0xB5, 0x05, 0x79, 0xD6, 0x96, 0x82, + 0xCA, 0x3F, 0x2C, 0x8A, 0x44, 0xCE, 0xCE, 0x99, 0xA2, 0x77, + 0x9E, 0xE0, 0xFE, 0x58, 0x97, 0x5A, 0xDA, 0x8B, 0xB8, 0x0A, + 0xA2, 0x3F, 0x26, 0x00, 0x5C, 0xAC, 0xD8, 0x33, 0x95, 0xBF, + 0x43, 0x0D, 0x09, 0xB5, 0x9A, 0x89, 0x4C, 0x46, 0x83, 0xAF, + 0xD1, 0xD3, 0x61, 0x33, 0xA1, 0x19, 0xD3, 0xD6, 0x81, 0xB0, + 0xDA, 0x55, 0x4B, 0xD3, +}; + +const uint32_t gphDnldNfc_DlSeqSz = sizeof(gphDnldNfc_DlSequence); diff --git a/nfc/recovery_seq.c b/nfc/recovery_seq.c index 5842284e8e..1f2b358a42 100644 --- a/nfc/recovery_seq.c +++ b/nfc/recovery_seq.c @@ -16,14 +16,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ -#if defined(RECOVERY_ENABLE) #include "recovery_seq.h" -recovery_info_t g_recovery_info; -recovery_frame_t g_recovery_frame; - -extern const uint32_t gphDnldNfc_DlSeqSz; /* Recovery user buffer size */ -extern const uint8_t gphDnldNfc_DlSequence[]; /* Recovery user buffer */ +struct recovery_info g_recovery_info; +struct recovery_frame g_recovery_frame; /** @brief Function to calculate crc value. * @@ -31,16 +27,18 @@ extern const uint8_t gphDnldNfc_DlSequence[]; /* Recovery user buffer */ * dwLength: length of input buffer * @return calculated uint16_t crc valueof input buffer. */ -static uint16_t calcCrc16(uint8_t* pbuffer, uint32_t dwLength) { +static uint16_t calcCrc16(uint8_t *pbuffer, uint32_t dwLength) +{ uint32_t i = 0; uint16_t crc_new = 0; uint16_t crc = DL_INVALID_CRC_VALUE; - if(NULL == pbuffer) { + + if (pbuffer == NULL) { pr_err("%s, invalid params", __func__); return crc; } for (i = 0; i < dwLength; i++) { - crc_new = (uint8_t)(crc >> MSB_POS) | (crc << MSB_POS ); + crc_new = (uint8_t)(crc >> MSB_POS) | (crc << MSB_POS); crc_new ^= pbuffer[i]; crc_new ^= (uint8_t)(crc_new & DL_CRC_MASK) >> 4; crc_new ^= crc_new << 12; @@ -52,29 +50,32 @@ static uint16_t calcCrc16(uint8_t* pbuffer, uint32_t dwLength) { /** @brief Function to build command frame for recover. * - * @return status code of recovery_status_t type. + * @return status code of recovery_status type. */ -static recovery_status_t build_cmd_frame() { +static enum recovery_status build_cmd_frame(void) +{ uint16_t len = 0; uint16_t wCrc = 0; uint16_t writeOffset = 0; + pr_debug(" %s Entry", __func__); - if(gphDnldNfc_DlSeqSz == 0) { + if (gphDnldNfc_DlSeqSz == 0) { pr_err(" %s invalid params", __func__); return STATUS_FAILED; } memset(g_recovery_frame.p_buffer, 0x00, MAX_FRAME_SIZE); g_recovery_frame.len = 0; - if(g_recovery_info.bFrameSegmented == false) { + if (g_recovery_info.bFrameSegmented == false) { len = gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset]; len <<= MSB_POS; len |= gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset + 1]; } else { /* last frame was segmented frame - * read length reamaining length */ + * read length reamaining length + */ len = g_recovery_info.wRemChunkBytes; } - if(len > MAX_DATA_SIZE) { + if (len > MAX_DATA_SIZE) { /* set remaining chunk */ g_recovery_info.wRemChunkBytes = (len - MAX_DATA_SIZE); len = MAX_DATA_SIZE; @@ -85,7 +86,7 @@ static recovery_status_t build_cmd_frame() { /* clear chunk bit for length variable */ len = DL_CLR_HDR_FRAGBIT(len); /* first chunk of segmented frame*/ - if(!g_recovery_info.bFrameSegmented) { + if (!g_recovery_info.bFrameSegmented) { /* ignore header from user buffer */ g_recovery_info.currentReadOffset += FW_HDR_LEN; g_recovery_info.remBytes -= FW_HDR_LEN; @@ -94,22 +95,23 @@ static recovery_status_t build_cmd_frame() { g_recovery_info.bFrameSegmented = true; } else { /* last chunk of segmented frame */ - if(g_recovery_info.bFrameSegmented) { + if (g_recovery_info.bFrameSegmented) { /* write header with user chunk length */ g_recovery_frame.p_buffer[writeOffset++] = (len >> MSB_POS) & SHIFT_MASK; g_recovery_frame.p_buffer[writeOffset++] = len & SHIFT_MASK; g_recovery_frame.len += FW_HDR_LEN; } else { /* normal Frame with in supported size increase - * len to read header from user data */ + * len to read header from user data + */ len += FW_HDR_LEN; } g_recovery_info.wRemChunkBytes = 0; g_recovery_info.bFrameSegmented = false; } - if(((writeOffset + len) > MAX_FRAME_SIZE) || + if (((writeOffset + len) > MAX_FRAME_SIZE) || ((g_recovery_info.currentReadOffset + len) > gphDnldNfc_DlSeqSz)) { - pr_err("%s frame offsets out of bound",__func__); + pr_err("%s frame offsets out of bound", __func__); return STATUS_FAILED; } memcpy(&g_recovery_frame.p_buffer[writeOffset], @@ -126,20 +128,21 @@ static recovery_status_t build_cmd_frame() { return STATUS_SUCCESS; } -/** @brief Function to tramsmit recovery frame. +/** @brief Function to transmit recovery frame. * @param nfc_dev nfc driver object. - * @return status code of recovery_status_t type. + * @return status code of recovery_status type. */ -static recovery_status_t transmit(nfc_dev_t* nfc_dev) { - char rsp_buf[MAX_BUFFER_SIZE]; +static enum recovery_status transmit(struct nfc_dev *nfc_dev) +{ int ret = 0; int frame_resp_len = 0; uint16_t respCRC = 0; uint16_t respCRCOffset = 0; + uint8_t *rsp_buf = nfc_dev->read_kbuf; pr_debug("%s Entry", __func__); - if(NULL == nfc_dev || g_recovery_frame.len <= 0) { - pr_err("%s invalid Params ", __func__); + if (nfc_dev == NULL || g_recovery_frame.len <= 0) { + pr_err("%s invalid Params", __func__); return STATUS_FAILED; } ret = nfc_dev->nfc_write(nfc_dev, g_recovery_frame.p_buffer, @@ -148,17 +151,17 @@ static recovery_status_t transmit(nfc_dev_t* nfc_dev) { pr_err(" %s: Write recovery frame error %d\n", __func__, ret); return STATUS_FAILED; } - pr_debug(" %s Reading response \n", __func__); + pr_debug(" %s Reading response\n", __func__); memset(rsp_buf, 0x00, MAX_BUFFER_SIZE); ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, FW_HDR_LEN, NCI_CMD_RSP_TIMEOUT); if (ret < FW_HDR_LEN) { pr_err(" %s - Read recovery frame response error ret %d\n", __func__, ret); return STATUS_FAILED; } - if( rsp_buf[0] != FW_MSG_CMD_RSP || + if (rsp_buf[0] != FW_MSG_CMD_RSP || rsp_buf[DL_FRAME_RESP_LEN_OFFSET] != DL_FRAME_RESP_LEN) { - pr_err("%s, invalid response", __func__); - return STATUS_FAILED; + pr_err("%s, invalid response", __func__); + return STATUS_FAILED; } frame_resp_len = rsp_buf[DL_FRAME_RESP_LEN_OFFSET] + FW_CRC_LEN; ret = nfc_dev->nfc_read(nfc_dev, rsp_buf + FW_HDR_LEN, frame_resp_len, NCI_CMD_RSP_TIMEOUT); @@ -167,22 +170,22 @@ static recovery_status_t transmit(nfc_dev_t* nfc_dev) { return STATUS_FAILED; } pr_debug(" %s: recovery frame Response 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", - __func__, rsp_buf[0], rsp_buf[1],rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5]); + __func__, rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5]); respCRCOffset = FW_HDR_LEN + rsp_buf[DL_FRAME_RESP_LEN_OFFSET]; respCRC = rsp_buf[respCRCOffset++]; respCRC <<= MSB_POS; respCRC |= rsp_buf[respCRCOffset]; - if(respCRC != calcCrc16(rsp_buf, DL_FRAME_RESP_LEN + FW_HDR_LEN)) { + if (respCRC != calcCrc16(rsp_buf, DL_FRAME_RESP_LEN + FW_HDR_LEN)) { pr_err("%s, invalid response crc", __func__); return STATUS_FAILED; } - if(g_recovery_info.bFrameSegmented && + if (g_recovery_info.bFrameSegmented && (rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT1 && rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT2)) { pr_err("%s, invalid stat flag in chunk response", __func__); return STATUS_FAILED; } - if(!g_recovery_info.bFrameSegmented && + if (!g_recovery_info.bFrameSegmented && rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_NON_SEGMENTED_FRAME_RESP_STAT) { pr_err("%s, invalid stat flag in response", __func__); return STATUS_FAILED; @@ -190,46 +193,14 @@ static recovery_status_t transmit(nfc_dev_t* nfc_dev) { return STATUS_SUCCESS; } -/** @brief Function to detect the fw state and print. - * @param nfc_dev nfc driver object. - * @return no return. - */ -static void detect_fw_state(nfc_dev_t* nfc_dev) { - const char get_session_state_cmd[] = { 0x00, 0x04, 0xF2, 0x00, 0x00, 0x00, 0xF5, 0x33 }; - char rsp_buf[MAX_BUFFER_SIZE]; - int ret = 0; - pr_debug("%s:Sending GET_SESSION_STATE cmd \n", __func__); - ret = nfc_dev->nfc_write(nfc_dev, get_session_state_cmd, - sizeof(get_session_state_cmd), MAX_RETRY_COUNT); - if (ret <= 0) { - pr_err("%s: - nfc get session state cmd err ret %d\n", __func__, ret); - return; - } - memset(rsp_buf, 0x00, DL_GET_SESSION_STATE_RSP_LEN); - pr_debug("%s: Reading response of GET_SESSION_STATE cmd\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT); - if (ret <= 0) { - pr_err("%s: - nfc get session state rsp err %d\n", __func__, ret); - return; - } - pr_debug("Response bytes are %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x", - rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5], - rsp_buf[6], rsp_buf[7]); - /*verify fw in non-teared state */ - if (rsp_buf[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) { - pr_err("%s NFCC is in teared state %d\n", __func__, __LINE__); - } else { - pr_info("%s NFCC is in recoverd state %d\n", __func__, __LINE__); - } -} - /** @brief Function to check input version with recovery fw version. * @param fw_major_version: input major_version to check. * @return true if input major_version matches with recovery fw major version * otherwise returns false. */ -static bool check_major_version(uint8_t fw_major_version) { - if(gphDnldNfc_DlSeqSz < RECOVERY_FW_MJ_VER_OFFSET) { +static bool check_major_version(uint8_t fw_major_version) +{ + if (gphDnldNfc_DlSeqSz < RECOVERY_FW_MJ_VER_OFFSET) { /* Recovery data corrupted */ pr_err("%s Not able to extract major version from recovery fw\n", __func__); return false; @@ -239,43 +210,40 @@ static bool check_major_version(uint8_t fw_major_version) { /** @brief Function to recover the nfcc. * @param nfc_dev nfc driver object. - * @return status code of type recovery_status_t. + * @return status code of type recovery_status. */ -recovery_status_t do_recovery(nfc_dev_t *nfc_dev) { - recovery_status_t status = STATUS_SUCCESS; +enum recovery_status do_recovery(struct nfc_dev *nfc_dev) +{ + enum recovery_status status = STATUS_SUCCESS; + g_recovery_info.remBytes = gphDnldNfc_DlSeqSz; g_recovery_info.currentReadOffset = 0; g_recovery_info.bFrameSegmented = false; g_recovery_info.wRemChunkBytes = 0; - + g_recovery_frame.p_buffer = nfc_dev->write_kbuf; pr_debug("%s Entry", __func__); - if(NULL == nfc_dev) { + if (nfc_dev == NULL) { pr_err("%s invalid params ", __func__); return STATUS_FAILED; } - if(!nfc_dev->recovery_required - || !(check_major_version(nfc_dev->fw_major_version))) { - pr_err("%s recovery not required or unsupported version", __func__); + if (!(check_major_version(nfc_dev->fw_major_version))) { + pr_err("%s unsupported version", __func__); status = STATUS_FAILED; goto EXIT_RECOVERY; } - while(g_recovery_info.remBytes > 0) { + while (g_recovery_info.remBytes > 0) { status = build_cmd_frame(); - if(status != STATUS_SUCCESS) { + if (status != STATUS_SUCCESS) { pr_err(" %s Unable to create recovery frame"); break; } status = transmit(nfc_dev); - if(status != STATUS_SUCCESS) { + if (status != STATUS_SUCCESS) { pr_err(" %s Unable to send recovery frame"); break; } } EXIT_RECOVERY: - detect_fw_state(nfc_dev); - /*set NCI mode for i2c products with dwl pin */ - enable_dwnld_mode(nfc_dev, false); pr_info("%s Recovery done status %d", __func__, status); return status; } -#endif diff --git a/nfc/recovery_seq.h b/nfc/recovery_seq.h index 86671de262..c06d25c38a 100644 --- a/nfc/recovery_seq.h +++ b/nfc/recovery_seq.h @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ -#if defined(RECOVERY_ENABLE) +#if IS_ENABLED(CONFIG_NXP_NFC_RECOVERY) #ifndef __RECOVERY_SEQ_H_ #define __RECOVERY_SEQ_H_ @@ -26,18 +26,14 @@ #define MAX_FRAME_SIZE 0x22A /* support for 256(0x100) & 554(0x22A) frame size*/ #define MAX_DATA_SIZE \ - (MAX_FRAME_SIZE - FW_CRC_LEN - FW_HDR_LEN) + (MAX_FRAME_SIZE - FW_CRC_LEN - FW_HDR_LEN) -#define FW_ROM_CODE_VER_OFFSET 4 -#define FW_MAJOR_VER_OFFSET 7 -#define RECOVERY_FW_SUPPORTED_ROM_VER 0x01 -#define RECOVERY_FW_SUPPORTED_MAJOR_VER 0x10 #define RECOVERY_FW_MJ_VER_OFFSET 5 #define DL_SET_HDR_FRAGBIT(n) \ - ((n) | (1 << 10)) /* Header chunk bit set macro */ + ((n) | (1 << 10)) /* Header chunk bit set macro */ #define DL_CLR_HDR_FRAGBIT(n) \ - ((n) & ~(1U << 10)) /* Header chunk bit clear macro */ + ((n) & ~(1U << 10)) /* Header chunk bit clear macro */ #define DL_FRAME_RESP_LEN 0x04 #define DL_FRAME_RESP_LEN_OFFSET 1 @@ -52,29 +48,32 @@ #define MSB_POS 8 /* Data buffer for frame to write */ -typedef struct recovery_frame { +struct recovery_frame { uint32_t len; - uint8_t p_buffer[MAX_FRAME_SIZE]; -} recovery_frame_t; + uint8_t *p_buffer; +}; /* Contains Info about user buffer and last data frame */ -typedef struct recovery_info { +struct recovery_info { uint32_t currentReadOffset; /* current offset within the user buffer to read/write */ uint32_t remBytes; /* Remaining bytes to write */ uint16_t wRemChunkBytes; /* Remaining bytes within the chunked frame */ bool bFrameSegmented; /* Indicates the current frame is segmented */ -} recovery_info_t; +}; /* indicates the error codes for nfc recovery module */ -typedef enum recovery_status { +enum recovery_status { STATUS_SUCCESS = 0x00, STATUS_FAILED = 0x01, -} recovery_status_t; +}; + +extern const uint32_t gphDnldNfc_DlSeqSz; /* Recovery user buffer size */ +extern const uint8_t gphDnldNfc_DlSequence[]; /* Recovery user buffer */ /** @brief Function to recover the nfcc. * @param nfc_dev nfc driver object. * @return status code of type recovery_status_t. */ -recovery_status_t do_recovery(nfc_dev_t *nfc_dev); +enum recovery_status do_recovery(struct nfc_dev *nfc_dev); #endif// end __RECOVERY_SEQ_H_ #endif From f64dad377ca84304fb7931eb2a35f7e0c7fbbe67 Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Thu, 29 Apr 2021 20:39:02 +0530 Subject: [PATCH 039/100] Updated corresponding to - NFC_AR_00_E000_12.04.01_OpnSrc --- nfc/Makefile | 1 - nfc/common.c | 428 ++++++++--------------------------------------- nfc/common.h | 188 +++++++++------------ nfc/common_ese.c | 199 ++++++++++++---------- nfc/common_ese.h | 80 ++++----- nfc/i2c_drv.c | 173 ++++++++++--------- nfc/i2c_drv.h | 19 ++- 7 files changed, 404 insertions(+), 684 deletions(-) diff --git a/nfc/Makefile b/nfc/Makefile index ddbea678de..16c477495a 100644 --- a/nfc/Makefile +++ b/nfc/Makefile @@ -3,6 +3,5 @@ # obj-$(CONFIG_NXP_NFC_I2C) += pn553_i2c.o pn553_i2c-objs := common.o common_ese.o i2c_drv.o -pn553_i2c-$(CONFIG_NXP_NFC_RECOVERY) += recovery_seq.o recovery_fw.o #ccflags-y += -DDEBUG diff --git a/nfc/common.c b/nfc/common.c index cf80332049..30231f8c37 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -1,7 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2021 NXP - * * + * Copyright (C) 2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2019-2021 NXP + * * This program 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 @@ -17,13 +17,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ +#include #include -#include #include -#include -#include "common.h" + #include "common_ese.h" -#include "recovery_seq.h" int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface) @@ -32,7 +30,7 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, struct platform_gpio *nfc_gpio = &nfc_configs->gpio; if (!np) { - pr_err("nfc of_node NULL\n"); + pr_err("%s: nfc of_node NULL\n", __func__); return -EINVAL; } @@ -40,26 +38,28 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, nfc_gpio->dwl_req = -EINVAL; nfc_gpio->ven = -EINVAL; - //required for i2c based chips only + /* irq required for i2c based chips only */ if (interface == PLATFORM_IF_I2C) { nfc_gpio->irq = of_get_named_gpio(np, DTS_IRQ_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->irq))) { - pr_err("nfc irq gpio invalid %d\n", nfc_gpio->irq); + pr_err("%s: irq gpio invalid %d\n", __func__, + nfc_gpio->irq); return -EINVAL; } pr_info("%s: irq %d\n", __func__, nfc_gpio->irq); } nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->ven))) { - pr_err("nfc ven gpio invalid %d\n", nfc_gpio->ven); + pr_err("%s: ven gpio invalid %d\n", __func__, nfc_gpio->ven); return -EINVAL; } - + /* some products like sn220 does not required fw dwl pin */ nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->dwl_req))) - pr_warn("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req); + pr_warn("%s: dwl_req gpio invalid %d\n", __func__, + nfc_gpio->dwl_req); - pr_info("%s: %d, %d, %d, %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven, + pr_info("%s: %d, %d, %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven, nfc_gpio->dwl_req); return 0; } @@ -67,11 +67,11 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, void set_valid_gpio(int gpio, int value) { if (gpio_is_valid(gpio)) { - pr_debug("%s gpio %d value %d\n", __func__, gpio, value); + pr_debug("%s: gpio %d value %d\n", __func__, gpio, value); gpio_set_value(gpio, value); - // hardware dependent delay - usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, - NFC_GPIO_SET_WAIT_TIME_USEC + 100); + /* hardware dependent delay */ + usleep_range(NFC_GPIO_SET_WAIT_TIME_US, + NFC_GPIO_SET_WAIT_TIME_US + 100); } } @@ -81,7 +81,7 @@ int get_valid_gpio(int gpio) if (gpio_is_valid(gpio)) { value = gpio_get_value(gpio); - pr_debug("%s gpio %d value %d\n", __func__, gpio, value); + pr_debug("%s: gpio %d value %d\n", __func__, gpio, value); } return value; } @@ -92,14 +92,14 @@ void gpio_set_ven(struct nfc_dev *nfc_dev, int value) if (gpio_get_value(nfc_gpio->ven) != value) { pr_debug("%s: value %d\n", __func__, value); - /*reset on change in level from high to low */ + /* reset on change in level from high to low */ if (value) ese_cold_reset_release(nfc_dev); gpio_set_value(nfc_gpio->ven, value); - // hardware dependent delay - usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, - NFC_GPIO_SET_WAIT_TIME_USEC + 100); + /* hardware dependent delay */ + usleep_range(NFC_GPIO_SET_WAIT_TIME_US, + NFC_GPIO_SET_WAIT_TIME_US + 100); } } @@ -111,32 +111,37 @@ int configure_gpio(unsigned int gpio, int flag) if (gpio_is_valid(gpio)) { ret = gpio_request(gpio, "nfc_gpio"); if (ret) { - pr_err("%s: unable to request nfc gpio [%d]\n", __func__, gpio); + pr_err("%s: unable to request nfc gpio [%d]\n", + __func__, gpio); return ret; } - /*set direction and value for output pin */ + /* set direction and value for output pin */ if (flag & GPIO_OUTPUT) { ret = gpio_direction_output(gpio, (GPIO_HIGH & flag)); - pr_debug("nfc o/p gpio %d level %d\n", gpio, gpio_get_value(gpio)); + pr_debug("%s: nfc o/p gpio %d level %d\n", __func__, + gpio, gpio_get_value(gpio)); } else { ret = gpio_direction_input(gpio); - pr_debug("nfc i/p gpio %d\n", gpio); + pr_debug("%s: nfc i/p gpio %d\n", __func__, gpio); } if (ret) { - pr_err("%s: unable to set direction for nfc gpio [%d]\n", __func__, gpio); + pr_err("%s: unable to set direction for nfc gpio [%d]\n", + __func__, gpio); gpio_free(gpio); return ret; } - /*Consider value as control for input IRQ pin */ + /* Consider value as control for input IRQ pin */ if (flag & GPIO_IRQ) { ret = gpio_to_irq(gpio); if (ret < 0) { - pr_err("%s: unable to set irq for nfc gpio [%d]\n", __func__, gpio); + pr_err("%s: unable to set irq [%d]\n", __func__, + gpio); gpio_free(gpio); return ret; } - pr_debug("%s: gpio_to_irq successful [%d]\n", __func__, gpio); + pr_debug("%s: gpio_to_irq successful [%d]\n", __func__, + gpio); return ret; } } else { @@ -170,20 +175,22 @@ void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count) } int nfc_misc_register(struct nfc_dev *nfc_dev, - const struct file_operations *nfc_fops, - int count, char *devname, char *classname) + const struct file_operations *nfc_fops, int count, + char *devname, char *classname) { int ret = 0; ret = alloc_chrdev_region(&nfc_dev->devno, 0, count, devname); if (ret < 0) { - pr_err("%s: failed to alloc chrdev region ret %d\n", __func__, ret); + pr_err("%s: failed to alloc chrdev region ret %d\n", __func__, + ret); return ret; } nfc_dev->nfc_class = class_create(THIS_MODULE, classname); if (IS_ERR(nfc_dev->nfc_class)) { ret = PTR_ERR(nfc_dev->nfc_class); - pr_err("%s: failed to register device class ret %d\n", __func__, ret); + pr_err("%s: failed to register device class ret %d\n", __func__, + ret); unregister_chrdev_region(nfc_dev->devno, count); return ret; } @@ -199,7 +206,8 @@ int nfc_misc_register(struct nfc_dev *nfc_dev, nfc_dev->devno, nfc_dev, devname); if (IS_ERR(nfc_dev->nfc_device)) { ret = PTR_ERR(nfc_dev->nfc_device); - pr_err("%s: failed to create the device ret %d\n", __func__, ret); + pr_err("%s: failed to create the device ret %d\n", __func__, + ret); cdev_del(&nfc_dev->c_dev); class_destroy(nfc_dev->nfc_class); unregister_chrdev_region(nfc_dev->devno, count); @@ -208,7 +216,7 @@ int nfc_misc_register(struct nfc_dev *nfc_dev, return 0; } -/* +/** * nfc_ioctl_power_states() - power control * @nfc_dev: nfc device data structure * @arg: mode that we want to move to @@ -271,19 +279,21 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) set_valid_gpio(nfc_gpio->dwl_req, 0); nfc_dev->nfc_state = NFC_STATE_NCI; } else { - pr_err("%s bad arg %lu\n", __func__, arg); + pr_err("%s: bad arg %lu\n", __func__, arg); ret = -ENOIOCTLCMD; } return ret; } -/** @brief IOCTL function to be used to set or get data from upper layer. +/** + * nfc_dev_ioctl - used to set or get data from upper layer. + * @pfile file node for opened device. + * @cmd ioctl type from upper layer. + * @arg ioctl arg from upper layer. * - * @param pfile fil node for opened device. - * @cmd IOCTL type from upper layer. - * @arg IOCTL arg from upper layer. + * NFC and ESE Device power control, based on the argument value * - * @return 0 on success, error code for failures. + * Return: -ENOIOCTLCMD if arg is not supported, 0 or other in any other case */ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) { @@ -293,7 +303,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) if (!nfc_dev) return -ENODEV; - pr_debug("%s cmd = %x arg = %zx\n", __func__, cmd, arg); + pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg); switch (cmd) { case NFC_SET_PWR: ret = nfc_ioctl_power_states(nfc_dev, arg); @@ -304,11 +314,8 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) case ESE_GET_PWR: ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE); break; - case NFC_GET_IRQ_STATE: - ret = gpio_get_value(nfc_dev->configs.gpio.irq); - break; default: - pr_err("%s bad cmd %lu\n", __func__, arg); + pr_err("%s: bad cmd %lu\n", __func__, arg); ret = -ENOIOCTLCMD; }; return ret; @@ -316,7 +323,11 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) int nfc_dev_open(struct inode *inode, struct file *filp) { - struct nfc_dev *nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev); + struct nfc_dev *nfc_dev = + container_of(inode->i_cdev, struct nfc_dev, c_dev); + + if (!nfc_dev) + return -ENODEV; pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); @@ -336,7 +347,11 @@ int nfc_dev_open(struct inode *inode, struct file *filp) int nfc_dev_close(struct inode *inode, struct file *filp) { - struct nfc_dev *nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev); + struct nfc_dev *nfc_dev = + container_of(inode->i_cdev, struct nfc_dev, c_dev); + + if (!nfc_dev) + return -ENODEV; pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); mutex_lock(&nfc_dev->dev_ref_mutex); @@ -347,11 +362,12 @@ int nfc_dev_close(struct inode *inode, struct file *filp) if (nfc_dev->dev_ref_count > 0) nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; else { - nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS_NFC); - /* Uncomment below line incase of eSE calls flow is via NFC driver + /* + * Use "ESE_RST_PROT_DIS" as argument + * if eSE calls flow is via NFC driver * i.e. direct calls from SPI HAL to NFC driver */ - //nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS); + nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS_NFC); } filp->private_data = NULL; @@ -359,320 +375,20 @@ int nfc_dev_close(struct inode *inode, struct file *filp) return 0; } -/** - * get_nfcc_chip_type_dl() - get chip type in fw download command; - * @nfc_dev: nfc device data structure - * - * Perform get version command and determine chip - * type from response. - * - * @Return: enum chip_types value - * - */ -static enum chip_types get_nfcc_chip_type_dl(struct nfc_dev *nfc_dev) -{ - int ret = 0; - int cmd_length = 0; - uint8_t *cmd = nfc_dev->write_kbuf; - uint8_t *rsp = nfc_dev->read_kbuf; - enum chip_types chip_type = CHIP_UNKNOWN; - - *cmd++ = 0x00; - *cmd++ = 0x04; - *cmd++ = 0xF1; - *cmd++ = 0x00; - *cmd++ = 0x00; - *cmd++ = 0x00; - *cmd++ = 0x6E; - *cmd++ = 0xEF; - cmd_length = cmd - nfc_dev->write_kbuf; - - pr_debug("%s:Sending GET_VERSION cmd of size=%d\n", __func__, cmd_length); - ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, MAX_RETRY_COUNT); - if (ret <= 0) { - pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret); - goto err; - } - memset(rsp, 0x00, DL_GET_VERSION_RSP_LEN_2); - pr_debug("%s:Reading response of GET_VERSION cmd\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_VERSION_RSP_LEN_2, NCI_CMD_RSP_TIMEOUT); - if (ret <= 0) { - pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret); - goto err; - } - if (rsp[0] == FW_MSG_CMD_RSP && ret >= DL_GET_VERSION_RSP_LEN_2) { - - nfc_dev->fw_major_version = rsp[FW_MAJOR_VER_OFFSET]; - - if (rsp[FW_ROM_CODE_VER_OFFSET] == SN1XX_ROM_VER && - rsp[FW_MAJOR_VER_OFFSET] == SN1xx_MAJOR_VER) - chip_type = CHIP_SN1XX; - else if (rsp[FW_ROM_CODE_VER_OFFSET] == SN220_ROM_VER && - rsp[FW_MAJOR_VER_OFFSET] == SN220_MAJOR_VER) - chip_type = CHIP_SN220; - pr_info("%s:NFC Chip Type 0x%02x Rom Version 0x%02x FW Minor 0x%02x Major 0x%02x\n", - __func__, rsp[3], rsp[4], rsp[6], rsp[7]); - } -err: - return chip_type; -} - -/** - * get_nfcc_session_state_dl() - gets the session state - * @nfc_dev: nfc device data structure - * - * Performs get session command and determine - * the nfcc state based on session status. - * - * @Return nfcc state based on session status. - * NFC_STATE_FW_TEARED if sessionis not closed - * NFC_STATE_FW_DWL if session closed - * NFC_STATE_UNKNOWN in error cases. - */ -enum nfc_state_flags get_nfcc_session_state_dl(struct nfc_dev *nfc_dev) -{ - int ret = 0; - int cmd_length = 0; - uint8_t *cmd = nfc_dev->write_kbuf; - uint8_t *rsp = nfc_dev->read_kbuf; - enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN; - - *cmd++ = 0x00; - *cmd++ = 0x04; - *cmd++ = 0xF2; - *cmd++ = 0x00; - *cmd++ = 0x00; - *cmd++ = 0x00; - *cmd++ = 0xF5; - *cmd++ = 0x33; - cmd_length = cmd - nfc_dev->write_kbuf; - - pr_debug("%s:Sending GET_SESSION_STATE cmd of size=%d\n", __func__, cmd_length); - ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, MAX_RETRY_COUNT); - if (ret <= 0) { - pr_err("%s: - nfc get session cmd error ret %d\n", __func__, ret); - goto err; - } - memset(rsp, 0x00, DL_GET_SESSION_STATE_RSP_LEN); - pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT); - if (ret <= 0) { - pr_err("%s: - nfc get session rsp error ret %d\n", __func__, ret); - goto err; - } - if (rsp[0] != FW_MSG_CMD_RSP) { - pr_err("%s: - nfc invalid get session state rsp\n", __func__); - goto err; - } - pr_debug("Response bytes are %02x%02x%02x%02x%02x%02x%02x%02x", - rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6], rsp[7]); - /*verify fw in non-teared state */ - if (rsp[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) { - pr_err("%s NFCC booted in FW teared state\n", __func__); - nfc_state = NFC_STATE_FW_TEARED; - } else { - pr_info("%s NFCC booted in FW DN mode\n", __func__); - nfc_state = NFC_STATE_FW_DWL; - } -err: - return nfc_state; -} - -/** - * get_nfcc_chip_type() - get nfcc chip type in nci mode. - * @nfc_dev: nfc device data structure. - * - * Function to perform nci core reset and extract - * chip type from the response. - * - * @Return: enum chip_types value - * - */ -static enum chip_types get_nfcc_chip_type(struct nfc_dev *nfc_dev) -{ - int ret = 0; - int cmd_length = 0; - uint8_t major_version = 0; - uint8_t rom_version = 0; - uint8_t *cmd = nfc_dev->write_kbuf; - uint8_t *rsp = nfc_dev->read_kbuf; - enum chip_types chip_type = CHIP_UNKNOWN; - - *cmd++ = 0x20; - *cmd++ = 0x00; - *cmd++ = 0x01; - *cmd++ = 0x00; - cmd_length = cmd - nfc_dev->write_kbuf; - - pr_debug("%s:Sending NCI Core Reset cmd of size=%d\n", __func__, cmd_length); - ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, NO_RETRY); - if (ret <= 0) { - pr_err("%s: - nfc nci core reset cmd error ret %d\n", __func__, ret); - goto err; - } - usleep_range(NCI_RESET_RESP_READ_DELAY, NCI_RESET_RESP_READ_DELAY + 100); - nfc_dev->nfc_enable_intr(nfc_dev); - - memset(rsp, 0x00, NCI_RESET_RSP_LEN); - pr_debug("%s:Reading NCI Core Reset rsp\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_RSP_LEN, NCI_CMD_RSP_TIMEOUT); - if (ret <= 0) { - pr_err("%s: - nfc nci core reset rsp error ret %d\n", __func__, ret); - goto err_disable_intr; - } - - pr_debug(" %s: nci core reset response 0x%02x%02x%02x%02x\n", - __func__, rsp[0], rsp[1], rsp[2], rsp[3]); - if (rsp[0] != NCI_MSG_RSP) { - /* reset response failed response*/ - pr_err("%s invalid nci core reset response", __func__); - goto err_disable_intr; - } - - memset(rsp, 0x00, NCI_RESET_NTF_LEN); - /* read nci rest response ntf */ - ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_NTF_LEN, NCI_CMD_RSP_TIMEOUT); - if (ret <= 0) { - pr_err("%s - nfc nci rest rsp ntf error status %d\n", __func__, ret); - goto err_disable_intr; - } - if (rsp[0] == NCI_MSG_NTF) { - /* read version info from NCI Reset Notification */ - rom_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 3]; - major_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 2]; - /* determine chip type based on version info */ - if (rom_version == SN1XX_ROM_VER && major_version == SN1xx_MAJOR_VER) - chip_type = CHIP_SN1XX; - else if (rom_version == SN220_ROM_VER && major_version == SN220_MAJOR_VER) - chip_type = CHIP_SN220; - pr_debug(" %s:NCI Core Reset ntf 0x%02x%02x%02x%02x\n", - __func__, rsp[0], rsp[1], rsp[2], rsp[3]); - } -err_disable_intr: - nfc_dev->nfc_disable_intr(nfc_dev); -err: - return chip_type; -} - -/** - * validate_download_gpio() - validate download gpio. - * @nfc_dev: nfc_dev device data structure. - * @chip_type: chip type of the platform. - * - * Validates dwnld gpio should configured for supported and - * should not be configured for unsupported platform. - * - * @Return: true if gpio validation successful ortherwise - * false if validation fails. - */ -static bool validate_download_gpio(struct nfc_dev *nfc_dev, enum chip_types chip_type) -{ - bool status = false; - struct platform_gpio *nfc_gpio; - - if (nfc_dev == NULL) { - pr_err("%s nfc devices structure is null\n"); - return status; - } - nfc_gpio = &nfc_dev->configs.gpio; - if (chip_type == CHIP_SN1XX) { - /* gpio should be configured for SN1xx */ - status = gpio_is_valid(nfc_gpio->dwl_req); - } else if (chip_type == CHIP_SN220) { - /* gpio should not be configured for SN220 */ - set_valid_gpio(nfc_gpio->dwl_req, 0); - gpio_free(nfc_gpio->dwl_req); - nfc_gpio->dwl_req = -EINVAL; - status = true; - } - return status; -} - -/* Check for availability of NFC controller hardware */ -int nfcc_hw_check(struct nfc_dev *nfc_dev) -{ - int ret = 0; - enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN; - enum chip_types chip_type = CHIP_UNKNOWN; - struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - - /*get fw version in nci mode*/ - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - chip_type = get_nfcc_chip_type(nfc_dev); - - /*get fw version in fw dwl mode*/ - if (chip_type == CHIP_UNKNOWN) { - nfc_dev->nfc_enable_intr(nfc_dev); - /*Chip is unknown, initially assume with fw dwl pin enabled*/ - set_valid_gpio(nfc_gpio->dwl_req, 1); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - chip_type = get_nfcc_chip_type_dl(nfc_dev); - /*get the state of nfcc normal/teared in fw dwl mode*/ - } else { - nfc_state = NFC_STATE_NCI; - } - - /*validate gpio config required as per the chip*/ - if (!validate_download_gpio(nfc_dev, chip_type)) { - pr_info("%s gpio validation fail", __func__); - ret = -ENXIO; - goto err; - } - - /*check whether the NFCC is in FW DN or Teared state*/ - if (nfc_state != NFC_STATE_NCI) - nfc_state = get_nfcc_session_state_dl(nfc_dev); - - /*nfcc state specific operations */ - switch (nfc_state) { - case NFC_STATE_FW_TEARED: - pr_warn("%s: - NFCC FW Teared State\n", __func__); -#if IS_ENABLED(CONFIG_NXP_NFC_RECOVERY) - /* recovery neeeded only for SN1xx */ - if (chip_type == CHIP_SN1XX) { - if (do_recovery(nfc_dev) == STATUS_FAILED) - pr_debug("%s: - nfcc recoverey failed\n", __func__); - else - pr_debug("%s: - nfcc recovered successfully\n", __func__); - nfc_state = get_nfcc_session_state_dl(nfc_dev); - } -#endif - /*fallthrough*/ - case NFC_STATE_FW_DWL: - case NFC_STATE_NCI: - break; - case NFC_STATE_UNKNOWN: - default: - ret = -ENXIO; - pr_err("%s: - NFCC HW not available\n", __func__); - goto err; - }; - nfc_dev->nfc_state = nfc_state; - nfc_dev->nfc_ven_enabled = true; -err: - nfc_dev->nfc_disable_intr(nfc_dev); - set_valid_gpio(nfc_gpio->dwl_req, 0); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - return ret; -} - int validate_nfc_state_nci(struct nfc_dev *nfc_dev) { struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; if (!gpio_get_value(nfc_gpio->ven)) { - pr_err("VEN LOW - NFCC powered off\n"); + pr_err("%s: ven low - nfcc powered off\n", __func__); return -ENODEV; } if (get_valid_gpio(nfc_gpio->dwl_req) == 1) { - pr_err("FW download in-progress\n"); + pr_err("%s: fw download in-progress\n", __func__); return -EBUSY; } if (nfc_dev->nfc_state != NFC_STATE_NCI) { - pr_err("FW download state\n"); + pr_err("%s: fw download state\n", __func__); return -EBUSY; } return 0; diff --git a/nfc/common.h b/nfc/common.h index 363c6f3f83..c96958fe3a 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -1,7 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2021 NXP - * * + * Copyright (C) 2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2019-2021 NXP + * * This program 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 @@ -19,96 +19,68 @@ ******************************************************************************/ #ifndef _COMMON_H_ #define _COMMON_H_ -#include -#include -#include -#include -#include + #include -#include -#include #include "i2c_drv.h" -#define DEV_COUNT 1 /* Max device count for this driver */ -#define CLASS_NAME "nfc" /* i2c device class */ +/* Max device count for this driver */ +#define DEV_COUNT 1 +/* i2c device class */ +#define CLASS_NAME "nfc" -// NFC character device name, this will be in /dev/ -#define NFC_CHAR_DEV_NAME "pn553" +/* NFC character device name, this will be in /dev/ */ +#define NFC_CHAR_DEV_NAME "pn553" -// NCI packet details -#define NCI_MSG_CMD 0x20 -#define NCI_MSG_RSP 0x40 -#define NCI_MSG_NTF 0x60 -#define NCI_HDR_LEN 3 -#define NCI_PAYLOAD_IDX 3 -#define NCI_PAYLOAD_LEN_IDX 2 -/*Time to wait for first NCI rest response*/ -#define NCI_RESET_RESP_READ_DELAY (10000) // 10ms -#define NCI_RESET_RESP_TIMEOUT (500) // 500ms +/* NCI packet details */ +#define NCI_CMD (0x20) +#define NCI_RSP (0x40) +#define NCI_HDR_LEN (3) +#define NCI_HDR_IDX (0) +#define NCI_HDR_OID_IDX (1) +#define NCI_PAYLOAD_IDX (3) +#define NCI_PAYLOAD_LEN_IDX (2) -// FW DNLD packet details -#define FW_MSG_CMD_RSP 0x00 -#define FW_HDR_LEN 2 -#define FW_PAYLOAD_LEN_IDX 1 -#define FW_CRC_LEN 2 -#define FW_MIN_PAYLOAD_LEN 4 -#define MIN_NFC_DL_FRAME_SIZE 3 +/* FW DNLD packet details */ +#define DL_HDR_LEN (2) +#define DL_CRC_LEN (2) -#define NCI_RESET_CMD_LEN (4) -#define NCI_RESET_RSP_LEN (4) -#define NCI_RESET_NTF_LEN (13) +#define MAX_NCI_PAYLOAD_LEN (255) +#define MAX_NCI_BUFFER_SIZE (NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN) +#define MAX_DL_PAYLOAD_LEN (550) +#define MAX_DL_BUFFER_SIZE (DL_HDR_LEN + DL_CRC_LEN + \ + MAX_DL_PAYLOAD_LEN) -#define SN1XX_ROM_VER 0x01 -#define SN1xx_MAJOR_VER 0x10 -#define SN220_ROM_VER 0x01 -#define SN220_MAJOR_VER 0x01 -#define FW_ROM_CODE_VER_OFFSET 4 -#define FW_MAJOR_VER_OFFSET 7 -#define DL_GET_VERSION_CMD_LEN (8) -#define DL_GET_VERSION_RSP_LEN_1 (12) -#define DL_GET_VERSION_RSP_LEN_2 (20) +/* Retry count for normal write */ +#define NO_RETRY (1) +/* Maximum retry count for standby writes */ +#define MAX_RETRY_COUNT (3) +#define MAX_WRITE_IRQ_COUNT (5) +#define MAX_IRQ_WAIT_TIME (90) +#define WAKEUP_SRC_TIMEOUT (2000) -#define DL_RESET_CMD_LEN (8) -#define DL_GET_SESSION_STATE_CMD_LEN (8) -#define DL_GET_SESSION_STATE_RSP_LEN (8) -#define GET_SESSION_STS_OFF (3) -#define NFCC_SESSION_STS_CLOSED (0x0) -#define MAX_NCI_PAYLOAD_LEN (255) -#define MAX_BUFFER_SIZE (NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN) -#define MAX_DL_PAYLOAD_LEN (550) -#define MAX_DL_BUFFER_SIZE (FW_HDR_LEN + FW_CRC_LEN + MAX_DL_PAYLOAD_LEN) -// Maximum retry count for standby writes -#define MAX_RETRY_COUNT (3) -// Retry count for normal write -#define NO_RETRY (1) -#define MAX_IRQ_WAIT_TIME (90) -#define WAKEUP_SRC_TIMEOUT (2000) +/* command response timeout */ +#define NCI_CMD_RSP_TIMEOUT_MS (2000) +/* Time to wait for NFCC to be ready again after any change in the GPIO */ +#define NFC_GPIO_SET_WAIT_TIME_US (10000) +/* Time to wait for IRQ low during write 5*3ms */ +#define NFC_WRITE_IRQ_WAIT_TIME_US (3000) +/* Time to wait before retrying i2c/I3C writes */ +#define WRITE_RETRY_WAIT_TIME_US (1000) +/* Time to wait before retrying read for some specific usecases */ +#define READ_RETRY_WAIT_TIME_US (3500) +#define NFC_MAGIC (0xE9) -/*command response timeout*/ -#define NCI_CMD_RSP_TIMEOUT (2000) //2s -/*Time to wait for NFCC to be ready again after any change in the GPIO*/ -#define NFC_GPIO_SET_WAIT_TIME_USEC (10000) -/*Time to wait after soft reset via any NCI/DL cmd*/ -#define NFC_SOFT_RESET_WAIT_TIME_USEC (5000) -/*Time to wait before retrying i2c/I3C writes*/ -#define WRITE_RETRY_WAIT_TIME_USEC (1000) -/*Time to wait before retrying read for some specific usecases*/ -#define READ_RETRY_WAIT_TIME_USEC (3500) -#define NFC_MAGIC 0xE9 +/* Ioctls */ +/* The type should be aligned with MW HAL definitions */ +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, long) +#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, long) +#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, long) -/*Ioctls*/ -// The type should be aligned with MW HAL definitions -#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, long) -#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, long) -#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, long) -/* NFC HAL can call this ioctl to get the current IRQ state */ -#define NFC_GET_IRQ_STATE _IO(NFC_MAGIC, 0x06) - -#define DTS_IRQ_GPIO_STR "nxp,pn544-irq" -#define DTS_VEN_GPIO_STR "nxp,pn544-ven" -#define DTS_FWDN_GPIO_STR "nxp,pn544-fw-dwnld" +#define DTS_IRQ_GPIO_STR "nxp,pn544-irq" +#define DTS_VEN_GPIO_STR "nxp,pn544-ven" +#define DTS_FWDN_GPIO_STR "nxp,pn544-fw-dwnld" enum nfcc_ioctl_request { /* NFC disable request with VEN LOW */ @@ -127,21 +99,21 @@ enum nfcc_ioctl_request { NFC_FW_DWL_LOW, }; -/*nfc platform interface type*/ +/* nfc platform interface type */ enum interface_flags { - /*I2C physical IF for NFCC */ + /* I2C physical IF for NFCC */ PLATFORM_IF_I2C = 0, }; -/*nfc state flags*/ +/* nfc state flags */ enum nfc_state_flags { - /*nfc in unknown state */ + /* nfc in unknown state */ NFC_STATE_UNKNOWN = 0, - /*nfc in download mode */ + /* nfc in download mode */ NFC_STATE_FW_DWL = 0x1, - /*nfc booted in NCI mode */ + /* nfc booted in NCI mode */ NFC_STATE_NCI = 0x2, - /*nfc booted in Fw teared mode */ + /* nfc booted in Fw teared mode */ NFC_STATE_FW_TEARED = 0x4, }; /* @@ -154,7 +126,7 @@ enum pm_state_flags { PM_STATE_IBI_BEFORE_RESUME, }; -/* Enum for GPIO values*/ +/* Enum for GPIO values */ enum gpio_values { GPIO_INPUT = 0x0, GPIO_OUTPUT = 0x1, @@ -163,35 +135,29 @@ enum gpio_values { GPIO_IRQ = 0x4, }; -// NFC GPIO variables +/* NFC GPIO variables */ struct platform_gpio { unsigned int irq; unsigned int ven; unsigned int dwl_req; }; -// NFC Struct to get all the required configs from DTS +/* NFC Struct to get all the required configs from DTS */ struct platform_configs { struct platform_gpio gpio; }; -//cold reset Features specific Parameters +/* cold reset Features specific Parameters */ struct cold_reset { - bool rsp_pending; /*cmd rsp pending status */ - bool in_progress; /*for cold reset when gurad timer in progress */ - bool reset_protection; /*reset protection enabled/disabled */ - uint8_t status; /*status from response buffer */ - uint8_t rst_prot_src; /*reset protection source (SPI, NFC) */ + bool rsp_pending; /* cmd rsp pending status */ + bool in_progress; /* for cold reset when gurad timer in progress */ + bool reset_protection; /* reset protection enabled/disabled */ + uint8_t status; /* status from response buffer */ + uint8_t rst_prot_src; /* reset protection source (SPI, NFC) */ struct timer_list timer; wait_queue_head_t read_wq; }; -enum chip_types { - CHIP_SN1XX = 0x01, - CHIP_SN220 = 0x02, - CHIP_UNKNOWN = 0xFF, -}; - /* Device specific structure */ struct nfc_dev { wait_queue_head_t read_wq; @@ -211,18 +177,17 @@ struct nfc_dev { uint8_t nfc_state; /* NFC VEN pin state */ bool nfc_ven_enabled; - /* current firmware major version */ - uint8_t fw_major_version; union { struct i2c_dev i2c_dev; }; struct platform_configs configs; struct cold_reset cold_reset; - /*function pointers for the common i2c functionality */ - int (*nfc_read)(struct nfc_dev *dev, char *buf, size_t count, int timeout); - int (*nfc_write)(struct nfc_dev *dev, const char *buf, const size_t count, - int max_retry_cnt); + /* function pointers for the common i2c functionality */ + int (*nfc_read)(struct nfc_dev *dev, char *buf, size_t count, + int timeout); + int (*nfc_write)(struct nfc_dev *dev, const char *buf, + const size_t count, int max_retry_cnt); int (*nfc_enable_intr)(struct nfc_dev *dev); int (*nfc_disable_intr)(struct nfc_dev *dev); }; @@ -233,12 +198,11 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface); int nfc_misc_register(struct nfc_dev *nfc_dev, - const struct file_operations *nfc_fops, int count, char *devname, - char *classname); + const struct file_operations *nfc_fops, int count, + char *devname, char *classname); void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count); int configure_gpio(unsigned int gpio, int flag); void gpio_set_ven(struct nfc_dev *nfc_dev, int value); void gpio_free_all(struct nfc_dev *nfc_dev); int validate_nfc_state_nci(struct nfc_dev *nfc_dev); -int nfcc_hw_check(struct nfc_dev *nfc_dev); -#endif //_COMMON_H_ +#endif /* _COMMON_H_ */ diff --git a/nfc/common_ese.c b/nfc/common_ese.c index cf63a15690..18b3d34e1f 100644 --- a/nfc/common_ese.c +++ b/nfc/common_ese.c @@ -1,6 +1,6 @@ /****************************************************************************** - * Copyright (C) 2020-2021 NXP - * * + * Copyright (C) 2020-2021 NXP + * * This program 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 @@ -16,23 +16,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ - -#include -#include -#include #include #include -#include -#include -#include -#include "common.h" +#include + #include "common_ese.h" static void cold_reset_gaurd_timer_callback(struct timer_list *t) { struct cold_reset *cold_reset = from_timer(cold_reset, t, timer); - pr_debug("%s: Enter\n", __func__); + pr_debug("%s: entry\n", __func__); cold_reset->in_progress = false; } @@ -41,18 +35,19 @@ static long start_cold_reset_guard_timer(struct cold_reset *cold_reset) long ret = -EINVAL; if (timer_pending(&cold_reset->timer) == 1) { - pr_debug("ese_cold_reset_guard_timer: delete pending timer\n"); + pr_debug("%s: delete pending timer\n", __func__); /* delete timer if already pending */ del_timer(&cold_reset->timer); } cold_reset->in_progress = true; timer_setup(&cold_reset->timer, cold_reset_gaurd_timer_callback, 0); ret = mod_timer(&cold_reset->timer, - jiffies + msecs_to_jiffies(ESE_CLD_RST_GUARD_TIME)); + jiffies + msecs_to_jiffies(ESE_CLD_RST_GUARD_TIME_MS)); return ret; } -static int send_cold_reset_protection_cmd(struct nfc_dev *nfc_dev, bool requestType) +static int send_cold_reset_protection_cmd(struct nfc_dev *nfc_dev, + bool requestType) { int ret = 0; int cmd_length = 0; @@ -62,30 +57,32 @@ static int send_cold_reset_protection_cmd(struct nfc_dev *nfc_dev, bool requestT mutex_lock(&nfc_dev->write_mutex); *cmd++ = NCI_PROP_MSG_CMD; - if (requestType) { /*reset protection*/ + if (requestType) { /* reset protection */ *cmd++ = RST_PROT_OID; *cmd++ = RST_PROT_PAYLOAD_SIZE; *cmd++ = (!cold_reset->reset_protection) ? 1 : 0; - } else { /*cold reset*/ + } else { /* cold reset */ *cmd++ = CLD_RST_OID; *cmd++ = CLD_RST_PAYLOAD_SIZE; } cmd_length = cmd - nfc_dev->write_kbuf; - ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, MAX_RETRY_COUNT); + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, + MAX_RETRY_COUNT); if (ret != cmd_length) { ret = -EIO; - pr_err("%s : nfc_write returned %d\n", __func__, ret); - goto exit; + pr_err("%s: nfc_write returned %d\n", __func__, ret); + goto exit; } cmd = nfc_dev->write_kbuf; - if (requestType) { - pr_debug("%s: NxpNciX: %d > %02X%02X%02X%02X\n", __func__, ret, cmd[0], cmd[1], - cmd[2], cmd[3]); - } else { - pr_debug("%s: NxpNciX: %d > %02X%02X%02X\n", __func__, ret, cmd[0], cmd[1], - cmd[2]); - } + if (requestType) + pr_debug(" %s: NxpNciX: %d > 0x%02x%02x%02x%02x\n", __func__, + ret, cmd[NCI_HDR_IDX], cmd[NCI_HDR_OID_IDX], + cmd[NCI_PAYLOAD_LEN_IDX], cmd[NCI_PAYLOAD_IDX]); + else + pr_debug(" %s: NxpNciX: %d > 0x%02x%02x%02x\n", __func__, ret, + cmd[NCI_HDR_IDX], cmd[NCI_HDR_OID_IDX], + cmd[NCI_PAYLOAD_LEN_IDX]); exit: mutex_unlock(&nfc_dev->write_mutex); return ret; @@ -97,64 +94,71 @@ void wakeup_on_prop_rsp(struct nfc_dev *nfc_dev, uint8_t *buf) cold_reset->status = -EIO; if ((NCI_HDR_LEN + buf[NCI_PAYLOAD_LEN_IDX]) != NCI_PROP_MSG_RSP_LEN) - pr_err("%s: - invalid response for cold_reset/protection\n", __func__); + pr_err("%s: invalid response for cold_reset/protection\n", + __func__); else cold_reset->status = buf[NCI_PAYLOAD_IDX]; - pr_debug("%s NxpNciR : len = 4 > %02X%02X%02X%02X\n", __func__, buf[0], buf[1], - buf[2], buf[3]); + pr_debug(" %s: NxpNciR 0x%02x%02x%02x%02x\n", __func__, + buf[NCI_HDR_IDX], buf[NCI_HDR_OID_IDX], + buf[NCI_PAYLOAD_LEN_IDX], buf[NCI_PAYLOAD_IDX]); cold_reset->rsp_pending = false; wake_up_interruptible(&cold_reset->read_wq); } static int validate_cold_reset_protection_request(struct cold_reset *cold_reset, - unsigned long arg) + unsigned long arg) { int ret = 0; if (!cold_reset->reset_protection) { if (IS_RST_PROT_EN_REQ(arg) && IS_SRC_VALID_PROT(arg)) { - pr_debug("%s:req - reset protection enable\n", __func__); + pr_debug("%s: reset protection enable\n", __func__); } else if (IS_CLD_RST_REQ(arg) && IS_SRC_VALID(arg)) { - pr_debug("%s:req - cold reset\n", __func__); + pr_debug("%s: cold reset\n", __func__); } else if (IS_RST_PROT_DIS_REQ(arg) && IS_SRC_VALID_PROT(arg)) { - pr_debug("%s:req - reset protection already disable\n", __func__); + pr_debug("%s: reset protection already disable\n", + __func__); ret = -EINVAL; } else { - pr_err("%s:Operation not permitted\n", __func__); + pr_err("%s: operation not permitted\n", __func__); ret = -EPERM; } } else { - if (IS_RST_PROT_DIS_REQ(arg) - && IS_SRC(arg, cold_reset->rst_prot_src)) { - pr_debug("%s:req - disable reset protection from same src\n", __func__); - } else if (IS_CLD_RST_REQ(arg) - && IS_SRC(arg, cold_reset->rst_prot_src)) { - pr_debug("%s:req - cold reset from same source\n", __func__); - } else if (IS_RST_PROT_EN_REQ(arg) - && IS_SRC(arg, cold_reset->rst_prot_src)) { - pr_debug("%s:req - enable reset protection from same src\n", __func__); + if (IS_RST_PROT_DIS_REQ(arg) && + IS_SRC(arg, cold_reset->rst_prot_src)) { + pr_debug("%s: disable reset protection from same src\n", + __func__); + } else if (IS_CLD_RST_REQ(arg) && + IS_SRC(arg, cold_reset->rst_prot_src)) { + pr_debug("%s: cold reset from same source\n", __func__); + } else if (IS_RST_PROT_EN_REQ(arg) && + IS_SRC(arg, cold_reset->rst_prot_src)) { + pr_debug("%s: enable reset protection from same src\n", + __func__); } else { - pr_err("%s: Operation not permitted\n", __func__); + pr_err("%s: operation not permitted\n", __func__); ret = -EPERM; } } return ret; } -static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, unsigned long arg) +static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, + unsigned long arg) { int ret = 0; + int timeout = 0; struct file filp; char *rsp = nfc_dev->read_kbuf; struct cold_reset *cold_reset = &nfc_dev->cold_reset; bool nfc_dev_opened = false; - /*check if NFCC not in the FW download or hard reset state */ + /* check if NFCC not in the FW download or hard reset state */ ret = validate_nfc_state_nci(nfc_dev); if (ret < 0) { - pr_err("%s: invalid cmd", __func__); + pr_err("%s: invalid cmd\n", __func__); return ret; } @@ -162,16 +166,16 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, unsigned long mutex_lock(&nfc_dev->dev_ref_mutex); nfc_dev_opened = (nfc_dev->dev_ref_count > 0) ? true : false; - /*check if NFCC not in the FW download or hard reset state */ + /* check if NFCC not in the FW download or hard reset state */ ret = validate_cold_reset_protection_request(cold_reset, arg); if (ret < 0) { - pr_err("%s: invalid cmd", __func__); + pr_err("%s: invalid cmd\n", __func__); goto err; } - /*check if cold reset already in progress */ + /* check if cold reset already in progress */ if (IS_CLD_RST_REQ(arg) && cold_reset->in_progress) { - pr_err("%s: cold reset already in progress", __func__); + pr_err("%s: cold reset already in progress\n", __func__); ret = -EBUSY; goto err; } @@ -179,65 +183,69 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, unsigned long cold_reset->status = -EIO; cold_reset->rsp_pending = true; - /*enable interrupt before sending cmd, when devnode not opened by HAL */ + /* enable interrupt before sending cmd, when devnode not opened by HAL */ if (!nfc_dev_opened) nfc_dev->nfc_enable_intr(nfc_dev); ret = send_cold_reset_protection_cmd(nfc_dev, IS_RST_PROT_REQ(arg)); if (ret < 0) { - pr_err("failed to send cold reset/protection command\n"); + pr_err("%s: failed to send cold reset/protection cmd\n", + __func__); cold_reset->rsp_pending = false; goto err; } ret = 0; - /*start the cold reset guard timer */ + /* start the cold reset guard timer */ if (IS_CLD_RST_REQ(arg)) { - /*Guard timer not needed when OSU over NFC*/ + /* Guard timer not needed when OSU over NFC */ if (!(cold_reset->reset_protection && IS_SRC_NFC(arg))) { ret = start_cold_reset_guard_timer(cold_reset); if (ret) { - pr_err("%s: Error in mod_timer\n", __func__); + pr_err("%s: error in mod_timer\n", __func__); goto err; } } } + timeout = NCI_CMD_RSP_TIMEOUT_MS; do { - /* Read is pending from the HAL service which will complete the response */ + /* Read pending response form the HAL service */ if (nfc_dev_opened) { - if (!wait_event_interruptible_timeout - (cold_reset->read_wq, - cold_reset->rsp_pending == false, - msecs_to_jiffies(NCI_CMD_RSP_TIMEOUT))) { - pr_err("%s:cold reset/protection response timeout\n", __func__); + if (!wait_event_interruptible_timeout( + cold_reset->read_wq, + cold_reset->rsp_pending == false, + msecs_to_jiffies(timeout))) { + pr_err("%s: cold reset/prot response timeout\n", + __func__); ret = -EAGAIN; } } else { - /* Read data as NFC thread is not active */ + /* Read response here as NFC thread is not active */ filp.private_data = nfc_dev; if (nfc_dev->interface == PLATFORM_IF_I2C) { filp.f_flags &= ~O_NONBLOCK; - ret = nfc_dev->nfc_read(nfc_dev, rsp, 3, NCI_CMD_RSP_TIMEOUT); + ret = nfc_dev->nfc_read(nfc_dev, rsp, 3, + timeout); if (!ret) break; - usleep_range(READ_RETRY_WAIT_TIME_USEC, - READ_RETRY_WAIT_TIME_USEC + 500); + usleep_range(READ_RETRY_WAIT_TIME_US, + READ_RETRY_WAIT_TIME_US + 500); } } } while (ret == -ERESTARTSYS || ret == -EFAULT); - - if (ret == 0) { /* success case */ + timeout = ESE_CLD_RST_REBOOT_GUARD_TIME_MS; + if (ret == 0) { /* success case */ ret = cold_reset->status; if (IS_RST_PROT_REQ(arg)) { cold_reset->reset_protection = IS_RST_PROT_EN_REQ(arg); - cold_reset->rst_prot_src = - IS_RST_PROT_EN_REQ(arg) ? GET_SRC(arg) : SRC_NONE; + cold_reset->rst_prot_src = IS_RST_PROT_EN_REQ(arg) ? + GET_SRC(arg) : + SRC_NONE; /* wait for reboot guard timer */ - } else if (wait_event_interruptible_timeout - (cold_reset->read_wq, true, - msecs_to_jiffies(ESE_CLD_RST_REBOOT_GUARD_TIME)) == - 0) { - pr_info("%s: reboot guard timer timeout", __func__); + } else if (wait_event_interruptible_timeout( + cold_reset->read_wq, true, + msecs_to_jiffies(timeout)) == 0) { + pr_info("%s: reboot guard timer timeout\n", __func__); } } err: @@ -245,11 +253,15 @@ err: return ret; } -/* - * Power management of the eSE - * eSE and NFCC both are powered using VEN gpio, - * VEN HIGH - eSE and NFCC both are powered on - * VEN LOW - eSE and NFCC both are power down +/** + * nfc_ese_pwr() - power control for ese + * @nfc_dev: nfc device data structure + * @arg: mode that we want to move to + * + * Device power control. Depending on the arg value, device moves to + * different states, refer common_ese.h for args + * + * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case */ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) { @@ -257,7 +269,7 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; if (arg == ESE_POWER_ON) { - /** + /* * Let's store the NFC VEN pin state * will check stored value in case of eSE power off request, * to find out if NFC MW also sent request to set VEN HIGH @@ -266,25 +278,28 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) */ nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_gpio->ven); if (!nfc_dev->nfc_ven_enabled) { - pr_debug("eSE HAL service setting ven HIGH\n"); + pr_debug("%s: ese hal service setting ven high\n", + __func__); gpio_set_ven(nfc_dev, 1); } else { - pr_debug("ven already HIGH\n"); + pr_debug("%s: ven already high\n", __func__); } } else if (arg == ESE_POWER_OFF) { if (!nfc_dev->nfc_ven_enabled) { - pr_debug("NFC not enabled, disabling ven\n"); + pr_debug("%s: nfc not enabled, disabling ven\n", + __func__); gpio_set_ven(nfc_dev, 0); } else { - pr_debug("keep ven high as NFC is enabled\n"); + pr_debug("%s: keep ven high as nfc is enabled\n", + __func__); } } else if (arg == ESE_POWER_STATE) { - // eSE get power state + /* eSE get power state */ ret = gpio_get_value(nfc_gpio->ven); } else if (IS_CLD_RST_REQ(arg) || IS_RST_PROT_REQ(arg)) { ret = perform_cold_reset_protection(nfc_dev, arg); } else { - pr_err("%s bad arg %lu\n", __func__, arg); + pr_err("%s: bad arg %lu\n", __func__, arg); ret = -ENOIOCTLCMD; } return ret; @@ -310,15 +325,15 @@ int perform_ese_cold_reset(unsigned long arg) if (IS_CLD_RST_REQ(arg) && IS_SRC_OTHER(arg)) { ret = nfc_ese_pwr(nfc_dev_legacy, arg); } else { - pr_err("%s : Operation not permitted\n", __func__); + pr_err("%s: operation not permitted\n", __func__); return -EPERM; } } - pr_debug("%s:%d exit, status:%lu", __func__, arg, ret); + pr_debug("%s: arg = %d ret = %lu\n", __func__, arg, ret); return ret; } EXPORT_SYMBOL(perform_ese_cold_reset); -#endif //ESE_LEGACY_INTERFACE +#endif /* ESE_LEGACY_INTERFACE */ void ese_cold_reset_release(struct nfc_dev *nfc_dev) { @@ -340,12 +355,12 @@ void common_ese_init(struct nfc_dev *nfc_dev) ese_cold_reset_release(nfc_dev); #ifdef ESE_LEGACY_INTERFACE nfc_dev_legacy = nfc_dev; -#endif //ESE_LEGACY_INTERFACE +#endif /* ESE_LEGACY_INTERFACE */ } void common_ese_exit(struct nfc_dev *nfc_dev) { #ifdef ESE_LEGACY_INTERFACE nfc_dev_legacy = NULL; -#endif //ESE_LEGACY_INTERFACE +#endif /* ESE_LEGACY_INTERFACE */ } diff --git a/nfc/common_ese.h b/nfc/common_ese.h index 46d8d2f27c..c8d563724b 100644 --- a/nfc/common_ese.h +++ b/nfc/common_ese.h @@ -1,6 +1,6 @@ /****************************************************************************** - * Copyright (C) 2020-2021 NXP - * * + * Copyright (C) 2020-2021 NXP + * * This program 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 @@ -16,33 +16,32 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ - #ifndef _COMMON_ESE_H_ #define _COMMON_ESE_H_ #include "common.h" -/*nci prop msg 1st byte*/ -#define NCI_PROP_MSG_GID 0x0F -#define NCI_PROP_MSG_CMD (NCI_MSG_CMD | NCI_PROP_MSG_GID) -#define NCI_PROP_MSG_RSP (NCI_MSG_RSP | NCI_PROP_MSG_GID) +/* nci prop msg 1st byte */ +#define NCI_PROP_MSG_GID 0x0F +#define NCI_PROP_MSG_CMD (NCI_CMD | NCI_PROP_MSG_GID) +#define NCI_PROP_MSG_RSP (NCI_RSP | NCI_PROP_MSG_GID) -/*nci prop msg 2nd byte*/ -#define CLD_RST_OID 0x1E -#define RST_PROT_OID 0x1F +/* nci prop msg 2nd byte */ +#define CLD_RST_OID 0x1E +#define RST_PROT_OID 0x1F -/*nci prop msg 3rd byte*/ -#define CLD_RST_PAYLOAD_SIZE 0x00 -#define RST_PROT_PAYLOAD_SIZE 0x01 +/* nci prop msg 3rd byte */ +#define CLD_RST_PAYLOAD_SIZE 0x00 +#define RST_PROT_PAYLOAD_SIZE 0x01 -/*nci prop msg response length*/ -#define NCI_PROP_MSG_RSP_LEN 0x04 +/* nci prop msg response length */ +#define NCI_PROP_MSG_RSP_LEN 0x04 -/*cold reset guard time to allow back to back cold reset after some time*/ -#define ESE_CLD_RST_GUARD_TIME (3000) //3s -/*guard time to reboot after reset*/ -#define ESE_CLD_RST_REBOOT_GUARD_TIME (50) //50ms -/*sources of reset protection and cold reset*/ +/* cold reset guard time to allow back to back cold reset after some time */ +#define ESE_CLD_RST_GUARD_TIME_MS (3000) +/* guard time to reboot after reset */ +#define ESE_CLD_RST_REBOOT_GUARD_TIME_MS (50) +/* sources of reset protection and cold reset */ enum reset_source { SRC_SPI = 0, SRC_NFC = 0x10, @@ -55,38 +54,41 @@ enum ese_ioctl_request { ESE_POWER_OFF, /* eSE POWER OFF */ ESE_POWER_STATE, /* eSE GET POWER STATE */ - /*ese reset requests from eSE service/hal/driver */ + /* ese reset requests from eSE service/hal/driver */ ESE_CLD_RST, /* eSE COLD RESET */ ESE_RST_PROT_EN, /* eSE RESET PROTECTION ENABLE */ ESE_RST_PROT_DIS, /* eSE RESET PROTECTION DISABLE */ - /*similar ese reset requests from nfc service/hal/driver */ + /* similar ese reset requests from nfc service/hal/driver */ ESE_CLD_RST_NFC = ESE_CLD_RST | SRC_NFC, ESE_RST_PROT_EN_NFC = ESE_RST_PROT_EN | SRC_NFC, ESE_RST_PROT_DIS_NFC = ESE_RST_PROT_DIS | SRC_NFC, - /*similar ese reset requests from other service/hal/driver */ + /* similar ese reset requests from other service/hal/driver */ ESE_CLD_RST_OTHER = ESE_CLD_RST | SRC_OTHER, }; -#define GET_SRC(arg) (arg & 0xF0) -#define IS_SRC(arg, src) (GET_SRC(arg) == src) -#define IS_SRC_SPI(arg) IS_SRC(arg, SRC_SPI) -#define IS_SRC_NFC(arg) IS_SRC(arg, SRC_NFC) -#define IS_SRC_OTHER(arg) IS_SRC(arg, SRC_OTHER) -#define IS_SRC_VALID(arg) (IS_SRC_SPI(arg) || IS_SRC_NFC(arg) || \ - IS_SRC_OTHER(arg)) -#define IS_SRC_VALID_PROT(arg) (IS_SRC_SPI(arg) || IS_SRC_NFC(arg)) +#define GET_SRC(arg) (arg & 0xF0) +#define IS_SRC(arg, src) (GET_SRC(arg) == src) +#define IS_SRC_SPI(arg) IS_SRC(arg, SRC_SPI) +#define IS_SRC_NFC(arg) IS_SRC(arg, SRC_NFC) +#define IS_SRC_OTHER(arg) IS_SRC(arg, SRC_OTHER) +#define IS_SRC_VALID(arg) (IS_SRC_SPI(arg) || \ + IS_SRC_NFC(arg) || \ + IS_SRC_OTHER(arg)) +#define IS_SRC_VALID_PROT(arg) (IS_SRC_SPI(arg) || \ + IS_SRC_NFC(arg)) -#define IS_RST(arg, type) ((arg & 0xF) == type) -#define IS_CLD_RST_REQ(arg) IS_RST(arg, ESE_CLD_RST) -#define IS_RST_PROT_EN_REQ(arg) IS_RST(arg, ESE_RST_PROT_EN) -#define IS_RST_PROT_DIS_REQ(arg) IS_RST(arg, ESE_RST_PROT_DIS) -#define IS_RST_PROT_REQ(arg) (IS_RST_PROT_EN_REQ(arg) || IS_RST_PROT_DIS_REQ(arg)) +#define IS_RST(arg, type) ((arg & 0xF) == type) +#define IS_CLD_RST_REQ(arg) IS_RST(arg, ESE_CLD_RST) +#define IS_RST_PROT_EN_REQ(arg) IS_RST(arg, ESE_RST_PROT_EN) +#define IS_RST_PROT_DIS_REQ(arg) IS_RST(arg, ESE_RST_PROT_DIS) +#define IS_RST_PROT_REQ(arg) (IS_RST_PROT_EN_REQ(arg) || \ + IS_RST_PROT_DIS_REQ(arg)) /* This macro evaluates to 1 if prop cmd response is received */ -#define IS_PROP_CMD_RSP(buf) \ - ((buf[0] == NCI_PROP_MSG_RSP) && ((buf[1] == CLD_RST_OID) || \ - (buf[1] == RST_PROT_OID))) +#define IS_PROP_CMD_RSP(buf) ((buf[0] == NCI_PROP_MSG_RSP) && \ + ((buf[1] == CLD_RST_OID) || \ + (buf[1] == RST_PROT_OID))) void wakeup_on_prop_rsp(struct nfc_dev *nfc_dev, uint8_t *buf); int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg); diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index d6768858d7..83a1ed5d9e 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -1,7 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015, The Linux Foundation. All rights reserved. - * Copyright (C) 2013-2021 NXP - * * + * Copyright (C) 2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2013-2021 NXP + * * This program 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 @@ -34,15 +34,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include + #include -#include #include #include #include -#include -#include "common.h" +#include + #include "common_ese.h" /** @@ -103,20 +101,19 @@ static irqreturn_t i2c_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } - int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) { int ret; struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - pr_debug("%s : reading %zu bytes.\n", __func__, count); + pr_debug("%s: reading %zu bytes.\n", __func__, count); - if (timeout > NCI_CMD_RSP_TIMEOUT) - timeout = NCI_CMD_RSP_TIMEOUT; + if (timeout > NCI_CMD_RSP_TIMEOUT_MS) + timeout = NCI_CMD_RSP_TIMEOUT_MS; - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; + if (count > MAX_NCI_BUFFER_SIZE) + count = MAX_NCI_BUFFER_SIZE; if (!gpio_get_value(nfc_gpio->irq)) { while (1) { @@ -127,18 +124,23 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) } if (!gpio_get_value(nfc_gpio->irq)) { if (timeout) { - ret = wait_event_interruptible_timeout(nfc_dev->read_wq, - !i2c_dev->irq_enabled, msecs_to_jiffies(timeout)); + ret = wait_event_interruptible_timeout( + nfc_dev->read_wq, + !i2c_dev->irq_enabled, + msecs_to_jiffies(timeout)); if (ret <= 0) { - pr_err("%s timeout/error in read\n", __func__); + pr_err("%s: timeout error\n", + __func__); goto err; } } else { - ret = wait_event_interruptible(nfc_dev->read_wq, + ret = wait_event_interruptible( + nfc_dev->read_wq, !i2c_dev->irq_enabled); if (ret) { - pr_err("%s error wakeup of read wq\n", __func__); + pr_err("%s: err wakeup of wq\n", + __func__); goto err; } } @@ -170,10 +172,12 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) if (nfc_dev->cold_reset.rsp_pending) { if (IS_PROP_CMD_RSP(buf)) { /* Read data */ - ret = i2c_master_recv(nfc_dev->i2c_dev.client, &buf[NCI_PAYLOAD_IDX], - buf[NCI_PAYLOAD_LEN_IDX]); + ret = i2c_master_recv(nfc_dev->i2c_dev.client, + &buf[NCI_PAYLOAD_IDX], + buf[NCI_PAYLOAD_LEN_IDX]); if (ret <= 0) { - pr_err("%s: error reading cold reset/prot rsp header\n", __func__); + pr_err("%s: error reading cold rst/prot rsp\n", + __func__); goto err; } wakeup_on_prop_rsp(nfc_dev, buf); @@ -194,19 +198,38 @@ int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, { int ret = -EINVAL; int retry_cnt; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; if (count > MAX_DL_BUFFER_SIZE) count = MAX_DL_BUFFER_SIZE; - pr_debug("%s : writing %zu bytes.\n", __func__, count); + pr_debug("%s: writing %zu bytes.\n", __func__, count); + /* + * Wait for any pending read for max 15ms before write + * This is to avoid any packet corruption during read, when + * the host cmds resets NFCC during any parallel read operation + */ + for (retry_cnt = 1; retry_cnt <= MAX_WRITE_IRQ_COUNT; retry_cnt++) { + if (gpio_get_value(nfc_gpio->irq)) { + pr_warn("%s: irq high during write, wait\n", __func__); + usleep_range(NFC_WRITE_IRQ_WAIT_TIME_US, + NFC_WRITE_IRQ_WAIT_TIME_US + 100); + } else { + break; + } + if (retry_cnt == MAX_WRITE_IRQ_COUNT && + gpio_get_value(nfc_gpio->irq)) { + pr_warn("%s: allow after maximum wait\n", __func__); + } + } for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) { ret = i2c_master_send(nfc_dev->i2c_dev.client, buf, count); if (ret <= 0) { - pr_warn("%s: failed to write ret(%d), Maybe in Standby Mode - Retry(%d)\n", __func__, - ret, retry_cnt); - usleep_range(WRITE_RETRY_WAIT_TIME_USEC, - WRITE_RETRY_WAIT_TIME_USEC + 100); + pr_warn("%s: write failed ret(%d), maybe in standby\n", + __func__, ret); + usleep_range(WRITE_RETRY_WAIT_TIME_US, + WRITE_RETRY_WAIT_TIME_US + 100); } else if (ret != count) { pr_err("%s: failed to write %d\n", __func__, ret); ret = -EIO; @@ -216,21 +239,21 @@ int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, return ret; } -ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) +ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, size_t count, + loff_t *offset) { - int ret = 0; + int ret; struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; if (filp->f_flags & O_NONBLOCK) { - pr_err(":f_falg has O_NONBLOCK. EAGAIN\n"); + pr_err("%s: f_flags has nonblock. try again\n", __func__); return -EAGAIN; } mutex_lock(&nfc_dev->read_mutex); ret = i2c_read(nfc_dev, nfc_dev->read_kbuf, count, 0); if (ret > 0) { if (copy_to_user(buf, nfc_dev->read_kbuf, ret)) { - pr_warn("%s : failed to copy to user space\n", __func__); + pr_warn("%s: failed to copy to user space\n", __func__); ret = -EFAULT; } } @@ -239,9 +262,9 @@ ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, } ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) + size_t count, loff_t *offset) { - int ret = 0; + int ret; struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; if (count > MAX_DL_BUFFER_SIZE) @@ -249,7 +272,7 @@ ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf, mutex_lock(&nfc_dev->write_mutex); if (copy_from_user(nfc_dev->write_kbuf, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); + pr_err("%s: failed to copy from user space\n", __func__); mutex_unlock(&nfc_dev->write_mutex); return -EFAULT; } @@ -277,15 +300,15 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) struct platform_gpio *nfc_gpio = &nfc_configs.gpio; pr_debug("%s: enter\n", __func__); - /*retrieve details of gpios from dt */ + /* retrieve details of gpios from dt */ ret = nfc_parse_dt(&client->dev, &nfc_configs, PLATFORM_IF_I2C); if (ret) { - pr_err("%s : failed to parse dt\n", __func__); + pr_err("%s: failed to parse dt\n", __func__); goto err; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); + pr_err("%s: need I2C_FUNC_I2C\n", __func__); ret = -ENODEV; goto err; } @@ -294,15 +317,15 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) ret = -ENOMEM; goto err; } - nfc_dev->read_kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); + nfc_dev->read_kbuf = kzalloc(MAX_NCI_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); if (!nfc_dev->read_kbuf) { ret = -ENOMEM; - goto err; + goto err_free_nfc_dev; } nfc_dev->write_kbuf = kzalloc(MAX_DL_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); if (!nfc_dev->write_kbuf) { ret = -ENOMEM; - goto err; + goto err_free_read_kbuf; } nfc_dev->interface = PLATFORM_IF_I2C; nfc_dev->nfc_state = NFC_STATE_NCI; @@ -312,26 +335,28 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) nfc_dev->nfc_write = i2c_write; nfc_dev->nfc_enable_intr = i2c_enable_irq; nfc_dev->nfc_disable_intr = i2c_disable_irq; - nfc_dev->fw_major_version = 0; ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT); if (ret) { - pr_err("%s: unable to request nfc reset gpio [%d]\n", __func__, nfc_gpio->ven); - goto err; + pr_err("%s: unable to request nfc reset gpio [%d]\n", __func__, + nfc_gpio->ven); + goto err_free_write_kbuf; } ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ); if (ret <= 0) { - pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__, nfc_gpio->irq); - goto err; + pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__, + nfc_gpio->irq); + goto err_free_gpio; } client->irq = ret; ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT); if (ret) { - pr_err("%s: unable to request nfc firm downl gpio [%d]\n", __func__, - nfc_gpio->dwl_req); + pr_err("%s: unable to request nfc firm downl gpio [%d]\n", + __func__, nfc_gpio->dwl_req); } - /*copy the retrieved gpio details from DT */ - memcpy(&nfc_dev->configs, &nfc_configs, sizeof(struct platform_configs)); + /* copy the retrieved gpio details from DT */ + memcpy(&nfc_dev->configs, &nfc_configs, + sizeof(struct platform_configs)); /* init mutex and queues */ init_waitqueue_head(&nfc_dev->read_wq); @@ -347,28 +372,23 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_mutex_destroy; } /* interrupt initializations */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pr_info("%s: requesting IRQ %d\n", __func__, client->irq); i2c_dev->irq_enabled = true; - ret = request_irq(client->irq, i2c_irq_handler, - IRQF_TRIGGER_HIGH, client->name, nfc_dev); + ret = request_irq(client->irq, i2c_irq_handler, IRQF_TRIGGER_HIGH, + client->name, nfc_dev); if (ret) { pr_err("%s: request_irq failed\n", __func__); goto err_nfc_misc_unregister; } i2c_disable_irq(nfc_dev); - - ret = nfcc_hw_check(nfc_dev); - if (ret != 0) { - pr_err("nfc hw check failed ret %d\n", ret); - goto err_nfc_misc_unregister; - } - + gpio_set_ven(nfc_dev, 1); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); device_init_wakeup(&client->dev, true); - device_set_wakeup_capable(&client->dev, true); i2c_set_clientdata(client, nfc_dev); i2c_dev->irq_wake_up = false; - pr_info("%s probing nfc i2c successfully", __func__); + pr_info("%s: probing nfc i2c successfully\n", __func__); return 0; err_nfc_misc_unregister: nfc_misc_unregister(nfc_dev, DEV_COUNT); @@ -376,11 +396,15 @@ err_mutex_destroy: mutex_destroy(&nfc_dev->dev_ref_mutex); mutex_destroy(&nfc_dev->read_mutex); mutex_destroy(&nfc_dev->write_mutex); -err: +err_free_gpio: gpio_free_all(nfc_dev); - kfree(nfc_dev->read_kbuf); +err_free_write_kbuf: kfree(nfc_dev->write_kbuf); +err_free_read_kbuf: + kfree(nfc_dev->read_kbuf); +err_free_nfc_dev: kfree(nfc_dev); +err: pr_err("%s: probing not successful, check hardware\n", __func__); return ret; } @@ -439,19 +463,18 @@ int nfc_i2c_dev_resume(struct device *device) return 0; } -static const struct i2c_device_id nfc_i2c_dev_id[] = { - {NFC_I2C_DEV_ID, 0}, - {} -}; +static const struct i2c_device_id nfc_i2c_dev_id[] = { { NFC_I2C_DEV_ID, 0 }, + {} }; static const struct of_device_id nfc_i2c_dev_match_table[] = { - {.compatible = NFC_I2C_DRV_STR,}, + { + .compatible = NFC_I2C_DRV_STR, + }, {} }; -static const struct dev_pm_ops nfc_i2c_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(nfc_i2c_dev_suspend, nfc_i2c_dev_resume) -}; +static const struct dev_pm_ops nfc_i2c_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS( + nfc_i2c_dev_suspend, nfc_i2c_dev_resume) }; static struct i2c_driver nfc_i2c_dev_driver = { .id_table = nfc_i2c_dev_id, @@ -471,10 +494,10 @@ static int __init nfc_i2c_dev_init(void) { int ret = 0; - pr_info("Loading NXP NFC I2C driver\n"); + pr_info("%s: Loading NXP NFC I2C driver\n", __func__); ret = i2c_add_driver(&nfc_i2c_dev_driver); if (ret != 0) - pr_err("NFC I2C add driver error ret %d\n", ret); + pr_err("%s: NFC I2C add driver error ret %d\n", __func__, ret); return ret; } @@ -482,7 +505,7 @@ module_init(nfc_i2c_dev_init); static void __exit nfc_i2c_dev_exit(void) { - pr_info("Unloading NXP NFC I2C driver\n"); + pr_info("%s: Unloading NXP NFC I2C driver\n", __func__); i2c_del_driver(&nfc_i2c_dev_driver); } diff --git a/nfc/i2c_drv.h b/nfc/i2c_drv.h index 47b8884687..1508fd4163 100644 --- a/nfc/i2c_drv.h +++ b/nfc/i2c_drv.h @@ -1,7 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2021 NXP - * * + * Copyright (C) 2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2019-2021 NXP + * * This program 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 @@ -19,16 +19,17 @@ ******************************************************************************/ #ifndef _I2C_DRV_H_ #define _I2C_DRV_H_ + #include -/*kept same as dts */ -#define NFC_I2C_DRV_STR "nxp,pn544" -#define NFC_I2C_DEV_ID "pn553" +/* kept same as dts */ +#define NFC_I2C_DRV_STR "nxp,pn544" +#define NFC_I2C_DEV_ID "pn553" -//Interface specific parameters +/* Interface specific parameters */ struct i2c_dev { struct i2c_client *client; - /*IRQ parameters */ + /* IRQ parameters */ bool irq_enabled; spinlock_t irq_enabled_lock; /* NFC_IRQ wake-up state */ @@ -42,4 +43,4 @@ int nfc_i2c_dev_remove(struct i2c_client *client); int nfc_i2c_dev_suspend(struct device *device); int nfc_i2c_dev_resume(struct device *device); -#endif //_I2C_DRV_H_ +#endif /* _I2C_DRV_H_ */ From 22458900cc1d36319df45281643569ebdbbd0cd7 Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Thu, 17 Jun 2021 15:03:32 +0530 Subject: [PATCH 040/100] Clean up for 12.04.01 --- nfc/recovery_fw.c | 1326 -------------------------------------------- nfc/recovery_seq.c | 249 --------- nfc/recovery_seq.h | 79 --- 3 files changed, 1654 deletions(-) delete mode 100644 nfc/recovery_fw.c delete mode 100644 nfc/recovery_seq.c delete mode 100644 nfc/recovery_seq.h diff --git a/nfc/recovery_fw.c b/nfc/recovery_fw.c deleted file mode 100644 index f19c046402..0000000000 --- a/nfc/recovery_fw.c +++ /dev/null @@ -1,1326 +0,0 @@ -/******************************************************************************************** - * - * Copyright 2021 NXP - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"),to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - ********************************************************************************************/ -#include - -const uint8_t gphDnldNfc_DlSequence[] = { - 0x01, 0x34, 0xC0, 0x00, 0xDE, 0x10, 0xAD, 0x69, 0xE0, 0x28, - 0xAC, 0xFA, 0xF2, 0x4A, 0x0F, 0x49, 0x7E, 0x6A, 0x61, 0xD1, - 0x00, 0xFD, 0x4A, 0x66, 0xDD, 0x42, 0x4D, 0xFF, 0x90, 0xA5, - 0x6C, 0x54, 0xF0, 0x53, 0x5E, 0x17, 0x1E, 0x28, 0x8B, 0xF2, - 0x56, 0x6D, 0x74, 0x7B, 0x4E, 0xBA, 0xEB, 0x8D, 0x22, 0x43, - 0x01, 0xE9, 0xC4, 0x85, 0x2B, 0xFB, 0xA7, 0xD9, 0x3C, 0x64, - 0x63, 0x2D, 0xBB, 0x63, 0x5C, 0xDB, 0x14, 0x4D, 0x86, 0xA0, - 0x73, 0xC1, 0x32, 0xA4, 0x12, 0xD0, 0xED, 0x12, 0x90, 0xCF, - 0xAF, 0x56, 0x35, 0x3D, 0x97, 0x6B, 0xAC, 0x81, 0x1B, 0xD6, - 0x77, 0x9A, 0x4F, 0x9C, 0x90, 0x7D, 0x16, 0x6E, 0xC4, 0xCD, - 0x2D, 0xD2, 0x57, 0x49, 0x99, 0x24, 0xBC, 0x06, 0x71, 0x04, - 0xA8, 0x14, 0xEF, 0x21, 0x55, 0x0D, 0xAD, 0x82, 0x88, 0x5C, - 0xEF, 0xDF, 0x03, 0x93, 0xB5, 0xE8, 0x21, 0x18, 0xE0, 0x54, - 0xB8, 0xE1, 0x7E, 0x88, 0xE9, 0xF7, 0xEE, 0x86, 0xD2, 0x36, - 0xD7, 0x4B, 0x99, 0x6C, 0x35, 0x8B, 0xE0, 0xA2, 0xA2, 0xFB, - 0xED, 0xB5, 0x9A, 0xA0, 0xEE, 0x19, 0x67, 0x66, 0x14, 0x14, - 0xEC, 0xEF, 0x3F, 0xC0, 0x25, 0x7C, 0xA8, 0x9F, 0x58, 0x11, - 0xCD, 0x99, 0x00, 0xBF, 0xB8, 0x6D, 0xD5, 0x06, 0x8A, 0x5D, - 0x40, 0xB0, 0x2C, 0x9A, 0x20, 0xA2, 0x30, 0xDA, 0xFD, 0xB0, - 0xE3, 0x05, 0x5F, 0xB7, 0x3B, 0x9C, 0xD6, 0xB8, 0x92, 0xAE, - 0x4B, 0xDC, 0xF2, 0x1D, 0xA4, 0x11, 0xCE, 0x0C, 0xFD, 0x37, - 0x6E, 0xBA, 0x8B, 0x6C, 0x84, 0x3E, 0x3A, 0x3D, 0x20, 0xBE, - 0x64, 0xA6, 0x56, 0x7F, 0x06, 0x66, 0x04, 0x38, 0x1D, 0x97, - 0xD9, 0x96, 0xE6, 0x07, 0x29, 0xE2, 0x1A, 0xC4, 0x5F, 0x0A, - 0xAC, 0x62, 0x50, 0xF8, 0xD2, 0x33, 0x3F, 0x7A, 0x50, 0x89, - 0x98, 0x44, 0xCB, 0xFD, 0x75, 0x79, 0x25, 0xB1, 0x3A, 0xDE, - 0x53, 0x86, 0x13, 0x54, 0x46, 0x0B, 0x5F, 0x94, 0xEC, 0x1B, - 0x72, 0x24, 0x35, 0x84, 0x67, 0xC8, 0xBE, 0xDB, 0xAC, 0xB2, - 0x0C, 0x94, 0x88, 0xE1, 0xC4, 0x36, 0xD1, 0x6B, 0xB9, 0x4C, - 0xAE, 0xB0, 0x55, 0xF8, 0xBE, 0xD4, 0x7D, 0x16, 0x76, 0x84, - 0x2E, 0x46, 0x0B, 0xF6, 0x0D, 0x43, 0xB6, 0xBB, 0x5F, 0x98, - 0x02, 0x26, 0xC0, 0x00, 0x02, 0x35, 0x79, 0x26, 0x91, 0x8C, - 0x34, 0x8D, 0x69, 0x6E, 0x7F, 0x6B, 0xBF, 0xBD, 0x81, 0x3F, - 0x9C, 0x94, 0x0C, 0x65, 0x47, 0xC5, 0x08, 0xA7, 0x14, 0x6F, - 0x5A, 0xAC, 0x7C, 0xAC, 0x0C, 0x15, 0xD5, 0x6F, 0xBF, 0xDC, - 0xCE, 0x97, 0xD0, 0xD5, 0xEB, 0x1D, 0x3C, 0x7A, 0xEB, 0x2A, - 0x4E, 0x76, 0x08, 0xF2, 0xEA, 0x3A, 0xA0, 0xB8, 0xFC, 0xA0, - 0x74, 0x92, 0x8F, 0x86, 0xB1, 0x15, 0x0D, 0x7D, 0x92, 0x0F, - 0x64, 0xCE, 0xCA, 0xC1, 0xC4, 0x20, 0xA2, 0x48, 0x2D, 0xB0, - 0x47, 0x24, 0xF1, 0x20, 0x77, 0xDF, 0x87, 0x0D, 0xFA, 0xC6, - 0x89, 0xEE, 0xBD, 0x5E, 0xD5, 0x85, 0x64, 0xBC, 0x40, 0x6E, - 0x86, 0x01, 0x3D, 0xB6, 0x83, 0x8C, 0xAA, 0xF3, 0x2D, 0x3A, - 0xBB, 0x0D, 0xE6, 0xA5, 0xC0, 0x64, 0x07, 0xCB, 0x57, 0x81, - 0x7E, 0xD8, 0x3C, 0x3D, 0x4A, 0x9F, 0x8E, 0xF0, 0x57, 0x2E, - 0x5E, 0x41, 0x42, 0x00, 0xB0, 0xC7, 0x4E, 0x17, 0xED, 0xC6, - 0xAB, 0x73, 0x71, 0x65, 0x1D, 0x60, 0x34, 0x2A, 0x2B, 0xAF, - 0x59, 0x82, 0x5E, 0x16, 0x48, 0x48, 0x0F, 0x86, 0x62, 0x0C, - 0x84, 0x56, 0x00, 0x03, 0x2A, 0xA6, 0x2C, 0x21, 0xD0, 0x70, - 0xF9, 0xE5, 0x37, 0x0E, 0x81, 0x20, 0x36, 0x4E, 0x86, 0x8D, - 0xCF, 0xED, 0xBD, 0x0D, 0x49, 0x75, 0x0E, 0x5B, 0x80, 0xF7, - 0xAF, 0x40, 0x56, 0x8B, 0xD8, 0xFC, 0xC6, 0xE4, 0x6D, 0xD6, - 0x2E, 0x0D, 0xD0, 0x76, 0x75, 0x39, 0x3E, 0xF0, 0xEA, 0xC5, - 0x23, 0x12, 0x06, 0x45, 0xEA, 0x04, 0x6D, 0xC1, 0xA2, 0x95, - 0x95, 0x40, 0xD6, 0x6B, 0x65, 0xD6, 0x7D, 0x62, 0xA5, 0xB4, - 0x6B, 0x6C, 0x24, 0x3E, 0xFB, 0xAB, 0x71, 0x4D, 0xFC, 0x24, - 0x9F, 0x71, 0x8C, 0x04, 0x9A, 0xEE, 0x6D, 0x72, 0x3A, 0x01, - 0x11, 0xC1, 0x01, 0xB2, 0xC2, 0xC8, 0xBA, 0x7D, 0x53, 0x56, - 0x0D, 0x3F, 0x35, 0xF6, 0x86, 0x46, 0x7C, 0x67, 0xBF, 0x83, - 0x04, 0x01, 0x98, 0xBC, 0x06, 0x08, 0xF3, 0x89, 0x88, 0x8E, - 0x93, 0xB3, 0xA9, 0x21, 0x18, 0x71, 0xFF, 0xFC, 0x4E, 0xF7, - 0xFE, 0x1A, 0x5D, 0xC9, 0x21, 0xF6, 0x3B, 0x27, 0x2C, 0x26, - 0x37, 0xE2, 0x4F, 0x8C, 0x94, 0x77, 0xC7, 0x0D, 0xB9, 0x74, - 0xCD, 0x9F, 0xE1, 0x70, 0xFD, 0x35, 0x11, 0xA2, 0xB6, 0xAC, - 0x39, 0x3D, 0xC9, 0x57, 0x94, 0x3F, 0x10, 0x89, 0x9F, 0x0F, - 0x7D, 0x49, 0x0E, 0xFE, 0x84, 0x34, 0x87, 0x5B, 0xA5, 0xA0, - 0x5E, 0x0D, 0xE4, 0x05, 0x5A, 0x45, 0x8B, 0x31, 0x28, 0xF0, - 0x80, 0x7A, 0xF9, 0x56, 0xE7, 0x60, 0xB0, 0x31, 0xBB, 0x75, - 0x7E, 0x30, 0x74, 0x53, 0x14, 0xF6, 0xDE, 0x24, 0x9E, 0xE0, - 0xB9, 0x9F, 0xE6, 0xB0, 0x5D, 0x5B, 0x7A, 0xF3, 0xFD, 0x0D, - 0x4C, 0xCA, 0xAD, 0x01, 0xE4, 0x3F, 0xFE, 0x1D, 0x03, 0xE7, - 0xD4, 0xC6, 0xC1, 0xE9, 0xF5, 0x9E, 0x72, 0x9C, 0x4A, 0x09, - 0x85, 0x2C, 0xBE, 0x46, 0x49, 0xE1, 0x0F, 0xBF, 0x27, 0xF2, - 0x81, 0xC3, 0x33, 0x95, 0xEC, 0xBE, 0x37, 0x2B, 0x65, 0xA5, - 0xEC, 0xF7, 0x69, 0x23, 0x3B, 0xA6, 0xA6, 0xC3, 0xC7, 0x9F, - 0x9B, 0x79, 0xE6, 0x37, 0xB4, 0xDB, 0x33, 0x3B, 0xC5, 0x19, - 0x50, 0x7B, 0xBB, 0x7B, 0x4B, 0xFF, 0x0A, 0x3A, 0x0F, 0xDE, - 0x9D, 0x1F, 0x70, 0xE0, 0x9C, 0x37, 0x9B, 0x61, 0x01, 0xD9, - 0xCB, 0x9F, 0xC7, 0x1F, 0x9B, 0x25, 0x7D, 0x18, 0xF0, 0x6F, - 0x12, 0x54, 0xC2, 0x17, 0x8F, 0xB2, 0x1F, 0x5D, 0x0F, 0x73, - 0xB2, 0xEE, 0xE9, 0x0E, 0xC4, 0xA1, 0x70, 0x48, 0xDF, 0x0B, - 0xB4, 0xDD, 0xFF, 0xC7, 0x01, 0xA6, 0xBC, 0x08, 0xCE, 0x0E, - 0xB4, 0x4A, 0xAE, 0xFF, 0x88, 0xA6, 0x4D, 0x60, 0xC7, 0x55, - 0x38, 0x74, 0x3C, 0x1D, 0x8F, 0x82, 0xD3, 0xD3, 0x31, 0x60, - 0xE4, 0xB2, 0x24, 0x76, 0xE7, 0xD8, 0x53, 0x05, 0x20, 0x3E, - 0x5C, 0xEF, 0x17, 0x4C, 0x20, 0x6F, 0x6A, 0x6D, 0x10, 0xA3, - 0xA4, 0xE9, 0xFB, 0x76, 0x66, 0x99, 0x5D, 0xD1, 0x34, 0x52, - 0x42, 0xBF, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x9E, 0xED, 0xAE, - 0xE5, 0x23, 0x85, 0x5C, 0xFF, 0xAD, 0x6E, 0x89, 0x02, 0x33, - 0x97, 0x74, 0x05, 0x59, 0x1E, 0x73, 0x4E, 0xD3, 0x9A, 0x97, - 0xD3, 0x85, 0x2B, 0x12, 0xFB, 0xA2, 0xF0, 0xA4, 0x4C, 0x2A, - 0x58, 0xFB, 0x56, 0x6C, 0xE9, 0xA6, 0x04, 0x07, 0x9F, 0xBC, - 0x76, 0x66, 0x01, 0x80, 0xB8, 0x1E, 0x4A, 0x8A, 0x0C, 0x76, - 0x8A, 0x3C, 0x5F, 0x25, 0xAD, 0x83, 0xF3, 0x10, 0x02, 0xE1, - 0x38, 0x4B, 0xFA, 0x81, 0xD2, 0xC5, 0x6D, 0x18, 0xA7, 0xD8, - 0x0A, 0x4E, 0xC9, 0xC7, 0xA3, 0x19, 0x52, 0x0D, 0xBB, 0xA9, - 0xDE, 0x9C, 0x90, 0x57, 0x71, 0x1A, 0x37, 0xA8, 0x70, 0x4D, - 0x75, 0x7E, 0x34, 0x90, 0x74, 0x0E, 0x02, 0xC8, 0x8A, 0x80, - 0x3D, 0x06, 0x67, 0xF4, 0xF2, 0xD4, 0x15, 0x66, 0x0D, 0x23, - 0xAE, 0x46, 0x0A, 0x23, 0x7B, 0x36, 0x96, 0x48, 0x7D, 0x99, - 0xF4, 0x09, 0xE3, 0xA9, 0x53, 0xAC, 0x94, 0xB7, 0x23, 0x7E, - 0x57, 0xCF, 0x90, 0xCD, 0x13, 0x0D, 0x50, 0xBD, 0xC9, 0xE4, - 0xC2, 0x22, 0x5F, 0x28, 0x11, 0xF8, 0x1F, 0x42, 0x33, 0xEE, - 0xF3, 0xB4, 0xED, 0x8F, 0xF4, 0xA0, 0xAE, 0xF5, 0xAE, 0x56, - 0x59, 0xC3, 0x65, 0xDB, 0xF2, 0x51, 0x6D, 0x15, 0xA3, 0xAF, - 0xA5, 0xC7, 0x9F, 0x7A, 0xE8, 0xCC, 0xB4, 0xD8, 0xCA, 0x39, - 0x3F, 0x79, 0xB3, 0x86, 0xDB, 0x37, 0x52, 0xDA, 0x5E, 0xDB, - 0x7F, 0x53, 0x60, 0x43, 0x75, 0x53, 0x93, 0xD4, 0xA2, 0xE2, - 0xE7, 0xB7, 0x42, 0xF0, 0x97, 0xA5, 0xB5, 0x52, 0xD3, 0xCF, - 0xE7, 0x70, 0x6F, 0x10, 0xD4, 0x85, 0xC4, 0x4B, 0x3D, 0x09, - 0xE1, 0x02, 0xB8, 0xED, 0xA5, 0xCC, 0x7B, 0x2D, 0x68, 0xEF, - 0xEF, 0x9E, 0x87, 0x8C, 0xB7, 0xC9, 0x85, 0xA8, 0x01, 0xC2, - 0xCF, 0x43, 0xB5, 0x6D, 0x30, 0x2A, 0x9F, 0x06, 0x96, 0xE0, - 0x43, 0xEC, 0x3F, 0xC1, 0x2F, 0x7D, 0x4D, 0x85, 0x76, 0xD3, - 0xF7, 0xFA, 0xC8, 0x84, 0x20, 0xA8, 0x3C, 0xD9, 0x3E, 0x4A, - 0xB4, 0x87, 0x05, 0xCF, 0x9B, 0x51, 0x68, 0xF9, 0x49, 0xBA, - 0x4D, 0x68, 0x97, 0x6E, 0x79, 0xDB, 0x04, 0x51, 0x66, 0x6F, - 0xF9, 0x59, 0x2D, 0x55, 0x96, 0x13, 0x59, 0x52, 0x30, 0xB8, - 0x73, 0xD1, 0x12, 0x33, 0x31, 0xEC, 0x4C, 0x0C, 0x8E, 0xD4, - 0x47, 0xE7, 0x30, 0xC6, 0x98, 0xB5, 0x5B, 0x35, 0x1B, 0xAC, - 0x51, 0xBB, 0xFA, 0xC3, 0x8D, 0x3E, 0x89, 0x83, 0x1C, 0xED, - 0xB1, 0x03, 0x9C, 0xC7, 0x5C, 0x89, 0xF9, 0xC2, 0xE3, 0x45, - 0x91, 0xDB, 0x41, 0x0A, 0x22, 0xD1, 0x90, 0x39, 0xD6, 0x9D, - 0x0A, 0xD8, 0x36, 0xDC, 0xDB, 0xDD, 0x63, 0x22, 0xF8, 0x7B, - 0x4D, 0x90, 0x4C, 0x27, 0x0F, 0xCC, 0x16, 0x0E, 0x32, 0x46, - 0xD7, 0x20, 0x5A, 0x43, 0xC4, 0xC5, 0x37, 0x2E, 0xEB, 0x3F, - 0x42, 0x2C, 0xFA, 0x99, 0xE2, 0xF9, 0x70, 0xB3, 0xC3, 0xCF, - 0x4C, 0x67, 0xEB, 0x7C, 0x9D, 0xAF, 0x96, 0x15, 0x97, 0xD2, - 0x07, 0x3B, 0xF6, 0xEF, 0x2F, 0x98, 0xAA, 0x1D, 0x45, 0xDC, - 0x11, 0xBA, 0xF6, 0x0C, 0x18, 0x64, 0x80, 0xF2, 0x6B, 0xBD, - 0x3C, 0x85, 0xC1, 0xCD, 0x78, 0xD0, 0x62, 0x79, 0x0F, 0xCD, - 0xCA, 0x3D, 0x94, 0x0A, 0x11, 0xEF, 0x11, 0x86, 0xFA, 0x3F, - 0x31, 0xB2, 0xF1, 0x2C, 0x74, 0x1B, 0x57, 0x05, 0xD4, 0x4F, - 0xAF, 0xE7, 0xCB, 0x60, 0x9E, 0x78, 0x82, 0xAD, 0xF3, 0x34, - 0x6A, 0x2F, 0xDC, 0xA1, 0xC9, 0xEA, 0x3E, 0x6E, 0x01, 0x80, - 0x17, 0x5B, 0xCC, 0xBB, 0xED, 0xD0, 0x30, 0x11, 0xBE, 0xEE, - 0x2E, 0x9F, 0xCE, 0xE1, 0xFF, 0x32, 0xB8, 0x7D, 0x40, 0xC8, - 0x46, 0x0F, 0x41, 0x16, 0xE1, 0xB3, 0x98, 0x47, 0xCE, 0xE1, - 0x41, 0xDE, 0x80, 0xA7, 0x56, 0x83, 0xA8, 0xDA, 0xC3, 0x49, - 0x33, 0x6F, 0x93, 0x68, 0xA0, 0xC6, 0x1A, 0x0B, 0x82, 0x38, - 0x56, 0xEE, 0xBB, 0x97, 0x5D, 0xBD, 0x8A, 0x32, 0x2D, 0xFE, - 0x40, 0xC7, 0x0D, 0xCA, 0x32, 0x08, 0xCC, 0xE2, 0x18, 0x57, - 0xBB, 0xC1, 0x60, 0x43, 0x02, 0x26, 0xC0, 0x00, 0x02, 0xAD, - 0x9E, 0x61, 0x0D, 0x67, 0x25, 0xE4, 0x6E, 0x8F, 0x6D, 0xEA, - 0x16, 0x98, 0xFA, 0x76, 0x6D, 0x6D, 0x3C, 0xED, 0x4B, 0x25, - 0x60, 0xC6, 0xAB, 0x59, 0x91, 0x43, 0xAA, 0xAA, 0xEC, 0x8F, - 0xA1, 0x3E, 0xB1, 0x78, 0x72, 0xEE, 0xD1, 0x91, 0xBA, 0xD9, - 0x9B, 0xE3, 0x55, 0x61, 0x98, 0x46, 0x4B, 0xC5, 0x41, 0x3B, - 0x9C, 0x88, 0x1D, 0x82, 0xD5, 0xD5, 0x99, 0x13, 0x64, 0x44, - 0x00, 0xBD, 0xBE, 0xC4, 0xF6, 0x6A, 0x2D, 0xE3, 0xD0, 0xE7, - 0x88, 0xD3, 0xA1, 0x48, 0x88, 0x84, 0x8A, 0x25, 0xAB, 0x90, - 0x43, 0xFB, 0x3D, 0x1B, 0x06, 0xB2, 0xFD, 0x24, 0x58, 0x0C, - 0xFA, 0x0A, 0xD3, 0x23, 0x73, 0xA7, 0xF8, 0x50, 0xC5, 0x1B, - 0x3A, 0x75, 0xF4, 0x24, 0xA8, 0x52, 0xFB, 0x1B, 0x61, 0xAB, - 0x79, 0x06, 0x54, 0xD9, 0x1D, 0x3A, 0x72, 0x4F, 0x8F, 0xD3, - 0xC7, 0x71, 0xA8, 0x66, 0x80, 0x49, 0x8D, 0x50, 0xD1, 0xBF, - 0xC8, 0x70, 0xAE, 0x4F, 0x64, 0x53, 0x26, 0x37, 0xDA, 0x6B, - 0x62, 0xFE, 0xF9, 0x60, 0xAD, 0xAD, 0x49, 0x51, 0x37, 0x2E, - 0x61, 0xA9, 0xAA, 0x72, 0xFD, 0x02, 0x20, 0x0B, 0xB0, 0xB0, - 0x07, 0x95, 0x0C, 0x38, 0x13, 0xB6, 0xA4, 0x33, 0xFA, 0xFA, - 0x12, 0xE1, 0x62, 0x00, 0x92, 0x46, 0x23, 0xAA, 0xD7, 0x9D, - 0xBD, 0xAF, 0x15, 0xCA, 0x8C, 0x88, 0x2A, 0x4B, 0x1B, 0xA8, - 0x06, 0xA0, 0xC2, 0x80, 0x8E, 0x98, 0x46, 0xA1, 0x84, 0x2C, - 0x4A, 0x0F, 0xEA, 0x70, 0xE6, 0xDD, 0x17, 0x30, 0x8A, 0x41, - 0x69, 0x8A, 0x1B, 0xC2, 0xC7, 0x18, 0xD5, 0xB3, 0x94, 0x4F, - 0x51, 0x15, 0xCC, 0x37, 0x9A, 0x9E, 0xFD, 0x12, 0x40, 0xC1, - 0xA3, 0x06, 0x0F, 0x36, 0xFC, 0x04, 0x18, 0x35, 0x40, 0x9C, - 0x9E, 0x46, 0x5E, 0x14, 0xB6, 0xF7, 0xBF, 0xE5, 0x21, 0x12, - 0xF2, 0xE2, 0x17, 0xB3, 0x63, 0x8C, 0xD1, 0xE3, 0xA9, 0x0A, - 0x80, 0x1B, 0x74, 0x7A, 0x58, 0x91, 0x88, 0x9D, 0xAE, 0xE6, - 0x05, 0x1D, 0x3C, 0x1E, 0xE9, 0x95, 0x08, 0x75, 0xEE, 0x20, - 0xA8, 0x4B, 0x3D, 0x36, 0xAF, 0xB0, 0xFA, 0x94, 0x62, 0x5D, - 0x9F, 0xD5, 0x50, 0x2A, 0x24, 0xFC, 0x1D, 0xDC, 0x39, 0xCB, - 0x0D, 0x5A, 0xA1, 0xDA, 0xEF, 0xC9, 0xB3, 0x62, 0xF8, 0x7D, - 0x0C, 0xE4, 0x6B, 0xEC, 0xF0, 0xF7, 0x96, 0x63, 0x58, 0x80, - 0x55, 0x22, 0x6D, 0x42, 0x38, 0xE9, 0x1D, 0x69, 0xD5, 0x2F, - 0x03, 0x3C, 0xCD, 0x27, 0x34, 0x99, 0x39, 0xF0, 0x5C, 0xE0, - 0x23, 0x70, 0x85, 0x4B, 0x30, 0xBD, 0x21, 0x01, 0xF6, 0x06, - 0x0B, 0xED, 0xBA, 0xA1, 0x6F, 0xE0, 0x6E, 0xD3, 0x78, 0xA8, - 0x56, 0x94, 0x92, 0x84, 0xA8, 0x60, 0x35, 0xA8, 0x86, 0x56, - 0x41, 0xEA, 0x12, 0x34, 0x86, 0x52, 0x18, 0x75, 0x43, 0x01, - 0x0A, 0xCE, 0xBA, 0x04, 0xF7, 0x32, 0x09, 0x2D, 0xB1, 0xAC, - 0x04, 0xB0, 0x4E, 0xEA, 0xBE, 0xDE, 0xDE, 0x95, 0x37, 0xDA, - 0x86, 0x72, 0xFE, 0x10, 0x16, 0xBB, 0xA7, 0xE9, 0x67, 0xC9, - 0x3C, 0x85, 0x18, 0xFF, 0xD7, 0x74, 0x25, 0x3A, 0x95, 0x04, - 0xD5, 0x7F, 0x99, 0x41, 0x6A, 0x6A, 0x2C, 0xF6, 0x3E, 0x3C, - 0x4B, 0xA7, 0xB9, 0xDA, 0x13, 0xFC, 0xF6, 0x46, 0xEF, 0x7E, - 0xB4, 0xA6, 0x1B, 0x36, 0x93, 0x5B, 0xDA, 0xDB, 0x6A, 0xC7, - 0x37, 0x58, 0x3C, 0x4F, 0x52, 0x7E, 0x39, 0xD7, 0xE2, 0xBA, - 0x79, 0xA7, 0x9A, 0x05, 0x8A, 0xF5, 0x65, 0x86, 0xF4, 0x52, - 0xBC, 0x79, 0x6D, 0xA9, 0xFE, 0xEE, 0xE6, 0xC5, 0x2B, 0x28, - 0x62, 0x8E, 0xF6, 0x6E, 0xD5, 0x08, 0x90, 0x96, 0x72, 0x7A, - 0x6B, 0x61, 0x8B, 0x6A, 0xE6, 0xCD, 0x05, 0x63, 0x12, 0x9A, - 0xF7, 0x01, 0xAC, 0xF7, 0x8F, 0x1F, 0xE0, 0xCA, 0x1E, 0xF9, - 0x86, 0xC1, 0xF6, 0x0D, 0x2D, 0x9F, 0x8A, 0x2C, 0x8B, 0x3C, - 0xE4, 0x89, 0xDF, 0x72, 0x86, 0x17, 0xA8, 0x7F, 0x9D, 0x8B, - 0x0D, 0x87, 0xCB, 0xC5, 0xAE, 0xE3, 0x90, 0xB1, 0xD9, 0x8B, - 0x5E, 0x04, 0x97, 0xAA, 0x19, 0x85, 0x02, 0x26, 0xC0, 0x00, - 0x02, 0x26, 0xDA, 0x00, 0x7E, 0x08, 0xC0, 0x08, 0x12, 0x9A, - 0x78, 0x4E, 0x9D, 0xA7, 0xB0, 0x5E, 0x0D, 0x76, 0x6D, 0x4D, - 0xC7, 0x89, 0x35, 0xDD, 0xB5, 0x58, 0x9F, 0x20, 0x3C, 0x41, - 0x77, 0x9B, 0x85, 0x06, 0x21, 0xA4, 0x99, 0x56, 0xF9, 0x5B, - 0x07, 0x01, 0x06, 0x1A, 0xE1, 0x1B, 0xC7, 0x9F, 0x46, 0x5D, - 0x1F, 0xB8, 0xB2, 0x91, 0xA5, 0xC2, 0x01, 0x94, 0xFA, 0x53, - 0x74, 0xFA, 0x6A, 0x5B, 0x63, 0x08, 0x2E, 0x24, 0xB0, 0xCF, - 0x03, 0x40, 0x9C, 0xA1, 0xF2, 0xDB, 0xA2, 0x35, 0xD7, 0xCA, - 0x78, 0x4E, 0x9D, 0x8B, 0x92, 0x4A, 0xD1, 0xEA, 0xF8, 0x14, - 0xCA, 0xA0, 0x32, 0x55, 0x95, 0xA0, 0x1F, 0xB7, 0x1D, 0x8B, - 0x8E, 0x8E, 0xA6, 0xF0, 0x2A, 0x30, 0x76, 0xB4, 0x9B, 0x6F, - 0xAB, 0xBC, 0xC7, 0xA8, 0xF6, 0x2B, 0x9D, 0x1D, 0xC2, 0x24, - 0x06, 0x10, 0x06, 0xE7, 0x59, 0x34, 0xE9, 0x30, 0xA8, 0xF5, - 0x61, 0x55, 0xEC, 0xFB, 0xA1, 0x43, 0x17, 0x10, 0x08, 0xFF, - 0x3C, 0x93, 0x03, 0xFF, 0x83, 0x35, 0x81, 0x77, 0x7E, 0x97, - 0xC2, 0xA0, 0x53, 0x2A, 0x26, 0xD4, 0xDF, 0xC0, 0xA3, 0x21, - 0x07, 0x14, 0x41, 0xD3, 0x7C, 0xE5, 0x40, 0x00, 0xDE, 0x32, - 0xF5, 0xB9, 0xBB, 0x61, 0x44, 0xBC, 0xA4, 0xFD, 0x67, 0xAA, - 0x69, 0xF4, 0x96, 0x93, 0xD2, 0xAF, 0xEA, 0xC5, 0x72, 0xDB, - 0xEA, 0x88, 0x2A, 0x5F, 0xC5, 0xAB, 0x00, 0xFA, 0xA9, 0x32, - 0x61, 0x58, 0xBE, 0xC0, 0x42, 0xA9, 0xFA, 0xB6, 0x44, 0xD6, - 0x59, 0xF8, 0x26, 0x8B, 0xB9, 0x0A, 0xD9, 0xE2, 0x5B, 0x1B, - 0x20, 0xD1, 0x34, 0x91, 0x81, 0xF3, 0xFF, 0xED, 0x6D, 0x81, - 0xF9, 0x7D, 0xE3, 0x73, 0x37, 0xC1, 0x01, 0x12, 0x28, 0x9B, - 0xEA, 0xDA, 0x0E, 0x3D, 0x68, 0x16, 0x23, 0xE1, 0x68, 0xFF, - 0x1A, 0x59, 0xCC, 0x89, 0xF8, 0x44, 0x70, 0x13, 0xB2, 0x98, - 0xB1, 0x31, 0xEA, 0xEC, 0x65, 0x21, 0x36, 0xEF, 0xCC, 0x85, - 0x62, 0xC3, 0xEC, 0x62, 0xE9, 0x06, 0xEC, 0xB3, 0x47, 0x94, - 0xE5, 0xF2, 0x6F, 0xFD, 0x80, 0xEE, 0x70, 0xB0, 0x06, 0x56, - 0x8B, 0xF2, 0xDC, 0x7A, 0x52, 0x90, 0xC2, 0xE4, 0x77, 0xDD, - 0xF7, 0xC2, 0x0C, 0x9C, 0xBE, 0x5A, 0x0F, 0xC6, 0x45, 0xB1, - 0x3A, 0x63, 0x38, 0x2C, 0xD9, 0xC4, 0x45, 0x08, 0x44, 0x90, - 0xE2, 0xBC, 0xA2, 0x5A, 0xE6, 0x2E, 0xFD, 0xCB, 0x36, 0x7F, - 0xA9, 0xAC, 0x8C, 0x34, 0x1A, 0x3C, 0xE2, 0x9B, 0x24, 0x45, - 0xE3, 0x9C, 0xCF, 0xF9, 0x96, 0xFE, 0x58, 0xB5, 0x29, 0x20, - 0x0B, 0xC9, 0x5C, 0xAF, 0xCF, 0x7F, 0xCB, 0x8A, 0x14, 0xE1, - 0xCD, 0xF7, 0x5B, 0x93, 0xBC, 0x7D, 0x7A, 0x3B, 0xD2, 0xF2, - 0xFA, 0x2B, 0x57, 0x02, 0x9C, 0xAC, 0xA2, 0x16, 0x11, 0x2D, - 0xDB, 0x3D, 0x42, 0x26, 0x87, 0xBE, 0x9F, 0x8B, 0x7B, 0x00, - 0x20, 0x09, 0x41, 0x05, 0xB0, 0x42, 0x98, 0x44, 0xD6, 0xCC, - 0x08, 0xA2, 0x20, 0x1F, 0x2A, 0x59, 0xB3, 0x05, 0x4F, 0xB4, - 0xA6, 0xF8, 0xF8, 0xFD, 0x27, 0xBB, 0xC5, 0xC3, 0x52, 0x4D, - 0x63, 0x37, 0xCF, 0xAE, 0x4C, 0x60, 0x1E, 0x98, 0x26, 0x12, - 0x3D, 0xB9, 0xE6, 0x87, 0x09, 0x17, 0xB1, 0xE4, 0x81, 0x2C, - 0x8E, 0x73, 0xA1, 0x40, 0x53, 0x96, 0xD8, 0x17, 0x7F, 0x39, - 0xA8, 0x4F, 0xE9, 0xEF, 0x30, 0xE2, 0x5E, 0xEF, 0x9C, 0x13, - 0x70, 0x21, 0x14, 0xA3, 0x5D, 0xEA, 0x43, 0xFB, 0xA6, 0x80, - 0x70, 0xB9, 0x4B, 0x68, 0x9C, 0x5A, 0x82, 0x59, 0x00, 0xFA, - 0x5E, 0x4C, 0x4F, 0x76, 0xB1, 0xF4, 0x45, 0xCD, 0xE6, 0x18, - 0x09, 0xE2, 0x36, 0x8A, 0x60, 0x4B, 0xF4, 0x61, 0x55, 0xC4, - 0xE9, 0x69, 0xC1, 0x03, 0x9E, 0x9C, 0xAF, 0x1C, 0xE5, 0xD1, - 0xFF, 0x45, 0x16, 0x43, 0xD7, 0xE5, 0x4B, 0xCC, 0xEA, 0x24, - 0x2E, 0xCE, 0xE3, 0x90, 0x17, 0xDB, 0xC4, 0x57, 0x4D, 0xF9, - 0xCB, 0xEC, 0x09, 0x62, 0xBD, 0xD8, 0x7A, 0x89, 0x55, 0x92, - 0x90, 0x7B, 0x22, 0x20, 0xD9, 0x9A, 0xC9, 0x19, 0x02, 0x26, - 0xC0, 0x00, 0x02, 0x2E, 0xA2, 0xCF, 0xDE, 0xE3, 0xDE, 0xA9, - 0x10, 0x3D, 0xEB, 0xD9, 0x4B, 0x51, 0x68, 0x41, 0x57, 0xCD, - 0x7C, 0xF4, 0x28, 0x84, 0x22, 0x1C, 0xA7, 0xA6, 0x8A, 0xDD, - 0x97, 0x5B, 0x8A, 0x07, 0x01, 0x97, 0x13, 0x20, 0x06, 0x12, - 0xC9, 0xBB, 0x6D, 0x12, 0x25, 0x6D, 0x08, 0x13, 0x3C, 0x32, - 0x48, 0xFE, 0x49, 0xD9, 0xC1, 0x3E, 0x00, 0x1C, 0xD9, 0xF0, - 0xE2, 0xB3, 0xE0, 0x07, 0xE1, 0x8F, 0xDF, 0x75, 0xE0, 0xB9, - 0x61, 0x1A, 0xBF, 0xAF, 0x66, 0xE0, 0xAB, 0x8A, 0x4B, 0x71, - 0xCB, 0x4F, 0xB7, 0x4C, 0x30, 0xC8, 0xB0, 0xC4, 0xC0, 0x38, - 0x73, 0xDD, 0x3C, 0xDC, 0x5D, 0x81, 0x40, 0x14, 0x23, 0x9C, - 0xD2, 0x48, 0xF9, 0xCB, 0xC4, 0x1B, 0xD5, 0xC7, 0x85, 0xB0, - 0x57, 0xC1, 0xF5, 0x41, 0x7A, 0x2E, 0xC6, 0x03, 0x86, 0x8C, - 0x4E, 0xAF, 0x24, 0x21, 0xB9, 0x0B, 0xE9, 0x24, 0x12, 0x02, - 0x3E, 0x35, 0x7C, 0x1D, 0x9A, 0x2D, 0x5E, 0xB7, 0xEE, 0x08, - 0x34, 0x2C, 0x2B, 0xAD, 0x8D, 0x02, 0xF6, 0xFE, 0x06, 0x88, - 0xD0, 0xA5, 0xA2, 0x1E, 0x5B, 0xD2, 0x88, 0x09, 0x9F, 0x43, - 0xDF, 0xC4, 0x85, 0x59, 0x50, 0x7B, 0x94, 0xD9, 0xBB, 0xBE, - 0xF5, 0x1D, 0x60, 0xD0, 0x90, 0x6F, 0xD5, 0x1E, 0x49, 0xF1, - 0x76, 0x04, 0x96, 0xCA, 0x3F, 0x44, 0x64, 0xBE, 0x41, 0xE7, - 0x4A, 0x6E, 0xA8, 0x11, 0x14, 0x21, 0xEA, 0x9E, 0x43, 0x6D, - 0x2E, 0xF6, 0x49, 0x7A, 0x8C, 0xD6, 0xF1, 0x4A, 0xC3, 0x17, - 0x16, 0x23, 0x3B, 0x02, 0x6A, 0xA7, 0x90, 0x1D, 0x8C, 0xBF, - 0xB4, 0x25, 0xDA, 0xB6, 0x0F, 0x2A, 0x60, 0xF5, 0xC1, 0x7F, - 0xFA, 0x1D, 0x0B, 0xAF, 0x28, 0x8A, 0x00, 0x8A, 0xBE, 0xA8, - 0x72, 0x20, 0x5F, 0xEC, 0x3F, 0x16, 0x6E, 0xAB, 0xC4, 0xFC, - 0x6B, 0x75, 0xD7, 0xFB, 0x73, 0x60, 0x7E, 0x25, 0xE5, 0xA3, - 0x91, 0x6A, 0x33, 0xD3, 0x9E, 0xAC, 0xFB, 0x8C, 0xD1, 0xC6, - 0x63, 0xF4, 0x3F, 0xB7, 0xD1, 0xD3, 0x88, 0x90, 0x4C, 0xA2, - 0x7E, 0x6B, 0x19, 0x61, 0xCC, 0xAB, 0x48, 0xDD, 0x8D, 0xE2, - 0x1B, 0xB7, 0x9E, 0x2F, 0x58, 0x10, 0x78, 0xAC, 0x94, 0xF6, - 0xD6, 0x62, 0x4D, 0x66, 0x78, 0x67, 0x9F, 0x1B, 0x3A, 0x78, - 0x4E, 0xA0, 0xDB, 0x47, 0x92, 0xC4, 0x43, 0x1A, 0x22, 0xFC, - 0x26, 0x38, 0xA4, 0xF2, 0x7A, 0x52, 0x31, 0x71, 0x63, 0x16, - 0x58, 0xF5, 0xA4, 0x4A, 0xCA, 0x73, 0xD5, 0x90, 0x39, 0x55, - 0x8F, 0xB2, 0xC0, 0x3F, 0x3A, 0xEC, 0x69, 0xC4, 0x42, 0xCE, - 0xB9, 0x1B, 0xA4, 0x32, 0x52, 0x14, 0x7C, 0xBB, 0xF6, 0xB3, - 0x5A, 0x7C, 0xF1, 0x75, 0x1E, 0x4B, 0xB8, 0xB0, 0xB3, 0x8E, - 0x13, 0x63, 0x7B, 0xF5, 0xB9, 0x93, 0x22, 0x98, 0xDF, 0x6C, - 0xEC, 0x51, 0x4F, 0xC8, 0x0B, 0xA0, 0x14, 0x57, 0x75, 0x1B, - 0xF6, 0xE9, 0x5D, 0xC2, 0x47, 0x65, 0xDF, 0x79, 0x0D, 0x48, - 0xBE, 0x4F, 0x46, 0xF0, 0x37, 0xA5, 0x7C, 0xA3, 0x6B, 0x3E, - 0xE6, 0xA2, 0x0E, 0x69, 0xAF, 0x3C, 0x46, 0x8A, 0x77, 0xD2, - 0xBF, 0x2A, 0x16, 0x00, 0x17, 0x2F, 0x9C, 0x4E, 0xD8, 0xA8, - 0x48, 0xD4, 0xCC, 0x0C, 0x29, 0xD1, 0x7A, 0xAE, 0x81, 0x4F, - 0x04, 0x76, 0x53, 0xCF, 0x22, 0x76, 0x39, 0x61, 0xB6, 0x76, - 0x42, 0xE6, 0x4E, 0x71, 0xB3, 0x06, 0xB9, 0x31, 0x04, 0x60, - 0x88, 0x04, 0x02, 0x89, 0x72, 0x13, 0xD8, 0x8E, 0xD7, 0xE7, - 0x88, 0xCC, 0x3B, 0x88, 0x4A, 0xC7, 0x96, 0x58, 0x12, 0xDA, - 0x75, 0x15, 0xE2, 0x9A, 0xFA, 0x9E, 0x7C, 0x0E, 0xD6, 0x86, - 0x64, 0x7F, 0x31, 0xE3, 0x5C, 0xD8, 0xCF, 0xC0, 0x6D, 0x9B, - 0x1A, 0x1D, 0x8E, 0x90, 0xED, 0x8E, 0x7B, 0xFD, 0xAF, 0xE0, - 0x85, 0xE2, 0x51, 0x49, 0xAE, 0xE6, 0x03, 0x78, 0x41, 0xB9, - 0x05, 0xA0, 0xB8, 0x25, 0x03, 0x51, 0xD1, 0x93, 0x05, 0xE1, - 0xAA, 0x19, 0x0F, 0x1A, 0xF0, 0xD6, 0x18, 0xB6, 0x23, 0xFD, - 0xBC, 0x6E, 0x10, 0xA5, 0x18, 0xE9, 0x3B, 0xE5, 0xA4, 0x22, - 0x02, 0x26, 0xC0, 0x00, 0x02, 0x55, 0x43, 0x38, 0x66, 0x6B, - 0x96, 0x00, 0x6F, 0x33, 0xEE, 0x72, 0x7A, 0x9E, 0xD2, 0x5C, - 0x1F, 0x87, 0x4C, 0xFC, 0xE9, 0x3C, 0xAB, 0xC7, 0x5E, 0x55, - 0xD6, 0xEF, 0x78, 0xB1, 0x4D, 0xA7, 0x92, 0x3F, 0x57, 0x3B, - 0xF5, 0x7F, 0xE0, 0xD6, 0xE0, 0xD0, 0x8D, 0xE5, 0xE1, 0xAE, - 0x48, 0xC1, 0xF7, 0xF3, 0xC3, 0xA4, 0xF7, 0x8F, 0xE7, 0x6F, - 0xB2, 0xB1, 0xA5, 0x6F, 0x6A, 0xCF, 0x5F, 0x3C, 0xF2, 0x50, - 0x31, 0x19, 0x89, 0xF1, 0x74, 0x55, 0xA2, 0xFF, 0x7A, 0x5D, - 0xCB, 0x96, 0xED, 0xE4, 0xEA, 0x28, 0x4B, 0xF7, 0xE4, 0x45, - 0x7D, 0x99, 0xAF, 0xC5, 0xDB, 0xC1, 0x2D, 0xE8, 0xE9, 0xEA, - 0x2B, 0xAD, 0x7E, 0x8E, 0x96, 0x25, 0xA0, 0x9E, 0xDA, 0x31, - 0xE4, 0xCD, 0xC6, 0x8D, 0x69, 0x39, 0x04, 0x53, 0x1B, 0xCA, - 0xEF, 0x96, 0x8E, 0xEF, 0xFB, 0x4E, 0xC8, 0x11, 0x8E, 0x42, - 0x03, 0xC2, 0x96, 0x1A, 0x2C, 0xD8, 0xCF, 0x17, 0x05, 0x36, - 0xF7, 0x02, 0xAB, 0xBD, 0x1A, 0xF3, 0x51, 0xC0, 0xE2, 0x1E, - 0x0D, 0x8D, 0xE9, 0x81, 0x57, 0xD1, 0xA1, 0x9A, 0x2C, 0x7D, - 0x43, 0xBD, 0x23, 0x50, 0xA9, 0x3D, 0x77, 0xC1, 0x5F, 0x2D, - 0x3A, 0x61, 0x56, 0xE1, 0x47, 0xB4, 0x6C, 0xB1, 0xDF, 0xD7, - 0x1E, 0x95, 0x00, 0x02, 0x5B, 0xDA, 0xBD, 0x39, 0x2A, 0x06, - 0x98, 0x2B, 0x54, 0x63, 0xC9, 0xDB, 0x30, 0xF2, 0xB6, 0xB6, - 0xC8, 0x22, 0xAB, 0xB5, 0x68, 0xA3, 0xB7, 0x94, 0x6C, 0x97, - 0x5B, 0xC0, 0x6F, 0xA5, 0x11, 0xFD, 0x9A, 0x52, 0x5A, 0xB5, - 0x3D, 0xEA, 0xC3, 0x23, 0xD1, 0xA7, 0x31, 0xA1, 0xCE, 0xA8, - 0x4A, 0x7C, 0x5D, 0xF6, 0x21, 0xC1, 0x38, 0x73, 0xA3, 0x83, - 0x00, 0x28, 0x9D, 0x76, 0x5A, 0xC5, 0x63, 0xDB, 0x47, 0x25, - 0xAB, 0xD7, 0x25, 0xAE, 0x7D, 0x87, 0xF1, 0xA1, 0xE6, 0x9C, - 0x83, 0x33, 0x30, 0xE1, 0xAD, 0x65, 0xFD, 0x0F, 0xBB, 0xD0, - 0xEF, 0xF5, 0xC3, 0x19, 0x9B, 0x9D, 0x13, 0xBA, 0xEF, 0x9F, - 0x13, 0x2F, 0x76, 0x55, 0x2C, 0x2A, 0xC3, 0x8B, 0x40, 0x79, - 0x49, 0x02, 0x88, 0xE7, 0x4B, 0x57, 0xF5, 0xC5, 0x56, 0x30, - 0xF2, 0xB8, 0x2D, 0x83, 0x6F, 0xB6, 0xBF, 0xE2, 0x7E, 0xFF, - 0x18, 0x61, 0x11, 0x6B, 0x77, 0xCC, 0x04, 0x8B, 0xE4, 0x7C, - 0xF9, 0x48, 0x9C, 0xE0, 0x10, 0x7F, 0x68, 0xFE, 0x40, 0xF0, - 0x23, 0x5C, 0x13, 0x56, 0xD7, 0xCC, 0xDA, 0x83, 0xD6, 0x5C, - 0xB2, 0xED, 0x3F, 0x4C, 0x1E, 0x0A, 0x2F, 0x9D, 0xA2, 0x08, - 0x95, 0xB1, 0x80, 0xFB, 0x04, 0xAC, 0xED, 0x88, 0x01, 0xDC, - 0x69, 0xC7, 0x2D, 0xE8, 0xEB, 0xD1, 0xCE, 0x8E, 0x32, 0x04, - 0x0B, 0xA5, 0x1E, 0xFA, 0x47, 0xA2, 0x8F, 0xB6, 0xF4, 0xC8, - 0xFE, 0x81, 0xFC, 0x68, 0xFF, 0x82, 0x9A, 0x9A, 0xB6, 0x2C, - 0x58, 0x55, 0xEE, 0xFC, 0xBB, 0x23, 0x47, 0xA4, 0xEB, 0xF8, - 0x08, 0xB1, 0xF0, 0xAA, 0xE3, 0x7A, 0xDC, 0xEF, 0xD6, 0xB4, - 0x60, 0x39, 0x6F, 0x0F, 0x8A, 0x4C, 0x65, 0x48, 0x65, 0x78, - 0x6D, 0xF8, 0x44, 0x13, 0xA2, 0x9A, 0x76, 0xE8, 0xA7, 0x06, - 0x33, 0x54, 0x74, 0x73, 0xE4, 0x69, 0x66, 0x27, 0xA0, 0x66, - 0xA0, 0x5A, 0x9E, 0x26, 0xF2, 0xA4, 0x3C, 0xA6, 0xCF, 0x86, - 0x0F, 0x9D, 0x0A, 0x75, 0xC1, 0x9C, 0x34, 0xD1, 0x40, 0x21, - 0x64, 0x62, 0x7B, 0xBF, 0xAE, 0xCD, 0x44, 0x17, 0x6D, 0x5F, - 0x21, 0x02, 0x17, 0x1A, 0x2C, 0xA4, 0x18, 0x1D, 0x4F, 0x2E, - 0xC8, 0xE2, 0xCF, 0xAE, 0x25, 0x4A, 0xC4, 0xA2, 0x5A, 0x2E, - 0x10, 0x09, 0x69, 0xB2, 0xEA, 0xF9, 0xB9, 0x4C, 0x36, 0xA4, - 0xD6, 0xCB, 0x03, 0x6E, 0x7B, 0xC1, 0xA4, 0x28, 0x1A, 0x09, - 0xBF, 0xF1, 0xA1, 0x3F, 0x75, 0xB8, 0x5A, 0xF3, 0x9F, 0x12, - 0x35, 0x4B, 0x16, 0x21, 0x3B, 0x8D, 0xF9, 0x87, 0xCB, 0x8A, - 0xEC, 0x29, 0x1B, 0xF0, 0xB3, 0x96, 0x77, 0xB7, 0x7B, 0xA8, - 0x6A, 0x98, 0xE4, 0x8B, 0x61, 0xB6, 0x47, 0xD7, 0x92, 0xB4, - 0x0B, 0x47, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x4B, 0x86, 0xD9, - 0x89, 0x5B, 0x11, 0x29, 0x1D, 0x8E, 0x56, 0xC4, 0x4A, 0x0D, - 0xD4, 0x9F, 0x43, 0x9F, 0xA2, 0x55, 0x58, 0xE1, 0xF6, 0xF6, - 0x58, 0xFB, 0xCD, 0x3F, 0x06, 0x4C, 0xC2, 0x60, 0x6D, 0xB7, - 0xB2, 0xFF, 0xFE, 0x89, 0x77, 0x7A, 0x1E, 0xA0, 0xC8, 0xDD, - 0x7F, 0x3E, 0x6B, 0x38, 0x2F, 0x41, 0x2B, 0xDF, 0x42, 0x14, - 0x50, 0x28, 0xEE, 0xDE, 0x3F, 0xD8, 0xFF, 0x09, 0x43, 0x7A, - 0x22, 0x4F, 0xF3, 0xFC, 0x60, 0x7E, 0x2C, 0x1A, 0xB6, 0x9E, - 0x21, 0x40, 0x76, 0x3B, 0x42, 0xFC, 0xBC, 0x1D, 0x00, 0xA4, - 0x55, 0x95, 0x47, 0xBD, 0x6E, 0x31, 0xAB, 0x05, 0xAD, 0x38, - 0x53, 0xB0, 0x24, 0x83, 0x7D, 0x0E, 0xA8, 0x40, 0xE6, 0x33, - 0x6D, 0xEF, 0x72, 0x35, 0xCF, 0x3C, 0x11, 0x67, 0x1D, 0x28, - 0xEF, 0x7B, 0x7A, 0x7A, 0x0E, 0xD2, 0x7F, 0xBA, 0xEB, 0xA0, - 0x49, 0x46, 0x29, 0x40, 0x5B, 0x62, 0xA9, 0xED, 0xC9, 0xAC, - 0xDD, 0xAF, 0xE9, 0xAF, 0xF9, 0x75, 0x70, 0xC7, 0xAD, 0xB2, - 0xB6, 0x51, 0x08, 0x23, 0x89, 0x1F, 0xCC, 0xDE, 0xB7, 0x6B, - 0x25, 0xC4, 0x77, 0x90, 0x01, 0xBA, 0x80, 0x62, 0x3E, 0xFF, - 0x93, 0x00, 0x15, 0x43, 0x7D, 0xBE, 0x80, 0x83, 0xBB, 0xB0, - 0xAA, 0x3B, 0xF2, 0x0A, 0x9D, 0x86, 0x23, 0xA4, 0xB7, 0xB7, - 0x44, 0x30, 0xA7, 0x17, 0x66, 0x70, 0xEE, 0x2D, 0x1F, 0xDF, - 0xBD, 0xD9, 0x14, 0x3E, 0x55, 0xC6, 0xC9, 0x5B, 0xC3, 0xF2, - 0xE5, 0x10, 0xD5, 0x1A, 0x93, 0xF6, 0x76, 0xAB, 0x71, 0x87, - 0xDE, 0xD5, 0x51, 0x99, 0x37, 0x6F, 0xEE, 0xB1, 0x63, 0xDA, - 0x7F, 0x3B, 0xAC, 0x77, 0x1B, 0x4B, 0xA3, 0xE3, 0x77, 0x41, - 0xEA, 0x23, 0xF3, 0xB9, 0x22, 0x75, 0x07, 0x8E, 0x64, 0x3E, - 0x32, 0xA9, 0x28, 0xAA, 0x93, 0x8F, 0xE8, 0xDA, 0x60, 0xE9, - 0xD7, 0x35, 0x7F, 0xD7, 0x8F, 0xC8, 0xE5, 0x5B, 0x61, 0x47, - 0xD6, 0xD4, 0xA7, 0xFF, 0x25, 0x8F, 0x03, 0xC3, 0x03, 0x07, - 0xED, 0x30, 0x45, 0x86, 0x73, 0x1E, 0x8F, 0x2F, 0x3D, 0xB4, - 0xC0, 0x37, 0x7A, 0xE7, 0x80, 0xEA, 0xA0, 0xDB, 0x98, 0xAE, - 0xF9, 0x24, 0x0C, 0x74, 0x36, 0x54, 0x13, 0x34, 0x30, 0xCF, - 0x0E, 0xC8, 0x9D, 0x94, 0xE7, 0xAF, 0x6A, 0xC0, 0x32, 0x32, - 0xA3, 0xDE, 0x3A, 0x5B, 0x72, 0x72, 0xE3, 0x8F, 0x91, 0xC5, - 0x44, 0xAB, 0x86, 0x7B, 0xE0, 0x6C, 0x80, 0x84, 0x64, 0x1D, - 0xC0, 0xF1, 0x28, 0x7C, 0x6A, 0x35, 0x76, 0xCF, 0x12, 0x56, - 0x84, 0x1C, 0x21, 0x51, 0x33, 0x00, 0xFF, 0xB2, 0x64, 0x30, - 0x44, 0x1C, 0xA5, 0x05, 0x09, 0xE2, 0x14, 0x8E, 0xF3, 0xD8, - 0x91, 0x21, 0x60, 0xC0, 0x51, 0x68, 0x62, 0xF5, 0x7E, 0x06, - 0xD5, 0xC0, 0xEE, 0xB8, 0x91, 0xF1, 0x52, 0x14, 0x6C, 0x27, - 0xB6, 0x6A, 0x1C, 0x64, 0xBF, 0x59, 0x47, 0x64, 0x03, 0x8D, - 0x4E, 0xEB, 0xA3, 0x73, 0x10, 0xE2, 0xBC, 0xA0, 0x30, 0x29, - 0xE6, 0xF5, 0xED, 0x04, 0xCA, 0xAA, 0xC2, 0xBA, 0xDB, 0x8E, - 0xBC, 0x00, 0x34, 0x3D, 0xB6, 0x12, 0xCB, 0xAF, 0xC0, 0x3D, - 0x97, 0xF7, 0x5A, 0x1B, 0x83, 0x90, 0x91, 0xD0, 0xE2, 0xCF, - 0xE6, 0x21, 0x07, 0xCF, 0x2E, 0xFD, 0x71, 0xA1, 0x10, 0x18, - 0x67, 0x3F, 0x8F, 0xE2, 0x86, 0xFA, 0xA6, 0xDF, 0x6D, 0xE4, - 0x31, 0x7D, 0x75, 0x12, 0x99, 0x23, 0xC7, 0xFB, 0xF2, 0x04, - 0x76, 0x4C, 0x93, 0x9B, 0xB9, 0x89, 0x1D, 0x88, 0x5A, 0x0E, - 0xDE, 0x5A, 0x27, 0x35, 0x88, 0xE7, 0x80, 0x14, 0x87, 0xCA, - 0x23, 0xE6, 0xEF, 0xA8, 0xEA, 0x73, 0x7D, 0x93, 0x0C, 0x61, - 0x81, 0x2E, 0x10, 0xDF, 0x13, 0x57, 0x96, 0xD9, 0x36, 0x68, - 0x93, 0x42, 0x7A, 0x67, 0x60, 0x44, 0x57, 0xD8, 0x6C, 0x4B, - 0xD4, 0xCC, 0x7E, 0x70, 0xE2, 0xCD, 0xC7, 0x14, 0x4A, 0xDE, - 0x32, 0x35, 0x8B, 0x4B, 0x14, 0xE0, 0x8D, 0x5C, 0x33, 0x72, - 0xC9, 0x5D, 0x1F, 0xF6, 0xD7, 0xC3, 0xCF, 0x72, 0xA1, 0x2C, - 0x98, 0x2C, 0x0E, 0xEA, 0x02, 0x26, 0xC0, 0x00, 0x02, 0xEC, - 0xFC, 0x5D, 0x99, 0x61, 0x74, 0x77, 0x64, 0xF2, 0x70, 0x18, - 0x1A, 0x0B, 0x9F, 0x5A, 0x64, 0xE4, 0xCE, 0xA9, 0xCE, 0xCF, - 0x15, 0x35, 0x0E, 0x90, 0x95, 0xD1, 0x78, 0xBC, 0x36, 0xDD, - 0x32, 0xB0, 0x72, 0xCF, 0xCE, 0xFE, 0x8D, 0xAA, 0xF4, 0x19, - 0x73, 0x80, 0x37, 0xB6, 0x7B, 0x88, 0xB5, 0x7F, 0x5B, 0x7E, - 0xC7, 0x1F, 0x40, 0x5E, 0xCF, 0xC5, 0xE3, 0x75, 0x43, 0xCA, - 0x9D, 0x7C, 0xA1, 0x5D, 0x12, 0xBE, 0x30, 0x0E, 0x2C, 0x6D, - 0xE1, 0xD4, 0xD9, 0xC0, 0x90, 0x9F, 0x13, 0x6C, 0x00, 0x75, - 0xC9, 0x98, 0xE8, 0x4A, 0x1E, 0x43, 0x27, 0xB2, 0x3D, 0x16, - 0x5D, 0xF7, 0x18, 0xF6, 0xF2, 0x57, 0xA8, 0x54, 0x57, 0x50, - 0xFD, 0x98, 0x0F, 0x99, 0x63, 0x9E, 0x94, 0x71, 0x8B, 0x6B, - 0x6A, 0xAC, 0x27, 0x7A, 0xE5, 0xFE, 0x49, 0x5F, 0xA9, 0x3F, - 0x72, 0x32, 0xE5, 0x67, 0x87, 0xE9, 0xCC, 0xBC, 0x64, 0xE9, - 0x6B, 0x15, 0x06, 0x60, 0x32, 0x43, 0x49, 0x53, 0x47, 0xB2, - 0x56, 0xCE, 0xBF, 0x5F, 0x9B, 0x16, 0x40, 0x7D, 0x90, 0x0E, - 0xFB, 0xFE, 0x66, 0x58, 0xB3, 0xFC, 0x42, 0xB5, 0x90, 0xE6, - 0xCA, 0x6C, 0xD0, 0x3C, 0xA0, 0x2D, 0x84, 0x5E, 0xA0, 0xE7, - 0xD7, 0x8B, 0xB0, 0x42, 0x56, 0x3D, 0x48, 0xAF, 0x18, 0xEF, - 0xAF, 0x27, 0x76, 0xE3, 0x26, 0x0B, 0xCA, 0xA0, 0x01, 0x4B, - 0x79, 0xD1, 0xAC, 0xD5, 0x8B, 0xCD, 0x70, 0x9F, 0x6E, 0xFB, - 0x72, 0xBB, 0x9B, 0xDA, 0x4A, 0xFA, 0x96, 0x45, 0x29, 0x59, - 0x16, 0x4B, 0x57, 0xC1, 0x7B, 0x5D, 0x94, 0x5E, 0xDA, 0xC1, - 0x2B, 0x3C, 0xD9, 0xD5, 0x6B, 0x23, 0xE7, 0x53, 0x9C, 0xAA, - 0x89, 0x07, 0xFC, 0x66, 0xBC, 0xBC, 0xDD, 0x5D, 0xC7, 0xC0, - 0x46, 0xAF, 0xF6, 0xCB, 0xBB, 0xD3, 0x37, 0xC1, 0x7F, 0xCD, - 0xAE, 0x69, 0x1F, 0xCA, 0x20, 0x07, 0x76, 0x3F, 0xD0, 0x71, - 0x4F, 0x19, 0x6A, 0x92, 0xA2, 0xD8, 0x81, 0xE7, 0x84, 0xC3, - 0x24, 0x55, 0xF3, 0x1F, 0xA6, 0x8B, 0xAF, 0x11, 0xA6, 0xAC, - 0x9B, 0x2D, 0x12, 0xD0, 0x0D, 0xBC, 0x20, 0x26, 0x01, 0x76, - 0x39, 0xBF, 0xAB, 0x52, 0xD6, 0x93, 0x76, 0x29, 0x4C, 0xD8, - 0x8F, 0xBA, 0xA9, 0xA1, 0xCE, 0x09, 0xCC, 0xB7, 0xC5, 0x34, - 0xCC, 0xC1, 0x27, 0xE9, 0x47, 0xFB, 0x02, 0xC0, 0x0B, 0xB7, - 0xE2, 0x1B, 0x9A, 0x05, 0x32, 0x99, 0x7E, 0xEF, 0xDA, 0xC3, - 0xE2, 0xB3, 0x0D, 0x2F, 0xD7, 0x32, 0x14, 0xAA, 0x90, 0x00, - 0x5B, 0x8F, 0xA9, 0x6D, 0xBD, 0x54, 0xAF, 0xE2, 0x47, 0x8C, - 0x20, 0xD4, 0x14, 0x34, 0x13, 0x08, 0x17, 0x1B, 0xA2, 0x3B, - 0xDC, 0x6D, 0x5A, 0x08, 0x04, 0x58, 0x38, 0xAC, 0x84, 0xBB, - 0x22, 0x64, 0x6B, 0xE6, 0xB9, 0x46, 0x4A, 0xB6, 0x39, 0xD2, - 0xF4, 0x6D, 0x13, 0x63, 0x7F, 0x79, 0x6F, 0x54, 0x38, 0x72, - 0x1A, 0x3D, 0x45, 0x28, 0x14, 0x8F, 0x9D, 0xFE, 0x51, 0x02, - 0x3F, 0x0C, 0xFD, 0xE4, 0x7A, 0xC4, 0xFC, 0x00, 0xF0, 0xF6, - 0x7E, 0x98, 0x36, 0x40, 0x35, 0x92, 0x3A, 0x42, 0xBE, 0xA6, - 0xAE, 0x3C, 0x55, 0xF5, 0x4E, 0x41, 0xF4, 0x22, 0x63, 0x80, - 0x2E, 0xC9, 0x65, 0x73, 0x43, 0x2F, 0xE7, 0xF9, 0xC5, 0x5C, - 0x21, 0xDD, 0xF5, 0x15, 0x38, 0xE4, 0xDD, 0x92, 0x08, 0x9D, - 0x75, 0x65, 0x13, 0x28, 0xA5, 0xF9, 0x45, 0x13, 0xE0, 0x8F, - 0xB2, 0x36, 0x91, 0xAA, 0xBE, 0x87, 0xD2, 0x78, 0x3F, 0xB0, - 0xEE, 0x0C, 0x4C, 0x8C, 0xD7, 0x56, 0x85, 0x21, 0x43, 0x40, - 0xC4, 0x26, 0x90, 0xC2, 0x63, 0xF0, 0xC3, 0x49, 0xA0, 0xF0, - 0x2A, 0xCA, 0xA3, 0x9A, 0x39, 0xA6, 0xAA, 0x98, 0x2B, 0x8E, - 0xBA, 0x0B, 0xD9, 0x21, 0xC4, 0xC9, 0x97, 0x1B, 0x57, 0x80, - 0x49, 0x3E, 0xC4, 0x4B, 0xD8, 0x5E, 0xE2, 0x43, 0xC2, 0x13, - 0x8D, 0x51, 0x28, 0x8B, 0x30, 0x7C, 0x17, 0xB0, 0x58, 0x15, - 0x5F, 0x56, 0xF8, 0xF3, 0x8F, 0x9A, 0xC0, 0x9B, 0x27, 0x90, - 0x23, 0x48, 0xED, 0x5E, 0x50, 0xE2, 0x02, 0x26, 0xC0, 0x00, - 0x02, 0x02, 0xCA, 0xFA, 0x0D, 0x3A, 0xC4, 0xBF, 0x20, 0x04, - 0xD3, 0xA1, 0x4F, 0xED, 0x80, 0x40, 0x81, 0x15, 0x67, 0x0D, - 0x65, 0x3E, 0x52, 0x9C, 0x30, 0x20, 0xD2, 0xD8, 0xAC, 0xAF, - 0x06, 0xE5, 0xDA, 0x8B, 0x8B, 0x3A, 0xCA, 0xDC, 0x59, 0x8F, - 0x2F, 0x93, 0x53, 0x5B, 0xAC, 0xCE, 0x1F, 0xDF, 0x3B, 0x50, - 0xBF, 0x70, 0xF1, 0x7A, 0xCC, 0xA2, 0x25, 0x88, 0xD1, 0xA0, - 0xBC, 0x9D, 0x41, 0x1F, 0x9C, 0x0A, 0x95, 0x27, 0xE2, 0x71, - 0x4C, 0x1C, 0x14, 0xDB, 0xEA, 0xCD, 0xA3, 0x7C, 0x39, 0x57, - 0x69, 0x95, 0xA5, 0x04, 0x4F, 0xA3, 0xC0, 0x24, 0xC1, 0x5B, - 0x39, 0xF4, 0x9F, 0xBC, 0xB2, 0xC3, 0x37, 0x28, 0x1F, 0xFA, - 0xB9, 0xD7, 0xFF, 0x7A, 0xA2, 0x52, 0x03, 0x1F, 0x96, 0x5B, - 0xC4, 0x83, 0x08, 0x75, 0xFF, 0xF6, 0xF2, 0xF9, 0x7C, 0x1D, - 0x09, 0xB4, 0x3B, 0xAE, 0xCD, 0x2E, 0xF2, 0x6F, 0x2F, 0x4F, - 0xBC, 0x2B, 0x5B, 0x6D, 0x9A, 0x1B, 0xE6, 0x5E, 0xF5, 0xA8, - 0x93, 0x98, 0xDC, 0x6E, 0x5E, 0x17, 0xCA, 0xAB, 0x90, 0xFD, - 0xFB, 0x68, 0x1F, 0x67, 0x88, 0x58, 0x85, 0x4F, 0xAA, 0xC3, - 0x68, 0x40, 0xD5, 0xBC, 0xAC, 0x1D, 0x94, 0xC5, 0xB6, 0x01, - 0x2A, 0xE8, 0xBD, 0xDD, 0xBB, 0x17, 0x9D, 0x0E, 0x55, 0x62, - 0x45, 0xFB, 0x21, 0xB6, 0x71, 0x76, 0xEB, 0xCC, 0xF5, 0xE7, - 0xF1, 0xCD, 0xB7, 0xCA, 0xBD, 0xFF, 0xA9, 0xF7, 0x1A, 0xAA, - 0x1A, 0xCD, 0xC1, 0x71, 0x62, 0xE3, 0xDD, 0x09, 0x06, 0xAA, - 0x23, 0xFD, 0xEF, 0x6B, 0xA7, 0x83, 0xD8, 0xE6, 0x70, 0x01, - 0xF0, 0xEF, 0x69, 0xA9, 0x4B, 0x9B, 0x83, 0x57, 0x77, 0xAD, - 0x51, 0xBE, 0xBA, 0xF6, 0x2A, 0x6F, 0x1F, 0x97, 0x9A, 0xFE, - 0xA8, 0xE2, 0xAA, 0x20, 0x51, 0x95, 0xBA, 0xAE, 0x66, 0xB3, - 0xA8, 0x61, 0xCF, 0x8B, 0xFA, 0x6B, 0x48, 0xC4, 0x22, 0xE1, - 0xDF, 0x3A, 0x0D, 0xA9, 0x09, 0xF1, 0x66, 0x0C, 0x46, 0x74, - 0x90, 0x8B, 0x68, 0x00, 0x4F, 0x4F, 0x3A, 0x90, 0x58, 0x56, - 0xF4, 0x8A, 0x71, 0xB6, 0x1A, 0x91, 0x59, 0x17, 0x5C, 0xC0, - 0x87, 0x82, 0x7E, 0xB0, 0x81, 0x90, 0xF1, 0x6A, 0x03, 0xB8, - 0xA0, 0xAB, 0xDD, 0x63, 0x96, 0x48, 0x19, 0x37, 0x1F, 0x0F, - 0x24, 0x7A, 0x70, 0x48, 0x7D, 0x28, 0x1F, 0xB3, 0xCD, 0x76, - 0x53, 0x83, 0xC5, 0x53, 0xE8, 0xAB, 0x3A, 0xFC, 0x5B, 0x8A, - 0xF0, 0x5A, 0x0F, 0xEF, 0xFF, 0xB0, 0xC1, 0x61, 0x61, 0x58, - 0x4A, 0x8C, 0x1C, 0x20, 0xFC, 0x46, 0x07, 0x58, 0xF0, 0x20, - 0x81, 0x66, 0x28, 0x0E, 0xC2, 0x16, 0xAB, 0x98, 0xFF, 0x6E, - 0x24, 0xAC, 0x78, 0x42, 0xAE, 0x7D, 0xAB, 0x6F, 0xB4, 0x11, - 0x1C, 0x0C, 0x40, 0xF8, 0xF4, 0x93, 0x63, 0xE4, 0x6A, 0xEB, - 0xC5, 0xD9, 0x6E, 0x35, 0xC9, 0xA7, 0x2D, 0x49, 0xEA, 0x5D, - 0x69, 0x73, 0x06, 0x1C, 0xC4, 0x7E, 0x46, 0xFD, 0x09, 0x88, - 0x77, 0x77, 0xE7, 0xEB, 0x31, 0x34, 0x16, 0x72, 0x76, 0x1B, - 0x4E, 0xF8, 0x67, 0x9F, 0xCA, 0x1C, 0x67, 0x4E, 0xD8, 0x88, - 0xAA, 0x01, 0x27, 0x8E, 0x08, 0x70, 0xF8, 0x0B, 0x23, 0xF6, - 0x84, 0x47, 0x2F, 0x4E, 0x5F, 0xB7, 0x2C, 0x39, 0xBF, 0x61, - 0xEC, 0x6D, 0x24, 0x5C, 0x57, 0xBE, 0xAE, 0x19, 0x20, 0xBE, - 0x55, 0x40, 0x1D, 0xB7, 0x5F, 0xC3, 0xF6, 0x5B, 0x19, 0xC6, - 0x8A, 0x94, 0x23, 0x5C, 0x95, 0x33, 0x4C, 0x90, 0xE0, 0x46, - 0xAC, 0x0A, 0x1D, 0x50, 0xFB, 0x0A, 0xAB, 0xA2, 0xEB, 0x2A, - 0x21, 0xBF, 0x15, 0xD5, 0x9E, 0x80, 0x3B, 0x16, 0xB0, 0x3F, - 0x6F, 0x6F, 0xF6, 0xBE, 0x92, 0xA1, 0x2F, 0x83, 0xA8, 0x3C, - 0xA6, 0xE7, 0x86, 0xCD, 0x3B, 0x96, 0xCE, 0xF1, 0x36, 0x7C, - 0x69, 0xD9, 0xD5, 0x0F, 0xC1, 0x4C, 0x7A, 0xE5, 0xAF, 0xAC, - 0x86, 0x90, 0x98, 0x3D, 0x2B, 0x94, 0xA2, 0x7C, 0x5B, 0xF7, - 0x27, 0xCD, 0xE5, 0x93, 0x60, 0x2C, 0x47, 0xE3, 0xFA, 0x18, - 0xCB, 0xEB, 0xDB, 0x0A, 0x49, 0x99, 0x0F, 0xAE, 0x02, 0x26, - 0xC0, 0x00, 0x02, 0xF3, 0x51, 0xA3, 0x96, 0x54, 0xDA, 0xE9, - 0x09, 0x47, 0x82, 0x50, 0xB8, 0x82, 0x39, 0x98, 0x54, 0x81, - 0x54, 0x91, 0x2C, 0xE6, 0xBC, 0x84, 0x03, 0x07, 0x26, 0x6D, - 0x0F, 0x5E, 0x2B, 0x45, 0xF5, 0x1D, 0x7B, 0xD6, 0x14, 0x03, - 0xD7, 0x09, 0x64, 0xEE, 0x05, 0xBA, 0xE0, 0x74, 0x67, 0x02, - 0xF5, 0x7E, 0x42, 0x42, 0xEC, 0x56, 0xE0, 0x9E, 0x82, 0x88, - 0x58, 0x3C, 0x96, 0xAF, 0x37, 0x95, 0x49, 0xC8, 0x87, 0xBD, - 0xFE, 0x7A, 0x6B, 0x4D, 0x37, 0xEE, 0x7C, 0xAA, 0x18, 0x5F, - 0x7E, 0x0B, 0x28, 0xA3, 0x95, 0x23, 0x42, 0xAB, 0xC1, 0xFA, - 0x41, 0xAE, 0xD5, 0xBD, 0x67, 0xA6, 0xC4, 0x7C, 0xAC, 0x2D, - 0xEF, 0x64, 0xC2, 0x5D, 0x30, 0x94, 0xF3, 0x97, 0x49, 0x00, - 0x39, 0x28, 0x57, 0x5D, 0x31, 0xBB, 0x1D, 0x10, 0x17, 0xE7, - 0x56, 0x55, 0xDF, 0x4C, 0xDD, 0xA6, 0x64, 0x02, 0xBC, 0x1C, - 0x2B, 0x4C, 0x30, 0xBF, 0x89, 0x7C, 0xFC, 0x7E, 0x84, 0xBC, - 0x51, 0x97, 0x6C, 0x74, 0x5B, 0x08, 0xE0, 0x96, 0x84, 0x81, - 0xF3, 0x17, 0x6B, 0xD6, 0xF6, 0x66, 0x06, 0x1B, 0x33, 0x4D, - 0xF8, 0xED, 0xC0, 0x53, 0x8B, 0x35, 0x6B, 0x85, 0x4F, 0x37, - 0x0F, 0x87, 0xF3, 0x85, 0x72, 0xAE, 0xCB, 0x3A, 0x23, 0x97, - 0xC0, 0xF6, 0xE7, 0x53, 0xDF, 0x57, 0x0E, 0x8E, 0x0B, 0x66, - 0x2A, 0xA2, 0x9D, 0xA8, 0xE2, 0x60, 0x57, 0xCA, 0x27, 0x7E, - 0xB1, 0xDB, 0x7B, 0x6A, 0xB0, 0xBE, 0xB5, 0x47, 0xEE, 0xE6, - 0xBA, 0x0E, 0xB2, 0x71, 0x0B, 0xF7, 0xE4, 0x27, 0x9D, 0x25, - 0xAA, 0x3F, 0xA9, 0x1A, 0x5B, 0xD9, 0x9D, 0xBB, 0x20, 0x32, - 0x37, 0xE1, 0xD3, 0x4A, 0xBA, 0x45, 0x9E, 0x00, 0x10, 0x3F, - 0x21, 0x6E, 0xA2, 0xCE, 0x30, 0xA0, 0x2A, 0x5B, 0x31, 0x51, - 0x05, 0xA1, 0x51, 0xED, 0x89, 0x5E, 0xB1, 0x09, 0xE6, 0x71, - 0xD8, 0x42, 0xFD, 0xA1, 0x04, 0x83, 0xFB, 0x09, 0x4F, 0x90, - 0x4D, 0x7E, 0x5A, 0xB9, 0x4C, 0xC9, 0xA3, 0x57, 0x4E, 0x54, - 0x98, 0xB3, 0xBD, 0xB7, 0x52, 0x9D, 0xDE, 0xF3, 0xD3, 0xE0, - 0x9C, 0x2D, 0x97, 0x46, 0x1B, 0xF9, 0x75, 0x37, 0x5D, 0x0A, - 0xA3, 0x4A, 0x18, 0x35, 0x80, 0xC5, 0x08, 0xA8, 0x37, 0x09, - 0x44, 0x92, 0xB1, 0x74, 0xFE, 0x28, 0x95, 0x55, 0xB6, 0x08, - 0xA0, 0x75, 0xE9, 0xA0, 0x4B, 0x8E, 0xE6, 0x61, 0x17, 0x2A, - 0xED, 0x15, 0x0B, 0x6C, 0x7C, 0xC3, 0x82, 0x57, 0x90, 0xC5, - 0xFF, 0xD8, 0xA5, 0xBF, 0xAA, 0xBE, 0xCF, 0x8E, 0x06, 0xFF, - 0x27, 0xDA, 0x40, 0x24, 0xDD, 0xC0, 0xBE, 0x4E, 0x19, 0x9D, - 0x23, 0xA2, 0x3A, 0x70, 0x64, 0xEB, 0xF6, 0xA7, 0xE9, 0x71, - 0x57, 0xE9, 0x63, 0x03, 0xAE, 0xEC, 0x73, 0x21, 0x23, 0x8D, - 0x61, 0x5A, 0x10, 0x54, 0xF9, 0x80, 0xE7, 0x47, 0x45, 0xD4, - 0x8B, 0x16, 0xEE, 0x2B, 0xD8, 0xC1, 0xEE, 0x0F, 0x4F, 0x78, - 0x40, 0x00, 0xB6, 0x25, 0x81, 0x2A, 0x37, 0x4D, 0x71, 0x92, - 0xFA, 0x56, 0x3F, 0xDC, 0x91, 0x01, 0x27, 0xC7, 0x17, 0xFD, - 0x27, 0x55, 0x6F, 0x32, 0x14, 0xE7, 0xEA, 0x18, 0xDA, 0x4A, - 0x70, 0x10, 0xF8, 0x72, 0x78, 0xA1, 0xC1, 0x13, 0x5F, 0x1B, - 0x98, 0x93, 0xC2, 0xBF, 0x29, 0xA3, 0x59, 0x79, 0x15, 0x57, - 0x17, 0xE5, 0x66, 0x7A, 0x3B, 0x8E, 0xB3, 0x3B, 0x9E, 0xC0, - 0x77, 0xBD, 0x2D, 0x95, 0x26, 0xF0, 0xD5, 0xB4, 0x30, 0xC8, - 0x0D, 0xCA, 0xB5, 0xDE, 0xB2, 0x21, 0x27, 0x9A, 0x27, 0xAF, - 0x89, 0xB4, 0x0D, 0x1B, 0x5A, 0x43, 0x3E, 0x69, 0x76, 0x25, - 0xAC, 0x42, 0x23, 0x5F, 0x5A, 0xA6, 0xDB, 0xE6, 0x77, 0x9D, - 0x2A, 0x99, 0x1B, 0xE7, 0x47, 0x05, 0x06, 0x47, 0x01, 0x14, - 0x0D, 0xEA, 0xF5, 0x28, 0x3A, 0x5B, 0x87, 0xF0, 0xFB, 0x7C, - 0x96, 0x39, 0x6C, 0x4A, 0x48, 0xA5, 0x7A, 0x94, 0xB0, 0xB8, - 0xBB, 0x03, 0xDA, 0xEA, 0x4F, 0xD1, 0x5B, 0x8B, 0x9D, 0x0A, - 0x5E, 0xAB, 0xD8, 0x89, 0x5C, 0x4D, 0xD1, 0xA7, 0xC4, 0x8A, - 0x02, 0x26, 0xC0, 0x00, 0x02, 0x14, 0x04, 0xA6, 0x12, 0xC1, - 0x4E, 0x67, 0x67, 0x6C, 0xEE, 0x9E, 0x7A, 0x55, 0x00, 0xCB, - 0x12, 0x7B, 0x69, 0x4C, 0x94, 0x57, 0x73, 0x71, 0xC8, 0x45, - 0xAA, 0x04, 0x75, 0x85, 0xED, 0x68, 0x7D, 0x09, 0xD5, 0x4A, - 0xD0, 0x86, 0xDB, 0x0B, 0xC3, 0x80, 0xD1, 0x11, 0xB3, 0x59, - 0xCF, 0xBD, 0x13, 0x7B, 0xD2, 0x30, 0xDF, 0xDD, 0x41, 0xD7, - 0xBC, 0x34, 0x11, 0x85, 0x58, 0x2A, 0x8E, 0x2B, 0xDC, 0x00, - 0x78, 0x94, 0x28, 0x52, 0xD9, 0x0C, 0x70, 0xCB, 0x7D, 0xE9, - 0xCF, 0x7C, 0x11, 0x91, 0x09, 0xA8, 0xD7, 0xBC, 0xC8, 0xA1, - 0xDF, 0xF3, 0xB4, 0x25, 0x3A, 0x88, 0x02, 0xF0, 0xBE, 0x8E, - 0x89, 0x2B, 0xA6, 0x43, 0x88, 0xD0, 0xCC, 0x27, 0x91, 0x77, - 0x8D, 0x01, 0x32, 0xA6, 0x0C, 0x3D, 0x86, 0x76, 0x03, 0x4F, - 0x01, 0xF6, 0x02, 0xB3, 0xD0, 0x7A, 0x39, 0x78, 0x1E, 0xF2, - 0x35, 0xB6, 0xB3, 0xC9, 0x50, 0xE7, 0x0A, 0xD1, 0x3C, 0xB4, - 0xE2, 0x02, 0x60, 0x13, 0x8A, 0x0F, 0x15, 0xEE, 0x48, 0x67, - 0x84, 0x9E, 0x8E, 0x56, 0x22, 0xB9, 0x0A, 0xE2, 0x36, 0xDE, - 0x97, 0x4E, 0x9F, 0x0A, 0xE0, 0xB8, 0x2A, 0x0D, 0x07, 0x7F, - 0xCE, 0x76, 0xEA, 0x58, 0x54, 0xBC, 0x7A, 0xA1, 0x87, 0x15, - 0x3F, 0xCE, 0xDA, 0x58, 0xA4, 0x51, 0x36, 0x49, 0xB0, 0x23, - 0xC0, 0x55, 0xFB, 0xE2, 0x47, 0xB6, 0xD6, 0x31, 0x90, 0xA9, - 0x99, 0x2A, 0xC3, 0x59, 0xAE, 0x60, 0x03, 0xC2, 0x56, 0xC0, - 0x03, 0xA9, 0x3E, 0xF0, 0xE9, 0x59, 0x30, 0xD5, 0x90, 0x15, - 0x72, 0x32, 0x30, 0xD1, 0xFA, 0xDD, 0xB3, 0x09, 0xF0, 0x1A, - 0xA3, 0x6E, 0x5E, 0xBB, 0xDE, 0x58, 0x08, 0x91, 0xFB, 0xA0, - 0xEC, 0x45, 0x7F, 0x05, 0x90, 0x78, 0xCF, 0x6F, 0x66, 0xF4, - 0x2A, 0x79, 0x93, 0x33, 0x17, 0x07, 0x86, 0xE6, 0xEC, 0xFD, - 0xEC, 0x07, 0x74, 0x17, 0x26, 0x84, 0x52, 0x54, 0x9A, 0xBC, - 0xDE, 0xEE, 0xD7, 0xE9, 0x2F, 0xA7, 0x60, 0xA6, 0x54, 0x74, - 0xB9, 0x83, 0x6D, 0xE6, 0xB7, 0x46, 0xDC, 0xC8, 0x09, 0x36, - 0x25, 0x1E, 0x8B, 0x61, 0x94, 0x2D, 0xBA, 0xE2, 0xAB, 0xE6, - 0xD0, 0xDB, 0x9C, 0x13, 0x74, 0x25, 0xDA, 0xD7, 0x69, 0x69, - 0xFA, 0x52, 0x3C, 0x15, 0xBB, 0xFC, 0x5D, 0xE2, 0x6E, 0xA5, - 0x26, 0x35, 0x65, 0xF4, 0xE0, 0x29, 0x77, 0xCF, 0xAB, 0xF9, - 0xAB, 0x8C, 0x9D, 0x7D, 0x60, 0xA4, 0xA0, 0x3D, 0x43, 0xB6, - 0x9D, 0xAE, 0x04, 0x46, 0x8A, 0xE2, 0x3B, 0x4C, 0xC8, 0xA4, - 0x5D, 0x61, 0xB4, 0x5B, 0x8B, 0x2E, 0xD5, 0x2A, 0x07, 0x27, - 0x6A, 0x34, 0x04, 0xBA, 0xF8, 0x72, 0x32, 0x99, 0x97, 0x8C, - 0xC0, 0xCD, 0x35, 0x68, 0xB8, 0xA9, 0x45, 0x76, 0xA5, 0xD4, - 0x17, 0x36, 0xB1, 0x25, 0xF7, 0x47, 0x69, 0x30, 0x68, 0x14, - 0x0B, 0x9C, 0x38, 0xB1, 0x29, 0x16, 0x88, 0xAD, 0xDF, 0x31, - 0x7E, 0x3C, 0x5F, 0xA4, 0x0D, 0x86, 0x5A, 0x29, 0x37, 0xA9, - 0x1B, 0xD5, 0x68, 0x9F, 0xE0, 0xE6, 0x32, 0x42, 0x12, 0x37, - 0x99, 0xC5, 0xB8, 0xA1, 0xD3, 0x5B, 0x90, 0x9C, 0xAD, 0x86, - 0x6B, 0x03, 0x82, 0x91, 0xD9, 0xF9, 0xDC, 0xD5, 0x41, 0x7B, - 0xF3, 0xE4, 0x08, 0x92, 0xCA, 0x6A, 0xAA, 0xBD, 0xFE, 0x25, - 0x50, 0xDC, 0x2C, 0x00, 0x65, 0x59, 0x9B, 0xD3, 0x30, 0xD2, - 0x39, 0xC0, 0x4D, 0xFD, 0x8C, 0x9D, 0x88, 0xD3, 0x52, 0xD6, - 0xC0, 0xA0, 0x1C, 0x08, 0x0B, 0x1F, 0x91, 0xAF, 0x60, 0x56, - 0xED, 0x8B, 0x37, 0xD3, 0x15, 0x08, 0x5C, 0xEA, 0xFA, 0x03, - 0x0A, 0x54, 0x92, 0x96, 0x34, 0x4F, 0x14, 0x0E, 0xD5, 0xB4, - 0xA0, 0x2E, 0xC0, 0xEC, 0x93, 0x8F, 0xA5, 0xF3, 0x82, 0x5F, - 0x0D, 0xA8, 0xBD, 0x28, 0x4B, 0x1C, 0x65, 0xC1, 0x97, 0x5B, - 0xEE, 0x99, 0xC5, 0xC2, 0xB9, 0x34, 0x4D, 0xDB, 0x6E, 0x42, - 0x26, 0x93, 0x49, 0x83, 0x36, 0x25, 0x72, 0x03, 0x08, 0xE2, - 0xE6, 0x67, 0x01, 0xBC, 0x7A, 0x10, 0x7A, 0xBC, 0x6B, 0x0B, - 0x4A, 0x94, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x72, 0x08, 0xBA, - 0x77, 0xE2, 0x2F, 0x48, 0xD4, 0x9E, 0xC4, 0x23, 0x45, 0x55, - 0xF1, 0x0B, 0x1B, 0x50, 0x47, 0x8C, 0x40, 0x7C, 0xF7, 0xE4, - 0xCF, 0xD6, 0x0A, 0x0A, 0xD3, 0x7F, 0x35, 0x85, 0x84, 0x78, - 0xF2, 0x28, 0xEA, 0x14, 0x06, 0x2A, 0xC0, 0x53, 0x22, 0x45, - 0x9B, 0xDA, 0xE9, 0xEE, 0x98, 0x5D, 0xEC, 0xEC, 0xEF, 0xA1, - 0x1A, 0xDD, 0x7C, 0xE2, 0x29, 0xFF, 0x2B, 0x8A, 0x00, 0x49, - 0xD6, 0x2E, 0x7C, 0x50, 0x26, 0x29, 0x65, 0x97, 0xB4, 0xA8, - 0x6B, 0x38, 0x95, 0xC0, 0x7F, 0x41, 0xAD, 0xD5, 0xA2, 0x54, - 0x37, 0xE1, 0x72, 0x3A, 0x28, 0x58, 0xCA, 0x88, 0xB4, 0xF8, - 0x34, 0x43, 0xFF, 0xE4, 0xE4, 0xC2, 0x37, 0x0B, 0x72, 0x77, - 0x2B, 0x94, 0x8C, 0xB8, 0xCD, 0x72, 0x1E, 0xDB, 0x0A, 0xFA, - 0x86, 0x0E, 0xBC, 0x76, 0xDE, 0x89, 0x20, 0xBB, 0x1A, 0xC3, - 0x07, 0xAA, 0x0F, 0x0D, 0xED, 0x58, 0x42, 0x74, 0x44, 0xD0, - 0x89, 0x61, 0x25, 0xAF, 0xC0, 0x18, 0xFE, 0x16, 0xC9, 0x37, - 0x03, 0x11, 0x11, 0xEC, 0x9F, 0xFF, 0x2B, 0x00, 0x4F, 0x37, - 0xB6, 0xEC, 0x54, 0x0A, 0xA1, 0x68, 0xE5, 0x69, 0x38, 0xD5, - 0x55, 0x9E, 0x94, 0xAF, 0x3D, 0x67, 0xFF, 0x4D, 0x5D, 0x66, - 0x1D, 0xD0, 0x45, 0x1B, 0xF9, 0x23, 0x5F, 0xCF, 0x18, 0xFB, - 0x3F, 0x13, 0x0A, 0x2E, 0x86, 0xC4, 0x44, 0x28, 0xAB, 0x72, - 0x78, 0x77, 0x14, 0xCA, 0x70, 0xBF, 0x3E, 0x79, 0x47, 0xAB, - 0x3D, 0x22, 0xB9, 0x57, 0xB8, 0x04, 0x4B, 0x62, 0x2A, 0x26, - 0x4C, 0xEE, 0x80, 0xF4, 0x1C, 0x5C, 0xE3, 0xFF, 0x23, 0xC8, - 0x7C, 0x27, 0x90, 0xC8, 0x61, 0xC3, 0x7C, 0xC8, 0x5B, 0x46, - 0xB8, 0xCC, 0x8A, 0x67, 0xFC, 0xB9, 0xF1, 0xE7, 0x21, 0x68, - 0x47, 0x37, 0x9D, 0xEB, 0x14, 0xC4, 0x55, 0x02, 0x43, 0xA6, - 0xAA, 0x50, 0xE2, 0x78, 0x66, 0xE9, 0x55, 0x2D, 0x4C, 0x84, - 0xDF, 0x81, 0xCF, 0x0C, 0xD4, 0x36, 0xCA, 0x3D, 0xF7, 0xEE, - 0x2A, 0x5D, 0x10, 0xC9, 0xEA, 0x19, 0xF2, 0xF3, 0xBD, 0x42, - 0xA9, 0xE1, 0xA6, 0xD1, 0x84, 0xE9, 0x1A, 0x26, 0xDC, 0xBE, - 0x72, 0x43, 0xC7, 0x79, 0x92, 0xD9, 0x5F, 0x7C, 0x42, 0xCD, - 0xFF, 0x76, 0xBE, 0xB9, 0x99, 0x60, 0x6B, 0x5E, 0xAD, 0xAC, - 0x62, 0xAD, 0xFD, 0x58, 0x1C, 0x4E, 0xC6, 0x6D, 0xE7, 0xF9, - 0x2E, 0xD1, 0xEC, 0x9F, 0x98, 0xAE, 0x4F, 0xB6, 0xE1, 0xB3, - 0x77, 0xDD, 0xA4, 0x5D, 0x24, 0x76, 0xF0, 0xED, 0xBE, 0x19, - 0xB1, 0x98, 0x85, 0x08, 0xAB, 0xF0, 0x39, 0x94, 0x1D, 0x12, - 0xCA, 0x8B, 0xD2, 0xCC, 0x97, 0x44, 0xCB, 0x89, 0x9B, 0x66, - 0x50, 0x51, 0x64, 0x9E, 0xB1, 0x9E, 0x2C, 0xAA, 0xE5, 0x91, - 0x59, 0x53, 0xB1, 0x5E, 0xB3, 0xBB, 0x99, 0x00, 0x53, 0xA9, - 0xC1, 0x6C, 0x59, 0x46, 0xFD, 0xCB, 0x53, 0x83, 0xDD, 0x37, - 0xA1, 0xA3, 0x65, 0x26, 0xC6, 0x48, 0x6D, 0x15, 0xE8, 0xC1, - 0xE3, 0x45, 0x10, 0x6E, 0x8A, 0xE1, 0xDB, 0x10, 0xDB, 0x58, - 0x16, 0x5C, 0x31, 0x2E, 0x06, 0xA8, 0xAE, 0xD7, 0xB2, 0x11, - 0x55, 0x07, 0x2E, 0x57, 0x57, 0x02, 0x48, 0xC0, 0x8B, 0x59, - 0x8C, 0xBE, 0x1A, 0x47, 0x52, 0x3E, 0xD0, 0x05, 0xEA, 0xBC, - 0x86, 0xEA, 0x31, 0xD9, 0x58, 0x52, 0xCF, 0x7D, 0xD2, 0x30, - 0x4E, 0x0D, 0x24, 0x6F, 0x39, 0xF6, 0xEB, 0xC8, 0x5D, 0xE4, - 0xFF, 0x8D, 0xB9, 0x71, 0x02, 0x71, 0x67, 0x89, 0xFA, 0xB8, - 0x4F, 0xC9, 0x77, 0x78, 0x60, 0x36, 0xDF, 0x0E, 0x96, 0xAC, - 0x4F, 0x44, 0x8A, 0x2C, 0xE5, 0x8C, 0xC3, 0x96, 0x79, 0xE2, - 0x43, 0x75, 0xF5, 0x59, 0xC0, 0x81, 0x0A, 0x54, 0xC2, 0xA3, - 0x28, 0x8A, 0x32, 0xCE, 0x91, 0x5A, 0x91, 0x06, 0x45, 0xEB, - 0x34, 0x1A, 0x87, 0xF9, 0x57, 0x91, 0x0D, 0x34, 0x7F, 0x82, - 0x91, 0x82, 0xC5, 0x26, 0xCB, 0xB3, 0x4F, 0xF2, 0x20, 0x6A, - 0x02, 0x95, 0x73, 0x7B, 0x4F, 0x4E, 0xAF, 0x8A, 0x40, 0x83, - 0xFE, 0xF9, 0xD2, 0xFD, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x0E, - 0xA2, 0xA8, 0x59, 0xF0, 0x82, 0x17, 0x4C, 0x0E, 0xF3, 0x83, - 0xA1, 0xB6, 0x36, 0x83, 0xCB, 0xFB, 0xA2, 0x66, 0x53, 0x65, - 0x40, 0x40, 0xAA, 0x3D, 0x82, 0x62, 0x54, 0x0A, 0x27, 0x6A, - 0xD6, 0x07, 0xAF, 0x91, 0xCF, 0x9B, 0x89, 0x58, 0xBC, 0xCE, - 0x74, 0x87, 0x9C, 0x7E, 0x30, 0xF3, 0x06, 0x2B, 0xF1, 0xB4, - 0x70, 0x9D, 0xAA, 0x41, 0xD7, 0x25, 0x75, 0xE5, 0x72, 0x25, - 0x00, 0xC7, 0x21, 0x9D, 0xEE, 0xD1, 0x24, 0x16, 0x0B, 0x12, - 0x22, 0x88, 0xB8, 0x9D, 0xA5, 0x38, 0xA0, 0x50, 0x39, 0x27, - 0xAE, 0x10, 0xF6, 0x9A, 0x0B, 0x77, 0x56, 0x3F, 0x96, 0xDF, - 0x22, 0xE5, 0xEA, 0xAC, 0x8F, 0xDF, 0xDD, 0x78, 0xEF, 0x5A, - 0x7B, 0x50, 0x72, 0x98, 0x92, 0xDD, 0x94, 0xB5, 0xDB, 0x99, - 0xCE, 0xF2, 0x7A, 0xF3, 0xFA, 0x80, 0xD3, 0xCD, 0x1F, 0xCA, - 0xA2, 0x2E, 0x21, 0x94, 0xF2, 0xB3, 0x71, 0x7C, 0x07, 0xE6, - 0xB9, 0x68, 0x1E, 0x13, 0x02, 0x15, 0xC8, 0x34, 0xA0, 0xB5, - 0xD9, 0x95, 0x1A, 0x9B, 0x57, 0xE7, 0xAF, 0xB0, 0xE1, 0xA7, - 0x95, 0xF2, 0x36, 0xA3, 0xF9, 0xC5, 0x2C, 0xF0, 0xC3, 0xE1, - 0xD1, 0x26, 0xA1, 0x8F, 0xE6, 0x07, 0xFB, 0x1F, 0x03, 0xFF, - 0xA5, 0x81, 0xF5, 0x5D, 0x21, 0x3B, 0x93, 0x66, 0x1A, 0x78, - 0x6F, 0xD4, 0x77, 0xB3, 0x91, 0x26, 0x6F, 0x1F, 0x5A, 0x8B, - 0x0F, 0x07, 0xEA, 0x24, 0x5F, 0x5E, 0x68, 0x9F, 0x89, 0x75, - 0x00, 0x23, 0x1C, 0x80, 0x55, 0x86, 0x93, 0x58, 0x94, 0x41, - 0x37, 0x0D, 0x23, 0xD3, 0x09, 0x72, 0x40, 0x79, 0xA2, 0x52, - 0x0D, 0xA3, 0x40, 0x3F, 0x54, 0x7E, 0x59, 0x55, 0x5B, 0x7D, - 0x0C, 0x52, 0xAA, 0x97, 0x0C, 0xC6, 0xCB, 0x0B, 0x6C, 0x83, - 0x45, 0x28, 0x62, 0x09, 0x0A, 0x74, 0x27, 0x1D, 0x4D, 0x02, - 0x07, 0xB3, 0xA5, 0x83, 0x9A, 0x43, 0xB3, 0x68, 0xF7, 0x97, - 0x3E, 0xD7, 0x34, 0x04, 0x83, 0xC7, 0x6F, 0x64, 0xB8, 0x0B, - 0xB9, 0xE9, 0x94, 0x46, 0xB9, 0x4D, 0xA7, 0xB4, 0x26, 0xF7, - 0x9C, 0x05, 0x94, 0x8B, 0xBE, 0x93, 0x03, 0xA7, 0x73, 0x65, - 0xAB, 0xC5, 0xE1, 0x2B, 0x3B, 0x4C, 0x56, 0x1F, 0x11, 0x7B, - 0xD3, 0xC0, 0x77, 0x48, 0x42, 0x27, 0x8D, 0x2A, 0xAA, 0x1E, - 0x18, 0x41, 0x76, 0xA1, 0x80, 0x99, 0x52, 0x50, 0x66, 0x7B, - 0x27, 0x4B, 0x49, 0xA1, 0xE8, 0xCA, 0xF1, 0x3E, 0x60, 0x2E, - 0x93, 0xEF, 0x4A, 0x20, 0x3C, 0xC4, 0xBB, 0x14, 0xD3, 0x8F, - 0x14, 0xAF, 0xC0, 0xF8, 0x4B, 0xC6, 0x49, 0x1A, 0x3B, 0x17, - 0x43, 0xC2, 0xAB, 0xF0, 0x01, 0xFC, 0x6E, 0x67, 0x86, 0xAC, - 0xE4, 0x6F, 0xF2, 0x26, 0xF2, 0xEC, 0x15, 0xA1, 0x96, 0x81, - 0xDD, 0xCF, 0xCA, 0xB4, 0xE1, 0x5A, 0xA0, 0xF5, 0xBB, 0x70, - 0xEB, 0xF9, 0xA6, 0x28, 0x66, 0xC3, 0xBE, 0xB9, 0xBD, 0xDD, - 0xEF, 0x8E, 0x9E, 0x3C, 0x91, 0x50, 0x38, 0x61, 0x40, 0x25, - 0x4D, 0xCD, 0xA0, 0xAF, 0xFE, 0x57, 0xB8, 0x96, 0xDD, 0x2B, - 0x52, 0x29, 0x91, 0x7A, 0x31, 0xE8, 0x9A, 0xBB, 0xC9, 0x70, - 0x2B, 0xE1, 0x40, 0x3A, 0x9F, 0xB7, 0x31, 0xBE, 0xE5, 0x46, - 0xDA, 0x8A, 0xDE, 0x13, 0x22, 0x87, 0x70, 0xFE, 0x96, 0x40, - 0x9F, 0xC1, 0x2B, 0xFE, 0x83, 0x31, 0xE9, 0xA5, 0x4C, 0x37, - 0xEB, 0xFD, 0xFB, 0x2C, 0xBD, 0x0C, 0x1F, 0xB2, 0x62, 0x32, - 0x0E, 0x76, 0x9A, 0x2C, 0xC2, 0x84, 0x34, 0xA0, 0x6D, 0x72, - 0x21, 0x47, 0xF9, 0x3E, 0xC6, 0x5C, 0xEE, 0xB6, 0xE1, 0xD9, - 0x2E, 0xDF, 0x50, 0xD6, 0x2C, 0x9B, 0x44, 0xBE, 0xF0, 0x01, - 0x8E, 0xB4, 0x34, 0x38, 0x9C, 0x6C, 0x3E, 0x26, 0xB2, 0x4C, - 0x8E, 0xF0, 0x41, 0x2F, 0x07, 0x0E, 0xE9, 0x69, 0x1C, 0x0A, - 0x00, 0x05, 0xB0, 0x09, 0xA7, 0x07, 0x18, 0x41, 0xD1, 0xF7, - 0x22, 0xE4, 0x85, 0x64, 0xB7, 0x83, 0xF7, 0xB1, 0xE2, 0xAC, - 0x2E, 0xD9, 0x83, 0x81, 0x18, 0xCB, 0xBD, 0xEE, 0xD9, 0x09, - 0x99, 0xBA, 0x95, 0x66, 0x1F, 0xBA, 0x02, 0x26, 0xC0, 0x00, - 0x02, 0x67, 0x72, 0x24, 0xB5, 0xFE, 0x8C, 0x50, 0x84, 0x47, - 0x41, 0x6A, 0x29, 0x1F, 0x17, 0xB2, 0x9E, 0x02, 0x67, 0x70, - 0x55, 0x03, 0x3F, 0x8F, 0x07, 0x20, 0x91, 0x6B, 0x22, 0x7F, - 0x06, 0xC3, 0xC9, 0x0A, 0xB5, 0x07, 0x0D, 0x91, 0x5F, 0x87, - 0x6D, 0xE2, 0xEE, 0x2B, 0x01, 0xE7, 0x45, 0x3F, 0x89, 0x1C, - 0x8B, 0x12, 0x33, 0x23, 0x61, 0x64, 0x3F, 0x4B, 0xF1, 0x27, - 0x0E, 0x8B, 0x7B, 0x7E, 0x64, 0x2E, 0xDE, 0xE0, 0x3F, 0x3E, - 0x5C, 0xAE, 0x8C, 0x73, 0xB2, 0x8B, 0x62, 0x0F, 0xF9, 0xEB, - 0xF0, 0x74, 0xBD, 0xB9, 0xCC, 0x43, 0x80, 0xC3, 0x05, 0x31, - 0x53, 0x6F, 0x72, 0x42, 0x8E, 0x14, 0xAD, 0xF0, 0x45, 0x36, - 0x88, 0xE4, 0xF9, 0x0F, 0xD9, 0xCA, 0x1E, 0x82, 0xC2, 0x89, - 0x44, 0xC3, 0x69, 0xC6, 0xDD, 0x27, 0xB5, 0xCA, 0xCF, 0x56, - 0x23, 0x5D, 0x50, 0xF9, 0x69, 0x87, 0xCF, 0x4D, 0x2F, 0xA8, - 0xEE, 0xD4, 0x55, 0x2A, 0xC7, 0x3A, 0x2D, 0x03, 0xCD, 0x38, - 0xDE, 0x4F, 0x29, 0x91, 0x14, 0xAD, 0x39, 0x05, 0x77, 0x5F, - 0x41, 0x48, 0x30, 0x63, 0xE6, 0x81, 0x40, 0x68, 0x75, 0x8D, - 0xC5, 0x70, 0x2D, 0xC9, 0xB9, 0x10, 0x75, 0xF3, 0x28, 0x91, - 0x99, 0x97, 0x16, 0x2E, 0x7C, 0xAD, 0x50, 0x80, 0x40, 0x00, - 0xEE, 0x8F, 0x59, 0xA1, 0x8F, 0x82, 0xDE, 0x1E, 0xDB, 0x56, - 0xA1, 0xD6, 0x2E, 0x06, 0x9D, 0x42, 0xCF, 0xA0, 0xB7, 0x1F, - 0x37, 0x22, 0x02, 0x2E, 0x33, 0xAE, 0xE4, 0x7B, 0x7C, 0xC6, - 0x11, 0x5E, 0xF6, 0xA5, 0x5B, 0x54, 0x8B, 0x28, 0x54, 0x01, - 0x4C, 0x41, 0x49, 0x8E, 0xAD, 0x22, 0xBB, 0x67, 0x7A, 0xF3, - 0xEC, 0xE3, 0x93, 0xE4, 0x3A, 0x71, 0xB2, 0x82, 0xC4, 0x8A, - 0x7B, 0x99, 0xA7, 0x6B, 0x69, 0x28, 0xE3, 0xC5, 0x89, 0xF7, - 0x3E, 0xF3, 0xC5, 0xB2, 0x40, 0x91, 0xF8, 0x6A, 0xE3, 0x63, - 0xB1, 0x5C, 0xE3, 0x79, 0xFF, 0x41, 0xE8, 0x2F, 0xCA, 0x11, - 0xA2, 0xED, 0x86, 0x59, 0x53, 0x9D, 0xF9, 0xE1, 0x15, 0x5D, - 0x38, 0x32, 0x69, 0x60, 0x45, 0x20, 0x74, 0xF5, 0xF6, 0x24, - 0xA2, 0x4E, 0xAE, 0xB5, 0x2F, 0xE2, 0xEE, 0xBD, 0xD3, 0x27, - 0xE1, 0x90, 0x89, 0x89, 0xA3, 0x7E, 0x2B, 0x73, 0x63, 0xB8, - 0x36, 0xFA, 0x17, 0x0C, 0x8F, 0x0F, 0xE8, 0xBE, 0xDC, 0x8D, - 0x52, 0x34, 0xB3, 0x52, 0x0E, 0xB1, 0x97, 0x8D, 0x69, 0xC8, - 0x27, 0x2E, 0xBC, 0xFC, 0xDB, 0x6C, 0x98, 0xE8, 0x50, 0xF1, - 0x7A, 0x14, 0xE7, 0xA4, 0x11, 0xD2, 0xDA, 0x71, 0xCB, 0x77, - 0x88, 0x7B, 0xEE, 0x24, 0x52, 0xF4, 0x83, 0x2F, 0x1B, 0x25, - 0x73, 0x7D, 0x57, 0xAE, 0x78, 0x42, 0xC7, 0x7F, 0x84, 0xDB, - 0x67, 0x7A, 0x81, 0xAB, 0xB5, 0xC4, 0x41, 0x38, 0xA0, 0x8D, - 0x8C, 0x50, 0x1F, 0x56, 0xF6, 0x9A, 0x2B, 0x57, 0x89, 0x20, - 0xA9, 0xE9, 0x1E, 0x55, 0x22, 0xD7, 0x88, 0xFA, 0x5D, 0x5F, - 0x51, 0x5C, 0x7C, 0x17, 0x6E, 0x1D, 0x1A, 0xE3, 0xE6, 0x24, - 0x67, 0xFE, 0xAA, 0xEF, 0x28, 0x25, 0xCA, 0xD7, 0x9B, 0x44, - 0x3A, 0x55, 0x6B, 0x2E, 0xDE, 0x7D, 0xD0, 0x1E, 0x16, 0xD6, - 0xA5, 0xA6, 0x97, 0xE0, 0x35, 0x90, 0x13, 0xD4, 0x16, 0x53, - 0xA2, 0x66, 0xCB, 0x12, 0xEE, 0xED, 0xA1, 0x42, 0x2C, 0x6A, - 0xF5, 0x13, 0x63, 0x5B, 0x2A, 0x0C, 0x8C, 0x3A, 0xC4, 0xAA, - 0x77, 0xFD, 0x03, 0x29, 0x47, 0x2E, 0x4E, 0xCE, 0x26, 0x2E, - 0xE2, 0x87, 0xD5, 0x49, 0xBE, 0xCE, 0x07, 0x71, 0x8F, 0xBB, - 0xDF, 0x5E, 0x73, 0x17, 0x28, 0x1B, 0x34, 0x55, 0xA2, 0xB1, - 0x99, 0x72, 0x90, 0xFD, 0xDF, 0xB3, 0xC7, 0x63, 0xFE, 0x1B, - 0x75, 0x6B, 0x6D, 0x73, 0xDE, 0x21, 0xD0, 0x18, 0xBE, 0x87, - 0xE8, 0xDA, 0x74, 0x1E, 0x78, 0x65, 0x6D, 0x30, 0x3B, 0xF1, - 0xEF, 0xE3, 0x32, 0xD6, 0xF8, 0x77, 0x31, 0xAB, 0x72, 0x72, - 0xF1, 0x43, 0x5C, 0x9F, 0xF1, 0x99, 0xA9, 0xB7, 0xD6, 0xEA, - 0x12, 0x4C, 0x96, 0x7E, 0x87, 0x76, 0xD2, 0xAB, 0x02, 0x26, - 0xC0, 0x00, 0x02, 0x91, 0x0F, 0xB9, 0x72, 0xF7, 0x06, 0x0A, - 0x2A, 0x92, 0x77, 0x84, 0x0C, 0xBE, 0x44, 0x6D, 0x58, 0x6C, - 0xBC, 0xE0, 0x19, 0x8A, 0xFC, 0x4C, 0x93, 0xDD, 0xB7, 0xC5, - 0x45, 0xBF, 0x0A, 0x66, 0x29, 0xEF, 0x95, 0x78, 0x07, 0x6D, - 0xD0, 0xAA, 0x6C, 0x32, 0xE9, 0xF8, 0xEA, 0x1A, 0x74, 0x79, - 0x51, 0x39, 0x25, 0xCB, 0x00, 0x7C, 0xD0, 0xE7, 0xBB, 0xC4, - 0x09, 0xC2, 0xFC, 0x0F, 0xA2, 0x29, 0x45, 0x30, 0x3F, 0x89, - 0x76, 0x36, 0xF2, 0x92, 0xAF, 0xAF, 0x60, 0xC3, 0x93, 0x3E, - 0x55, 0x6B, 0x87, 0xAE, 0xBF, 0x6E, 0x2C, 0x54, 0xFD, 0xAF, - 0x74, 0x4F, 0x0F, 0xAA, 0xC7, 0x4F, 0x4C, 0x6B, 0x18, 0xFE, - 0xC6, 0x84, 0x27, 0xC0, 0x78, 0xD2, 0xD9, 0xE3, 0x7B, 0x41, - 0x1C, 0x1C, 0xBF, 0xDA, 0xDF, 0xCC, 0x49, 0x41, 0xC0, 0xC0, - 0x65, 0xE0, 0x8F, 0x44, 0x19, 0xE4, 0x78, 0xAD, 0xCD, 0xC5, - 0x5A, 0x9D, 0x11, 0x22, 0x43, 0xD7, 0x6E, 0x39, 0xD5, 0x2B, - 0xA7, 0x73, 0x3F, 0x99, 0xA8, 0xA3, 0x02, 0x73, 0x99, 0xF0, - 0x62, 0x87, 0xF4, 0x8B, 0xD7, 0x4F, 0x47, 0x9C, 0x18, 0x72, - 0x98, 0xB0, 0x33, 0x1B, 0x5E, 0x29, 0x04, 0xEA, 0x71, 0x6B, - 0x45, 0xCB, 0xC0, 0x9E, 0x15, 0x6E, 0x92, 0xDA, 0x50, 0xC3, - 0x58, 0x07, 0x29, 0x5E, 0xC5, 0xBD, 0x3B, 0xCE, 0xAC, 0x11, - 0xE5, 0xBB, 0x3D, 0x7E, 0xB8, 0xC3, 0x1F, 0x94, 0x9F, 0xD9, - 0x63, 0x35, 0x56, 0x23, 0x45, 0xAF, 0x23, 0xF0, 0x0B, 0x7B, - 0xE3, 0xFB, 0x81, 0x2E, 0xD3, 0x20, 0xE3, 0x1D, 0x97, 0x84, - 0xC1, 0x88, 0x77, 0x87, 0x3C, 0xAB, 0xE9, 0x1E, 0x69, 0x04, - 0x7D, 0x7B, 0xE6, 0x6B, 0xDB, 0xE9, 0xF2, 0xB6, 0x66, 0x10, - 0x0F, 0x4D, 0x57, 0x3F, 0xF5, 0x3E, 0xDA, 0xEA, 0xBC, 0xD4, - 0x5B, 0xA1, 0x20, 0xB0, 0x69, 0xC0, 0x8A, 0xA1, 0x28, 0xC0, - 0xEF, 0xFE, 0x2D, 0x0B, 0xF8, 0x06, 0x23, 0x4B, 0x1C, 0x77, - 0x0A, 0x10, 0xBF, 0xA7, 0xD9, 0x24, 0x9E, 0xA2, 0x1B, 0x90, - 0x6C, 0xFD, 0x85, 0x3A, 0xD3, 0xC6, 0x39, 0xA7, 0xA2, 0x28, - 0xC5, 0xC1, 0x2F, 0xD2, 0x28, 0xDC, 0x4F, 0x63, 0x0D, 0x6B, - 0x54, 0xB4, 0x27, 0x95, 0xC3, 0xC1, 0xE0, 0x08, 0xB0, 0x9D, - 0x7F, 0x6C, 0xFE, 0xF5, 0x65, 0xCE, 0x0E, 0xCE, 0x24, 0xCD, - 0xAE, 0x4C, 0x0F, 0x82, 0x54, 0x48, 0xAF, 0x37, 0xAE, 0x64, - 0x31, 0x07, 0xEE, 0xE6, 0x6B, 0xEF, 0xAF, 0x7F, 0x2A, 0x07, - 0x2E, 0xB6, 0xD0, 0xAC, 0x70, 0x87, 0x19, 0x9E, 0xD3, 0xFB, - 0x89, 0xBD, 0xBA, 0xFF, 0xB9, 0x92, 0x4B, 0x25, 0x65, 0xA3, - 0x09, 0xCD, 0xFE, 0x32, 0x19, 0xF3, 0xF4, 0x05, 0xA4, 0x13, - 0xDF, 0x65, 0xA3, 0x4C, 0xE8, 0xF3, 0x3C, 0xA3, 0x11, 0x95, - 0xEA, 0xC3, 0x34, 0xCA, 0xC6, 0xB9, 0x34, 0x6B, 0x53, 0x18, - 0xCC, 0xF9, 0x44, 0x28, 0x1E, 0x90, 0x74, 0xA6, 0xB1, 0x59, - 0x4D, 0xAE, 0x18, 0x53, 0x1D, 0x60, 0xCF, 0xCC, 0x15, 0xDA, - 0x4E, 0x2B, 0x6F, 0x8F, 0x4E, 0x39, 0x89, 0xE3, 0x67, 0x05, - 0xB5, 0x9C, 0x36, 0x5B, 0x3C, 0xA0, 0x9F, 0x46, 0x24, 0xE7, - 0x61, 0x42, 0x1C, 0xA7, 0xD7, 0x27, 0x5B, 0x5C, 0xF5, 0xFD, - 0x5F, 0x03, 0x79, 0x5F, 0x36, 0xA0, 0x85, 0x13, 0x40, 0x48, - 0x8C, 0x44, 0xB4, 0x64, 0x54, 0x83, 0xD8, 0xB6, 0x83, 0xB8, - 0x4E, 0x46, 0xCF, 0x98, 0xA5, 0x1C, 0xAA, 0xF0, 0x03, 0xD6, - 0x26, 0x80, 0x0F, 0x2A, 0xC5, 0xF4, 0xD1, 0x28, 0x0C, 0x5F, - 0xF8, 0x63, 0x8D, 0x68, 0x26, 0x3A, 0xE5, 0x5D, 0xAE, 0x17, - 0x64, 0xF2, 0x60, 0x73, 0x6D, 0xBD, 0x75, 0x90, 0xD2, 0x50, - 0xC4, 0x9A, 0x4C, 0x3E, 0x4B, 0xAE, 0x57, 0xBE, 0xCD, 0x42, - 0xC1, 0xA7, 0xCB, 0xAD, 0x73, 0x15, 0xF6, 0x69, 0x36, 0xB5, - 0xC3, 0x15, 0x1D, 0xC0, 0x09, 0x4B, 0x6B, 0x4F, 0xA3, 0xD2, - 0xAF, 0x9E, 0xF4, 0x9A, 0xC1, 0x5F, 0xF5, 0x0A, 0x95, 0x93, - 0xA4, 0x57, 0xA9, 0x61, 0x8D, 0x98, 0xB1, 0x19, 0xCC, 0x95, - 0x02, 0x26, 0xC0, 0x00, 0x02, 0x6E, 0x4C, 0x0F, 0xB4, 0x2D, - 0xBC, 0x3A, 0x51, 0xAE, 0x16, 0xBA, 0xEC, 0x72, 0x04, 0x3E, - 0x8D, 0x3D, 0x4E, 0x0E, 0x29, 0x4B, 0x6F, 0x00, 0xF5, 0xE2, - 0x12, 0x0B, 0xAC, 0x73, 0x7E, 0xA5, 0x12, 0x8D, 0x59, 0x45, - 0x73, 0xC8, 0xB9, 0x57, 0xCB, 0x78, 0xAD, 0xA3, 0xBD, 0x95, - 0x18, 0x04, 0x86, 0xB9, 0xFE, 0x9F, 0xBF, 0x67, 0x03, 0x08, - 0xA9, 0x91, 0xF3, 0x71, 0x1A, 0x6C, 0xD2, 0x74, 0xAA, 0x40, - 0xCC, 0x30, 0x7D, 0x0B, 0x78, 0xEF, 0xC7, 0xDC, 0x95, 0xC3, - 0x29, 0x5D, 0x18, 0xBC, 0x38, 0x7C, 0xFE, 0x65, 0xEF, 0x44, - 0xF0, 0x61, 0x91, 0x3E, 0x59, 0x75, 0x96, 0x84, 0x75, 0xD9, - 0xA2, 0x99, 0xDB, 0xFA, 0x9B, 0x7D, 0x09, 0x06, 0x8D, 0xDA, - 0xCC, 0xA1, 0x6E, 0x2E, 0xDB, 0x12, 0x83, 0xA6, 0x2E, 0x9C, - 0xC8, 0x5A, 0xE9, 0xBB, 0xC3, 0x70, 0x16, 0x0C, 0x6E, 0x2A, - 0xDA, 0xD0, 0xDF, 0xF4, 0xAF, 0xAA, 0x42, 0x0A, 0x16, 0x8C, - 0x73, 0xAA, 0xAD, 0x75, 0x7B, 0xCC, 0x29, 0xB5, 0x18, 0xB9, - 0x58, 0xBF, 0xDB, 0x91, 0x44, 0x74, 0x25, 0x3E, 0x54, 0xC3, - 0x2D, 0x8A, 0x2E, 0x85, 0xD0, 0x92, 0x02, 0xAE, 0xA1, 0xF9, - 0x70, 0xC5, 0x33, 0x49, 0x57, 0xE1, 0x90, 0x48, 0x54, 0x73, - 0x04, 0xAD, 0x1E, 0x41, 0xE8, 0xD7, 0x24, 0xFE, 0x85, 0x83, - 0x47, 0x0F, 0x9C, 0x33, 0xF9, 0xF5, 0x10, 0xAD, 0x42, 0xFA, - 0x7B, 0xE7, 0x1C, 0x35, 0xB3, 0x8D, 0x0E, 0x2E, 0xD7, 0xCB, - 0x40, 0x32, 0x9C, 0x64, 0x3A, 0x68, 0x33, 0xF3, 0xBE, 0xD9, - 0xCD, 0xC9, 0x73, 0xEB, 0x67, 0x6E, 0x52, 0x25, 0x2F, 0xD9, - 0x7A, 0x93, 0x8B, 0x1D, 0x9D, 0xB2, 0xAF, 0xF3, 0xEE, 0x6F, - 0xB5, 0xC7, 0x8F, 0xD5, 0x4F, 0xC9, 0x7C, 0xAC, 0x05, 0x9A, - 0x16, 0x82, 0x04, 0xC4, 0xF5, 0x47, 0xD7, 0x61, 0xC7, 0xBC, - 0x8D, 0x76, 0xA9, 0xFA, 0xA6, 0x17, 0x32, 0x3A, 0x2C, 0x93, - 0x4D, 0x0B, 0x57, 0x50, 0xF5, 0xD8, 0xE6, 0xB2, 0x52, 0x4F, - 0xE5, 0x1F, 0xDB, 0xA0, 0x17, 0xEF, 0x44, 0x9A, 0x8D, 0xBF, - 0x8D, 0xB4, 0x66, 0x11, 0xF2, 0xB1, 0x51, 0x50, 0xB4, 0xDE, - 0xE0, 0x30, 0x5B, 0x1F, 0x92, 0xAC, 0x30, 0x43, 0xB3, 0x1F, - 0x32, 0xDC, 0x84, 0x2F, 0x29, 0xE9, 0x78, 0xBC, 0x5A, 0xA2, - 0x9A, 0xA8, 0xFC, 0xE2, 0xB4, 0xE7, 0x8C, 0xCC, 0x65, 0xA9, - 0x37, 0x85, 0xD8, 0x0B, 0xB3, 0xA3, 0x4F, 0x28, 0xBE, 0x4D, - 0x45, 0x97, 0xAA, 0x2E, 0xEC, 0x6D, 0x4C, 0x9E, 0x19, 0x5F, - 0xD1, 0x47, 0x87, 0x8A, 0x76, 0xCF, 0x20, 0xCC, 0xDC, 0xC5, - 0x37, 0xDD, 0x45, 0xE8, 0x13, 0xFD, 0x72, 0x92, 0x7E, 0x97, - 0xA4, 0xA7, 0x58, 0xC1, 0x0E, 0xB6, 0x9E, 0x20, 0xCC, 0xD3, - 0x5F, 0x94, 0x25, 0xD3, 0xB8, 0xB0, 0x51, 0x82, 0x45, 0x64, - 0x4B, 0x6D, 0xCB, 0x9F, 0xC6, 0x5F, 0xDD, 0x1D, 0x1B, 0xB0, - 0x7D, 0xEB, 0xEC, 0x85, 0xB0, 0x90, 0x36, 0xE0, 0xE5, 0x5F, - 0x66, 0xA3, 0x69, 0x72, 0x2C, 0x35, 0x52, 0x45, 0x8A, 0xD9, - 0x31, 0xCB, 0xD9, 0xDD, 0xF0, 0x62, 0x6A, 0x4B, 0x47, 0xEF, - 0x13, 0xD7, 0x65, 0x17, 0xC4, 0xE9, 0xD1, 0xA3, 0xF4, 0x5E, - 0x17, 0x73, 0x4C, 0xA5, 0x81, 0xD7, 0xBD, 0xB3, 0x34, 0x98, - 0x61, 0x01, 0x50, 0x1D, 0x7D, 0x7A, 0x82, 0x38, 0x93, 0x9F, - 0x0A, 0xAC, 0x42, 0x5B, 0x10, 0x4C, 0x57, 0x10, 0x4A, 0x97, - 0xD3, 0xCC, 0x8F, 0x23, 0xD1, 0xA6, 0xCB, 0xAD, 0x47, 0x8F, - 0x41, 0x24, 0x2B, 0xEB, 0xB9, 0x0B, 0x71, 0x1C, 0x27, 0x31, - 0x91, 0x21, 0x77, 0xA2, 0x01, 0x2D, 0x6F, 0x9B, 0x99, 0x5F, - 0xAC, 0xD4, 0x8E, 0x1D, 0xBB, 0x2C, 0xA3, 0xA1, 0xA2, 0xC3, - 0x2A, 0xAD, 0x6B, 0xA4, 0x62, 0xAA, 0xAE, 0xEA, 0xEE, 0x10, - 0x30, 0xB3, 0x9E, 0x2A, 0x13, 0x09, 0xF8, 0xC4, 0x2B, 0x8C, - 0xE1, 0x51, 0x62, 0xE7, 0x5D, 0xE8, 0x00, 0x50, 0x46, 0x7E, - 0xC7, 0x9A, 0x3F, 0x21, 0xD9, 0x0C, 0xB3, 0xA7, 0x2E, 0x5F, - 0x4B, 0x42, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x12, 0xA7, 0x07, - 0x49, 0x33, 0x98, 0x05, 0x3D, 0xD0, 0x14, 0xD2, 0x03, 0xA9, - 0xA5, 0x66, 0x6B, 0x53, 0x43, 0x97, 0x83, 0x21, 0x8F, 0x46, - 0x67, 0x3C, 0x86, 0xDB, 0x7B, 0xBA, 0xD2, 0xC5, 0xB4, 0x09, - 0x0F, 0x2D, 0xD3, 0x4E, 0xD2, 0xB7, 0xFC, 0x75, 0x52, 0x16, - 0x8A, 0x56, 0x5A, 0xCC, 0xE6, 0xFE, 0x5C, 0xE8, 0xAE, 0x48, - 0x7F, 0x81, 0xF2, 0x46, 0x00, 0xE5, 0x53, 0xAF, 0xC7, 0x01, - 0x12, 0x9A, 0xF9, 0xDC, 0x96, 0x79, 0xC6, 0x61, 0xC6, 0xAC, - 0xCE, 0x0B, 0x6C, 0x9F, 0xFD, 0x16, 0xCA, 0xD1, 0xD6, 0xAB, - 0xE4, 0xCB, 0x64, 0x88, 0xF7, 0x17, 0x7F, 0xCD, 0xBB, 0x8F, - 0xF9, 0x5C, 0x75, 0x7C, 0x3D, 0xBE, 0x03, 0x68, 0x30, 0xA8, - 0xC7, 0x82, 0x62, 0xDD, 0x5A, 0x42, 0x3D, 0x8D, 0x02, 0xD1, - 0x68, 0xF2, 0x04, 0x0B, 0xFA, 0xC2, 0x23, 0xB9, 0x26, 0xAA, - 0x5F, 0x43, 0x7D, 0xE5, 0xD2, 0x97, 0xB8, 0xD5, 0x6F, 0xBE, - 0x56, 0xC6, 0xCA, 0xE7, 0x56, 0xDA, 0x14, 0x4A, 0xA6, 0x35, - 0x3F, 0xBF, 0xBC, 0x9D, 0xCD, 0x51, 0x55, 0x98, 0xAB, 0xC0, - 0x42, 0xC8, 0x7D, 0x67, 0xB3, 0xDD, 0x2B, 0x6B, 0xA0, 0x06, - 0x9F, 0x13, 0x79, 0xBC, 0xE2, 0xC8, 0x9E, 0xC3, 0xFF, 0x94, - 0x9E, 0x3D, 0x60, 0xAE, 0xB3, 0x28, 0x44, 0xC5, 0xE1, 0xD8, - 0x40, 0x7F, 0xC0, 0x8F, 0x93, 0xFC, 0xDA, 0xEC, 0x70, 0x14, - 0xB1, 0x07, 0xA1, 0x21, 0x6D, 0xA2, 0xA3, 0xEF, 0x80, 0xF1, - 0xC4, 0xCC, 0xA1, 0x77, 0xD9, 0xA3, 0xD9, 0x31, 0xFB, 0xC5, - 0xE5, 0xDE, 0xC1, 0xF2, 0x6F, 0xFC, 0x73, 0x35, 0xC4, 0x1D, - 0x2C, 0x15, 0x57, 0x64, 0x57, 0x4A, 0x0D, 0x4F, 0xCB, 0xD3, - 0x3E, 0x12, 0x82, 0x5C, 0xFC, 0xED, 0x7B, 0xA1, 0x3F, 0x72, - 0x1E, 0x6B, 0x12, 0x6A, 0xB9, 0x55, 0xD2, 0xC3, 0x04, 0x52, - 0x01, 0xBB, 0x54, 0x20, 0x0A, 0xA5, 0xDA, 0xDD, 0x2D, 0x56, - 0xF4, 0xD0, 0x08, 0x62, 0x1E, 0x68, 0x30, 0x40, 0x57, 0x8A, - 0xC2, 0xDD, 0xBF, 0x0D, 0x7B, 0x28, 0xE0, 0x82, 0x1A, 0x3F, - 0xDC, 0xEA, 0x07, 0xC4, 0x32, 0x74, 0x14, 0x18, 0x9C, 0x00, - 0x9C, 0x91, 0xC0, 0x7A, 0x0A, 0x18, 0x89, 0xAD, 0xA8, 0x3D, - 0x42, 0x21, 0x0F, 0x08, 0x8D, 0xA4, 0xD5, 0xA7, 0x08, 0x09, - 0x3C, 0x21, 0x7E, 0x4E, 0x17, 0xB9, 0x1A, 0x80, 0x22, 0x45, - 0x33, 0x43, 0x24, 0xDD, 0xC4, 0x66, 0xD2, 0xB4, 0x4E, 0x40, - 0xD5, 0x5F, 0xEA, 0x86, 0x9F, 0x8B, 0x41, 0x9D, 0xD0, 0x96, - 0xC9, 0x64, 0x32, 0x39, 0xA1, 0x89, 0x56, 0x7E, 0x1D, 0x22, - 0x08, 0x08, 0xB5, 0x60, 0x1F, 0x52, 0x41, 0xA4, 0x8F, 0xC0, - 0x52, 0x6B, 0xA7, 0xBB, 0x52, 0x0E, 0x96, 0xEE, 0x62, 0x62, - 0x1A, 0xCF, 0x4C, 0x65, 0x59, 0x32, 0x2D, 0x3C, 0x1D, 0x40, - 0x57, 0xB0, 0xE9, 0xF2, 0xBA, 0x04, 0xD2, 0xBE, 0x22, 0xA9, - 0x93, 0x8E, 0xC2, 0x32, 0x06, 0x20, 0xDC, 0x9F, 0xE5, 0xC2, - 0x57, 0xFC, 0xC5, 0xDE, 0xE7, 0xD3, 0xCA, 0xB6, 0xD8, 0x85, - 0xB2, 0xE1, 0xAD, 0x23, 0x47, 0x02, 0x3F, 0xD7, 0xBD, 0x51, - 0x2A, 0x6B, 0x33, 0x2D, 0x23, 0x6D, 0xD5, 0x72, 0x1F, 0xEC, - 0x8F, 0x7F, 0x1B, 0x22, 0x2D, 0x9E, 0x44, 0x58, 0xE0, 0xA3, - 0x50, 0x54, 0xCF, 0x6B, 0x5E, 0x59, 0x7A, 0xF0, 0xDA, 0x2E, - 0x9C, 0xC4, 0xD3, 0xD9, 0x83, 0x56, 0xBB, 0x09, 0x58, 0xFF, - 0x00, 0xDD, 0xDA, 0x57, 0x5C, 0xC3, 0xED, 0x10, 0x6E, 0xD6, - 0xD0, 0xF0, 0xB9, 0xD1, 0x2C, 0x1E, 0x4E, 0x33, 0xA7, 0x44, - 0x9C, 0x87, 0xB2, 0x91, 0x16, 0x2C, 0x44, 0x1E, 0x66, 0x79, - 0x06, 0x12, 0x26, 0xB6, 0x36, 0x1F, 0xBA, 0x56, 0x9F, 0xAB, - 0x64, 0x63, 0xE4, 0x90, 0x75, 0x72, 0xF9, 0x35, 0x77, 0x2B, - 0x38, 0xE5, 0x4F, 0x29, 0xF1, 0x4C, 0xD8, 0xBD, 0x20, 0x60, - 0x65, 0x26, 0x57, 0xCE, 0x52, 0x4B, 0x18, 0xD4, 0xDF, 0xCE, - 0xC0, 0x78, 0x60, 0x83, 0xD4, 0xDF, 0xE9, 0xA2, 0x61, 0x37, - 0x78, 0x7D, 0xEB, 0xE5, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x47, - 0xA5, 0x8E, 0xA4, 0x38, 0x2C, 0xDC, 0x61, 0xFB, 0xD1, 0x29, - 0xFD, 0x30, 0xA5, 0xEE, 0xB0, 0x2F, 0xF6, 0x53, 0x4B, 0x4E, - 0xE9, 0x26, 0x67, 0x28, 0xC0, 0x06, 0x59, 0x13, 0x88, 0xF8, - 0x9B, 0xE8, 0x6B, 0x9E, 0x5A, 0xCF, 0x8D, 0x8D, 0xE1, 0x80, - 0x1A, 0xE1, 0x4A, 0x59, 0x92, 0x6A, 0x57, 0x38, 0x79, 0x1E, - 0x5D, 0xA4, 0x35, 0xA5, 0xD3, 0x80, 0x41, 0x97, 0x69, 0xB7, - 0xDF, 0xE8, 0x07, 0xFA, 0xA6, 0x64, 0xFD, 0xB2, 0xD0, 0x66, - 0xB4, 0x35, 0x52, 0xCC, 0xC9, 0x82, 0xCF, 0xFA, 0xB3, 0xE0, - 0xE6, 0x96, 0x35, 0xEF, 0xD5, 0xF6, 0xA1, 0x0B, 0xAD, 0xE0, - 0x50, 0x7D, 0x9B, 0x36, 0x8D, 0xD2, 0x6E, 0x27, 0x14, 0x2D, - 0x6D, 0xCE, 0xC2, 0xF8, 0xDA, 0x64, 0xDC, 0xFD, 0xC8, 0x79, - 0x72, 0x00, 0xE3, 0xF9, 0x3F, 0x40, 0x0D, 0x0F, 0x40, 0x3A, - 0xE3, 0xFE, 0xEA, 0x93, 0x18, 0x7F, 0x2D, 0xFA, 0x7C, 0x6B, - 0xCB, 0x45, 0x8C, 0xD5, 0x8E, 0xE3, 0x95, 0x4C, 0xF9, 0x60, - 0x83, 0x8E, 0x07, 0xC0, 0x17, 0xE9, 0x6C, 0xAF, 0x2C, 0x08, - 0x04, 0xF5, 0x8B, 0xB7, 0xB8, 0x09, 0xAD, 0x91, 0x02, 0x9A, - 0x28, 0x25, 0xE7, 0x80, 0x5C, 0xCB, 0x69, 0xA0, 0xDA, 0x43, - 0x4F, 0x4C, 0x4A, 0xA1, 0xCB, 0x45, 0x0E, 0x2F, 0x87, 0x77, - 0x43, 0x7E, 0x0E, 0x42, 0xE7, 0x21, 0x2B, 0x73, 0x90, 0x21, - 0x7B, 0x9B, 0x87, 0xEC, 0x27, 0x76, 0xFF, 0x9F, 0xEB, 0x79, - 0xF9, 0x70, 0xE6, 0x73, 0x51, 0x4B, 0x8D, 0xE4, 0xB6, 0x76, - 0xFF, 0x23, 0x71, 0xD9, 0x87, 0x43, 0x29, 0xE4, 0xA0, 0xDE, - 0xB7, 0xCF, 0x92, 0x03, 0x84, 0x07, 0x17, 0xA1, 0xE6, 0x7B, - 0x43, 0x14, 0xA3, 0x30, 0xC0, 0x1B, 0x44, 0x91, 0xCF, 0x80, - 0x48, 0x92, 0x2B, 0x6D, 0x59, 0x8E, 0x63, 0x8C, 0xE8, 0xC3, - 0xA9, 0x04, 0x33, 0x3F, 0x75, 0x6A, 0x2B, 0x7B, 0xEC, 0x74, - 0x26, 0xAD, 0x34, 0x68, 0xB9, 0x9F, 0x63, 0xEE, 0xEA, 0x42, - 0x0D, 0xC7, 0x24, 0x7B, 0xD4, 0x5E, 0x5A, 0x91, 0xF1, 0x41, - 0x2E, 0x6B, 0x0D, 0xB9, 0x75, 0xCE, 0x51, 0x1E, 0x6E, 0xF2, - 0x6B, 0x9C, 0xD4, 0xBD, 0xAF, 0x54, 0x63, 0x1A, 0xA0, 0x29, - 0x65, 0x22, 0x04, 0x9D, 0xE2, 0x6F, 0x37, 0x4B, 0xC2, 0xC2, - 0x62, 0x1B, 0x94, 0xE0, 0xF9, 0xC8, 0xB0, 0x94, 0x43, 0x29, - 0x0D, 0x4F, 0x23, 0x4A, 0xBA, 0x83, 0x15, 0x97, 0x96, 0xC8, - 0x0A, 0x85, 0xD2, 0x80, 0x8B, 0x0C, 0x16, 0x57, 0x32, 0xCA, - 0xA4, 0xF6, 0x20, 0xB5, 0x49, 0x30, 0xCC, 0xD3, 0x1C, 0xAB, - 0xE0, 0xAE, 0x52, 0x7B, 0x71, 0x40, 0x80, 0xAC, 0x30, 0x78, - 0xEE, 0x5A, 0xD3, 0x82, 0x3F, 0x51, 0x34, 0xE8, 0x38, 0xD4, - 0x8D, 0x09, 0xEB, 0xDC, 0x9E, 0x82, 0xF7, 0xE2, 0xAA, 0xCD, - 0x2D, 0x17, 0x0C, 0x08, 0x22, 0xAF, 0xED, 0xE4, 0xC0, 0xC1, - 0xBB, 0x9C, 0x47, 0xC1, 0x23, 0x81, 0x03, 0x85, 0xDD, 0x00, - 0x5C, 0x4D, 0x7F, 0xF1, 0x02, 0xF8, 0xA9, 0xA1, 0x8E, 0xB1, - 0xCD, 0xFC, 0x6F, 0xC5, 0x0D, 0x37, 0xD9, 0x83, 0x15, 0x23, - 0x14, 0x03, 0x54, 0x37, 0xFC, 0xAC, 0xB6, 0xC8, 0x0A, 0x47, - 0x3F, 0x22, 0x6F, 0xD7, 0xFA, 0xBB, 0x8D, 0x17, 0xB2, 0x7C, - 0x0F, 0x65, 0xB4, 0xA2, 0x3A, 0x5F, 0x55, 0x34, 0xEC, 0xCA, - 0x89, 0xDD, 0xD4, 0x44, 0x77, 0x30, 0x9A, 0x20, 0x6A, 0x1A, - 0x9D, 0xBE, 0x39, 0x25, 0x2E, 0xE2, 0x0C, 0xDD, 0xE0, 0x50, - 0x8F, 0xD7, 0x38, 0x01, 0xB1, 0x25, 0xC1, 0xFD, 0x06, 0xD0, - 0x60, 0xC9, 0xEB, 0x1D, 0x77, 0x6D, 0xA2, 0x18, 0xB2, 0x0B, - 0x03, 0xE6, 0xF7, 0x07, 0x51, 0xFC, 0xAF, 0xE9, 0xD4, 0xFC, - 0x80, 0x69, 0x1C, 0xE1, 0x82, 0x96, 0x39, 0x37, 0xC1, 0xD3, - 0xB1, 0x81, 0x62, 0xB7, 0x20, 0x7F, 0xDF, 0xB7, 0x84, 0xD2, - 0xCC, 0xFB, 0x7E, 0x90, 0xBB, 0x05, 0x1B, 0x81, 0xA2, 0xE0, - 0x66, 0x11, 0x8A, 0x37, 0x93, 0x0F, 0x67, 0x81, 0x77, 0x03, - 0xA6, 0xE2, 0x52, 0xB6, 0x0F, 0x9A, 0x02, 0x26, 0xC0, 0x00, - 0x02, 0x1D, 0x9D, 0x63, 0xD2, 0x5B, 0xB0, 0x79, 0x8A, 0xF4, - 0x7F, 0x08, 0x9B, 0x5E, 0xAB, 0x6E, 0xD1, 0xCC, 0x2B, 0x7C, - 0xFF, 0x0D, 0x0E, 0xDD, 0x5F, 0xAA, 0x4C, 0x53, 0x45, 0x53, - 0x48, 0xCD, 0xCD, 0xF7, 0xBA, 0x5B, 0xB9, 0x84, 0xBB, 0x00, - 0xC2, 0xF0, 0xFB, 0x30, 0x5F, 0x04, 0x4E, 0x25, 0x4C, 0x06, - 0x03, 0x8D, 0xC5, 0x37, 0xA6, 0x9D, 0x1C, 0xD8, 0x13, 0xA7, - 0x96, 0xBE, 0xED, 0x22, 0xD7, 0xBA, 0x9F, 0x4C, 0x2E, 0xF9, - 0xD0, 0x5B, 0xBB, 0xF8, 0xB8, 0x0A, 0xF3, 0xEC, 0x31, 0x3F, - 0x84, 0x6E, 0x3A, 0x12, 0x8B, 0x6A, 0x2E, 0x28, 0xCE, 0xB8, - 0x1A, 0xC6, 0xE6, 0x4A, 0xD9, 0x74, 0x04, 0x24, 0xD8, 0x79, - 0x8D, 0x62, 0x0C, 0xB0, 0xAE, 0xAF, 0x67, 0xB4, 0xA1, 0x3D, - 0x93, 0x1D, 0xA2, 0x52, 0x98, 0x3F, 0x57, 0x73, 0x94, 0xB6, - 0x94, 0xBD, 0x0F, 0x42, 0x6A, 0x64, 0x7B, 0x17, 0xAC, 0x8D, - 0x46, 0xD0, 0xE4, 0x1B, 0x8C, 0x56, 0xB6, 0x47, 0xCB, 0xFD, - 0x56, 0x61, 0x6E, 0xA0, 0xBF, 0x6B, 0x8E, 0x68, 0x05, 0x55, - 0xA4, 0xB3, 0x8C, 0x76, 0x48, 0x73, 0x4C, 0x8D, 0x9D, 0xA2, - 0xA0, 0xA1, 0xFB, 0xD0, 0x33, 0x32, 0x39, 0xD2, 0x10, 0x1C, - 0x3C, 0x93, 0xC9, 0xCA, 0x6A, 0x6E, 0x7C, 0xB6, 0xF1, 0x03, - 0xF3, 0x45, 0x51, 0x05, 0x48, 0x30, 0xF0, 0xC6, 0x84, 0xFD, - 0x4E, 0x3B, 0x03, 0xE0, 0x62, 0xB8, 0x53, 0x55, 0xB6, 0xB8, - 0x02, 0x7C, 0xB9, 0xD5, 0x5C, 0xA2, 0x9B, 0x97, 0x8A, 0xA4, - 0xDF, 0x42, 0xEB, 0x91, 0x2C, 0x98, 0x82, 0xA9, 0xAE, 0xB0, - 0x13, 0xF6, 0x6E, 0x90, 0x42, 0xFE, 0xD3, 0xAA, 0x1E, 0xBA, - 0x69, 0xFC, 0xF8, 0x20, 0xEA, 0x5D, 0xA8, 0xFE, 0x64, 0x56, - 0x26, 0x4C, 0x6C, 0x69, 0x8F, 0xAC, 0x30, 0xCF, 0xAE, 0x8B, - 0xD5, 0x63, 0x10, 0xDD, 0xCE, 0x6E, 0x0C, 0xAB, 0x31, 0x46, - 0xDF, 0x8A, 0x33, 0x28, 0x8A, 0x1C, 0xEB, 0xBE, 0xAA, 0x71, - 0x44, 0x5C, 0x89, 0xEA, 0x00, 0x34, 0x23, 0xEB, 0x18, 0x83, - 0x7F, 0xB1, 0x9B, 0x3A, 0xBF, 0x08, 0x68, 0xB6, 0xC8, 0xE2, - 0xD8, 0x2D, 0x5E, 0xA2, 0x99, 0xB9, 0xBC, 0xF8, 0x31, 0xD1, - 0xFD, 0x31, 0xD4, 0x32, 0x05, 0x58, 0x5C, 0xFB, 0xCD, 0x8C, - 0xFF, 0x75, 0x99, 0x93, 0xC8, 0x0C, 0xE8, 0xE8, 0x60, 0x11, - 0xB8, 0x5F, 0x15, 0xB5, 0x89, 0x47, 0xE1, 0x1C, 0x23, 0x1B, - 0x8E, 0x56, 0x02, 0xD3, 0x5F, 0xBD, 0xA9, 0x9F, 0x67, 0x06, - 0xCA, 0x0C, 0x6E, 0x9C, 0xFB, 0x2D, 0x3A, 0xE3, 0xF6, 0x2C, - 0x72, 0x86, 0xCD, 0x68, 0xAC, 0x7B, 0x22, 0xA3, 0x01, 0x15, - 0x50, 0xB7, 0xA0, 0x05, 0x88, 0xD0, 0xDF, 0xBD, 0xDA, 0x3B, - 0xC4, 0xFF, 0x40, 0xA1, 0x46, 0x55, 0x28, 0xB3, 0x0C, 0x1E, - 0xF8, 0xE9, 0x0A, 0x39, 0xD1, 0x66, 0xDF, 0x5B, 0x2B, 0x2C, - 0xCA, 0xA5, 0x36, 0x32, 0x0D, 0xAC, 0x8E, 0xDF, 0x75, 0x9A, - 0xE5, 0x8B, 0xE5, 0x99, 0x6B, 0xD6, 0xB7, 0x83, 0x6B, 0xFE, - 0xEA, 0xC9, 0x71, 0xB5, 0xB9, 0xAE, 0xBE, 0x74, 0xB6, 0x58, - 0x28, 0x06, 0x23, 0xCF, 0x8D, 0x09, 0xBC, 0xE3, 0x18, 0x6C, - 0xFA, 0x53, 0x02, 0xE8, 0x3D, 0x44, 0xB3, 0xFE, 0xB3, 0x11, - 0x70, 0x10, 0xDF, 0xC3, 0x93, 0x64, 0x0F, 0x19, 0x35, 0xF0, - 0x82, 0x3A, 0xE3, 0x04, 0xE3, 0x1D, 0xFE, 0x52, 0xE8, 0x52, - 0xA1, 0x7B, 0x19, 0x23, 0x8E, 0x3F, 0x5D, 0x16, 0x60, 0xCB, - 0x13, 0x1A, 0x26, 0x6D, 0xDB, 0x82, 0xEB, 0x72, 0xEE, 0x76, - 0x77, 0x36, 0xEC, 0xEE, 0x09, 0x90, 0xAF, 0x35, 0x25, 0x5A, - 0x29, 0x61, 0x7A, 0xE6, 0x8C, 0x6C, 0x2A, 0x3B, 0x3B, 0xC4, - 0xC5, 0xD4, 0xCF, 0x41, 0x40, 0x04, 0xF3, 0x0F, 0x4B, 0x1B, - 0x99, 0x7D, 0xCF, 0x1F, 0xC5, 0xEB, 0xC5, 0xF5, 0xA1, 0x16, - 0xA2, 0x2A, 0x2E, 0xD5, 0x78, 0xC5, 0xAD, 0x9C, 0x48, 0x76, - 0xF2, 0x58, 0xDE, 0x68, 0x19, 0x58, 0x8C, 0xEA, 0xF5, 0xD0, - 0x54, 0x4F, 0x73, 0x60, 0x92, 0x71, 0x27, 0xF7, 0x02, 0x26, - 0xC0, 0x00, 0x02, 0x24, 0xC2, 0xE1, 0xD7, 0x77, 0x1A, 0x4D, - 0x5F, 0x7B, 0xC6, 0xC7, 0x52, 0x42, 0x9C, 0x26, 0xBE, 0x75, - 0x2E, 0x37, 0x00, 0xD8, 0x2C, 0xEF, 0x37, 0xC2, 0xF8, 0x88, - 0x89, 0xBA, 0x60, 0x35, 0xCE, 0xD5, 0xC4, 0x3D, 0x00, 0x6A, - 0xF1, 0xE1, 0x66, 0x4C, 0xFF, 0x79, 0xC7, 0xDF, 0x04, 0x99, - 0x02, 0xEB, 0x0E, 0x9D, 0xBE, 0x2C, 0x06, 0xB8, 0xE1, 0xC8, - 0xAE, 0xC4, 0xE8, 0xB7, 0xE7, 0x66, 0xEF, 0x01, 0x72, 0x45, - 0xB2, 0xBF, 0x69, 0xF7, 0xA2, 0x72, 0xEC, 0x91, 0x82, 0x9D, - 0xE5, 0x91, 0x9A, 0x6D, 0x4D, 0x0D, 0x29, 0x58, 0xE3, 0xA2, - 0xBB, 0x4F, 0x7B, 0xED, 0xA6, 0xEC, 0x0D, 0x91, 0xF6, 0xE7, - 0x68, 0x61, 0xDF, 0x8A, 0x1A, 0x5A, 0x2A, 0x21, 0x51, 0x80, - 0x31, 0xD5, 0xD6, 0xFB, 0xE5, 0x0D, 0x01, 0x49, 0x22, 0x05, - 0xEE, 0xA2, 0x7A, 0xF6, 0x6C, 0xCD, 0x9D, 0x95, 0x79, 0x7E, - 0x9D, 0x22, 0x91, 0x59, 0x31, 0x80, 0x55, 0xC9, 0x66, 0xC8, - 0x33, 0x36, 0x56, 0x65, 0xCC, 0x26, 0x88, 0xE7, 0xC0, 0x01, - 0xF4, 0x22, 0xF9, 0xE6, 0xF1, 0x18, 0x69, 0xAB, 0x93, 0x80, - 0x95, 0xBF, 0xA4, 0xB7, 0x7F, 0x56, 0x7D, 0xC0, 0xEE, 0xA7, - 0x01, 0x5B, 0x9B, 0xA6, 0x80, 0x5A, 0x17, 0x31, 0xC8, 0x93, - 0xF6, 0x6F, 0xFD, 0x27, 0x9A, 0x09, 0xB8, 0x48, 0x04, 0xD5, - 0x1F, 0xBB, 0x8B, 0xED, 0xB7, 0x08, 0x43, 0xBF, 0x82, 0xB1, - 0xAF, 0xD9, 0x35, 0x03, 0xE8, 0x36, 0xB4, 0xCD, 0x74, 0x74, - 0x30, 0x85, 0x73, 0x1F, 0x51, 0xED, 0xA5, 0xFD, 0x64, 0xFC, - 0xF1, 0x22, 0x21, 0x36, 0x3C, 0x5E, 0x46, 0x74, 0x9D, 0x94, - 0x2C, 0x0F, 0xDF, 0x2B, 0x6E, 0x5E, 0xA8, 0x7C, 0x80, 0xA4, - 0x4C, 0xE4, 0x1A, 0xE2, 0x80, 0x29, 0x5F, 0x85, 0x76, 0x95, - 0xD0, 0x2D, 0x26, 0x50, 0xB2, 0x14, 0x37, 0xA3, 0x3A, 0x4E, - 0xB9, 0x68, 0xCB, 0x1D, 0x9A, 0x9B, 0x33, 0xD0, 0x3D, 0x1B, - 0x0F, 0x3F, 0xA2, 0x95, 0xE0, 0x80, 0xA1, 0x39, 0x03, 0x14, - 0x5F, 0x21, 0x27, 0x54, 0xB5, 0x4D, 0x1F, 0x7A, 0x9A, 0x1E, - 0xB1, 0xC9, 0x63, 0xBE, 0xEC, 0x0C, 0xC1, 0x16, 0x80, 0x0F, - 0xFD, 0x3B, 0x3F, 0xFD, 0x97, 0xF8, 0x4F, 0xD9, 0xFE, 0xC7, - 0x6A, 0xE5, 0x40, 0x5B, 0xB8, 0x50, 0xA8, 0x94, 0x6F, 0x9F, - 0xD8, 0x23, 0xE8, 0xBC, 0x16, 0x9B, 0xF8, 0xC5, 0x0C, 0x48, - 0x28, 0x1B, 0x51, 0x8B, 0x1C, 0x9F, 0x37, 0x97, 0x6B, 0x0B, - 0x1C, 0x2B, 0xCF, 0x7F, 0x9E, 0xC4, 0x54, 0x8F, 0x4D, 0xBF, - 0x43, 0xBB, 0x40, 0x20, 0x79, 0x1F, 0x29, 0xF2, 0x43, 0x65, - 0x0D, 0xC8, 0x16, 0xAC, 0xE4, 0xF3, 0x82, 0x67, 0x01, 0xD9, - 0x19, 0x80, 0xAD, 0x16, 0x1F, 0xF6, 0xFA, 0xD3, 0xD8, 0x74, - 0x6F, 0xE5, 0x00, 0x8E, 0x77, 0x95, 0x51, 0x83, 0xD4, 0xF2, - 0x8B, 0x79, 0x2D, 0xBA, 0xB1, 0x10, 0x0C, 0x0F, 0xCC, 0x7D, - 0x24, 0x7A, 0xF5, 0xDF, 0x54, 0x54, 0xC0, 0xAF, 0x80, 0x3D, - 0x7E, 0x9C, 0x8F, 0x27, 0xA7, 0x0A, 0xE4, 0x8C, 0xB7, 0x5C, - 0x61, 0xF4, 0xAD, 0xB3, 0xD8, 0xA9, 0x1B, 0xEC, 0x13, 0xCB, - 0xD8, 0xD3, 0x81, 0xBA, 0x9D, 0xCA, 0xD9, 0xAE, 0xC4, 0x43, - 0x69, 0xF4, 0xDE, 0xF9, 0xE0, 0xFE, 0x5D, 0x53, 0x6D, 0xDA, - 0x5F, 0xED, 0x5F, 0x30, 0x81, 0x2C, 0xDE, 0x92, 0x04, 0xDE, - 0x94, 0xBB, 0x45, 0xAF, 0x14, 0x84, 0xC9, 0xE3, 0xBD, 0xBD, - 0x7F, 0x52, 0xE9, 0x6B, 0x34, 0xCA, 0x06, 0x3A, 0xE1, 0x79, - 0x22, 0x3C, 0xA8, 0x34, 0xED, 0x7E, 0x26, 0x18, 0x84, 0xDB, - 0x92, 0x48, 0xFD, 0xD6, 0x82, 0x04, 0x1D, 0x82, 0x1A, 0xA6, - 0x28, 0x74, 0x31, 0xA5, 0x74, 0x1F, 0xD9, 0x0F, 0xF2, 0xC8, - 0x4C, 0x38, 0x8F, 0xAF, 0x2A, 0xE0, 0x5F, 0xD6, 0xA4, 0x1C, - 0xE3, 0xF8, 0x70, 0xD5, 0x4C, 0xF8, 0x3C, 0x92, 0x0A, 0x01, - 0xEF, 0xB7, 0xEA, 0x57, 0xA5, 0x88, 0x4C, 0x10, 0x68, 0x99, - 0xC8, 0x4F, 0x1D, 0x67, 0x8E, 0x43, 0x7D, 0x3D, 0x5E, 0x20, - 0x02, 0x26, 0xC0, 0x00, 0x02, 0x68, 0x4F, 0x5F, 0x8D, 0xC4, - 0x7F, 0x74, 0xCD, 0xFE, 0xFB, 0x21, 0x22, 0x03, 0x06, 0xFA, - 0x2E, 0x4C, 0xFF, 0x35, 0xBB, 0x9E, 0x93, 0x44, 0x35, 0x8A, - 0xFF, 0x97, 0x39, 0x36, 0x8D, 0x53, 0x4D, 0xFA, 0x04, 0xA8, - 0x98, 0x13, 0x9C, 0xAA, 0x87, 0x0D, 0x8B, 0x50, 0x0D, 0x9C, - 0xB1, 0xAC, 0x4C, 0x59, 0x9B, 0xA2, 0xE4, 0x4C, 0xFC, 0x46, - 0xC5, 0xA6, 0x00, 0x4A, 0xA8, 0xD3, 0x24, 0x40, 0x9E, 0x48, - 0x8F, 0xC0, 0x8C, 0x0E, 0x16, 0x02, 0x3C, 0xF5, 0x12, 0x3D, - 0x97, 0xCE, 0xDE, 0x11, 0xBE, 0x46, 0xE8, 0x8F, 0x15, 0x3B, - 0xB3, 0x1D, 0x74, 0xCB, 0xEE, 0x77, 0x2D, 0xEB, 0xAD, 0x87, - 0x39, 0x85, 0xD7, 0xBC, 0x38, 0x87, 0x2A, 0x0B, 0xB5, 0xB0, - 0xD1, 0x09, 0x7D, 0x12, 0xC6, 0x4D, 0x9A, 0xF8, 0x00, 0xC5, - 0xA2, 0xF9, 0x9A, 0xFF, 0x30, 0x5D, 0x6E, 0x79, 0xD7, 0xBA, - 0xB3, 0xCC, 0x2A, 0x43, 0x61, 0xAC, 0x38, 0x99, 0x10, 0xDF, - 0x60, 0x94, 0x7B, 0x49, 0xD9, 0xC2, 0x4C, 0x6D, 0x3F, 0xD7, - 0x38, 0x85, 0xE7, 0x91, 0x26, 0x9E, 0x7F, 0x7E, 0xA4, 0x91, - 0x9B, 0x92, 0x02, 0xC1, 0x1F, 0xAF, 0x5C, 0x6B, 0xBA, 0x27, - 0xAD, 0x33, 0xCC, 0xE6, 0x20, 0x23, 0x61, 0xBE, 0x4A, 0xDA, - 0x28, 0x63, 0xB2, 0xE2, 0xAC, 0xA9, 0x51, 0x50, 0x9A, 0xAB, - 0xCA, 0x8C, 0x5C, 0xF3, 0x0A, 0x44, 0x03, 0xA9, 0x94, 0x92, - 0x1D, 0xC5, 0xB2, 0x09, 0xF3, 0x0E, 0xB3, 0x6A, 0x1D, 0x72, - 0xDC, 0x71, 0x4A, 0xAE, 0x4E, 0x0B, 0x1B, 0xCF, 0xF3, 0xCF, - 0x4B, 0x38, 0xD1, 0xCA, 0x27, 0xC2, 0x6A, 0x41, 0x0F, 0x3A, - 0x1D, 0xCD, 0x3E, 0xB1, 0x1A, 0xF7, 0x16, 0x48, 0x4A, 0xAA, - 0xA7, 0x28, 0x16, 0x07, 0x9B, 0xE0, 0x41, 0x99, 0xF1, 0x47, - 0x8C, 0x48, 0x6C, 0x2D, 0x93, 0x9E, 0x47, 0x2B, 0x9A, 0x96, - 0x20, 0x44, 0xF4, 0x2A, 0xCB, 0xB0, 0xDA, 0xBD, 0x17, 0x38, - 0xCB, 0x45, 0x9F, 0x21, 0xA8, 0x93, 0x26, 0x67, 0x51, 0x36, - 0x6F, 0x05, 0x4A, 0x08, 0x72, 0xFB, 0xA3, 0x98, 0xBF, 0x9E, - 0x39, 0xEC, 0xAF, 0xDA, 0x8A, 0xFD, 0xC1, 0xB2, 0xC4, 0x4D, - 0xFE, 0xCD, 0xBD, 0x7F, 0xF8, 0xCE, 0x4F, 0x7E, 0x4E, 0xBA, - 0xD1, 0x87, 0x3E, 0x5F, 0x77, 0xA2, 0x96, 0x3E, 0x8B, 0x15, - 0xDE, 0xE7, 0xBF, 0x7F, 0x97, 0x0F, 0xE1, 0xE7, 0x2F, 0x58, - 0x5D, 0xEF, 0x56, 0x39, 0x66, 0x63, 0x61, 0x94, 0x3D, 0x31, - 0xC8, 0x8D, 0xA8, 0xAC, 0xB5, 0x4C, 0x20, 0x1A, 0xD4, 0x18, - 0x34, 0x61, 0xA2, 0x4F, 0x65, 0xB3, 0x12, 0xFE, 0xA9, 0x02, - 0xCC, 0x47, 0x8F, 0x1C, 0x39, 0xFD, 0xDB, 0x08, 0x62, 0xFD, - 0x74, 0x8D, 0xF9, 0xAA, 0x34, 0xCA, 0x20, 0x67, 0xE8, 0xBC, - 0xAB, 0xED, 0x8C, 0x09, 0xC1, 0xA1, 0xE2, 0x3A, 0x41, 0xB7, - 0x1D, 0x82, 0x99, 0xAA, 0x79, 0x93, 0xB5, 0x1D, 0x6A, 0xE8, - 0xFC, 0x31, 0xBF, 0x67, 0xD8, 0xE9, 0x36, 0xD4, 0xBF, 0x9E, - 0xBF, 0xAB, 0x13, 0x20, 0xE3, 0x01, 0x29, 0x60, 0x28, 0x19, - 0xD2, 0x0E, 0xBC, 0x21, 0x3E, 0xD6, 0xC0, 0xC3, 0xDD, 0x64, - 0xFC, 0x98, 0x45, 0x26, 0x9B, 0x5C, 0xCB, 0xE2, 0x76, 0x0A, - 0x0D, 0x13, 0x1A, 0x7F, 0xEF, 0xE2, 0x44, 0xA3, 0xD8, 0xCE, - 0xD6, 0x0E, 0x5A, 0xA8, 0x40, 0x7B, 0x9E, 0xA0, 0xBE, 0xD6, - 0x63, 0x56, 0x77, 0x57, 0x69, 0x2C, 0xF8, 0xB6, 0x8D, 0x08, - 0xF3, 0x80, 0xA1, 0x2F, 0x53, 0xE2, 0x2F, 0xFD, 0xE6, 0x86, - 0x91, 0x83, 0x12, 0x7E, 0x73, 0xCF, 0xC8, 0x12, 0x58, 0xCD, - 0x9B, 0x30, 0x2C, 0x1E, 0xB8, 0x1E, 0xA3, 0x66, 0x27, 0xE9, - 0x33, 0xB2, 0x57, 0x9B, 0xF7, 0xFC, 0x04, 0xE1, 0xDF, 0xA4, - 0xC5, 0x7A, 0x39, 0xCE, 0xDF, 0xEB, 0x03, 0x89, 0x37, 0xFB, - 0xB0, 0x17, 0x12, 0x55, 0x52, 0x60, 0x25, 0xD1, 0xA6, 0x54, - 0xED, 0xD2, 0xBA, 0xE9, 0x66, 0x5A, 0xCA, 0xE3, 0x71, 0xF8, - 0xE7, 0x35, 0x1C, 0xAC, 0x00, 0x2C, 0xBD, 0x52, 0x6F, 0xE0, - 0x96, 0x91, 0x02, 0x26, 0xC0, 0x00, 0x02, 0x02, 0xB1, 0x96, - 0x3E, 0x04, 0x9B, 0x7A, 0x13, 0x3F, 0xA3, 0x05, 0x16, 0xBF, - 0x79, 0xE5, 0x67, 0x77, 0x23, 0x1E, 0x4D, 0x4C, 0x26, 0x7C, - 0x9D, 0x3E, 0xF5, 0x37, 0x49, 0xAC, 0x5C, 0xA7, 0x9F, 0xD7, - 0x8B, 0x61, 0x4B, 0x21, 0xEC, 0x27, 0x9A, 0x62, 0x75, 0xD1, - 0xCB, 0xEB, 0x58, 0x98, 0x84, 0xD1, 0xD9, 0xD8, 0x00, 0x0E, - 0x38, 0xCB, 0x40, 0xE9, 0xC0, 0x87, 0x62, 0x6D, 0xD6, 0xBE, - 0x5E, 0x47, 0x40, 0xCE, 0x39, 0xD2, 0x28, 0xFF, 0x32, 0x08, - 0xFB, 0xF1, 0x86, 0xEF, 0xF1, 0x1F, 0xC7, 0x28, 0xE0, 0x2A, - 0x9B, 0xAA, 0xA7, 0xEC, 0xBA, 0x63, 0x27, 0x98, 0xCC, 0x4C, - 0x35, 0x48, 0xE2, 0x83, 0xE2, 0xE4, 0x7E, 0xCF, 0xF2, 0x38, - 0xED, 0x1C, 0xE7, 0x17, 0xCB, 0xAC, 0xCC, 0xDA, 0xF5, 0x3B, - 0xD3, 0xC5, 0xFE, 0xB5, 0x04, 0x3A, 0xFC, 0xF7, 0x66, 0x66, - 0x89, 0xB5, 0xAD, 0x1C, 0x18, 0xFE, 0x63, 0xF6, 0x9E, 0x8D, - 0x73, 0xDC, 0x9D, 0x54, 0xDD, 0x02, 0x3B, 0x1D, 0x3F, 0x3D, - 0xD1, 0x4C, 0xCB, 0x3C, 0x09, 0x8E, 0x5A, 0x06, 0x5C, 0x03, - 0x59, 0xF4, 0x7B, 0xF6, 0x39, 0x02, 0x2B, 0xDC, 0x76, 0x82, - 0x2A, 0x33, 0x34, 0x34, 0x57, 0x9F, 0xC8, 0xF0, 0xF0, 0x14, - 0x29, 0x0C, 0x6E, 0x92, 0x36, 0x56, 0x3B, 0xA6, 0x68, 0xF0, - 0x3B, 0x3C, 0xA7, 0x8F, 0x60, 0x85, 0x5D, 0xAD, 0x14, 0xBF, - 0xA7, 0x8B, 0x8E, 0xED, 0x20, 0x0A, 0x64, 0xB2, 0x05, 0xF9, - 0x59, 0x45, 0xC0, 0x97, 0x2D, 0x0D, 0x3A, 0x77, 0xC0, 0xBD, - 0xA2, 0x9F, 0xD4, 0x21, 0xA5, 0x23, 0x7D, 0x1A, 0xE2, 0x4D, - 0x72, 0x44, 0xF6, 0x3E, 0x2A, 0x12, 0xF6, 0xB3, 0xDD, 0x15, - 0x63, 0xCC, 0x7A, 0x5E, 0x60, 0xC2, 0xB0, 0xEE, 0x2C, 0x35, - 0x08, 0x35, 0xE8, 0xA8, 0x08, 0x86, 0xA6, 0xC9, 0xA2, 0x84, - 0xBF, 0x90, 0x14, 0x92, 0x95, 0x6A, 0x08, 0x39, 0x30, 0xB2, - 0x94, 0x3E, 0x0D, 0xE9, 0x3B, 0x28, 0xC7, 0x89, 0x6F, 0xFE, - 0xB9, 0x83, 0x00, 0xE9, 0x9A, 0xA5, 0x47, 0x82, 0xEB, 0xAE, - 0xA8, 0x2F, 0xD4, 0x89, 0xDB, 0x00, 0xC0, 0xA3, 0xE8, 0x79, - 0xC8, 0x5D, 0x90, 0xA5, 0x5F, 0xB6, 0x11, 0x42, 0x99, 0x1E, - 0x7C, 0x9C, 0xB5, 0xA6, 0x90, 0x85, 0xE8, 0xED, 0x14, 0x55, - 0x99, 0x13, 0x10, 0xFD, 0x94, 0xF6, 0x48, 0x86, 0x26, 0x5A, - 0x36, 0x15, 0x53, 0xE5, 0x02, 0xD4, 0x46, 0xA4, 0x3B, 0x97, - 0xB0, 0x65, 0x25, 0xD2, 0x52, 0x08, 0x7D, 0x12, 0x28, 0xC3, - 0x0A, 0x26, 0xF1, 0xCD, 0x10, 0x90, 0xB0, 0x61, 0x6C, 0x31, - 0xEE, 0xC4, 0x79, 0x86, 0x36, 0x94, 0x38, 0x26, 0xD8, 0xA0, - 0x44, 0x90, 0x38, 0x08, 0xCA, 0xCA, 0x8A, 0xEF, 0x6D, 0xFD, - 0xBF, 0xAC, 0xE2, 0x87, 0xC4, 0xD3, 0xB6, 0x68, 0xA5, 0x02, - 0x05, 0xB4, 0xC1, 0xA3, 0x38, 0x60, 0x1B, 0x7F, 0xA5, 0xF2, - 0xA8, 0x17, 0xB0, 0x17, 0x88, 0x0F, 0xE8, 0xE1, 0x25, 0x9C, - 0x4E, 0x82, 0x37, 0x0C, 0xC3, 0xFF, 0x6D, 0x99, 0x9F, 0xB3, - 0x8B, 0x92, 0x2B, 0x96, 0x6B, 0xD3, 0xDF, 0x3F, 0x45, 0xD8, - 0xA2, 0x46, 0xAA, 0x06, 0x7D, 0xA7, 0x57, 0xEC, 0x87, 0x99, - 0xFA, 0x2F, 0x93, 0x6D, 0x65, 0x77, 0xD3, 0x72, 0x2B, 0x3D, - 0xFC, 0x9D, 0x0D, 0x2C, 0x88, 0x75, 0x37, 0x4B, 0x18, 0xA9, - 0x2D, 0xA9, 0xD6, 0xE3, 0x75, 0xFA, 0x29, 0xCE, 0x91, 0x51, - 0x74, 0xF9, 0x71, 0xFB, 0x0B, 0x1F, 0x24, 0x3D, 0xA8, 0xF3, - 0x56, 0x67, 0x7A, 0x13, 0xAA, 0xFF, 0x1C, 0x6D, 0xDD, 0x0F, - 0x14, 0xBC, 0x34, 0x35, 0xE0, 0xAF, 0x7A, 0x55, 0x8C, 0x9A, - 0xE0, 0xA6, 0x35, 0x1F, 0xAB, 0xC3, 0xF7, 0x14, 0x7E, 0xFF, - 0x13, 0x64, 0xAF, 0x1C, 0x11, 0x68, 0x25, 0x4D, 0x07, 0x05, - 0x3F, 0x76, 0x61, 0x29, 0x32, 0xB5, 0xEF, 0xF7, 0x7E, 0xE8, - 0x5C, 0xE2, 0xAA, 0x17, 0x3F, 0x5C, 0x48, 0xFA, 0x05, 0xB0, - 0xDF, 0x1F, 0x2B, 0x9B, 0x25, 0xAA, 0xA8, 0x1F, 0x80, 0xF5, - 0xE5, 0x9C, 0xC2, 0xF5, 0x02, 0x06, 0xC0, 0x00, 0x02, 0x96, - 0xA3, 0xD9, 0x49, 0x25, 0x73, 0x8B, 0x32, 0xB3, 0xD6, 0x68, - 0x6E, 0x3F, 0xDE, 0x58, 0xCB, 0xA8, 0x00, 0x34, 0xB2, 0x7D, - 0x5A, 0x88, 0x7F, 0x1B, 0x3A, 0xA7, 0xD2, 0x56, 0x5B, 0x20, - 0x6F, 0x6B, 0x43, 0x58, 0xC9, 0x48, 0x1F, 0x76, 0xE3, 0xA5, - 0x79, 0x0D, 0xD3, 0xC7, 0xBB, 0x76, 0xE8, 0xC2, 0xD5, 0x77, - 0x2B, 0x39, 0x93, 0x7F, 0x9B, 0x33, 0xB3, 0x0C, 0x12, 0x50, - 0x8A, 0x95, 0xB3, 0x27, 0xCB, 0x49, 0xDB, 0x3C, 0x6A, 0xB9, - 0x06, 0xD8, 0x31, 0x8E, 0x14, 0x6A, 0x3F, 0x5B, 0x03, 0x98, - 0xD8, 0x5C, 0xCA, 0x46, 0x14, 0xDA, 0xAB, 0x51, 0xDF, 0x72, - 0x3A, 0xAD, 0x8E, 0xDA, 0x9A, 0x44, 0x0E, 0x4C, 0xB0, 0x92, - 0xF6, 0x6A, 0x0E, 0xC8, 0x37, 0x0F, 0x93, 0x73, 0xB0, 0xB5, - 0x11, 0x12, 0x3F, 0xCF, 0x29, 0x50, 0x6B, 0xD9, 0x22, 0x2C, - 0x76, 0x71, 0x07, 0xBC, 0x00, 0x10, 0xB8, 0x54, 0x6A, 0x9A, - 0x59, 0x82, 0x4E, 0xE9, 0x02, 0x8B, 0x9C, 0xC9, 0x4B, 0xD3, - 0x7F, 0xAD, 0xA5, 0xF9, 0x7C, 0xB4, 0x00, 0xB4, 0x5A, 0xAF, - 0x23, 0x12, 0xF2, 0x5B, 0xB9, 0x2C, 0xFD, 0x73, 0xB9, 0xFC, - 0x4B, 0x4F, 0xAF, 0xD2, 0x80, 0xC2, 0xF7, 0x15, 0xEC, 0xE1, - 0x4B, 0xEF, 0xA3, 0x99, 0x59, 0x0C, 0xD5, 0x2F, 0x98, 0xF5, - 0x38, 0xD2, 0xFC, 0xF3, 0x82, 0xA7, 0xE0, 0x15, 0x35, 0x27, - 0xCD, 0xCF, 0xCE, 0xA4, 0x65, 0x92, 0x1E, 0x6C, 0x25, 0x8F, - 0xB7, 0x78, 0x15, 0x5B, 0x7A, 0x9D, 0xB0, 0xEC, 0xDE, 0x0A, - 0xF5, 0x0B, 0xCD, 0xD4, 0xF6, 0xC4, 0xD5, 0xA9, 0xC1, 0x4E, - 0xE0, 0xA2, 0x8B, 0xC4, 0x43, 0x97, 0xAC, 0xC9, 0x41, 0xF2, - 0x5A, 0x36, 0xD1, 0xD6, 0x7E, 0xC2, 0xD3, 0x06, 0xCB, 0x78, - 0x47, 0x78, 0x05, 0x35, 0x61, 0xE6, 0xD4, 0xDC, 0x65, 0x75, - 0x63, 0x5B, 0x71, 0xD7, 0x3C, 0x27, 0x9B, 0x26, 0x70, 0xAB, - 0x4D, 0x97, 0xE5, 0x83, 0x7C, 0xEB, 0x5B, 0x8F, 0xD6, 0xBC, - 0x84, 0x9D, 0xF8, 0x08, 0x65, 0x10, 0x6E, 0x48, 0xBE, 0xD2, - 0x86, 0xC0, 0xEB, 0x08, 0x27, 0x38, 0xF8, 0x6E, 0x5D, 0xBA, - 0x5B, 0xC6, 0x78, 0xED, 0xB1, 0x8D, 0x57, 0xFC, 0xA4, 0xDD, - 0xF3, 0xDF, 0xB9, 0x36, 0x92, 0xB8, 0x00, 0x06, 0x5F, 0xAD, - 0x04, 0xE3, 0x8D, 0x64, 0x64, 0x7A, 0xE0, 0x57, 0x4C, 0x68, - 0x56, 0xDC, 0x1F, 0x93, 0xA5, 0xD7, 0xEE, 0xFC, 0x8A, 0xB9, - 0x26, 0x99, 0xC5, 0x1A, 0x63, 0xD6, 0x9B, 0xBC, 0xA2, 0xF3, - 0xE1, 0x84, 0xDC, 0xFB, 0x0C, 0x4F, 0xB4, 0x0D, 0x75, 0x8B, - 0xDD, 0xB6, 0x76, 0x2C, 0x33, 0x46, 0xDD, 0x94, 0xE0, 0x8C, - 0x37, 0x03, 0x14, 0x44, 0xC2, 0x0F, 0x6C, 0x03, 0xA6, 0x39, - 0x1E, 0xB5, 0x00, 0x83, 0xC6, 0x59, 0x81, 0xD6, 0x11, 0x3A, - 0x22, 0x6F, 0x74, 0x1C, 0x8B, 0x4C, 0xF3, 0x1C, 0x59, 0x2F, - 0x19, 0x18, 0xB5, 0x20, 0x24, 0x9C, 0x14, 0x45, 0x7E, 0x98, - 0xFB, 0x71, 0xC4, 0xCC, 0x19, 0x99, 0x28, 0x9E, 0x63, 0xC2, - 0xD6, 0x0D, 0x47, 0x2A, 0x3B, 0x36, 0xB7, 0x8C, 0xF1, 0x98, - 0x33, 0x96, 0x9D, 0x09, 0x99, 0x74, 0xE3, 0x41, 0xCD, 0x67, - 0xCE, 0x11, 0xBA, 0x35, 0xE3, 0x44, 0x3D, 0xE0, 0xB9, 0x53, - 0x79, 0x58, 0x0F, 0xC5, 0x98, 0xCC, 0xAB, 0xF8, 0x37, 0x5C, - 0x96, 0xCE, 0xB5, 0xDA, 0xB5, 0x05, 0x79, 0xD6, 0x96, 0x82, - 0xCA, 0x3F, 0x2C, 0x8A, 0x44, 0xCE, 0xCE, 0x99, 0xA2, 0x77, - 0x9E, 0xE0, 0xFE, 0x58, 0x97, 0x5A, 0xDA, 0x8B, 0xB8, 0x0A, - 0xA2, 0x3F, 0x26, 0x00, 0x5C, 0xAC, 0xD8, 0x33, 0x95, 0xBF, - 0x43, 0x0D, 0x09, 0xB5, 0x9A, 0x89, 0x4C, 0x46, 0x83, 0xAF, - 0xD1, 0xD3, 0x61, 0x33, 0xA1, 0x19, 0xD3, 0xD6, 0x81, 0xB0, - 0xDA, 0x55, 0x4B, 0xD3, -}; - -const uint32_t gphDnldNfc_DlSeqSz = sizeof(gphDnldNfc_DlSequence); diff --git a/nfc/recovery_seq.c b/nfc/recovery_seq.c deleted file mode 100644 index 1f2b358a42..0000000000 --- a/nfc/recovery_seq.c +++ /dev/null @@ -1,249 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2021 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#include "recovery_seq.h" - -struct recovery_info g_recovery_info; -struct recovery_frame g_recovery_frame; - -/** @brief Function to calculate crc value. - * - * @param pbuffer: input buffer for crc calculation. - * dwLength: length of input buffer - * @return calculated uint16_t crc valueof input buffer. - */ -static uint16_t calcCrc16(uint8_t *pbuffer, uint32_t dwLength) -{ - uint32_t i = 0; - uint16_t crc_new = 0; - uint16_t crc = DL_INVALID_CRC_VALUE; - - if (pbuffer == NULL) { - pr_err("%s, invalid params", __func__); - return crc; - } - for (i = 0; i < dwLength; i++) { - crc_new = (uint8_t)(crc >> MSB_POS) | (crc << MSB_POS); - crc_new ^= pbuffer[i]; - crc_new ^= (uint8_t)(crc_new & DL_CRC_MASK) >> 4; - crc_new ^= crc_new << 12; - crc_new ^= (crc_new & DL_CRC_MASK) << 5; - crc = crc_new; - } - return crc; -} - -/** @brief Function to build command frame for recover. - * - * @return status code of recovery_status type. - */ -static enum recovery_status build_cmd_frame(void) -{ - uint16_t len = 0; - uint16_t wCrc = 0; - uint16_t writeOffset = 0; - - pr_debug(" %s Entry", __func__); - if (gphDnldNfc_DlSeqSz == 0) { - pr_err(" %s invalid params", __func__); - return STATUS_FAILED; - } - memset(g_recovery_frame.p_buffer, 0x00, MAX_FRAME_SIZE); - g_recovery_frame.len = 0; - if (g_recovery_info.bFrameSegmented == false) { - len = gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset]; - len <<= MSB_POS; - len |= gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset + 1]; - } else { - /* last frame was segmented frame - * read length reamaining length - */ - len = g_recovery_info.wRemChunkBytes; - } - if (len > MAX_DATA_SIZE) { - /* set remaining chunk */ - g_recovery_info.wRemChunkBytes = (len - MAX_DATA_SIZE); - len = MAX_DATA_SIZE; - /* set chunk bit to write in header */ - len = DL_SET_HDR_FRAGBIT(len); - g_recovery_frame.p_buffer[writeOffset++] = (len >> MSB_POS) & SHIFT_MASK; - g_recovery_frame.p_buffer[writeOffset++] = len & SHIFT_MASK; - /* clear chunk bit for length variable */ - len = DL_CLR_HDR_FRAGBIT(len); - /* first chunk of segmented frame*/ - if (!g_recovery_info.bFrameSegmented) { - /* ignore header from user buffer */ - g_recovery_info.currentReadOffset += FW_HDR_LEN; - g_recovery_info.remBytes -= FW_HDR_LEN; - } - g_recovery_frame.len += FW_HDR_LEN; - g_recovery_info.bFrameSegmented = true; - } else { - /* last chunk of segmented frame */ - if (g_recovery_info.bFrameSegmented) { - /* write header with user chunk length */ - g_recovery_frame.p_buffer[writeOffset++] = (len >> MSB_POS) & SHIFT_MASK; - g_recovery_frame.p_buffer[writeOffset++] = len & SHIFT_MASK; - g_recovery_frame.len += FW_HDR_LEN; - } else { - /* normal Frame with in supported size increase - * len to read header from user data - */ - len += FW_HDR_LEN; - } - g_recovery_info.wRemChunkBytes = 0; - g_recovery_info.bFrameSegmented = false; - } - if (((writeOffset + len) > MAX_FRAME_SIZE) || - ((g_recovery_info.currentReadOffset + len) > gphDnldNfc_DlSeqSz)) { - pr_err("%s frame offsets out of bound", __func__); - return STATUS_FAILED; - } - memcpy(&g_recovery_frame.p_buffer[writeOffset], - &gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset], len); - g_recovery_info.currentReadOffset += len; - g_recovery_frame.len += len; - writeOffset += len; - g_recovery_info.remBytes -= len; - wCrc = calcCrc16(g_recovery_frame.p_buffer, - g_recovery_frame.len); - g_recovery_frame.p_buffer[writeOffset++] = (wCrc >> MSB_POS) & SHIFT_MASK; - g_recovery_frame.p_buffer[writeOffset++] = wCrc & SHIFT_MASK; - g_recovery_frame.len += FW_CRC_LEN; - return STATUS_SUCCESS; -} - -/** @brief Function to transmit recovery frame. - * @param nfc_dev nfc driver object. - * @return status code of recovery_status type. - */ -static enum recovery_status transmit(struct nfc_dev *nfc_dev) -{ - int ret = 0; - int frame_resp_len = 0; - uint16_t respCRC = 0; - uint16_t respCRCOffset = 0; - uint8_t *rsp_buf = nfc_dev->read_kbuf; - - pr_debug("%s Entry", __func__); - if (nfc_dev == NULL || g_recovery_frame.len <= 0) { - pr_err("%s invalid Params", __func__); - return STATUS_FAILED; - } - ret = nfc_dev->nfc_write(nfc_dev, g_recovery_frame.p_buffer, - g_recovery_frame.len, MAX_RETRY_COUNT); - if (ret <= 0) { - pr_err(" %s: Write recovery frame error %d\n", __func__, ret); - return STATUS_FAILED; - } - pr_debug(" %s Reading response\n", __func__); - memset(rsp_buf, 0x00, MAX_BUFFER_SIZE); - ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, FW_HDR_LEN, NCI_CMD_RSP_TIMEOUT); - if (ret < FW_HDR_LEN) { - pr_err(" %s - Read recovery frame response error ret %d\n", __func__, ret); - return STATUS_FAILED; - } - if (rsp_buf[0] != FW_MSG_CMD_RSP || - rsp_buf[DL_FRAME_RESP_LEN_OFFSET] != DL_FRAME_RESP_LEN) { - pr_err("%s, invalid response", __func__); - return STATUS_FAILED; - } - frame_resp_len = rsp_buf[DL_FRAME_RESP_LEN_OFFSET] + FW_CRC_LEN; - ret = nfc_dev->nfc_read(nfc_dev, rsp_buf + FW_HDR_LEN, frame_resp_len, NCI_CMD_RSP_TIMEOUT); - if (ret < frame_resp_len) { - pr_err(" %s - Read recovery frame response error ret %d\n", __func__, ret); - return STATUS_FAILED; - } - pr_debug(" %s: recovery frame Response 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", - __func__, rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5]); - respCRCOffset = FW_HDR_LEN + rsp_buf[DL_FRAME_RESP_LEN_OFFSET]; - respCRC = rsp_buf[respCRCOffset++]; - respCRC <<= MSB_POS; - respCRC |= rsp_buf[respCRCOffset]; - if (respCRC != calcCrc16(rsp_buf, DL_FRAME_RESP_LEN + FW_HDR_LEN)) { - pr_err("%s, invalid response crc", __func__); - return STATUS_FAILED; - } - if (g_recovery_info.bFrameSegmented && - (rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT1 - && rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT2)) { - pr_err("%s, invalid stat flag in chunk response", __func__); - return STATUS_FAILED; - } - if (!g_recovery_info.bFrameSegmented && - rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_NON_SEGMENTED_FRAME_RESP_STAT) { - pr_err("%s, invalid stat flag in response", __func__); - return STATUS_FAILED; - } - return STATUS_SUCCESS; -} - -/** @brief Function to check input version with recovery fw version. - * @param fw_major_version: input major_version to check. - * @return true if input major_version matches with recovery fw major version - * otherwise returns false. - */ -static bool check_major_version(uint8_t fw_major_version) -{ - if (gphDnldNfc_DlSeqSz < RECOVERY_FW_MJ_VER_OFFSET) { - /* Recovery data corrupted */ - pr_err("%s Not able to extract major version from recovery fw\n", __func__); - return false; - } - return (fw_major_version == gphDnldNfc_DlSequence[RECOVERY_FW_MJ_VER_OFFSET]); -} - -/** @brief Function to recover the nfcc. - * @param nfc_dev nfc driver object. - * @return status code of type recovery_status. - */ -enum recovery_status do_recovery(struct nfc_dev *nfc_dev) -{ - enum recovery_status status = STATUS_SUCCESS; - - g_recovery_info.remBytes = gphDnldNfc_DlSeqSz; - g_recovery_info.currentReadOffset = 0; - g_recovery_info.bFrameSegmented = false; - g_recovery_info.wRemChunkBytes = 0; - g_recovery_frame.p_buffer = nfc_dev->write_kbuf; - pr_debug("%s Entry", __func__); - if (nfc_dev == NULL) { - pr_err("%s invalid params ", __func__); - return STATUS_FAILED; - } - if (!(check_major_version(nfc_dev->fw_major_version))) { - pr_err("%s unsupported version", __func__); - status = STATUS_FAILED; - goto EXIT_RECOVERY; - } - while (g_recovery_info.remBytes > 0) { - status = build_cmd_frame(); - if (status != STATUS_SUCCESS) { - pr_err(" %s Unable to create recovery frame"); - break; - } - status = transmit(nfc_dev); - if (status != STATUS_SUCCESS) { - pr_err(" %s Unable to send recovery frame"); - break; - } - } -EXIT_RECOVERY: - pr_info("%s Recovery done status %d", __func__, status); - return status; -} diff --git a/nfc/recovery_seq.h b/nfc/recovery_seq.h deleted file mode 100644 index c06d25c38a..0000000000 --- a/nfc/recovery_seq.h +++ /dev/null @@ -1,79 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2021 NXP - * * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#if IS_ENABLED(CONFIG_NXP_NFC_RECOVERY) - -#ifndef __RECOVERY_SEQ_H_ -#define __RECOVERY_SEQ_H_ - -#include "common.h" - -#define MAX_FRAME_SIZE 0x22A /* support for 256(0x100) & 554(0x22A) frame size*/ - -#define MAX_DATA_SIZE \ - (MAX_FRAME_SIZE - FW_CRC_LEN - FW_HDR_LEN) - -#define RECOVERY_FW_MJ_VER_OFFSET 5 - -#define DL_SET_HDR_FRAGBIT(n) \ - ((n) | (1 << 10)) /* Header chunk bit set macro */ -#define DL_CLR_HDR_FRAGBIT(n) \ - ((n) & ~(1U << 10)) /* Header chunk bit clear macro */ - -#define DL_FRAME_RESP_LEN 0x04 -#define DL_FRAME_RESP_LEN_OFFSET 1 -#define DL_FRAME_RESP_STAT_OFFSET 2 -#define DL_SEGMENTED_FRAME_RESP_STAT1 0x2D -#define DL_SEGMENTED_FRAME_RESP_STAT2 0x2E -#define DL_NON_SEGMENTED_FRAME_RESP_STAT 0x00 -#define DL_INVALID_CRC_VALUE 0xffffU -#define DL_CRC_MASK 0xff - -#define SHIFT_MASK 0x00FF -#define MSB_POS 8 - -/* Data buffer for frame to write */ -struct recovery_frame { - uint32_t len; - uint8_t *p_buffer; -}; - -/* Contains Info about user buffer and last data frame */ -struct recovery_info { - uint32_t currentReadOffset; /* current offset within the user buffer to read/write */ - uint32_t remBytes; /* Remaining bytes to write */ - uint16_t wRemChunkBytes; /* Remaining bytes within the chunked frame */ - bool bFrameSegmented; /* Indicates the current frame is segmented */ -}; - -/* indicates the error codes for nfc recovery module */ -enum recovery_status { - STATUS_SUCCESS = 0x00, - STATUS_FAILED = 0x01, -}; - -extern const uint32_t gphDnldNfc_DlSeqSz; /* Recovery user buffer size */ -extern const uint8_t gphDnldNfc_DlSequence[]; /* Recovery user buffer */ - -/** @brief Function to recover the nfcc. - * @param nfc_dev nfc driver object. - * @return status code of type recovery_status_t. - */ -enum recovery_status do_recovery(struct nfc_dev *nfc_dev); -#endif// end __RECOVERY_SEQ_H_ -#endif From f94d1b082c8fc4ecd0099fb32b0458d08c6632d5 Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Fri, 2 Jul 2021 17:51:36 +0530 Subject: [PATCH 041/100] Updated corresponding to - NFC_AR_00_E000_12.07.00_OpnSrc --- nfc/common.c | 39 +++++++++++++++++++++++++++++++++------ nfc/common.h | 2 ++ nfc/common_ese.c | 5 ++++- nfc/i2c_drv.c | 16 ++++++++++++++-- 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 30231f8c37..094eb40c81 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -224,7 +224,8 @@ int nfc_misc_register(struct nfc_dev *nfc_dev, * Device power control. Depending on the arg value, device moves to * different states, refer common.h for args * - * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case + * Return: -ENOIOCTLCMD if arg is not supported, 0 if Success(or no issue) + * and error ret code otherwise */ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) { @@ -293,7 +294,10 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) * * NFC and ESE Device power control, based on the argument value * - * Return: -ENOIOCTLCMD if arg is not supported, 0 or other in any other case + * Return: -ENOIOCTLCMD if arg is not supported + * 0 if Success(or no issue) + * 0 or 1 in case of arg is ESE_GET_PWR/ESE_POWER_STATE + * and error ret code otherwise */ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) { @@ -323,8 +327,8 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) int nfc_dev_open(struct inode *inode, struct file *filp) { - struct nfc_dev *nfc_dev = - container_of(inode->i_cdev, struct nfc_dev, c_dev); + struct nfc_dev *nfc_dev = NULL; + nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev); if (!nfc_dev) return -ENODEV; @@ -345,10 +349,33 @@ int nfc_dev_open(struct inode *inode, struct file *filp) return 0; } +int nfc_dev_flush(struct file *pfile, fl_owner_t id) +{ + struct nfc_dev *nfc_dev = pfile->private_data; + + if (!nfc_dev) + return -ENODEV; + /* + * release blocked user thread waiting for pending read during close + */ + if (!mutex_trylock(&nfc_dev->read_mutex)) { + nfc_dev->release_read = true; + nfc_dev->nfc_disable_intr(nfc_dev); + wake_up(&nfc_dev->read_wq); + pr_debug("%s: waiting for release of blocked read\n", __func__); + mutex_lock(&nfc_dev->read_mutex); + nfc_dev->release_read = false; + } else { + pr_debug("%s: read thread already released\n", __func__); + } + mutex_unlock(&nfc_dev->read_mutex); + return 0; +} + int nfc_dev_close(struct inode *inode, struct file *filp) { - struct nfc_dev *nfc_dev = - container_of(inode->i_cdev, struct nfc_dev, c_dev); + struct nfc_dev *nfc_dev = NULL; + nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev); if (!nfc_dev) return -ENODEV; diff --git a/nfc/common.h b/nfc/common.h index c96958fe3a..c4f3388ad7 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -177,6 +177,7 @@ struct nfc_dev { uint8_t nfc_state; /* NFC VEN pin state */ bool nfc_ven_enabled; + bool release_read; union { struct i2c_dev i2c_dev; }; @@ -193,6 +194,7 @@ struct nfc_dev { }; int nfc_dev_open(struct inode *inode, struct file *filp); +int nfc_dev_flush(struct file *pfile, fl_owner_t id); int nfc_dev_close(struct inode *inode, struct file *filp); long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, diff --git a/nfc/common_ese.c b/nfc/common_ese.c index 18b3d34e1f..0abfc1a0c1 100644 --- a/nfc/common_ese.c +++ b/nfc/common_ese.c @@ -261,7 +261,10 @@ err: * Device power control. Depending on the arg value, device moves to * different states, refer common_ese.h for args * - * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case + * Return: -ENOIOCTLCMD if arg is not supported + * 0 if Success(or no issue) + * 0 or 1 in case of arg is ESE_POWER_STATE + * and error ret code otherwise */ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) { diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 83a1ed5d9e..381ae3811b 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -128,7 +128,6 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) nfc_dev->read_wq, !i2c_dev->irq_enabled, msecs_to_jiffies(timeout)); - if (ret <= 0) { pr_err("%s: timeout error\n", __func__); @@ -154,6 +153,18 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) ret = -EIO; goto err; } + /* + * NFC service wanted to close the driver so, + * release the calling reader thread asap. + * + * This can happen in case of nfc node close call from + * eSE HAL in that case the NFC HAL reader thread + * will again call read system call + */ + if (nfc_dev->release_read) { + pr_debug("%s: releasing read\n", __func__); + return 0; + } pr_warn("%s: spurious interrupt detected\n", __func__); } } @@ -218,7 +229,7 @@ int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, break; } if (retry_cnt == MAX_WRITE_IRQ_COUNT && - gpio_get_value(nfc_gpio->irq)) { + gpio_get_value(nfc_gpio->irq)) { pr_warn("%s: allow after maximum wait\n", __func__); } } @@ -287,6 +298,7 @@ static const struct file_operations nfc_i2c_dev_fops = { .read = nfc_i2c_dev_read, .write = nfc_i2c_dev_write, .open = nfc_dev_open, + .flush = nfc_dev_flush, .release = nfc_dev_close, .unlocked_ioctl = nfc_dev_ioctl, }; From 6b429ad0d111cf147cb443d7a63cf672a4adcbea Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Thu, 19 Aug 2021 13:43:24 +0530 Subject: [PATCH 042/100] Updated corresponding to - NFC_AR_00_E800_12.0A.00_OpnSrc --- nfc/Kconfig | 13 +++++++++++++ nfc/i2c_drv.c | 11 ++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 nfc/Kconfig diff --git a/nfc/Kconfig b/nfc/Kconfig new file mode 100644 index 0000000000..facfd412a1 --- /dev/null +++ b/nfc/Kconfig @@ -0,0 +1,13 @@ +# +# near field communication driver configuration +# + +config NXP_NFC_I2C + tristate "NXP NCI based NFC I2C Slave Driver for SNxxx" + depends on I2C + help + This enables the NFC driver for SNxxx based devices. + This is for I2C connected version. NCI protocol logic + resides in the usermode and it has no other NFC dependencies. + + If unsure, say N. diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 381ae3811b..e65d1a8792 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -256,12 +256,13 @@ ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, size_t count, int ret; struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; - if (filp->f_flags & O_NONBLOCK) { - pr_err("%s: f_flags has nonblock. try again\n", __func__); - return -EAGAIN; - } mutex_lock(&nfc_dev->read_mutex); - ret = i2c_read(nfc_dev, nfc_dev->read_kbuf, count, 0); + if (filp->f_flags & O_NONBLOCK) { + ret = i2c_master_recv(nfc_dev->i2c_dev.client, nfc_dev->read_kbuf, count); + pr_debug("%s: NONBLOCK read ret = %d\n", __func__, ret); + } else { + ret = i2c_read(nfc_dev, nfc_dev->read_kbuf, count, 0); + } if (ret > 0) { if (copy_to_user(buf, nfc_dev->read_kbuf, ret)) { pr_warn("%s: failed to copy to user space\n", __func__); From 5e8c04a48dda6dfa4ec7230526db5d5f410464ac Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Thu, 7 Oct 2021 00:21:34 +0530 Subject: [PATCH 043/100] Updated corresponding to - NFC_AR_00_E800_12.0D.00_OpnSrc --- nfc/Kbuild | 6 ++++++ nfc/Makefile | 15 +++++++++------ nfc/common_ese.c | 3 --- 3 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 nfc/Kbuild diff --git a/nfc/Kbuild b/nfc/Kbuild new file mode 100644 index 0000000000..198d574a94 --- /dev/null +++ b/nfc/Kbuild @@ -0,0 +1,6 @@ +obj-$(CONFIG_NXP_NFC_I2C) := pn553_i2c.o + +pn553_i2c-y := common.o \ + common_ese.o \ + i2c_drv.o + diff --git a/nfc/Makefile b/nfc/Makefile index 16c477495a..4191dea226 100644 --- a/nfc/Makefile +++ b/nfc/Makefile @@ -1,7 +1,10 @@ -# -# Makefile for nfc devices -# -obj-$(CONFIG_NXP_NFC_I2C) += pn553_i2c.o -pn553_i2c-objs := common.o common_ese.o i2c_drv.o -#ccflags-y += -DDEBUG +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build +all: + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean diff --git a/nfc/common_ese.c b/nfc/common_ese.c index 0abfc1a0c1..c1795063d4 100644 --- a/nfc/common_ese.c +++ b/nfc/common_ese.c @@ -150,7 +150,6 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, { int ret = 0; int timeout = 0; - struct file filp; char *rsp = nfc_dev->read_kbuf; struct cold_reset *cold_reset = &nfc_dev->cold_reset; bool nfc_dev_opened = false; @@ -221,9 +220,7 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, } } else { /* Read response here as NFC thread is not active */ - filp.private_data = nfc_dev; if (nfc_dev->interface == PLATFORM_IF_I2C) { - filp.f_flags &= ~O_NONBLOCK; ret = nfc_dev->nfc_read(nfc_dev, rsp, 3, timeout); if (!ret) From a63df4ba2f0a4a794e05dfaa971982ab02c9471c Mon Sep 17 00:00:00 2001 From: Gerrit SelfHelp Service Account Date: Wed, 3 Nov 2021 10:49:21 -0700 Subject: [PATCH 044/100] Initial empty repository From e89ae5f94aab49b5c400196035a4b1ffc97c5244 Mon Sep 17 00:00:00 2001 From: Tapas Dey Date: Wed, 17 Nov 2021 12:00:44 +0530 Subject: [PATCH 045/100] NFC: FR72092, To move NFC module to vendor techpackage As a part FR72092 requirement, moved the NFC driver module out of kernel tree to be compiled as vendor techpackage. Change-Id: I177d81782a7059bf6b9b4556b384737708c43348 --- Android.bp | 7 + Android.mk | 14 + Kbuild | 15 + Kconfig | 10 + Makefile | 14 + config/gki_nfc.conf | 1 + config/gki_nfc_conf.h | 6 + include/uapi/linux/nfc/nfcinfo.h | 26 + nfc_kernel_dlkm_vendor_board.mk | 4 + nfc_kernel_dlkm_vendor_product.mk | 1 + qti/ese_cold_reset.c | 336 +++++++++++ qti/ese_cold_reset.h | 81 +++ qti/nfc_common.c | 951 ++++++++++++++++++++++++++++++ qti/nfc_common.h | 346 +++++++++++ qti/nfc_i2c_drv.c | 577 ++++++++++++++++++ qti/nfc_i2c_drv.h | 81 +++ 16 files changed, 2470 insertions(+) create mode 100644 Android.bp create mode 100644 Android.mk create mode 100644 Kbuild create mode 100644 Kconfig create mode 100644 Makefile create mode 100644 config/gki_nfc.conf create mode 100644 config/gki_nfc_conf.h create mode 100644 include/uapi/linux/nfc/nfcinfo.h create mode 100644 nfc_kernel_dlkm_vendor_board.mk create mode 100644 nfc_kernel_dlkm_vendor_product.mk create mode 100644 qti/ese_cold_reset.c create mode 100644 qti/ese_cold_reset.h create mode 100644 qti/nfc_common.c create mode 100644 qti/nfc_common.h create mode 100644 qti/nfc_i2c_drv.c create mode 100644 qti/nfc_i2c_drv.h diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000000..be32d9b7b1 --- /dev/null +++ b/Android.bp @@ -0,0 +1,7 @@ +cc_library_headers { + name: "qti_nfc_kernel_headers", + export_include_dirs: [ + "include/uapi/linux/nfc", + ], + vendor_available: true, +} diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000000..f5eb11e2ed --- /dev/null +++ b/Android.mk @@ -0,0 +1,14 @@ +# Android makefile for nfc kernel modules + +# Path to DLKM make scripts +DLKM_DIR := $(TOP)/device/qcom/common/dlkm + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := nfc_i2c.ko +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*) + +include $(DLKM_DIR)/Build_external_kernelmodule.mk diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000000..14531aecd4 --- /dev/null +++ b/Kbuild @@ -0,0 +1,15 @@ +#Makefile for qti nfc drivers + +include $(NFC_ROOT)/config/gki_nfc.conf + +LINUXINCLUDE += -I$(NFC_ROOT)/include/uapi/linux/nfc + +LINUXINCLUDE += -include $(NFC_ROOT)/config/gki_nfc_conf.h + +obj-$(CONFIG_NFC_QTI_I2C) += nfc_i2c.o + +#source files +nfc_i2c-objs += qti/ese_cold_reset.o \ + qti/nfc_common.o \ + qti/nfc_i2c_drv.o + diff --git a/Kconfig b/Kconfig new file mode 100644 index 0000000000..623e0ae0a0 --- /dev/null +++ b/Kconfig @@ -0,0 +1,10 @@ +menuconfig NFC_QTI_I2C + tristate "QTI NCI based NFC I2C Slave Driver for SNxxx" + depends on I2C + help + This enables the NFC driver for SNxxx based devices. + This is for I2C connected version. NCI protocol logic + resides in the usermode and it has no other NFC dependencies. + + If unsure, say N. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..2f7bcf4f7e --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +M ?= $(shell pwd) + +KBUILD_OPTIONS+= NFC_ROOT=$(KERNEL_SRC)/$(M) + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/config/gki_nfc.conf b/config/gki_nfc.conf new file mode 100644 index 0000000000..2e606798ec --- /dev/null +++ b/config/gki_nfc.conf @@ -0,0 +1 @@ +export CONFIG_NFC_QTI_I2C=m diff --git a/config/gki_nfc_conf.h b/config/gki_nfc_conf.h new file mode 100644 index 0000000000..745406be62 --- /dev/null +++ b/config/gki_nfc_conf.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_NFC_QTI_I2C 1 diff --git a/include/uapi/linux/nfc/nfcinfo.h b/include/uapi/linux/nfc/nfcinfo.h new file mode 100644 index 0000000000..aaf78b3928 --- /dev/null +++ b/include/uapi/linux/nfc/nfcinfo.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + */ + +#ifndef _UAPI_NFCINFO_H_ +#define _UAPI_NFCINFO_H_ + +#include + +#define NFCC_MAGIC 0xE9 +#define NFCC_GET_INFO _IOW(NFCC_MAGIC, 0x09, unsigned int) + +struct nqx_devinfo { + unsigned char chip_type; + unsigned char rom_version; + unsigned char fw_major; + unsigned char fw_minor; +}; + +union nqx_uinfo { + unsigned int i; + struct nqx_devinfo info; +}; + +#endif diff --git a/nfc_kernel_dlkm_vendor_board.mk b/nfc_kernel_dlkm_vendor_board.mk new file mode 100644 index 0000000000..933ebdca5d --- /dev/null +++ b/nfc_kernel_dlkm_vendor_board.mk @@ -0,0 +1,4 @@ +# Build NFC kernel driver +ifeq ($(call is-board-platform-in-list, kalama),true) +BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nfc_i2c.ko +endif diff --git a/nfc_kernel_dlkm_vendor_product.mk b/nfc_kernel_dlkm_vendor_product.mk new file mode 100644 index 0000000000..d8150bf3da --- /dev/null +++ b/nfc_kernel_dlkm_vendor_product.mk @@ -0,0 +1 @@ +PRODUCT_PACKAGES += nfc_i2c.ko diff --git a/qti/ese_cold_reset.c b/qti/ese_cold_reset.c new file mode 100644 index 0000000000..1c2a7c1c76 --- /dev/null +++ b/qti/ese_cold_reset.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include "nfc_common.h" + +/** + * send_ese_cmd() - Send eSE command to NFC controller. + * @nfc_dev: NFC device handle. + * + * Return: 0 on pass and negative value on failure. + */ +static int send_ese_cmd(struct nfc_dev *nfc_dev) +{ + int ret; + + if (nfc_dev->nfc_state == NFC_STATE_FW_DWL) { + dev_err(nfc_dev->nfc_device, + "cannot send ese cmd as FW download is in-progress\n"); + return -EBUSY; + } + if (!gpio_get_value(nfc_dev->configs.gpio.ven)) { + dev_err(nfc_dev->nfc_device, + "cannot send ese cmd as NFCC powered off\n"); + return -ENODEV; + } + + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->cold_reset.cmd_buf, + nfc_dev->cold_reset.cmd_len, + MAX_RETRY_COUNT); + if (ret <= 0) + dev_err(nfc_dev->nfc_device, + "%s: write failed after max retry, ret %d\n", + __func__, ret); + + return ret; +} + +/** + * read_cold_reset_rsp() - Read response of the cold reset command. + * @nfc_dev: NFC device handle. + * @header: Pointer to NCI header if it is already read. + * + * Return: 0 on pass and negative value on failure. + */ +int read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header) +{ + int ret = -EPERM; + struct cold_reset *cold_rst = &nfc_dev->cold_reset; + char *rsp_buf = NULL; + + rsp_buf = kzalloc(cold_rst->rsp_len, GFP_DMA | GFP_KERNEL); + if (!rsp_buf) + return -ENOMEM; + + /* + * read header if NFC is disabled + * for enable case, header is read by nfc read thread(for i2c) + */ + if ((!cold_rst->is_nfc_enabled) && + (nfc_dev->interface == PLATFORM_IF_I2C)) { + ret = i2c_master_recv(nfc_dev->i2c_dev.client, rsp_buf, NCI_HDR_LEN); + if (ret <= 0) { + dev_err(nfc_dev->nfc_device, + "%s: failure to read cold reset rsp header\n", + __func__); + ret = -EIO; + goto error; + } + /* + * return failure, if packet is not a response packet or + * if response's OID doesn't match with the CMD's OID + */ + if (!(rsp_buf[0] & NCI_RSP_PKT_TYPE) || + (rsp_buf[1] != cold_rst->cmd_buf[1])) { + + dev_err(nfc_dev->nfc_device, + "%s: - invalid cold reset response 0x%x 0x%x\n", + __func__, rsp_buf[0], rsp_buf[1]); + ret = -EINVAL; + goto error; + } + } else if (header) { + memcpy(rsp_buf, header, NCI_HDR_LEN); + } else { + dev_err(nfc_dev->nfc_device, + "%s: - invalid or NULL header\n", __func__); + ret = -EINVAL; + goto error; + } + + if ((NCI_HDR_LEN + rsp_buf[NCI_PAYLOAD_LEN_IDX]) > + cold_rst->rsp_len) { + dev_err(nfc_dev->nfc_device, + "%s: - no space for cold_reset resp\n", __func__); + ret = -ENOMEM; + goto error; + } + + if (nfc_dev->interface == PLATFORM_IF_I2C) { + ret = nfc_dev->nfc_read(nfc_dev, + &rsp_buf[NCI_PAYLOAD_IDX], + rsp_buf[NCI_PAYLOAD_LEN_IDX], + NCI_CMD_RSP_TIMEOUT); + + if (ret <= 0) { + dev_err(nfc_dev->nfc_device, + "%s: failure to read cold reset rsp payload\n", + __func__); + ret = -EIO; + goto error; + } + ret = cold_rst->status = rsp_buf[NCI_PAYLOAD_IDX]; + + pr_debug("nfc ese rsp hdr 0x%x 0x%x 0x%x, payload byte0 0x%x\n", + rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3]); + } + +error: + kfree(rsp_buf); + + return ret; +} + + +/** + * ese_cold_reset_ioctl() - This function handles the eSE cold reset ioctls. + * @nfc_dev: NFC device handle. + * @arg: ioctl argument. + * + * Return: 0 on pass and negative value on failure. + */ + +int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) +{ + int ret; + struct ese_ioctl_arg ioctl_arg; + + if (!arg) { + dev_err(nfc_dev->nfc_device, "arg is invalid\n"); + return -EINVAL; + } + + ret = copy_from_user((void *)&ioctl_arg, (const void *)arg, + sizeof(ioctl_arg)); + if (ret) { + dev_err(nfc_dev->nfc_device, + "ese ioctl arg copy from user failed\n"); + return -EFAULT; + } + + nfc_dev->cold_reset.arg = kzalloc(sizeof(struct ese_cold_reset_arg), + GFP_KERNEL); + if (!nfc_dev->cold_reset.arg) + return -ENOMEM; + + ret = copy_struct_from_user(nfc_dev->cold_reset.arg, + sizeof(struct ese_cold_reset_arg), + u64_to_user_ptr(ioctl_arg.buf), + sizeof(struct ese_cold_reset_arg)); + if (ret) { + dev_err(nfc_dev->nfc_device, + "ese ioctl arg buffer copy from user failed\n"); + + ret = -EFAULT; + goto err; + } + + switch (nfc_dev->cold_reset.arg->sub_cmd) { + + case ESE_COLD_RESET_DO: + + /* + * cold reset allowed during protection enable, only if the + * source is same as the one which enabled protection. + */ + if (nfc_dev->cold_reset.is_crp_en && + (nfc_dev->cold_reset.arg->src != + nfc_dev->cold_reset.last_src_ese_prot)) { + dev_err(nfc_dev->nfc_device, + "cold reset from %d denied, protection is on\n", + nfc_dev->cold_reset.arg->src); + ret = -EACCES; + goto err; + } + + nfc_dev->cold_reset.cmd_buf = kzalloc(COLD_RESET_CMD_LEN, + GFP_DMA | GFP_KERNEL); + if (!nfc_dev->cold_reset.cmd_buf) { + ret = -ENOMEM; + goto err; + } + + nfc_dev->cold_reset.cmd_buf[0] = PROP_NCI_CMD_GID; + nfc_dev->cold_reset.cmd_buf[1] = COLD_RESET_OID; + nfc_dev->cold_reset.cmd_buf[2] = COLD_RESET_CMD_PL_LEN; + nfc_dev->cold_reset.cmd_len = NCI_HDR_LEN + + COLD_RESET_CMD_PL_LEN; + nfc_dev->cold_reset.rsp_len = COLD_RESET_RSP_LEN; + break; + + case ESE_COLD_RESET_PROTECT_EN: + + if (nfc_dev->cold_reset.is_crp_en) { + if (nfc_dev->cold_reset.arg->src != + nfc_dev->cold_reset.last_src_ese_prot) { + dev_err(nfc_dev->nfc_device, + "ese protection enable denied\n"); + ret = -EACCES; + goto err; + } + pr_warn("ese protection already enabled\n"); + + ret = 0; + /* free buffers and exit with pass */ + goto err; + } + + case ESE_COLD_RESET_PROTECT_DIS: + + if (nfc_dev->cold_reset.is_crp_en && + nfc_dev->cold_reset.arg->src != + nfc_dev->cold_reset.last_src_ese_prot) { + pr_err("ese cold reset protection disable denied\n"); + ret = -EACCES; + goto err; + } + nfc_dev->cold_reset.cmd_buf = kzalloc(COLD_RESET_PROT_CMD_LEN, + GFP_DMA | GFP_KERNEL); + if (!nfc_dev->cold_reset.cmd_buf) { + ret = -ENOMEM; + goto err; + } + + nfc_dev->cold_reset.cmd_buf[0] = PROP_NCI_CMD_GID; + nfc_dev->cold_reset.cmd_buf[1] = COLD_RESET_PROT_OID; + nfc_dev->cold_reset.cmd_buf[2] = COLD_RESET_PROT_CMD_PL_LEN; + nfc_dev->cold_reset.cmd_len = NCI_HDR_LEN + + COLD_RESET_PROT_CMD_PL_LEN; + nfc_dev->cold_reset.rsp_len = COLD_RESET_PROT_RSP_LEN; + if (nfc_dev->cold_reset.arg->sub_cmd == + ESE_COLD_RESET_PROTECT_EN) + nfc_dev->cold_reset.cmd_buf[3] = 0x1; + else + nfc_dev->cold_reset.cmd_buf[3] = 0x0; + + break; + + default: + pr_err("%s invalid ese ioctl sub cmd %d\n", __func__, + nfc_dev->cold_reset.arg->sub_cmd); + ret = -ENOIOCTLCMD; + goto err; + } + + pr_debug("nfc ese cmd hdr 0x%x 0x%x 0x%x\n", + nfc_dev->cold_reset.cmd_buf[0], + nfc_dev->cold_reset.cmd_buf[1], + nfc_dev->cold_reset.cmd_buf[2]); + + ret = send_ese_cmd(nfc_dev); + if (ret <= 0) { + pr_err("failed to send ese command\n"); + goto err; + } + + nfc_dev->cold_reset.rsp_pending = true; + + /* check if NFC is enabled */ + if (nfc_dev->cold_reset.is_nfc_enabled) { + /* + * nfc_read thread will initiate cold reset response + * and it will signal for data available + */ + wait_event_interruptible(nfc_dev->cold_reset.read_wq, + !nfc_dev->cold_reset.rsp_pending); + } else { + + /* + * Read data as NFC read thread is not active + */ + + if (nfc_dev->interface == PLATFORM_IF_I2C) { + ret = is_nfc_data_available_for_read(nfc_dev); + if (ret <= 0) { + nfc_dev->nfc_disable_intr(nfc_dev); + nfc_dev->cold_reset.rsp_pending = false; + goto err; + } + + ret = read_cold_reset_rsp(nfc_dev, NULL); + nfc_dev->cold_reset.rsp_pending = false; + if (ret < 0) { + pr_err("%s rsp read err\n", __func__); + goto err; + } + } else { + /* + * Enable intr as it is disabled when NFC is in disable + * state + */ + nfc_dev->nfc_enable_intr(nfc_dev); + + wait_event_interruptible( + nfc_dev->cold_reset.read_wq, + !nfc_dev->cold_reset.rsp_pending); + } + + nfc_dev->nfc_disable_intr(nfc_dev); + } + + if (nfc_dev->cold_reset.arg->sub_cmd == ESE_COLD_RESET_PROTECT_EN) { + nfc_dev->cold_reset.is_crp_en = true; + nfc_dev->cold_reset.last_src_ese_prot = + nfc_dev->cold_reset.arg->src; + } else if (nfc_dev->cold_reset.arg->sub_cmd == + ESE_COLD_RESET_PROTECT_DIS) { + nfc_dev->cold_reset.is_crp_en = false; + nfc_dev->cold_reset.last_src_ese_prot = + ESE_COLD_RESET_ORIGIN_NONE; + } else + pr_debug("ese cmd is %d\n", nfc_dev->cold_reset.arg->sub_cmd); + + ret = nfc_dev->cold_reset.status; +err: + kfree(nfc_dev->cold_reset.cmd_buf); + kfree(nfc_dev->cold_reset.arg); + nfc_dev->cold_reset.arg = NULL; + nfc_dev->cold_reset.cmd_buf = NULL; + + return ret; +} diff --git a/qti/ese_cold_reset.h b/qti/ese_cold_reset.h new file mode 100644 index 0000000000..f009d16f18 --- /dev/null +++ b/qti/ese_cold_reset.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + */ + +#ifndef __ESE_COLD_RESET_H +#define __ESE_COLD_RESET_H + +#include + +#define MAX_BUFF_SIZE 264 + +/* ESE_COLD_RESET MACROS */ +#define COLD_RESET_CMD_LEN 3 +#define COLD_RESET_RSP_LEN 4 +#define COLD_RESET_PROT_CMD_LEN 4 +#define COLD_RESET_PROT_RSP_LEN 4 +#define PROP_NCI_CMD_GID 0x2F +#define COLD_RESET_CMD_PL_LEN 0x00 +#define COLD_RESET_PROT_CMD_PL_LEN 0x01 +#define PROP_NCI_RSP_GID 0x4F +#define COLD_RESET_OID 0x1E +#define COLD_RESET_PROT_OID 0x1F + +#define ESE_COLD_RESET _IOWR(NFCC_MAGIC, 0x08, struct ese_ioctl_arg) + +enum ese_ioctl_arg_type { + ESE_ARG_TYPE_COLD_RESET = 0, +}; + +/* ESE_COLD_RESET ioctl origin, max 4 are supported */ +enum ese_cold_reset_origin { + ESE_COLD_RESET_ORIGIN_ESE = 0, + ESE_COLD_RESET_ORIGIN_NFC, + ESE_COLD_RESET_ORIGIN_OTHER = 0x20, + ESE_COLD_RESET_ORIGIN_NONE = 0xFF, +}; + +/* ESE_COLD_RESET ioctl sub commands, max 8 are supported */ +enum ese_cold_reset_sub_cmd { + ESE_COLD_RESET_DO = 0, + ESE_COLD_RESET_PROTECT_EN, + ESE_COLD_RESET_PROTECT_DIS, +}; + +/* Data passed in buf of ese cold reset ioctl */ +struct ese_cold_reset_arg { + __u8 src; + __u8 sub_cmd; + __u16 rfu; +}; + +/* Argument buffer passed to ese ioctl */ +struct ese_ioctl_arg { + __u64 buf; + __u32 buf_size; + __u8 type; +}; + +/* Features specific Parameters */ +struct cold_reset { + wait_queue_head_t read_wq; + char *cmd_buf; + struct ese_cold_reset_arg *arg; + uint16_t cmd_len; + uint16_t rsp_len; + /* Source of last ese protection command */ + uint8_t last_src_ese_prot; + uint8_t status; + /* Is cold reset protection enabled */ + bool is_crp_en; + bool rsp_pending; + /* Is NFC enabled from UI */ + bool is_nfc_enabled; +}; + +struct nfc_dev; +int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg); +int read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header); + +#endif diff --git a/qti/nfc_common.c b/qti/nfc_common.c new file mode 100644 index 0000000000..6db09e212f --- /dev/null +++ b/qti/nfc_common.c @@ -0,0 +1,951 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021 NXP + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include "nfc_common.h" + +int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, + uint8_t interface) +{ + int ret; + struct device_node *np = dev->of_node; + struct platform_gpio *nfc_gpio = &nfc_configs->gpio; + struct platform_ldo *ldo = &nfc_configs->ldo; + + if (!np) { + pr_err("nfc of_node NULL\n"); + return -EINVAL; + } + + nfc_gpio->irq = -EINVAL; + nfc_gpio->dwl_req = -EINVAL; + nfc_gpio->ven = -EINVAL; + nfc_gpio->clkreq = -EINVAL; + + /* required for i2c based chips only */ + if (interface == PLATFORM_IF_I2C) { + nfc_gpio->irq = of_get_named_gpio(np, DTS_IRQ_GPIO_STR, 0); + if ((!gpio_is_valid(nfc_gpio->irq))) { + pr_err("nfc irq gpio invalid %d\n", nfc_gpio->irq); + return -EINVAL; + } + pr_info("%s: irq %d\n", __func__, nfc_gpio->irq); + } + nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); + if ((!gpio_is_valid(nfc_gpio->ven))) { + pr_err("nfc ven gpio invalid %d\n", nfc_gpio->ven); + return -EINVAL; + } + + nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); + + /* not returning failure for dwl gpio as it is optional for sn220 */ + if ((!gpio_is_valid(nfc_gpio->dwl_req))) + pr_warn("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req); + + nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0); + if (!gpio_is_valid(nfc_gpio->clkreq)) { + dev_err(dev, "clkreq gpio invalid %d\n", nfc_gpio->dwl_req); + return -EINVAL; + } + + pr_info("%s: ven %d, dwl req %d, clkreq %d\n", __func__, + nfc_gpio->ven, nfc_gpio->dwl_req, nfc_gpio->clkreq); + + // optional property + ret = of_property_read_u32_array(np, NFC_LDO_VOL_DT_NAME, + (u32 *) ldo->vdd_levels, + ARRAY_SIZE(ldo->vdd_levels)); + if (ret) { + dev_err(dev, "error reading NFC VDDIO min and max value\n"); + // set default as per datasheet + ldo->vdd_levels[0] = NFC_VDDIO_MIN; + ldo->vdd_levels[1] = NFC_VDDIO_MAX; + } + + // optional property + ret = of_property_read_u32(np, NFC_LDO_CUR_DT_NAME, &ldo->max_current); + if (ret) { + dev_err(dev, "error reading NFC current value\n"); + // set default as per datasheet + ldo->max_current = NFC_CURRENT_MAX; + } + + return 0; +} + +/** + * nfc_ldo_vote() + * @nfc_dev: NFC device containing regulator handle + * + * LDO voting based on voltage and current entries in DT + * + * Return: 0 on success and -ve on failure + */ +int nfc_ldo_vote(struct nfc_dev *nfc_dev) +{ + int ret; + + ret = regulator_set_voltage(nfc_dev->reg, + nfc_dev->configs.ldo.vdd_levels[0], + nfc_dev->configs.ldo.vdd_levels[1]); + if (ret < 0) { + pr_err("%s: set voltage failed\n", __func__); + return ret; + } + + /* pass expected current from NFC in uA */ + ret = regulator_set_load(nfc_dev->reg, nfc_dev->configs.ldo.max_current); + if (ret < 0) { + pr_err("%s: set load failed\n", __func__); + return ret; + } + + ret = regulator_enable(nfc_dev->reg); + if (ret < 0) + pr_err("%s: regulator_enable failed\n", __func__); + else + nfc_dev->is_vreg_enabled = true; + return ret; +} + +/** + * nfc_ldo_config() + * @dev: device instance to read DT entry + * @nfc_dev: NFC device containing regulator handle + * + * Configure LDO if entry is present in DT file otherwise + * return with success as it's optional + * + * Return: 0 on success and -ve on failure + */ +int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev) +{ + int ret; + + if (of_get_property(dev->of_node, NFC_LDO_SUPPLY_NAME, NULL)) { + // Get the regulator handle + nfc_dev->reg = regulator_get(dev, NFC_LDO_SUPPLY_DT_NAME); + if (IS_ERR(nfc_dev->reg)) { + ret = PTR_ERR(nfc_dev->reg); + nfc_dev->reg = NULL; + pr_err("%s: regulator_get failed, ret = %d\n", + __func__, ret); + return ret; + } + } else { + nfc_dev->reg = NULL; + pr_err("%s: regulator entry not present\n", __func__); + // return success as it's optional to configure LDO + return 0; + } + + // LDO config supported by platform DT + ret = nfc_ldo_vote(nfc_dev); + if (ret < 0) { + pr_err("%s: LDO voting failed, ret = %d\n", __func__, ret); + regulator_put(nfc_dev->reg); + } + return ret; +} + +/** + * nfc_ldo_unvote() + * @nfc_dev: NFC device containing regulator handle + * + * set voltage and load to zero and disable regulator + * + * Return: 0 on success and -ve on failure + */ +int nfc_ldo_unvote(struct nfc_dev *nfc_dev) +{ + int ret; + + if (!nfc_dev->is_vreg_enabled) { + pr_err("%s: regulator already disabled\n", __func__); + return -EINVAL; + } + + ret = regulator_disable(nfc_dev->reg); + if (ret < 0) { + pr_err("%s: regulator_disable failed\n", __func__); + return ret; + } + nfc_dev->is_vreg_enabled = false; + + ret = regulator_set_voltage(nfc_dev->reg, 0, NFC_VDDIO_MAX); + if (ret < 0) { + pr_err("%s: set voltage failed\n", __func__); + return ret; + } + + ret = regulator_set_load(nfc_dev->reg, 0); + if (ret < 0) + pr_err("%s: set load failed\n", __func__); + return ret; +} + +void set_valid_gpio(int gpio, int value) +{ + if (gpio_is_valid(gpio)) { + pr_debug("%s gpio %d value %d\n", __func__, gpio, value); + gpio_set_value(gpio, value); + /* hardware dependent delay */ + usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, + NFC_GPIO_SET_WAIT_TIME_USEC + 100); + } +} + +int get_valid_gpio(int gpio) +{ + int value = -EINVAL; + + if (gpio_is_valid(gpio)) { + value = gpio_get_value(gpio); + pr_debug("%s gpio %d value %d\n", __func__, gpio, value); + } + return value; +} + +void gpio_set_ven(struct nfc_dev *nfc_dev, int value) +{ + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + if (gpio_get_value(nfc_gpio->ven) != value) { + pr_debug("%s: value %d\n", __func__, value); + + gpio_set_value(nfc_gpio->ven, value); + /* hardware dependent delay */ + usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, + NFC_GPIO_SET_WAIT_TIME_USEC + 100); + } +} + +int configure_gpio(unsigned int gpio, int flag) +{ + int ret; + + pr_debug("%s: nfc gpio [%d] flag [%01x]\n", __func__, gpio, flag); + + if (gpio_is_valid(gpio)) { + ret = gpio_request(gpio, "nfc_gpio"); + if (ret) { + pr_err("%s: unable to request nfc gpio [%d]\n", + __func__, gpio); + return ret; + } + /* set direction and value for output pin */ + if (flag & GPIO_OUTPUT) { + ret = gpio_direction_output(gpio, (GPIO_HIGH & flag)); + pr_debug("nfc o/p gpio %d level %d\n", gpio, gpio_get_value(gpio)); + } else { + ret = gpio_direction_input(gpio); + pr_debug("nfc i/p gpio %d\n", gpio); + } + + if (ret) { + pr_err + ("%s: unable to set direction for nfc gpio [%d]\n", + __func__, gpio); + gpio_free(gpio); + return ret; + } + // Consider value as control for input IRQ pin + if (flag & GPIO_IRQ) { + ret = gpio_to_irq(gpio); + if (ret < 0) { + pr_err("%s: unable to set irq for nfc gpio [%d]\n", + __func__, gpio); + gpio_free(gpio); + return ret; + } + pr_debug + ("%s: gpio_to_irq successful [%d]\n", + __func__, gpio); + return ret; + } + } else { + pr_err("%s: invalid gpio\n", __func__); + ret = -EINVAL; + } + return ret; +} + +void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count) +{ + pr_debug("%s: entry\n", __func__); + + kfree(nfc_dev->kbuf); + device_destroy(nfc_dev->nfc_class, nfc_dev->devno); + cdev_del(&nfc_dev->c_dev); + class_destroy(nfc_dev->nfc_class); + unregister_chrdev_region(nfc_dev->devno, count); + if (nfc_dev->ipcl) + ipc_log_context_destroy(nfc_dev->ipcl); +} + +int nfc_misc_register(struct nfc_dev *nfc_dev, + const struct file_operations *nfc_fops, int count, + char *devname, char *classname) +{ + int ret = 0; + + ret = alloc_chrdev_region(&nfc_dev->devno, 0, count, devname); + if (ret < 0) { + pr_err("%s: failed to alloc chrdev region ret %d\n", + __func__, ret); + return ret; + } + nfc_dev->nfc_class = class_create(THIS_MODULE, classname); + if (IS_ERR(nfc_dev->nfc_class)) { + ret = PTR_ERR(nfc_dev->nfc_class); + pr_err("%s: failed to register device class ret %d\n", + __func__, ret); + unregister_chrdev_region(nfc_dev->devno, count); + return ret; + } + cdev_init(&nfc_dev->c_dev, nfc_fops); + ret = cdev_add(&nfc_dev->c_dev, nfc_dev->devno, count); + if (ret < 0) { + pr_err("%s: failed to add cdev ret %d\n", __func__, ret); + class_destroy(nfc_dev->nfc_class); + unregister_chrdev_region(nfc_dev->devno, count); + return ret; + } + nfc_dev->nfc_device = device_create(nfc_dev->nfc_class, NULL, + nfc_dev->devno, nfc_dev, devname); + if (IS_ERR(nfc_dev->nfc_device)) { + ret = PTR_ERR(nfc_dev->nfc_device); + pr_err("%s: failed to create the device ret %d\n", + __func__, ret); + cdev_del(&nfc_dev->c_dev); + class_destroy(nfc_dev->nfc_class); + unregister_chrdev_region(nfc_dev->devno, count); + return ret; + } + + nfc_dev->ipcl = ipc_log_context_create(NUM_OF_IPC_LOG_PAGES, + dev_name(nfc_dev->nfc_device), 0); + + nfc_dev->kbuflen = MAX_BUFFER_SIZE; + nfc_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); + if (!nfc_dev->kbuf) { + nfc_misc_unregister(nfc_dev, count); + return -ENOMEM; + } + + nfc_dev->cold_reset.rsp_pending = false; + nfc_dev->cold_reset.is_nfc_enabled = false; + nfc_dev->cold_reset.is_crp_en = false; + nfc_dev->cold_reset.last_src_ese_prot = ESE_COLD_RESET_ORIGIN_NONE; + + init_waitqueue_head(&nfc_dev->cold_reset.read_wq); + + return 0; +} + +/* + * Power management of the eSE + * eSE and NFCC both are powered using VEN gpio, + * VEN HIGH - eSE and NFCC both are powered on + * VEN LOW - eSE and NFCC both are power down + */ +int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) +{ + int ret = 0; + + if (arg == ESE_POWER_ON) { + /* + * Let's store the NFC VEN pin state + * will check stored value in case of eSE power off request, + * to find out if NFC MW also sent request to set VEN HIGH + * VEN state will remain HIGH if NFC is enabled otherwise + * it will be set as LOW + */ + nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_dev->configs.gpio.ven); + if (!nfc_dev->nfc_ven_enabled) { + pr_debug("eSE HAL service setting ven HIGH\n"); + gpio_set_ven(nfc_dev, 1); + } else { + pr_debug("ven already HIGH\n"); + } + nfc_dev->is_ese_session_active = true; + } else if (arg == ESE_POWER_OFF) { + if (!nfc_dev->nfc_ven_enabled) { + pr_debug("NFC not enabled, disabling ven\n"); + gpio_set_ven(nfc_dev, 0); + } else { + pr_debug("keep ven high as NFC is enabled\n"); + } + nfc_dev->is_ese_session_active = false; + } else if (arg == ESE_POWER_STATE) { + /* get VEN gpio state for eSE, as eSE also enabled through same GPIO */ + ret = gpio_get_value(nfc_dev->configs.gpio.ven); + } else { + pr_err("%s bad arg %lu\n", __func__, arg); + ret = -ENOIOCTLCMD; + } + return ret; +} + +/* + * nfc_ioctl_power_states() - power control + * @nfc_dev: nfc device data structure + * @arg: mode that we want to move to + * + * Device power control. Depending on the arg value, device moves to + * different states, refer nfcc_ioctl_request in nfc_common.h for args + * + * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case + */ +static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) +{ + int ret = 0; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + if (arg == NFC_POWER_OFF) { + /* + * We are attempting a hardware reset so let us disable + * interrupts to avoid spurious notifications to upper + * layers. + */ + nfc_dev->nfc_disable_intr(nfc_dev); + set_valid_gpio(nfc_gpio->dwl_req, 0); + gpio_set_ven(nfc_dev, 0); + nfc_dev->nfc_ven_enabled = false; + + } else if (arg == NFC_POWER_ON) { + nfc_dev->nfc_enable_intr(nfc_dev); + set_valid_gpio(nfc_gpio->dwl_req, 0); + + gpio_set_ven(nfc_dev, 1); + nfc_dev->nfc_ven_enabled = true; + + } else if (arg == NFC_FW_DWL_VEN_TOGGLE) { + /* + * We are switching to download Mode, toggle the enable pin + * in order to set the NFCC in the new mode + */ + nfc_dev->nfc_disable_intr(nfc_dev); + set_valid_gpio(nfc_gpio->dwl_req, 1); + nfc_dev->nfc_state = NFC_STATE_FW_DWL; + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + nfc_dev->nfc_enable_intr(nfc_dev); + } else if (arg == NFC_FW_DWL_HIGH) { + /* + * Setting firmware download gpio to HIGH + * before FW download start + */ + pr_debug("set fw gpio high\n"); + set_valid_gpio(nfc_gpio->dwl_req, 1); + nfc_dev->nfc_state = NFC_STATE_FW_DWL; + + } else if (arg == NFC_VEN_FORCED_HARD_RESET) { + nfc_dev->nfc_disable_intr(nfc_dev); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + nfc_dev->nfc_enable_intr(nfc_dev); + pr_info("%s VEN forced reset done\n", __func__); + + } else if (arg == NFC_FW_DWL_LOW) { + /* + * Setting firmware download gpio to LOW + * FW download finished + */ + pr_debug("set fw gpio LOW\n"); + set_valid_gpio(nfc_gpio->dwl_req, 0); + nfc_dev->nfc_state = NFC_STATE_NCI; + + } else if (arg == NFC_ENABLE) { + /* + * Setting flag true when NFC is enabled + */ + nfc_dev->cold_reset.is_nfc_enabled = true; + } else if (arg == NFC_DISABLE) { + /* + * Setting flag true when NFC is disabled + */ + nfc_dev->cold_reset.is_nfc_enabled = false; + } else { + pr_err("%s bad arg %lu\n", __func__, arg); + ret = -ENOIOCTLCMD; + } + return ret; +} + +/* + * Inside nfc_ioctl_nfcc_info + * + * @brief nfc_ioctl_nfcc_info + * + * Check the NFC Chipset and firmware version details + */ +unsigned int nfc_ioctl_nfcc_info(struct file *filp, unsigned long arg) +{ + unsigned int r = 0; + struct nfc_dev *nfc_dev = filp->private_data; + + r = nfc_dev->nqx_info.i; + pr_debug("nfc : %s r = 0x%x\n", __func__, r); + + return r; +} + +/** @brief IOCTL function to be used to set or get data from upper layer. + * + * @param pfile fil node for opened device. + * @cmd IOCTL type from upper layer. + * @arg IOCTL arg from upper layer. + * + * @return 0 on success, error code for failures. + */ +long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct nfc_dev *nfc_dev = pfile->private_data; + + if (!nfc_dev) + return -ENODEV; + + pr_debug("%s cmd = %x arg = %zx\n", __func__, cmd, arg); + + switch (cmd) { + case NFC_SET_PWR: + ret = nfc_ioctl_power_states(nfc_dev, arg); + break; + case ESE_SET_PWR: + ret = nfc_ese_pwr(nfc_dev, arg); + break; + case ESE_GET_PWR: + ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE); + break; + case NFCC_GET_INFO: + ret = nfc_ioctl_nfcc_info(pfile, arg); + break; + case NFC_GET_PLATFORM_TYPE: + ret = nfc_dev->interface; + break; + case ESE_COLD_RESET: + pr_debug("nfc ese cold reset ioctl\n"); + ret = ese_cold_reset_ioctl(nfc_dev, arg); + break; + case NFC_GET_IRQ_STATE: + ret = gpio_get_value(nfc_dev->configs.gpio.irq); + break; + default: + pr_err("%s Unsupported ioctl cmd 0x%x, arg %lu\n", + __func__, cmd, arg); + ret = -ENOIOCTLCMD; + } + return ret; +} + +int nfc_dev_open(struct inode *inode, struct file *filp) +{ + struct nfc_dev *nfc_dev = container_of(inode->i_cdev, + struct nfc_dev, c_dev); + + if (!nfc_dev) + return -ENODEV; + + pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); + + mutex_lock(&nfc_dev->dev_ref_mutex); + + filp->private_data = nfc_dev; + + if (nfc_dev->dev_ref_count == 0) { + set_valid_gpio(nfc_dev->configs.gpio.dwl_req, 0); + nfc_dev->nfc_enable_intr(nfc_dev); + } + nfc_dev->dev_ref_count = nfc_dev->dev_ref_count + 1; + + mutex_unlock(&nfc_dev->dev_ref_mutex); + + return 0; +} + +int nfc_dev_close(struct inode *inode, struct file *filp) +{ + struct nfc_dev *nfc_dev = container_of(inode->i_cdev, + struct nfc_dev, c_dev); + + if (!nfc_dev) + return -ENODEV; + + pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); + + mutex_lock(&nfc_dev->dev_ref_mutex); + + if (nfc_dev->dev_ref_count == 1) { + nfc_dev->nfc_disable_intr(nfc_dev); + set_valid_gpio(nfc_dev->configs.gpio.dwl_req, 0); + } + + if (nfc_dev->dev_ref_count > 0) + nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; + + filp->private_data = NULL; + + mutex_unlock(&nfc_dev->dev_ref_mutex); + + return 0; +} + +int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev) +{ + int ret; + + nfc_dev->nfc_enable_intr(nfc_dev); + + ret = wait_event_interruptible_timeout(nfc_dev->read_wq, + !nfc_dev->i2c_dev.irq_enabled, + msecs_to_jiffies(MAX_IRQ_WAIT_TIME)); + return ret; +} + +/** + * get_nfcc_chip_type_dl() - get chip type in fw download command; + * @nfc_dev: nfc device data structure + * + * Perform get version command and determine chip + * type from response. + * + * @Return: enum chip_types value + * + */ +static enum chip_types get_nfcc_chip_type_dl(struct nfc_dev *nfc_dev) +{ + int ret = 0; + uint8_t *cmd = nfc_dev->write_kbuf; + uint8_t *rsp = nfc_dev->read_kbuf; + enum chip_types chip_type = CHIP_UNKNOWN; + + *cmd++ = DL_CMD; + *cmd++ = DL_GET_VERSION_CMD_PAYLOAD_LEN; + *cmd++ = DL_GET_VERSION_CMD_ID; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_GET_VERSION_CMD_CRC_1; + *cmd++ = DL_GET_VERSION_CMD_CRC_2; + + pr_debug("%s:Sending GET_VERSION cmd of size = %d\n", __func__, DL_GET_VERSION_CMD_LEN); + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, DL_GET_VERSION_CMD_LEN, + MAX_RETRY_COUNT); + if (ret <= 0) { + pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret); + goto err; + } + memset(rsp, 0x00, DL_GET_VERSION_RSP_LEN_2); + pr_debug("%s:Reading response of GET_VERSION cmd\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_VERSION_RSP_LEN_2, NCI_CMD_RSP_TIMEOUT); + if (ret <= 0) { + pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret); + goto err; + } + if (rsp[0] == FW_MSG_CMD_RSP && ret >= DL_GET_VERSION_RSP_LEN_2) { + + nfc_dev->fw_major_version = rsp[FW_MAJOR_VER_OFFSET]; + + if (rsp[FW_ROM_CODE_VER_OFFSET] == SN1XX_ROM_VER && + rsp[FW_MAJOR_VER_OFFSET] == SN1xx_MAJOR_VER) + chip_type = CHIP_SN1XX; + else if (rsp[FW_ROM_CODE_VER_OFFSET] == SN220_ROM_VER && + rsp[FW_MAJOR_VER_OFFSET] == SN220_MAJOR_VER) + chip_type = CHIP_SN220; + + pr_debug("%s:NFC Chip Type 0x%02x Rom Version 0x%02x FW Minor 0x%02x Major 0x%02x\n", + __func__, rsp[GET_VERSION_RSP_CHIP_TYPE_OFFSET], + rsp[FW_ROM_CODE_VER_OFFSET], + rsp[GET_VERSION_RSP_MINOR_VERSION_OFFSET], + rsp[FW_MAJOR_VER_OFFSET]); + + nfc_dev->nqx_info.info.chip_type = rsp[GET_VERSION_RSP_CHIP_TYPE_OFFSET]; + nfc_dev->nqx_info.info.rom_version = rsp[FW_ROM_CODE_VER_OFFSET]; + nfc_dev->nqx_info.info.fw_minor = rsp[GET_VERSION_RSP_MINOR_VERSION_OFFSET]; + nfc_dev->nqx_info.info.fw_major = rsp[FW_MAJOR_VER_OFFSET]; + } +err: + return chip_type; +} + +/** + * get_nfcc_session_state_dl() - gets the session state + * @nfc_dev: nfc device data structure + * + * Performs get session command and determine + * the nfcc state based on session status. + * + * @Return nfcc state based on session status. + * NFC_STATE_FW_TEARED if sessionis not closed + * NFC_STATE_FW_DWL if session closed + * NFC_STATE_UNKNOWN in error cases. + */ +enum nfc_state_flags get_nfcc_session_state_dl(struct nfc_dev *nfc_dev) +{ + int ret = 0; + uint8_t *cmd = nfc_dev->write_kbuf; + uint8_t *rsp = nfc_dev->read_kbuf; + enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN; + + *cmd++ = DL_CMD; + *cmd++ = DL_GET_SESSION_STATE_CMD_PAYLOAD_LEN; + *cmd++ = DL_GET_SESSION_CMD_ID; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_GET_SESSION_CMD_CRC_1; + *cmd++ = DL_GET_SESSION_CMD_CRC_2; + + pr_debug("%s:Sending GET_SESSION_STATE cmd of size = %d\n", __func__, + DL_GET_SESSION_STATE_CMD_LEN); + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, DL_GET_SESSION_STATE_CMD_LEN, + MAX_RETRY_COUNT); + if (ret <= 0) { + pr_err("%s: - nfc get session cmd error ret %d\n", __func__, ret); + goto err; + } + memset(rsp, 0x00, DL_GET_SESSION_STATE_RSP_LEN); + pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT); + if (ret <= 0) { + pr_err("%s: - nfc get session rsp error ret %d\n", __func__, ret); + goto err; + } + if (rsp[0] != FW_MSG_CMD_RSP) { + pr_err("%s: - nfc invalid get session state rsp\n", __func__); + goto err; + } + pr_debug("Response bytes are %02x%02x%02x%02x%02x%02x%02x%02x\n", + rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6], rsp[7]); + /*verify fw in non-teared state */ + if (rsp[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) { + pr_err("%s NFCC booted in FW teared state\n", __func__); + nfc_state = NFC_STATE_FW_TEARED; + } else { + pr_info("%s NFCC booted in FW DN mode\n", __func__); + nfc_state = NFC_STATE_FW_DWL; + } +err: + return nfc_state; +} + +/** + * get_nfcc_chip_type() - get nfcc chip type in nci mode. + * @nfc_dev: nfc device data structure. + * + * Function to perform nci core reset and extract + * chip type from the response. + * + * @Return: enum chip_types value + * + */ +static enum chip_types get_nfcc_chip_type(struct nfc_dev *nfc_dev) +{ + int ret = 0; + uint8_t major_version = 0; + uint8_t rom_version = 0; + uint8_t *cmd = nfc_dev->write_kbuf; + uint8_t *rsp = nfc_dev->read_kbuf; + enum chip_types chip_type = CHIP_UNKNOWN; + + *cmd++ = NCI_MSG_CMD; + *cmd++ = NCI_CORE_RESET_CMD_OID; + *cmd++ = NCI_CORE_RESET_CMD_PAYLOAD_LEN; + *cmd++ = NCI_CORE_RESET_KEEP_CONFIG; + + pr_debug("%s:Sending NCI Core Reset cmd of size = %d\n", __func__, NCI_RESET_CMD_LEN); + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, NCI_RESET_CMD_LEN, NO_RETRY); + if (ret <= 0) { + pr_err("%s: - nfc nci core reset cmd error ret %d\n", __func__, ret); + goto err; + } + + /* to flush out debug NTF this delay is required */ + usleep_range(NCI_RESET_RESP_READ_DELAY, NCI_RESET_RESP_READ_DELAY + 100); + nfc_dev->nfc_enable_intr(nfc_dev); + + memset(rsp, 0x00, NCI_RESET_RSP_LEN); + pr_debug("%s:Reading NCI Core Reset rsp\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_RSP_LEN, NCI_CMD_RSP_TIMEOUT); + if (ret <= 0) { + pr_err("%s: - nfc nci core reset rsp error ret %d\n", __func__, ret); + goto err_disable_intr; + } + + pr_debug(" %s: nci core reset response 0x%02x%02x%02x%02x\n", + __func__, rsp[0], rsp[1], rsp[2], rsp[3]); + if (rsp[0] != NCI_MSG_RSP) { + /* reset response failed response*/ + pr_err("%s invalid nci core reset response\n", __func__); + goto err_disable_intr; + } + + memset(rsp, 0x00, NCI_RESET_NTF_LEN); + /* read nci rest response ntf */ + ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_NTF_LEN, NCI_CMD_RSP_TIMEOUT); + if (ret <= 0) { + pr_err("%s - nfc nci rest rsp ntf error status %d\n", __func__, ret); + goto err_disable_intr; + } + + if (rsp[0] == NCI_MSG_NTF) { + /* read version info from NCI Reset Notification */ + rom_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 3]; + major_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 2]; + /* determine chip type based on version info */ + if (rom_version == SN1XX_ROM_VER && major_version == SN1xx_MAJOR_VER) + chip_type = CHIP_SN1XX; + else if (rom_version == SN220_ROM_VER && major_version == SN220_MAJOR_VER) + chip_type = CHIP_SN220; + pr_debug(" %s:NCI Core Reset ntf 0x%02x%02x%02x%02x\n", + __func__, rsp[0], rsp[1], rsp[2], rsp[3]); + + nfc_dev->nqx_info.info.chip_type = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - + NFC_CHIP_TYPE_OFF]; + nfc_dev->nqx_info.info.rom_version = rom_version; + nfc_dev->nqx_info.info.fw_major = major_version; + nfc_dev->nqx_info.info.fw_minor = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - + NFC_FW_MINOR_OFF]; + } +err_disable_intr: + nfc_dev->nfc_disable_intr(nfc_dev); +err: + return chip_type; +} + +/** + * validate_download_gpio() - validate download gpio. + * @nfc_dev: nfc_dev device data structure. + * @chip_type: chip type of the platform. + * + * Validates dwnld gpio should configured for supported and + * should not be configured for unsupported platform. + * + * @Return: true if gpio validation successful ortherwise + * false if validation fails. + */ +static bool validate_download_gpio(struct nfc_dev *nfc_dev, enum chip_types chip_type) +{ + bool status = false; + struct platform_gpio *nfc_gpio; + + if (nfc_dev == NULL) { + pr_err("%s nfc devices structure is null\n"); + return status; + } + nfc_gpio = &nfc_dev->configs.gpio; + if (chip_type == CHIP_SN1XX) { + /* gpio should be configured for SN1xx */ + status = gpio_is_valid(nfc_gpio->dwl_req); + } else if (chip_type == CHIP_SN220) { + /* gpio should not be configured for SN220 */ + set_valid_gpio(nfc_gpio->dwl_req, 0); + gpio_free(nfc_gpio->dwl_req); + nfc_gpio->dwl_req = -EINVAL; + status = true; + } + return status; +} + +/* Check for availability of NFC controller hardware */ +int nfcc_hw_check(struct nfc_dev *nfc_dev) +{ + int ret = 0; + enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN; + enum chip_types chip_type = CHIP_UNKNOWN; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + /*get fw version in nci mode*/ + gpio_set_ven(nfc_dev, 1); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + chip_type = get_nfcc_chip_type(nfc_dev); + + /*get fw version in fw dwl mode*/ + if (chip_type == CHIP_UNKNOWN) { + nfc_dev->nfc_enable_intr(nfc_dev); + /*Chip is unknown, initially assume with fw dwl pin enabled*/ + set_valid_gpio(nfc_gpio->dwl_req, 1); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + chip_type = get_nfcc_chip_type_dl(nfc_dev); + /*get the state of nfcc normal/teared in fw dwl mode*/ + } else { + nfc_state = NFC_STATE_NCI; + } + + /*validate gpio config required as per the chip*/ + if (!validate_download_gpio(nfc_dev, chip_type)) { + pr_info("%s gpio validation fail\n", __func__); + ret = -ENXIO; + goto err; + } + + /*check whether the NFCC is in FW DN or Teared state*/ + if (nfc_state != NFC_STATE_NCI) + nfc_state = get_nfcc_session_state_dl(nfc_dev); + + /*nfcc state specific operations */ + switch (nfc_state) { + case NFC_STATE_FW_TEARED: + pr_warn("%s: - NFCC FW Teared State\n", __func__); + case NFC_STATE_FW_DWL: + case NFC_STATE_NCI: + break; + case NFC_STATE_UNKNOWN: + default: + ret = -ENXIO; + pr_err("%s: - NFCC HW not available\n", __func__); + goto err; + } + nfc_dev->nfc_state = nfc_state; +err: + nfc_dev->nfc_disable_intr(nfc_dev); + set_valid_gpio(nfc_gpio->dwl_req, 0); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + nfc_dev->nfc_ven_enabled = true; + return ret; +} + +int validate_nfc_state_nci(struct nfc_dev *nfc_dev) +{ + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + if (!gpio_get_value(nfc_gpio->ven)) { + pr_err("VEN LOW - NFCC powered off\n"); + return -ENODEV; + } + if (get_valid_gpio(nfc_gpio->dwl_req) == 1) { + pr_err("FW download in-progress\n"); + return -EBUSY; + } + if (nfc_dev->nfc_state != NFC_STATE_NCI) { + pr_err("FW download state\n"); + return -EBUSY; + } + return 0; +} diff --git a/qti/nfc_common.h b/qti/nfc_common.h new file mode 100644 index 0000000000..eac4663b58 --- /dev/null +++ b/qti/nfc_common.h @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021 NXP + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#ifndef _NFC_COMMON_H_ +#define _NFC_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nfc_i2c_drv.h" +#include "ese_cold_reset.h" + +// Max device count for this driver +#define DEV_COUNT 1 + +// NFC device class +#define CLASS_NAME "qti-nfc" + +// NFC character device name, this will be in /dev/ +#define NFC_CHAR_DEV_NAME "nq-nci" + +// NCI packet details +#define NCI_MSG_CMD 0x20 +#define NCI_MSG_RSP 0x40 +#define NCI_MSG_NTF 0x60 +#define DL_CMD 0x00 +#define DL_PAYLOAD_BYTE_ZERO 0x00 +#define NCI_HDR_LEN 3 +#define NCI_PAYLOAD_IDX 3 +#define NCI_PAYLOAD_LEN_IDX 2 + +/*Time to wait for first NCI rest response*/ +#define NCI_RESET_RESP_READ_DELAY (10000) // 10ms +#define NCI_RESET_RESP_TIMEOUT (500) // 500ms + +// FW DNLD packet details +#define FW_MSG_CMD_RSP 0x00 +#define FW_HDR_LEN 2 +#define FW_PAYLOAD_LEN_IDX 1 +#define FW_CRC_LEN 2 + +#define NCI_RSP_PKT_TYPE (0x40) +#define FW_MIN_PAYLOAD_LEN 4 +#define MIN_NFC_DL_FRAME_SIZE 3 + +#define NCI_RESET_CMD_LEN (4) +#define NCI_RESET_RSP_LEN (4) +#define NCI_CORE_RESET_CMD_OID (0x0) +#define NCI_CORE_RESET_CMD_PAYLOAD_LEN (0x1) +#define NCI_CORE_RESET_KEEP_CONFIG (0x0) +#define NCI_RESET_NTF_LEN (13) +#define SN1XX_ROM_VER 0x01 +#define SN1xx_MAJOR_VER 0x10 +#define SN220_ROM_VER 0x01 +#define SN220_MAJOR_VER 0x01 +#define FW_ROM_CODE_VER_OFFSET 4 +#define FW_MAJOR_VER_OFFSET 7 +#define GET_VERSION_RSP_CHIP_TYPE_OFFSET 3 +#define GET_VERSION_RSP_MINOR_VERSION_OFFSET 6 +#define DL_GET_VERSION_CMD_LEN (8) +#define DL_GET_VERSION_RSP_LEN_1 (12) /* SN110 */ +#define DL_GET_VERSION_RSP_LEN_2 (20) /* SN220 */ +#define DL_GET_VERSION_CMD_PAYLOAD_LEN (4) +#define DL_GET_VERSION_CMD_ID (0xF1) +#define DL_GET_VERSION_CMD_CRC_1 (0x6E) +#define DL_GET_VERSION_CMD_CRC_2 (0xEF) + +#define DL_RESET_CMD_LEN (8) +#define DL_GET_SESSION_STATE_CMD_LEN (8) +#define DL_GET_SESSION_STATE_RSP_LEN (8) +#define DL_GET_SESSION_STATE_CMD_PAYLOAD_LEN (4) +#define DL_GET_SESSION_CMD_ID (0xF2) +#define DL_GET_SESSION_CMD_CRC_1 (0xF5) +#define DL_GET_SESSION_CMD_CRC_2 (0x33) +#define GET_SESSION_STS_OFF (3) +#define NFCC_SESSION_STS_CLOSED (0x0) + +/* Below offsets should be subtracted from NCI header length + payload length */ + +#define NFC_CHIP_TYPE_OFF (4) +#define NFC_FW_MINOR_OFF (1) + +#define GET_VERSION_CMD_LEN 8 +#define GET_SESSION_STATE_CMD_LEN 8 +#define MAX_NCI_PAYLOAD_LEN (255) +#define MAX_BUFFER_SIZE (NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN) +/* + * From MW 11.04 buffer size increased to support + * frame size of 554 in FW download mode + * Frame len(2) + Frame Header(6) + DATA(512) + HASH(32) + CRC(2) + RFU(4) + */ +#define MAX_DL_PAYLOAD_LEN (550) +#define MAX_DL_BUFFER_SIZE (FW_HDR_LEN + FW_CRC_LEN + MAX_DL_PAYLOAD_LEN) +// Maximum retry count for standby writes +#define MAX_RETRY_COUNT (3) + +// Retry count for normal write +#define NO_RETRY (1) +#define MAX_IRQ_WAIT_TIME (90) +#define WAKEUP_SRC_TIMEOUT (2000) + +/*command response timeout*/ +#define NCI_CMD_RSP_TIMEOUT (2000) //2s +/*Time to wait for NFCC to be ready again after any change in the GPIO*/ +#define NFC_GPIO_SET_WAIT_TIME_USEC (10000) +/*Time to wait after soft reset via any NCI/DL cmd*/ +#define NFC_SOFT_RESET_WAIT_TIME_USEC (5000) +/*Time to wait before retrying i2c writes*/ +#define WRITE_RETRY_WAIT_TIME_USEC (1000) +/*Time to wait before retrying read for some specific usecases*/ +#define READ_RETRY_WAIT_TIME_USEC (3500) +#define NFC_MAGIC 0xE9 + +// Ioctls +// The type should be aligned with MW HAL definitions + +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, unsigned int) +#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, unsigned int) +#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, unsigned int) +#define NFC_GET_PLATFORM_TYPE _IO(NFC_MAGIC, 0x04) + +/* NFC HAL can call this ioctl to get the current IRQ state */ +#define NFC_GET_IRQ_STATE _IO(NFC_MAGIC, 0x06) + +#define DTS_IRQ_GPIO_STR "qcom,sn-irq" +#define DTS_VEN_GPIO_STR "qcom,sn-ven" +#define DTS_FWDN_GPIO_STR "qcom,sn-firm" +#define DTS_CLKREQ_GPIO_STR "qcom,sn-clkreq" +#define DTS_CLKSRC_GPIO_STR "qcom,clk-src" +#define NFC_LDO_SUPPLY_DT_NAME "qcom,sn-vdd-1p8" +#define NFC_LDO_SUPPLY_NAME "qcom,sn-vdd-1p8-supply" +#define NFC_LDO_VOL_DT_NAME "qcom,sn-vdd-1p8-voltage" +#define NFC_LDO_CUR_DT_NAME "qcom,sn-vdd-1p8-current" + +//as per SN1x0 datasheet +#define NFC_VDDIO_MIN 1650000 //in uV +#define NFC_VDDIO_MAX 1950000 //in uV +#define NFC_CURRENT_MAX 157000 //in uA + + +#define NUM_OF_IPC_LOG_PAGES (2) +#define PKT_MAX_LEN (4) // no of max bytes to print for cmd/resp + +#define GET_IPCLOG_MAX_PKT_LEN(c) ((c > PKT_MAX_LEN) ? PKT_MAX_LEN : c) + +#define NFCLOG_IPC(nfc_dev, log_to_dmesg, x...) \ +do { \ + ipc_log_string(nfc_dev->ipcl, x); \ + if (log_to_dmesg) { \ + if (nfc_dev->nfc_device) \ + dev_err((nfc_dev->nfc_device), x); \ + else \ + pr_err(x); \ + } \ +} while (0) + +enum ese_ioctl_request { + /* eSE POWER ON */ + ESE_POWER_ON = 0, + /* eSE POWER OFF */ + ESE_POWER_OFF, + /* eSE POWER STATE */ + ESE_POWER_STATE +}; + +enum nfcc_ioctl_request { + /* NFC disable request with VEN LOW */ + NFC_POWER_OFF = 0, + /* NFC enable request with VEN Toggle */ + NFC_POWER_ON, + /* firmware download request with VEN Toggle */ + NFC_FW_DWL_VEN_TOGGLE, + /* ISO reset request */ + NFC_ISO_RESET, + /* request for firmware download gpio HIGH */ + NFC_FW_DWL_HIGH, + /* VEN hard reset request */ + NFC_VEN_FORCED_HARD_RESET, + /* request for firmware download gpio LOW */ + NFC_FW_DWL_LOW, + /* NFC enable without VEN gpio modification */ + NFC_ENABLE, + /* NFC disable without VEN gpio modification */ + NFC_DISABLE, +}; + +/*nfc platform interface type*/ +enum interface_flags { + /*I2C physical IF for NFCC */ + PLATFORM_IF_I2C = 0, +}; + +/*nfc state flags*/ +enum nfc_state_flags { + /*nfc in unknown state */ + NFC_STATE_UNKNOWN = 0, + /*nfc in download mode */ + NFC_STATE_FW_DWL = 0x1, + /*nfc booted in NCI mode */ + NFC_STATE_NCI = 0x2, + /*nfc booted in Fw teared mode */ + NFC_STATE_FW_TEARED = 0x4, +}; +/* + * Power state for IBI handing, mainly needed to defer the IBI handling + * for the IBI received in suspend state to do it later in resume call + */ +enum pm_state_flags { + PM_STATE_NORMAL = 0, + PM_STATE_SUSPEND, + PM_STATE_IBI_BEFORE_RESUME, +}; + +/* Enum for GPIO values*/ +enum gpio_values { + GPIO_INPUT = 0x0, + GPIO_OUTPUT = 0x1, + GPIO_HIGH = 0x2, + GPIO_OUTPUT_HIGH = 0x3, + GPIO_IRQ = 0x4, +}; + +// NFC GPIO variables +struct platform_gpio { + unsigned int irq; + unsigned int ven; + unsigned int clkreq; + unsigned int dwl_req; +}; + +// NFC LDO entries from DT +struct platform_ldo { + int vdd_levels[2]; + int max_current; +}; + +// NFC Struct to get all the required configs from DTS +struct platform_configs { + struct platform_gpio gpio; + struct platform_ldo ldo; +}; + +enum chip_types { + CHIP_SN1XX = 0x01, + CHIP_SN220 = 0x02, + CHIP_UNKNOWN = 0xFF, +}; + +/* Device specific structure */ +struct nfc_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct mutex write_mutex; + uint8_t *read_kbuf; + uint8_t *write_kbuf; + struct mutex dev_ref_mutex; + unsigned int dev_ref_count; + struct class *nfc_class; + struct device *nfc_device; + struct cdev c_dev; + dev_t devno; + /* Interface flag */ + uint8_t interface; + /* nfc state flags */ + uint8_t nfc_state; + /* NFC VEN pin state */ + bool nfc_ven_enabled; + /* current firmware major version */ + uint8_t fw_major_version; + bool is_vreg_enabled; + bool is_ese_session_active; + struct i2c_dev i2c_dev; + struct platform_configs configs; + struct cold_reset cold_reset; + struct regulator *reg; + + /* read buffer*/ + size_t kbuflen; + u8 *kbuf; + + union nqx_uinfo nqx_info; + + void *ipcl; + + int (*nfc_read)(struct nfc_dev *dev, char *buf, size_t count, int timeout); + int (*nfc_write)(struct nfc_dev *dev, const char *buf, const size_t count, + int max_retry_cnt); + int (*nfc_enable_intr)(struct nfc_dev *dev); + int (*nfc_disable_intr)(struct nfc_dev *dev); +}; + +int nfc_dev_open(struct inode *inode, struct file *filp); +int nfc_dev_close(struct inode *inode, struct file *filp); +long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); +int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, + uint8_t interface); +int nfc_misc_register(struct nfc_dev *nfc_dev, + const struct file_operations *nfc_fops, int count, char *devname, + char *classname); +void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count); +int configure_gpio(unsigned int gpio, int flag); +void gpio_set_ven(struct nfc_dev *nfc_dev, int value); +int nfcc_hw_check(struct nfc_dev *nfc_dev); +int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev); +int nfc_ldo_vote(struct nfc_dev *nfc_dev); +int nfc_ldo_unvote(struct nfc_dev *nfc_dev); +int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev); +int validate_nfc_state_nci(struct nfc_dev *nfc_dev); +void set_nfcc_state_from_rsp(struct nfc_dev *dev, const char *buf, + const int count); +void enable_dwnld_mode(struct nfc_dev *nfc_dev, bool value); +#endif //_NFC_COMMON_H_ diff --git a/qti/nfc_i2c_drv.c b/qti/nfc_i2c_drv.c new file mode 100644 index 0000000000..58d318dd21 --- /dev/null +++ b/qti/nfc_i2c_drv.c @@ -0,0 +1,577 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2021 NXP + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "nfc_common.h" + +/** + * i2c_disable_irq() + * + * Check if interrupt is disabled or not + * and disable interrupt + * + * Return: int + */ +int i2c_disable_irq(struct nfc_dev *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->i2c_dev.irq_enabled_lock, flags); + if (dev->i2c_dev.irq_enabled) { + disable_irq_nosync(dev->i2c_dev.client->irq); + dev->i2c_dev.irq_enabled = false; + } + spin_unlock_irqrestore(&dev->i2c_dev.irq_enabled_lock, flags); + + return 0; +} + +/** + * i2c_enable_irq() + * + * Check if interrupt is enabled or not + * and enable interrupt + * + * Return: int + */ +int i2c_enable_irq(struct nfc_dev *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->i2c_dev.irq_enabled_lock, flags); + if (!dev->i2c_dev.irq_enabled) { + dev->i2c_dev.irq_enabled = true; + enable_irq(dev->i2c_dev.client->irq); + } + spin_unlock_irqrestore(&dev->i2c_dev.irq_enabled_lock, flags); + + return 0; +} + +static irqreturn_t i2c_irq_handler(int irq, void *dev_id) +{ + struct nfc_dev *nfc_dev = dev_id; + struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; + + if (device_may_wakeup(&i2c_dev->client->dev)) + pm_wakeup_event(&i2c_dev->client->dev, WAKEUP_SRC_TIMEOUT); + + i2c_disable_irq(nfc_dev); + wake_up(&nfc_dev->read_wq); + + return IRQ_HANDLED; +} + +int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) +{ + int ret; + struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + uint16_t i = 0; + uint16_t disp_len = GET_IPCLOG_MAX_PKT_LEN(count); + + pr_debug("%s : reading %zu bytes.\n", __func__, count); + + if (timeout > NCI_CMD_RSP_TIMEOUT) + timeout = NCI_CMD_RSP_TIMEOUT; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (!gpio_get_value(nfc_gpio->irq)) { + while (1) { + ret = 0; + if (!i2c_dev->irq_enabled) { + i2c_dev->irq_enabled = true; + enable_irq(i2c_dev->client->irq); + } + if (!gpio_get_value(nfc_gpio->irq)) { + if (timeout) { + ret = wait_event_interruptible_timeout(nfc_dev->read_wq, + !i2c_dev->irq_enabled, msecs_to_jiffies(timeout)); + + if (ret <= 0) { + pr_err("%s timeout/error in read\n", __func__); + goto err; + } + } else { + ret = wait_event_interruptible(nfc_dev->read_wq, + !i2c_dev->irq_enabled); + if (ret) { + pr_err("%s error wakeup of read wq\n", __func__); + ret = -EINTR; + goto err; + } + } + } + i2c_disable_irq(nfc_dev); + + if (gpio_get_value(nfc_gpio->irq)) + break; + if (!gpio_get_value(nfc_gpio->ven)) { + pr_info("%s: releasing read\n", __func__); + ret = -EIO; + goto err; + } + pr_warn("%s: spurious interrupt detected\n", __func__); + } + } + + memset(buf, 0x00, count); + /* Read data */ + ret = i2c_master_recv(nfc_dev->i2c_dev.client, buf, count); + NFCLOG_IPC(nfc_dev, false, "%s of %d bytes, ret %d", __func__, count, + ret); + if (ret <= 0) { + pr_err("%s: returned %d\n", __func__, ret); + goto err; + } + + for (i = 0; i < disp_len; i++) + NFCLOG_IPC(nfc_dev, false, " %02x", buf[i]); + + /* check if it's response of cold reset command + * NFC HAL process shouldn't receive this data as + * command was esepowermanager + */ + if (nfc_dev->cold_reset.rsp_pending && nfc_dev->cold_reset.cmd_buf + && (buf[0] == PROP_NCI_RSP_GID) + && (buf[1] == nfc_dev->cold_reset.cmd_buf[1])) { + read_cold_reset_rsp(nfc_dev, buf); + nfc_dev->cold_reset.rsp_pending = false; + wake_up_interruptible(&nfc_dev->cold_reset.read_wq); + /* + * NFC process doesn't know about cold reset command + * being sent as it was initiated by eSE process + * we shouldn't return any data to NFC process + */ + return 0; + } + +err: + return ret; +} + +int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, + int max_retry_cnt) +{ + int ret = -EINVAL; + int retry_cnt; + uint16_t i = 0; + uint16_t disp_len = GET_IPCLOG_MAX_PKT_LEN(count); + + if (count > MAX_DL_BUFFER_SIZE) + count = MAX_DL_BUFFER_SIZE; + + pr_debug("%s : writing %zu bytes.\n", __func__, count); + + NFCLOG_IPC(nfc_dev, false, "%s sending %d B", __func__, count); + + for (i = 0; i < disp_len; i++) + NFCLOG_IPC(nfc_dev, false, " %02x", buf[i]); + + for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) { + + ret = i2c_master_send(nfc_dev->i2c_dev.client, buf, count); + NFCLOG_IPC(nfc_dev, false, "%s ret %d", __func__, ret); + if (ret <= 0) { + pr_warn("%s: write failed ret %d, Maybe in Standby Mode - Retry(%d)\n", + __func__, ret, retry_cnt); + usleep_range(WRITE_RETRY_WAIT_TIME_USEC, + WRITE_RETRY_WAIT_TIME_USEC + 100); + } else if (ret != count) { + pr_err("%s: failed to write %d\n", __func__, ret); + ret = -EIO; + } else if (ret == count) + break; + } + return ret; +} + +ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + int ret = 0; + struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; + + if (filp->f_flags & O_NONBLOCK) { + pr_err(":f_flag has O_NONBLOCK. EAGAIN\n"); + return -EAGAIN; + } + mutex_lock(&nfc_dev->read_mutex); + ret = i2c_read(nfc_dev, nfc_dev->read_kbuf, count, 0); + if (ret > 0) { + if (copy_to_user(buf, nfc_dev->read_kbuf, ret)) { + pr_warn("%s : failed to copy to user space\n", __func__); + ret = -EFAULT; + } + } + mutex_unlock(&nfc_dev->read_mutex); + return ret; +} + +ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + int ret; + struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; + + if (count > MAX_DL_BUFFER_SIZE) + count = MAX_DL_BUFFER_SIZE; + + if (!nfc_dev) + return -ENODEV; + + mutex_lock(&nfc_dev->write_mutex); + if (copy_from_user(nfc_dev->write_kbuf, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + mutex_unlock(&nfc_dev->write_mutex); + return -EFAULT; + } + ret = i2c_write(nfc_dev, nfc_dev->write_kbuf, count, NO_RETRY); + mutex_unlock(&nfc_dev->write_mutex); + return ret; +} + +static const struct file_operations nfc_i2c_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = nfc_i2c_dev_read, + .write = nfc_i2c_dev_write, + .open = nfc_dev_open, + .release = nfc_dev_close, + .unlocked_ioctl = nfc_dev_ioctl, +}; + +int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + struct nfc_dev *nfc_dev = NULL; + struct i2c_dev *i2c_dev = NULL; + struct platform_configs nfc_configs; + struct platform_gpio *nfc_gpio = &nfc_configs.gpio; + + pr_debug("%s: enter\n", __func__); + + //retrieve details of gpios from dt + + ret = nfc_parse_dt(&client->dev, &nfc_configs, PLATFORM_IF_I2C); + if (ret) { + pr_err("%s : failed to parse dt\n", __func__); + goto err; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + ret = -ENODEV; + goto err; + } + nfc_dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL); + if (nfc_dev == NULL) { + ret = -ENOMEM; + goto err; + } + nfc_dev->read_kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); + if (!nfc_dev->read_kbuf) { + ret = -ENOMEM; + goto err_free_nfc_dev; + } + nfc_dev->write_kbuf = kzalloc(MAX_DL_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); + if (!nfc_dev->write_kbuf) { + ret = -ENOMEM; + goto err_free_read_kbuf; + } + nfc_dev->interface = PLATFORM_IF_I2C; + nfc_dev->nfc_state = NFC_STATE_NCI; + nfc_dev->i2c_dev.client = client; + i2c_dev = &nfc_dev->i2c_dev; + nfc_dev->nfc_read = i2c_read; + nfc_dev->nfc_write = i2c_write; + nfc_dev->nfc_enable_intr = i2c_enable_irq; + nfc_dev->nfc_disable_intr = i2c_disable_irq; + nfc_dev->fw_major_version = 0; + ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc reset gpio [%d]\n", + __func__, nfc_gpio->ven); + goto err_free_write_kbuf; + } + ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ); + if (ret <= 0) { + pr_err("%s: unable to request nfc irq gpio [%d]\n", + __func__, nfc_gpio->irq); + goto err_free_ven; + } + client->irq = ret; + ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc firm downl gpio [%d]\n", + __func__, nfc_gpio->dwl_req); + //not returning failure here as dwl gpio is a optional gpio for sn220 + } + + ret = configure_gpio(nfc_gpio->clkreq, GPIO_INPUT); + if (ret) { + pr_err("%s: unable to request nfc clkreq gpio [%d]\n", + __func__, nfc_gpio->clkreq); + goto err_free_dwl_req; + } + + /*copy the retrieved gpio details from DT */ + memcpy(&nfc_dev->configs, &nfc_configs, sizeof(struct platform_configs)); + + /* init mutex and queues */ + init_waitqueue_head(&nfc_dev->read_wq); + mutex_init(&nfc_dev->read_mutex); + mutex_init(&nfc_dev->write_mutex); + mutex_init(&nfc_dev->dev_ref_mutex); + spin_lock_init(&i2c_dev->irq_enabled_lock); + ret = nfc_misc_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT, + NFC_CHAR_DEV_NAME, CLASS_NAME); + if (ret) { + pr_err("%s: nfc_misc_register failed\n", __func__); + goto err_mutex_destroy; + } + /* interrupt initializations */ + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + i2c_dev->irq_enabled = true; + ret = request_irq(client->irq, i2c_irq_handler, + IRQF_TRIGGER_HIGH, client->name, nfc_dev); + if (ret) { + pr_err("%s: request_irq failed\n", __func__); + goto err_nfc_misc_unregister; + } + i2c_disable_irq(nfc_dev); + i2c_set_clientdata(client, nfc_dev); + + ret = nfc_ldo_config(&client->dev, nfc_dev); + if (ret) { + pr_err("LDO config failed\n"); + goto err_ldo_config_failed; + } + + ret = nfcc_hw_check(nfc_dev); + if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { + pr_err("nfc hw check failed ret %d\n", ret); + goto err_nfcc_hw_check; + } + + device_init_wakeup(&client->dev, true); + i2c_dev->irq_wake_up = false; + nfc_dev->is_ese_session_active = false; + + pr_info("%s success\n", __func__); + return 0; + +err_nfcc_hw_check: + if (nfc_dev->reg) { + nfc_ldo_unvote(nfc_dev); + regulator_put(nfc_dev->reg); + } +err_ldo_config_failed: + free_irq(client->irq, nfc_dev); +err_nfc_misc_unregister: + nfc_misc_unregister(nfc_dev, DEV_COUNT); +err_mutex_destroy: + mutex_destroy(&nfc_dev->dev_ref_mutex); + mutex_destroy(&nfc_dev->read_mutex); + mutex_destroy(&nfc_dev->write_mutex); + gpio_free(nfc_gpio->clkreq); +err_free_dwl_req: + if (gpio_is_valid(nfc_gpio->dwl_req)) + gpio_free(nfc_gpio->dwl_req); + gpio_free(nfc_gpio->irq); +err_free_ven: + gpio_free(nfc_gpio->ven); +err_free_write_kbuf: + kfree(nfc_dev->write_kbuf); +err_free_read_kbuf: + kfree(nfc_dev->read_kbuf); +err_free_nfc_dev: + kfree(nfc_dev); +err: + pr_err("%s: failed\n", __func__); + return ret; +} + +int nfc_i2c_dev_remove(struct i2c_client *client) +{ + int ret = 0; + struct nfc_dev *nfc_dev = NULL; + + pr_info("%s: remove device\n", __func__); + nfc_dev = i2c_get_clientdata(client); + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + ret = -ENODEV; + return ret; + } + + if (nfc_dev->dev_ref_count > 0) { + pr_err("%s: device already in use\n", __func__); + return -EBUSY; + } + + gpio_set_value(nfc_dev->configs.gpio.ven, 0); + // HW dependent delay before LDO goes into LPM mode + usleep_range(10000, 10100); + if (nfc_dev->reg) { + nfc_ldo_unvote(nfc_dev); + regulator_put(nfc_dev->reg); + } + + device_init_wakeup(&client->dev, false); + free_irq(client->irq, nfc_dev); + nfc_misc_unregister(nfc_dev, DEV_COUNT); + mutex_destroy(&nfc_dev->dev_ref_mutex); + mutex_destroy(&nfc_dev->read_mutex); + mutex_destroy(&nfc_dev->write_mutex); + + if (gpio_is_valid(nfc_dev->configs.gpio.clkreq)) + gpio_free(nfc_dev->configs.gpio.clkreq); + + if (gpio_is_valid(nfc_dev->configs.gpio.dwl_req)) + gpio_free(nfc_dev->configs.gpio.dwl_req); + + if (gpio_is_valid(nfc_dev->configs.gpio.irq)) + gpio_free(nfc_dev->configs.gpio.irq); + + if (gpio_is_valid(nfc_dev->configs.gpio.ven)) + gpio_free(nfc_dev->configs.gpio.ven); + + kfree(nfc_dev->read_kbuf); + kfree(nfc_dev->write_kbuf); + kfree(nfc_dev); + return ret; +} + +int nfc_i2c_dev_suspend(struct device *device) +{ + struct i2c_client *client = to_i2c_client(device); + struct nfc_dev *nfc_dev = i2c_get_clientdata(client); + struct i2c_dev *i2c_dev = NULL; + + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + return -ENODEV; + } + + i2c_dev = &nfc_dev->i2c_dev; + + NFCLOG_IPC(nfc_dev, false, "%s: irq_enabled = %d", __func__, + i2c_dev->irq_enabled); + + if (device_may_wakeup(&client->dev) && i2c_dev->irq_enabled) { + if (!enable_irq_wake(client->irq)) + i2c_dev->irq_wake_up = true; + } + return 0; +} + +int nfc_i2c_dev_resume(struct device *device) +{ + struct i2c_client *client = to_i2c_client(device); + struct nfc_dev *nfc_dev = i2c_get_clientdata(client); + struct i2c_dev *i2c_dev = NULL; + + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + return -ENODEV; + } + + i2c_dev = &nfc_dev->i2c_dev; + + NFCLOG_IPC(nfc_dev, false, "%s: irq_wake_up = %d", __func__, + i2c_dev->irq_wake_up); + + if (device_may_wakeup(&client->dev) && i2c_dev->irq_wake_up) { + if (!disable_irq_wake(client->irq)) + i2c_dev->irq_wake_up = false; + } + return 0; +} + +static const struct i2c_device_id nfc_i2c_dev_id[] = { + {NFC_I2C_DEV_ID, 0}, + {} +}; + +static const struct of_device_id nfc_i2c_dev_match_table[] = { + {.compatible = NFC_I2C_DRV_STR,}, + {} +}; + +static const struct dev_pm_ops nfc_i2c_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(nfc_i2c_dev_suspend, nfc_i2c_dev_resume) +}; + +static struct i2c_driver nfc_i2c_dev_driver = { + .id_table = nfc_i2c_dev_id, + .probe = nfc_i2c_dev_probe, + .remove = nfc_i2c_dev_remove, + .driver = { + .name = NFC_I2C_DRV_STR, + .pm = &nfc_i2c_dev_pm_ops, + .of_match_table = nfc_i2c_dev_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; + +MODULE_DEVICE_TABLE(of, nfc_i2c_dev_match_table); + +static int __init nfc_i2c_dev_init(void) +{ + int ret = 0; + + ret = i2c_add_driver(&nfc_i2c_dev_driver); + if (ret != 0) + pr_err("NFC I2C add driver error ret %d\n", ret); + return ret; +} + +module_init(nfc_i2c_dev_init); + +static void __exit nfc_i2c_dev_exit(void) +{ + pr_debug("Unloading NFC I2C driver\n"); + i2c_del_driver(&nfc_i2c_dev_driver); +} + +module_exit(nfc_i2c_dev_exit); + +MODULE_DESCRIPTION("QTI NFC I2C driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qti/nfc_i2c_drv.h b/qti/nfc_i2c_drv.h new file mode 100644 index 0000000000..5ba871a1e4 --- /dev/null +++ b/qti/nfc_i2c_drv.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021 NXP + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#ifndef _NFC_I2C_DRV_H_ +#define _NFC_I2C_DRV_H_ +#include + +#define NFC_I2C_DRV_STR "qcom,sn-nci" /*kept same as dts */ +#define NFC_I2C_DEV_ID "sn-i2c" + +struct nfc_dev; + +//Interface specific parameters +struct i2c_dev { + struct i2c_client *client; + /*IRQ parameters */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + /* NFC_IRQ wake-up state */ + bool irq_wake_up; +}; + +long nfc_i2c_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); +int nfc_i2c_dev_probe(struct i2c_client *client, + const struct i2c_device_id *id); +int nfc_i2c_dev_remove(struct i2c_client *client); +int nfc_i2c_dev_suspend(struct device *device); +int nfc_i2c_dev_resume(struct device *device); + +#if IS_ENABLED(CONFIG_NFC_QTI_I2C) + +int i2c_enable_irq(struct nfc_dev *dev); +int i2c_disable_irq(struct nfc_dev *dev); +int i2c_write(struct nfc_dev *dev, const char *buf, size_t count, + int max_retry_cnt); +int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout); + +#else + +static inline int i2c_enable_irq(struct nfc_dev *dev) +{ + return -ENXIO; +} + +static inline int i2c_disable_irq(struct nfc_dev *dev) +{ + return -ENXIO; +} + +static inline int i2c_write(struct nfc_dev *dev, const char *buf, + size_t count, int max_retry_cnt) +{ + return -ENXIO; +} + +static inline int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout) +{ + return -ENXIO; +} + +#endif + +#endif //_NFC_I2C_DRV_H_ From 55d2657f94c157da0ac322163acc5b55ad29eff5 Mon Sep 17 00:00:00 2001 From: nxf35421 Date: Fri, 17 Dec 2021 17:25:16 +0530 Subject: [PATCH 046/100] Updated corresponding to - NFC_AR_00_E800_12.10.00_OpnSrc --- nfc/common.c | 25 ++++++++++++++++++++ nfc/common.h | 8 ++++--- nfc/common_ese.c | 61 ++++++++++++++++++++++-------------------------- nfc/i2c_drv.c | 32 ++++++++++++++++++++++--- 4 files changed, 87 insertions(+), 39 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 094eb40c81..a4f8029fa1 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -286,6 +286,31 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) return ret; } +#ifdef CONFIG_COMPAT +/** + * nfc_dev_compat_ioctl - used to set or get data from upper layer. + * @pfile file node for opened device. + * @cmd ioctl type from upper layer. + * @arg ioctl arg from upper layer. + * + * NFC and ESE Device power control, based on the argument value + * + * Return: -ENOIOCTLCMD if arg is not supported + * 0 if Success(or no issue) + * 0 or 1 in case of arg is ESE_GET_PWR/ESE_POWER_STATE + * and error ret code otherwise + */ +long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + arg = (compat_u64)arg; + pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg); + ret = nfc_dev_ioctl(pfile, cmd, arg); + return ret; +} +#endif + /** * nfc_dev_ioctl - used to set or get data from upper layer. * @pfile file node for opened device. diff --git a/nfc/common.h b/nfc/common.h index c4f3388ad7..bcdd26dd33 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -74,9 +74,9 @@ /* Ioctls */ /* The type should be aligned with MW HAL definitions */ -#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, long) -#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, long) -#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, long) +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) +#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) +#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) #define DTS_IRQ_GPIO_STR "nxp,pn544-irq" #define DTS_VEN_GPIO_STR "nxp,pn544-ven" @@ -196,6 +196,8 @@ struct nfc_dev { int nfc_dev_open(struct inode *inode, struct file *filp); int nfc_dev_flush(struct file *pfile, fl_owner_t id); int nfc_dev_close(struct inode *inode, struct file *filp); +long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, + unsigned long arg); long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface); diff --git a/nfc/common_ese.c b/nfc/common_ese.c index c1795063d4..5c725a6845 100644 --- a/nfc/common_ese.c +++ b/nfc/common_ese.c @@ -54,7 +54,6 @@ static int send_cold_reset_protection_cmd(struct nfc_dev *nfc_dev, uint8_t *cmd = nfc_dev->write_kbuf; struct cold_reset *cold_reset = &nfc_dev->cold_reset; - mutex_lock(&nfc_dev->write_mutex); *cmd++ = NCI_PROP_MSG_CMD; if (requestType) { /* reset protection */ @@ -84,7 +83,6 @@ static int send_cold_reset_protection_cmd(struct nfc_dev *nfc_dev, cmd[NCI_HDR_IDX], cmd[NCI_HDR_OID_IDX], cmd[NCI_PAYLOAD_LEN_IDX]); exit: - mutex_unlock(&nfc_dev->write_mutex); return ret; } @@ -152,7 +150,6 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, int timeout = 0; char *rsp = nfc_dev->read_kbuf; struct cold_reset *cold_reset = &nfc_dev->cold_reset; - bool nfc_dev_opened = false; /* check if NFCC not in the FW download or hard reset state */ ret = validate_nfc_state_nci(nfc_dev); @@ -161,10 +158,6 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, return ret; } - /* check if NFC is enabled */ - mutex_lock(&nfc_dev->dev_ref_mutex); - nfc_dev_opened = (nfc_dev->dev_ref_count > 0) ? true : false; - /* check if NFCC not in the FW download or hard reset state */ ret = validate_cold_reset_protection_request(cold_reset, arg); if (ret < 0) { @@ -178,21 +171,23 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, ret = -EBUSY; goto err; } - /* set default value for status as failure */ + + /* enable interrupt if not enabled incase when devnode not opened by HAL */ + nfc_dev->nfc_enable_intr(nfc_dev); + + mutex_lock(&nfc_dev->write_mutex); + /* write api has 15ms maximum wait to clear any pending read before */ cold_reset->status = -EIO; cold_reset->rsp_pending = true; - - /* enable interrupt before sending cmd, when devnode not opened by HAL */ - if (!nfc_dev_opened) - nfc_dev->nfc_enable_intr(nfc_dev); - ret = send_cold_reset_protection_cmd(nfc_dev, IS_RST_PROT_REQ(arg)); if (ret < 0) { + mutex_unlock(&nfc_dev->write_mutex); + cold_reset->rsp_pending = false; pr_err("%s: failed to send cold reset/protection cmd\n", __func__); - cold_reset->rsp_pending = false; goto err; } + ret = 0; /* start the cold reset guard timer */ if (IS_CLD_RST_REQ(arg)) { @@ -200,6 +195,7 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, if (!(cold_reset->reset_protection && IS_SRC_NFC(arg))) { ret = start_cold_reset_guard_timer(cold_reset); if (ret) { + mutex_unlock(&nfc_dev->write_mutex); pr_err("%s: error in mod_timer\n", __func__); goto err; } @@ -208,28 +204,27 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, timeout = NCI_CMD_RSP_TIMEOUT_MS; do { + /* call read api directly if reader thread is not blocked */ + if (mutex_trylock(&nfc_dev->read_mutex)) { + pr_debug("%s: reader thread not pending\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp, 3, + timeout); + mutex_unlock(&nfc_dev->read_mutex); + if (!ret) + break; + usleep_range(READ_RETRY_WAIT_TIME_US, + READ_RETRY_WAIT_TIME_US + 500); /* Read pending response form the HAL service */ - if (nfc_dev_opened) { - if (!wait_event_interruptible_timeout( - cold_reset->read_wq, - cold_reset->rsp_pending == false, - msecs_to_jiffies(timeout))) { - pr_err("%s: cold reset/prot response timeout\n", - __func__); - ret = -EAGAIN; - } - } else { - /* Read response here as NFC thread is not active */ - if (nfc_dev->interface == PLATFORM_IF_I2C) { - ret = nfc_dev->nfc_read(nfc_dev, rsp, 3, - timeout); - if (!ret) - break; - usleep_range(READ_RETRY_WAIT_TIME_US, - READ_RETRY_WAIT_TIME_US + 500); - } + } else if (!wait_event_interruptible_timeout( + cold_reset->read_wq, + cold_reset->rsp_pending == false, + msecs_to_jiffies(timeout))) { + pr_err("%s: cold reset/prot response timeout\n", __func__); + ret = -EAGAIN; } } while (ret == -ERESTARTSYS || ret == -EFAULT); + mutex_unlock(&nfc_dev->write_mutex); + timeout = ESE_CLD_RST_REBOOT_GUARD_TIME_MS; if (ret == 0) { /* success case */ ret = cold_reset->status; diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index e65d1a8792..2792484263 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -40,7 +40,9 @@ #include #include #include - +#ifdef CONFIG_COMPAT +#include +#endif #include "common_ese.h" /** @@ -256,6 +258,10 @@ ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, size_t count, int ret; struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + return -ENODEV; + } mutex_lock(&nfc_dev->read_mutex); if (filp->f_flags & O_NONBLOCK) { ret = i2c_master_recv(nfc_dev->i2c_dev.client, nfc_dev->read_kbuf, count); @@ -282,6 +288,11 @@ ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf, if (count > MAX_DL_BUFFER_SIZE) count = MAX_DL_BUFFER_SIZE; + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + return -ENODEV; + } + mutex_lock(&nfc_dev->write_mutex); if (copy_from_user(nfc_dev->write_kbuf, buf, count)) { pr_err("%s: failed to copy from user space\n", __func__); @@ -302,6 +313,9 @@ static const struct file_operations nfc_i2c_dev_fops = { .flush = nfc_dev_flush, .release = nfc_dev_close, .unlocked_ioctl = nfc_dev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = nfc_dev_compat_ioctl, +#endif }; int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -454,12 +468,18 @@ int nfc_i2c_dev_suspend(struct device *device) { struct i2c_client *client = to_i2c_client(device); struct nfc_dev *nfc_dev = i2c_get_clientdata(client); - struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; + struct i2c_dev *i2c_dev = NULL; + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + return -ENODEV; + } + i2c_dev = &nfc_dev->i2c_dev; if (device_may_wakeup(&client->dev) && i2c_dev->irq_enabled) { if (!enable_irq_wake(client->irq)) i2c_dev->irq_wake_up = true; } + pr_debug("%s: irq_wake_up = %d", __func__, i2c_dev->irq_wake_up); return 0; } @@ -467,12 +487,18 @@ int nfc_i2c_dev_resume(struct device *device) { struct i2c_client *client = to_i2c_client(device); struct nfc_dev *nfc_dev = i2c_get_clientdata(client); - struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; + struct i2c_dev *i2c_dev = NULL; + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + return -ENODEV; + } + i2c_dev = &nfc_dev->i2c_dev; if (device_may_wakeup(&client->dev) && i2c_dev->irq_wake_up) { if (!disable_irq_wake(client->irq)) i2c_dev->irq_wake_up = false; } + pr_debug("%s: irq_wake_up = %d", __func__, i2c_dev->irq_wake_up); return 0; } From 182705d22131a3c98797a9f2c5e153c59f2b46fc Mon Sep 17 00:00:00 2001 From: Abhishek Dhumal Date: Wed, 29 Dec 2021 15:08:27 +0530 Subject: [PATCH 047/100] driver: eSE: Fix possible invalid buffer access Add NULL check for buffer to avoid invalid access. Change-Id: Id7ec5d655291eb6b8a2d08e8775a61bdecdc73ca Signed-off-by: Gaurav Singhal --- qti/ese_cold_reset.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qti/ese_cold_reset.c b/qti/ese_cold_reset.c index 1c2a7c1c76..41893fd658 100644 --- a/qti/ese_cold_reset.c +++ b/qti/ese_cold_reset.c @@ -76,6 +76,7 @@ int read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header) * if response's OID doesn't match with the CMD's OID */ if (!(rsp_buf[0] & NCI_RSP_PKT_TYPE) || + (!cold_rst->cmd_buf) || (rsp_buf[1] != cold_rst->cmd_buf[1])) { dev_err(nfc_dev->nfc_device, From 92e090c560a488f3f85a8ff15ccb150bee80d327 Mon Sep 17 00:00:00 2001 From: Abhishek Dhumal Date: Wed, 29 Dec 2021 15:32:05 +0530 Subject: [PATCH 048/100] driver: eSE: Fix possible use after free Shared variable is accessed without any mutual exclusion, it may result into overwriting memory address and cause invalid write access to buffer after free or invalid free. Convert shared variable to local as it's usage was limited with in API itself, it will avoid overwriting memory address by another thread as all of them will have their own copy. Change-Id: I36692313396f6c60e1be4479711feb14bb92ae4c Signed-off-by: Gaurav Singhal --- qti/ese_cold_reset.c | 37 +++++++++++++++++-------------------- qti/ese_cold_reset.h | 1 - 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/qti/ese_cold_reset.c b/qti/ese_cold_reset.c index 41893fd658..7d596ca27e 100644 --- a/qti/ese_cold_reset.c +++ b/qti/ese_cold_reset.c @@ -140,6 +140,7 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) { int ret; struct ese_ioctl_arg ioctl_arg; + struct ese_cold_reset_arg *cold_reset_arg = NULL; if (!arg) { dev_err(nfc_dev->nfc_device, "arg is invalid\n"); @@ -154,12 +155,11 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) return -EFAULT; } - nfc_dev->cold_reset.arg = kzalloc(sizeof(struct ese_cold_reset_arg), - GFP_KERNEL); - if (!nfc_dev->cold_reset.arg) + cold_reset_arg = kzalloc(sizeof(struct ese_cold_reset_arg), GFP_KERNEL); + if (!cold_reset_arg) return -ENOMEM; - ret = copy_struct_from_user(nfc_dev->cold_reset.arg, + ret = copy_struct_from_user(cold_reset_arg, sizeof(struct ese_cold_reset_arg), u64_to_user_ptr(ioctl_arg.buf), sizeof(struct ese_cold_reset_arg)); @@ -171,7 +171,7 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) goto err; } - switch (nfc_dev->cold_reset.arg->sub_cmd) { + switch (cold_reset_arg->sub_cmd) { case ESE_COLD_RESET_DO: @@ -180,11 +180,11 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) * source is same as the one which enabled protection. */ if (nfc_dev->cold_reset.is_crp_en && - (nfc_dev->cold_reset.arg->src != + (cold_reset_arg->src != nfc_dev->cold_reset.last_src_ese_prot)) { dev_err(nfc_dev->nfc_device, "cold reset from %d denied, protection is on\n", - nfc_dev->cold_reset.arg->src); + cold_reset_arg->src); ret = -EACCES; goto err; } @@ -207,7 +207,7 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) case ESE_COLD_RESET_PROTECT_EN: if (nfc_dev->cold_reset.is_crp_en) { - if (nfc_dev->cold_reset.arg->src != + if (cold_reset_arg->src != nfc_dev->cold_reset.last_src_ese_prot) { dev_err(nfc_dev->nfc_device, "ese protection enable denied\n"); @@ -224,7 +224,7 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) case ESE_COLD_RESET_PROTECT_DIS: if (nfc_dev->cold_reset.is_crp_en && - nfc_dev->cold_reset.arg->src != + cold_reset_arg->src != nfc_dev->cold_reset.last_src_ese_prot) { pr_err("ese cold reset protection disable denied\n"); ret = -EACCES; @@ -243,8 +243,7 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) nfc_dev->cold_reset.cmd_len = NCI_HDR_LEN + COLD_RESET_PROT_CMD_PL_LEN; nfc_dev->cold_reset.rsp_len = COLD_RESET_PROT_RSP_LEN; - if (nfc_dev->cold_reset.arg->sub_cmd == - ESE_COLD_RESET_PROTECT_EN) + if (cold_reset_arg->sub_cmd == ESE_COLD_RESET_PROTECT_EN) nfc_dev->cold_reset.cmd_buf[3] = 0x1; else nfc_dev->cold_reset.cmd_buf[3] = 0x0; @@ -253,7 +252,7 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) default: pr_err("%s invalid ese ioctl sub cmd %d\n", __func__, - nfc_dev->cold_reset.arg->sub_cmd); + cold_reset_arg->sub_cmd); ret = -ENOIOCTLCMD; goto err; } @@ -314,23 +313,21 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) nfc_dev->nfc_disable_intr(nfc_dev); } - if (nfc_dev->cold_reset.arg->sub_cmd == ESE_COLD_RESET_PROTECT_EN) { + if (cold_reset_arg->sub_cmd == ESE_COLD_RESET_PROTECT_EN) { nfc_dev->cold_reset.is_crp_en = true; - nfc_dev->cold_reset.last_src_ese_prot = - nfc_dev->cold_reset.arg->src; - } else if (nfc_dev->cold_reset.arg->sub_cmd == - ESE_COLD_RESET_PROTECT_DIS) { + nfc_dev->cold_reset.last_src_ese_prot = cold_reset_arg->src; + } else if (cold_reset_arg->sub_cmd == ESE_COLD_RESET_PROTECT_DIS) { nfc_dev->cold_reset.is_crp_en = false; nfc_dev->cold_reset.last_src_ese_prot = ESE_COLD_RESET_ORIGIN_NONE; } else - pr_debug("ese cmd is %d\n", nfc_dev->cold_reset.arg->sub_cmd); + pr_debug("ese cmd is %d\n", cold_reset_arg->sub_cmd); ret = nfc_dev->cold_reset.status; err: kfree(nfc_dev->cold_reset.cmd_buf); - kfree(nfc_dev->cold_reset.arg); - nfc_dev->cold_reset.arg = NULL; + kfree(cold_reset_arg); + cold_reset_arg = NULL; nfc_dev->cold_reset.cmd_buf = NULL; return ret; diff --git a/qti/ese_cold_reset.h b/qti/ese_cold_reset.h index f009d16f18..3cf2507407 100644 --- a/qti/ese_cold_reset.h +++ b/qti/ese_cold_reset.h @@ -61,7 +61,6 @@ struct ese_ioctl_arg { struct cold_reset { wait_queue_head_t read_wq; char *cmd_buf; - struct ese_cold_reset_arg *arg; uint16_t cmd_len; uint16_t rsp_len; /* Source of last ese protection command */ From edbd2aaad62572187fc2b244981cdc4980326fa8 Mon Sep 17 00:00:00 2001 From: nxf24591 Date: Tue, 1 Feb 2022 17:31:42 +0530 Subject: [PATCH 049/100] Updated corresponding to - NFC_AR_00_E800_13.02.01_OpnSrc --- nfc/Kbuild | 8 ++++---- nfc/common.h | 8 ++++---- nfc/i2c_drv.c | 25 ++++++++++--------------- nfc/i2c_drv.h | 4 ++-- 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/nfc/Kbuild b/nfc/Kbuild index 198d574a94..9a4e9a23da 100644 --- a/nfc/Kbuild +++ b/nfc/Kbuild @@ -1,6 +1,6 @@ -obj-$(CONFIG_NXP_NFC_I2C) := pn553_i2c.o +obj-$(CONFIG_NXP_NFC_I2C) := nfc_i2c.o -pn553_i2c-y := common.o \ - common_ese.o \ - i2c_drv.o +nfc_i2c-y := common.o \ + common_ese.o \ + i2c_drv.o diff --git a/nfc/common.h b/nfc/common.h index bcdd26dd33..675e06ccd4 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -30,7 +30,7 @@ #define CLASS_NAME "nfc" /* NFC character device name, this will be in /dev/ */ -#define NFC_CHAR_DEV_NAME "pn553" +#define NFC_CHAR_DEV_NAME "nxp-nci" /* NCI packet details */ #define NCI_CMD (0x20) @@ -78,9 +78,9 @@ #define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) #define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) -#define DTS_IRQ_GPIO_STR "nxp,pn544-irq" -#define DTS_VEN_GPIO_STR "nxp,pn544-ven" -#define DTS_FWDN_GPIO_STR "nxp,pn544-fw-dwnld" +#define DTS_IRQ_GPIO_STR "nxp,sn-irq" +#define DTS_VEN_GPIO_STR "nxp,sn-ven-rstn" +#define DTS_FWDN_GPIO_STR "nxp,sn-dwl-req" enum nfcc_ioctl_request { /* NFC disable request with VEN LOW */ diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 2792484263..32cfc43a4c 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -323,27 +323,27 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) int ret = 0; struct nfc_dev *nfc_dev = NULL; struct i2c_dev *i2c_dev = NULL; - struct platform_configs nfc_configs; - struct platform_gpio *nfc_gpio = &nfc_configs.gpio; - + struct platform_configs *nfc_configs = NULL; + struct platform_gpio *nfc_gpio = NULL; pr_debug("%s: enter\n", __func__); + nfc_dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL); + if (nfc_dev == NULL) { + ret = -ENOMEM; + goto err; + } + nfc_configs = &nfc_dev->configs; + nfc_gpio = &nfc_configs->gpio; /* retrieve details of gpios from dt */ - ret = nfc_parse_dt(&client->dev, &nfc_configs, PLATFORM_IF_I2C); + ret = nfc_parse_dt(&client->dev,nfc_configs, PLATFORM_IF_I2C); if (ret) { pr_err("%s: failed to parse dt\n", __func__); goto err; } - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { pr_err("%s: need I2C_FUNC_I2C\n", __func__); ret = -ENODEV; goto err; } - nfc_dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL); - if (nfc_dev == NULL) { - ret = -ENOMEM; - goto err; - } nfc_dev->read_kbuf = kzalloc(MAX_NCI_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); if (!nfc_dev->read_kbuf) { ret = -ENOMEM; @@ -380,11 +380,6 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) pr_err("%s: unable to request nfc firm downl gpio [%d]\n", __func__, nfc_gpio->dwl_req); } - - /* copy the retrieved gpio details from DT */ - memcpy(&nfc_dev->configs, &nfc_configs, - sizeof(struct platform_configs)); - /* init mutex and queues */ init_waitqueue_head(&nfc_dev->read_wq); mutex_init(&nfc_dev->read_mutex); diff --git a/nfc/i2c_drv.h b/nfc/i2c_drv.h index 1508fd4163..628ca0862d 100644 --- a/nfc/i2c_drv.h +++ b/nfc/i2c_drv.h @@ -23,8 +23,8 @@ #include /* kept same as dts */ -#define NFC_I2C_DRV_STR "nxp,pn544" -#define NFC_I2C_DEV_ID "pn553" +#define NFC_I2C_DRV_STR "nxp,sn-nci" +#define NFC_I2C_DEV_ID "sn-i2c" /* Interface specific parameters */ struct i2c_dev { From a6c862cb8af78423cc6e8b043644bb123fe1f98d Mon Sep 17 00:00:00 2001 From: Tapas Dey Date: Thu, 6 Jan 2022 18:10:46 +0530 Subject: [PATCH 050/100] NFC: driver: Fix compilation issues on NFC driver Modified code to fix compilation issues on NFC driver for MW version 12.10.00 and retained QC specific code. Change-Id: I9eeba3f6534a3c67c3b32b6361b4ef5d42965265 --- Android.mk | 2 +- Kbuild | 10 +- Kconfig | 19 +- config/gki_nfc.conf | 2 +- config/gki_nfc_conf.h | 9 +- nfc/Kbuild | 6 - nfc/Kconfig | 13 - nfc/Makefile | 10 - nfc/common.c | 97 ++- nfc/common.h | 133 ++++- nfc/common_ese.c | 361 ------------ nfc/common_ese.h | 99 ---- nfc/common_nxp.c | 332 +++++++++++ nfc/common_nxp.h | 77 +++ nfc/common_qcom.c | 163 +++++ {qti => nfc}/ese_cold_reset.c | 55 +- {qti => nfc}/ese_cold_reset.h | 0 nfc/i2c_drv.c | 94 ++- nfc/i2c_drv.h | 23 +- nfc_kernel_dlkm_vendor_board.mk | 2 +- nfc_kernel_dlkm_vendor_product.mk | 2 +- qti/nfc_common.c | 951 ------------------------------ qti/nfc_common.h | 346 ----------- qti/nfc_i2c_drv.c | 577 ------------------ qti/nfc_i2c_drv.h | 81 --- 25 files changed, 930 insertions(+), 2534 deletions(-) delete mode 100644 nfc/Kbuild delete mode 100644 nfc/Kconfig delete mode 100644 nfc/Makefile delete mode 100644 nfc/common_ese.c delete mode 100644 nfc/common_ese.h create mode 100644 nfc/common_nxp.c create mode 100644 nfc/common_nxp.h create mode 100644 nfc/common_qcom.c rename {qti => nfc}/ese_cold_reset.c (83%) rename {qti => nfc}/ese_cold_reset.h (100%) delete mode 100644 qti/nfc_common.c delete mode 100644 qti/nfc_common.h delete mode 100644 qti/nfc_i2c_drv.c delete mode 100644 qti/nfc_i2c_drv.h diff --git a/Android.mk b/Android.mk index f5eb11e2ed..3913c583d8 100644 --- a/Android.mk +++ b/Android.mk @@ -7,7 +7,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := nfc_i2c.ko +LOCAL_MODULE := nxp-nci.ko LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*) diff --git a/Kbuild b/Kbuild index 14531aecd4..93012c8f01 100644 --- a/Kbuild +++ b/Kbuild @@ -6,10 +6,12 @@ LINUXINCLUDE += -I$(NFC_ROOT)/include/uapi/linux/nfc LINUXINCLUDE += -include $(NFC_ROOT)/config/gki_nfc_conf.h -obj-$(CONFIG_NFC_QTI_I2C) += nfc_i2c.o +obj-$(CONFIG_NXP_NFC_I2C) += nxp-nci.o #source files -nfc_i2c-objs += qti/ese_cold_reset.o \ - qti/nfc_common.o \ - qti/nfc_i2c_drv.o +nxp-nci-objs += nfc/ese_cold_reset.o \ + nfc/common.o \ + nfc/common_nxp.o \ + nfc/common_qcom.o \ + nfc/i2c_drv.o diff --git a/Kconfig b/Kconfig index 623e0ae0a0..facfd412a1 100644 --- a/Kconfig +++ b/Kconfig @@ -1,10 +1,13 @@ -menuconfig NFC_QTI_I2C - tristate "QTI NCI based NFC I2C Slave Driver for SNxxx" - depends on I2C - help - This enables the NFC driver for SNxxx based devices. - This is for I2C connected version. NCI protocol logic - resides in the usermode and it has no other NFC dependencies. +# +# near field communication driver configuration +# - If unsure, say N. +config NXP_NFC_I2C + tristate "NXP NCI based NFC I2C Slave Driver for SNxxx" + depends on I2C + help + This enables the NFC driver for SNxxx based devices. + This is for I2C connected version. NCI protocol logic + resides in the usermode and it has no other NFC dependencies. + If unsure, say N. diff --git a/config/gki_nfc.conf b/config/gki_nfc.conf index 2e606798ec..28cd8d20ed 100644 --- a/config/gki_nfc.conf +++ b/config/gki_nfc.conf @@ -1 +1 @@ -export CONFIG_NFC_QTI_I2C=m +export CONFIG_NXP_NFC_I2C=m diff --git a/config/gki_nfc_conf.h b/config/gki_nfc_conf.h index 745406be62..76869b9838 100644 --- a/config/gki_nfc_conf.h +++ b/config/gki_nfc_conf.h @@ -1,6 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2021, The Linux Foundation. All rights reserved. - */ + * + ***************************************************************************/ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + ***************************************************************************/ -#define CONFIG_NFC_QTI_I2C 1 +#define CONFIG_NXP_NFC_I2C 1 diff --git a/nfc/Kbuild b/nfc/Kbuild deleted file mode 100644 index 198d574a94..0000000000 --- a/nfc/Kbuild +++ /dev/null @@ -1,6 +0,0 @@ -obj-$(CONFIG_NXP_NFC_I2C) := pn553_i2c.o - -pn553_i2c-y := common.o \ - common_ese.o \ - i2c_drv.o - diff --git a/nfc/Kconfig b/nfc/Kconfig deleted file mode 100644 index facfd412a1..0000000000 --- a/nfc/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# near field communication driver configuration -# - -config NXP_NFC_I2C - tristate "NXP NCI based NFC I2C Slave Driver for SNxxx" - depends on I2C - help - This enables the NFC driver for SNxxx based devices. - This is for I2C connected version. NCI protocol logic - resides in the usermode and it has no other NFC dependencies. - - If unsure, say N. diff --git a/nfc/Makefile b/nfc/Makefile deleted file mode 100644 index 4191dea226..0000000000 --- a/nfc/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) - -modules_install: - $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean diff --git a/nfc/common.c b/nfc/common.c index a4f8029fa1..c9b37cdcbb 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -17,17 +17,23 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + *****************************************************************************/ #include #include #include -#include "common_ese.h" +#include "common.h" int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface) { + int ret; struct device_node *np = dev->of_node; struct platform_gpio *nfc_gpio = &nfc_configs->gpio; + struct platform_ldo *ldo = &nfc_configs->ldo; if (!np) { pr_err("%s: nfc of_node NULL\n", __func__); @@ -42,7 +48,7 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, if (interface == PLATFORM_IF_I2C) { nfc_gpio->irq = of_get_named_gpio(np, DTS_IRQ_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->irq))) { - pr_err("%s: irq gpio invalid %d\n", __func__, + pr_err("%s: nfc irq gpio invalid %d\n", __func__, nfc_gpio->irq); return -EINVAL; } @@ -50,17 +56,38 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, } nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->ven))) { - pr_err("%s: ven gpio invalid %d\n", __func__, nfc_gpio->ven); + pr_err("%s: nfc ven gpio invalid %d\n", __func__, nfc_gpio->ven); return -EINVAL; } /* some products like sn220 does not required fw dwl pin */ nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); + /* not returning failure for dwl gpio as it is optional for sn220 */ if ((!gpio_is_valid(nfc_gpio->dwl_req))) - pr_warn("%s: dwl_req gpio invalid %d\n", __func__, + pr_warn("%s: nfc dwl_req gpio invalid %d\n", __func__, nfc_gpio->dwl_req); - pr_info("%s: %d, %d, %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven, + pr_info("%s: irq %d, ven %d, dwl %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven, nfc_gpio->dwl_req); + + /* optional property */ + ret = of_property_read_u32_array(np, NFC_LDO_VOL_DT_NAME, + (u32 *) ldo->vdd_levels, + ARRAY_SIZE(ldo->vdd_levels)); + if (ret) { + dev_err(dev, "error reading NFC VDDIO min and max value\n"); + // set default as per datasheet + ldo->vdd_levels[0] = NFC_VDDIO_MIN; + ldo->vdd_levels[1] = NFC_VDDIO_MAX; + } + + /* optional property */ + ret = of_property_read_u32(np, NFC_LDO_CUR_DT_NAME, &ldo->max_current); + if (ret) { + dev_err(dev, "error reading NFC current value\n"); + // set default as per datasheet + ldo->max_current = NFC_CURRENT_MAX; + } + return 0; } @@ -92,9 +119,6 @@ void gpio_set_ven(struct nfc_dev *nfc_dev, int value) if (gpio_get_value(nfc_gpio->ven) != value) { pr_debug("%s: value %d\n", __func__, value); - /* reset on change in level from high to low */ - if (value) - ese_cold_reset_release(nfc_dev); gpio_set_value(nfc_gpio->ven, value); /* hardware dependent delay */ @@ -168,10 +192,13 @@ void gpio_free_all(struct nfc_dev *nfc_dev) void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count) { pr_debug("%s: entry\n", __func__); + kfree(nfc_dev->kbuf); device_destroy(nfc_dev->nfc_class, nfc_dev->devno); cdev_del(&nfc_dev->c_dev); class_destroy(nfc_dev->nfc_class); unregister_chrdev_region(nfc_dev->devno, count); + if (nfc_dev->ipcl) + ipc_log_context_destroy(nfc_dev->ipcl); } int nfc_misc_register(struct nfc_dev *nfc_dev, @@ -213,6 +240,23 @@ int nfc_misc_register(struct nfc_dev *nfc_dev, unregister_chrdev_region(nfc_dev->devno, count); return ret; } + nfc_dev->ipcl = ipc_log_context_create(NUM_OF_IPC_LOG_PAGES, + dev_name(nfc_dev->nfc_device), 0); + + nfc_dev->kbuflen = MAX_NCI_BUFFER_SIZE; + nfc_dev->kbuf = kzalloc(MAX_NCI_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); + if (!nfc_dev->kbuf) { + nfc_misc_unregister(nfc_dev, count); + return -ENOMEM; + } + + nfc_dev->cold_reset.rsp_pending = false; + nfc_dev->cold_reset.is_nfc_enabled = false; + nfc_dev->cold_reset.is_crp_en = false; + nfc_dev->cold_reset.last_src_ese_prot = ESE_COLD_RESET_ORIGIN_NONE; + + init_waitqueue_head(&nfc_dev->cold_reset.read_wq); + return 0; } @@ -264,6 +308,7 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) * Setting firmware download gpio to HIGH * before FW download start */ + pr_debug("set fw gpio high\n"); set_valid_gpio(nfc_gpio->dwl_req, 1); nfc_dev->nfc_state = NFC_STATE_FW_DWL; @@ -272,15 +317,29 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) gpio_set_ven(nfc_dev, 0); gpio_set_ven(nfc_dev, 1); nfc_dev->nfc_enable_intr(nfc_dev); + pr_info("%s VEN forced reset done\n", __func__); + } else if (arg == NFC_FW_DWL_LOW) { /* * Setting firmware download gpio to LOW * FW download finished */ + pr_debug("set fw gpio LOW\n"); set_valid_gpio(nfc_gpio->dwl_req, 0); nfc_dev->nfc_state = NFC_STATE_NCI; - } else { - pr_err("%s: bad arg %lu\n", __func__, arg); + + } else if (arg == NFC_ENABLE) { + /* + * Setting flag true when NFC is enabled + */ + nfc_dev->cold_reset.is_nfc_enabled = true; + } else if (arg == NFC_DISABLE) { + /* + * Setting flag true when NFC is disabled + */ + nfc_dev->cold_reset.is_nfc_enabled = false; + } else { + pr_err("%s bad arg %lu\n", __func__, arg); ret = -ENOIOCTLCMD; } return ret; @@ -343,10 +402,17 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) case ESE_GET_PWR: ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE); break; + case NFCC_GET_INFO: + ret = nfc_ioctl_nfcc_info(pfile, arg); + break; + case ESE_COLD_RESET: + pr_debug("nfc ese cold reset ioctl\n"); + ret = ese_cold_reset_ioctl(nfc_dev, arg); + break; default: pr_err("%s: bad cmd %lu\n", __func__, arg); ret = -ENOIOCTLCMD; - }; + } return ret; } @@ -413,14 +479,7 @@ int nfc_dev_close(struct inode *inode, struct file *filp) } if (nfc_dev->dev_ref_count > 0) nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; - else { - /* - * Use "ESE_RST_PROT_DIS" as argument - * if eSE calls flow is via NFC driver - * i.e. direct calls from SPI HAL to NFC driver - */ - nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS_NFC); - } + filp->private_data = NULL; mutex_unlock(&nfc_dev->dev_ref_mutex); diff --git a/nfc/common.h b/nfc/common.h index bcdd26dd33..1c723bf79c 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -17,41 +17,68 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + *****************************************************************************/ #ifndef _COMMON_H_ #define _COMMON_H_ #include - +#include +#include +#include +#include #include "i2c_drv.h" +#include "ese_cold_reset.h" /* Max device count for this driver */ #define DEV_COUNT 1 /* i2c device class */ -#define CLASS_NAME "nfc" +#define CLASS_NAME "qti-nfc" /* NFC character device name, this will be in /dev/ */ -#define NFC_CHAR_DEV_NAME "pn553" +#define NFC_CHAR_DEV_NAME "nq-nci" /* NCI packet details */ #define NCI_CMD (0x20) #define NCI_RSP (0x40) +#define NCI_NTF (0x60) #define NCI_HDR_LEN (3) #define NCI_HDR_IDX (0) +#define DL_CMD 0x00 +#define DL_PAYLOAD_BYTE_ZERO 0x00 #define NCI_HDR_OID_IDX (1) #define NCI_PAYLOAD_IDX (3) #define NCI_PAYLOAD_LEN_IDX (2) -/* FW DNLD packet details */ +/*Time to wait for first NCI rest response*/ +#define NCI_RESET_RESP_READ_DELAY (10000) // 10ms +#define NCI_RESET_RESP_TIMEOUT (500) // 500ms + +// FW DNLD packet details +#define FW_MSG_CMD_RSP 0x00 #define DL_HDR_LEN (2) +#define FW_PAYLOAD_LEN_IDX 1 #define DL_CRC_LEN (2) +#define NCI_RSP_PKT_TYPE (0x40) +#define FW_MIN_PAYLOAD_LEN 4 +#define MIN_NFC_DL_FRAME_SIZE 3 + +#define GET_VERSION_CMD_LEN 8 +#define GET_SESSION_STATE_CMD_LEN 8 #define MAX_NCI_PAYLOAD_LEN (255) #define MAX_NCI_BUFFER_SIZE (NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN) +/* + * From MW 11.04 buffer size increased to support + * frame size of 554 in FW download mode + * Frame len(2) + Frame Header(6) + DATA(512) + HASH(32) + CRC(2) + RFU(4) + */ #define MAX_DL_PAYLOAD_LEN (550) #define MAX_DL_BUFFER_SIZE (DL_HDR_LEN + DL_CRC_LEN + \ MAX_DL_PAYLOAD_LEN) - /* Retry count for normal write */ #define NO_RETRY (1) /* Maximum retry count for standby writes */ @@ -64,6 +91,8 @@ #define NCI_CMD_RSP_TIMEOUT_MS (2000) /* Time to wait for NFCC to be ready again after any change in the GPIO */ #define NFC_GPIO_SET_WAIT_TIME_US (10000) +/*Time to wait after soft reset via any NCI/DL cmd*/ +#define NFC_SOFT_RESET_WAIT_TIME_USEC (5000) /* Time to wait for IRQ low during write 5*3ms */ #define NFC_WRITE_IRQ_WAIT_TIME_US (3000) /* Time to wait before retrying i2c/I3C writes */ @@ -72,15 +101,51 @@ #define READ_RETRY_WAIT_TIME_US (3500) #define NFC_MAGIC (0xE9) -/* Ioctls */ -/* The type should be aligned with MW HAL definitions */ -#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) -#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) -#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) +// Ioctls +// The type should be aligned with MW HAL definitions -#define DTS_IRQ_GPIO_STR "nxp,pn544-irq" -#define DTS_VEN_GPIO_STR "nxp,pn544-ven" -#define DTS_FWDN_GPIO_STR "nxp,pn544-fw-dwnld" +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, unsigned int) +#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, unsigned int) +#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, unsigned int) + +#define DTS_IRQ_GPIO_STR "qcom,sn-irq" +#define DTS_VEN_GPIO_STR "qcom,sn-ven" +#define DTS_FWDN_GPIO_STR "qcom,sn-firm" +#define NFC_LDO_SUPPLY_DT_NAME "qcom,sn-vdd-1p8" +#define NFC_LDO_SUPPLY_NAME "qcom,sn-vdd-1p8-supply" +#define NFC_LDO_VOL_DT_NAME "qcom,sn-vdd-1p8-voltage" +#define NFC_LDO_CUR_DT_NAME "qcom,sn-vdd-1p8-current" + +//as per SN1x0 datasheet +#define NFC_VDDIO_MIN 1650000 //in uV +#define NFC_VDDIO_MAX 1950000 //in uV +#define NFC_CURRENT_MAX 157000 //in uA + + +#define NUM_OF_IPC_LOG_PAGES (2) +#define PKT_MAX_LEN (4) // no of max bytes to print for cmd/resp + +#define GET_IPCLOG_MAX_PKT_LEN(c) ((c > PKT_MAX_LEN) ? PKT_MAX_LEN : c) + +#define NFCLOG_IPC(nfc_dev, log_to_dmesg, x...) \ +do { \ + ipc_log_string(nfc_dev->ipcl, x); \ + if (log_to_dmesg) { \ + if (nfc_dev->nfc_device) \ + dev_err((nfc_dev->nfc_device), x); \ + else \ + pr_err(x); \ + } \ +} while (0) + +enum ese_ioctl_request { + /* eSE POWER ON */ + ESE_POWER_ON = 0, + /* eSE POWER OFF */ + ESE_POWER_OFF, + /* eSE POWER STATE */ + ESE_POWER_STATE +}; enum nfcc_ioctl_request { /* NFC disable request with VEN LOW */ @@ -97,6 +162,10 @@ enum nfcc_ioctl_request { NFC_VEN_FORCED_HARD_RESET, /* request for firmware download gpio LOW */ NFC_FW_DWL_LOW, + /* NFC enable without VEN gpio modification */ + NFC_ENABLE, + /* NFC disable without VEN gpio modification */ + NFC_DISABLE, }; /* nfc platform interface type */ @@ -142,21 +211,18 @@ struct platform_gpio { unsigned int dwl_req; }; +// NFC LDO entries from DT +struct platform_ldo { + int vdd_levels[2]; + int max_current; +}; + /* NFC Struct to get all the required configs from DTS */ struct platform_configs { struct platform_gpio gpio; + struct platform_ldo ldo; }; -/* cold reset Features specific Parameters */ -struct cold_reset { - bool rsp_pending; /* cmd rsp pending status */ - bool in_progress; /* for cold reset when gurad timer in progress */ - bool reset_protection; /* reset protection enabled/disabled */ - uint8_t status; /* status from response buffer */ - uint8_t rst_prot_src; /* reset protection source (SPI, NFC) */ - struct timer_list timer; - wait_queue_head_t read_wq; -}; /* Device specific structure */ struct nfc_dev { @@ -177,12 +243,25 @@ struct nfc_dev { uint8_t nfc_state; /* NFC VEN pin state */ bool nfc_ven_enabled; + /* current firmware major version */ + uint8_t fw_major_version; + bool is_vreg_enabled; + bool is_ese_session_active; bool release_read; union { struct i2c_dev i2c_dev; }; struct platform_configs configs; struct cold_reset cold_reset; + struct regulator *reg; + + /* read buffer*/ + size_t kbuflen; + u8 *kbuf; + + union nqx_uinfo nqx_info; + + void *ipcl; /* function pointers for the common i2c functionality */ int (*nfc_read)(struct nfc_dev *dev, char *buf, size_t count, @@ -207,6 +286,14 @@ int nfc_misc_register(struct nfc_dev *nfc_dev, void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count); int configure_gpio(unsigned int gpio, int flag); void gpio_set_ven(struct nfc_dev *nfc_dev, int value); +void set_valid_gpio(int gpio, int value); +int nfcc_hw_check(struct nfc_dev *nfc_dev); +unsigned int nfc_ioctl_nfcc_info(struct file *, unsigned long); void gpio_free_all(struct nfc_dev *nfc_dev); +int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev); +int nfc_ldo_vote(struct nfc_dev *nfc_dev); +int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg); +int nfc_ldo_unvote(struct nfc_dev *nfc_dev); +int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev); int validate_nfc_state_nci(struct nfc_dev *nfc_dev); #endif /* _COMMON_H_ */ diff --git a/nfc/common_ese.c b/nfc/common_ese.c deleted file mode 100644 index 5c725a6845..0000000000 --- a/nfc/common_ese.c +++ /dev/null @@ -1,361 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2020-2021 NXP - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#include -#include -#include - -#include "common_ese.h" - -static void cold_reset_gaurd_timer_callback(struct timer_list *t) -{ - struct cold_reset *cold_reset = from_timer(cold_reset, t, timer); - - pr_debug("%s: entry\n", __func__); - cold_reset->in_progress = false; -} - -static long start_cold_reset_guard_timer(struct cold_reset *cold_reset) -{ - long ret = -EINVAL; - - if (timer_pending(&cold_reset->timer) == 1) { - pr_debug("%s: delete pending timer\n", __func__); - /* delete timer if already pending */ - del_timer(&cold_reset->timer); - } - cold_reset->in_progress = true; - timer_setup(&cold_reset->timer, cold_reset_gaurd_timer_callback, 0); - ret = mod_timer(&cold_reset->timer, - jiffies + msecs_to_jiffies(ESE_CLD_RST_GUARD_TIME_MS)); - return ret; -} - -static int send_cold_reset_protection_cmd(struct nfc_dev *nfc_dev, - bool requestType) -{ - int ret = 0; - int cmd_length = 0; - uint8_t *cmd = nfc_dev->write_kbuf; - struct cold_reset *cold_reset = &nfc_dev->cold_reset; - - *cmd++ = NCI_PROP_MSG_CMD; - - if (requestType) { /* reset protection */ - *cmd++ = RST_PROT_OID; - *cmd++ = RST_PROT_PAYLOAD_SIZE; - *cmd++ = (!cold_reset->reset_protection) ? 1 : 0; - } else { /* cold reset */ - *cmd++ = CLD_RST_OID; - *cmd++ = CLD_RST_PAYLOAD_SIZE; - } - cmd_length = cmd - nfc_dev->write_kbuf; - - ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, - MAX_RETRY_COUNT); - if (ret != cmd_length) { - ret = -EIO; - pr_err("%s: nfc_write returned %d\n", __func__, ret); - goto exit; - } - cmd = nfc_dev->write_kbuf; - if (requestType) - pr_debug(" %s: NxpNciX: %d > 0x%02x%02x%02x%02x\n", __func__, - ret, cmd[NCI_HDR_IDX], cmd[NCI_HDR_OID_IDX], - cmd[NCI_PAYLOAD_LEN_IDX], cmd[NCI_PAYLOAD_IDX]); - else - pr_debug(" %s: NxpNciX: %d > 0x%02x%02x%02x\n", __func__, ret, - cmd[NCI_HDR_IDX], cmd[NCI_HDR_OID_IDX], - cmd[NCI_PAYLOAD_LEN_IDX]); -exit: - return ret; -} - -void wakeup_on_prop_rsp(struct nfc_dev *nfc_dev, uint8_t *buf) -{ - struct cold_reset *cold_reset = &nfc_dev->cold_reset; - - cold_reset->status = -EIO; - if ((NCI_HDR_LEN + buf[NCI_PAYLOAD_LEN_IDX]) != NCI_PROP_MSG_RSP_LEN) - pr_err("%s: invalid response for cold_reset/protection\n", - __func__); - else - cold_reset->status = buf[NCI_PAYLOAD_IDX]; - - pr_debug(" %s: NxpNciR 0x%02x%02x%02x%02x\n", __func__, - buf[NCI_HDR_IDX], buf[NCI_HDR_OID_IDX], - buf[NCI_PAYLOAD_LEN_IDX], buf[NCI_PAYLOAD_IDX]); - - cold_reset->rsp_pending = false; - wake_up_interruptible(&cold_reset->read_wq); -} - -static int validate_cold_reset_protection_request(struct cold_reset *cold_reset, - unsigned long arg) -{ - int ret = 0; - - if (!cold_reset->reset_protection) { - if (IS_RST_PROT_EN_REQ(arg) && IS_SRC_VALID_PROT(arg)) { - pr_debug("%s: reset protection enable\n", __func__); - } else if (IS_CLD_RST_REQ(arg) && IS_SRC_VALID(arg)) { - pr_debug("%s: cold reset\n", __func__); - } else if (IS_RST_PROT_DIS_REQ(arg) && IS_SRC_VALID_PROT(arg)) { - pr_debug("%s: reset protection already disable\n", - __func__); - ret = -EINVAL; - } else { - pr_err("%s: operation not permitted\n", __func__); - ret = -EPERM; - } - } else { - if (IS_RST_PROT_DIS_REQ(arg) && - IS_SRC(arg, cold_reset->rst_prot_src)) { - pr_debug("%s: disable reset protection from same src\n", - __func__); - } else if (IS_CLD_RST_REQ(arg) && - IS_SRC(arg, cold_reset->rst_prot_src)) { - pr_debug("%s: cold reset from same source\n", __func__); - } else if (IS_RST_PROT_EN_REQ(arg) && - IS_SRC(arg, cold_reset->rst_prot_src)) { - pr_debug("%s: enable reset protection from same src\n", - __func__); - } else { - pr_err("%s: operation not permitted\n", __func__); - ret = -EPERM; - } - } - return ret; -} - -static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, - unsigned long arg) -{ - int ret = 0; - int timeout = 0; - char *rsp = nfc_dev->read_kbuf; - struct cold_reset *cold_reset = &nfc_dev->cold_reset; - - /* check if NFCC not in the FW download or hard reset state */ - ret = validate_nfc_state_nci(nfc_dev); - if (ret < 0) { - pr_err("%s: invalid cmd\n", __func__); - return ret; - } - - /* check if NFCC not in the FW download or hard reset state */ - ret = validate_cold_reset_protection_request(cold_reset, arg); - if (ret < 0) { - pr_err("%s: invalid cmd\n", __func__); - goto err; - } - - /* check if cold reset already in progress */ - if (IS_CLD_RST_REQ(arg) && cold_reset->in_progress) { - pr_err("%s: cold reset already in progress\n", __func__); - ret = -EBUSY; - goto err; - } - - /* enable interrupt if not enabled incase when devnode not opened by HAL */ - nfc_dev->nfc_enable_intr(nfc_dev); - - mutex_lock(&nfc_dev->write_mutex); - /* write api has 15ms maximum wait to clear any pending read before */ - cold_reset->status = -EIO; - cold_reset->rsp_pending = true; - ret = send_cold_reset_protection_cmd(nfc_dev, IS_RST_PROT_REQ(arg)); - if (ret < 0) { - mutex_unlock(&nfc_dev->write_mutex); - cold_reset->rsp_pending = false; - pr_err("%s: failed to send cold reset/protection cmd\n", - __func__); - goto err; - } - - ret = 0; - /* start the cold reset guard timer */ - if (IS_CLD_RST_REQ(arg)) { - /* Guard timer not needed when OSU over NFC */ - if (!(cold_reset->reset_protection && IS_SRC_NFC(arg))) { - ret = start_cold_reset_guard_timer(cold_reset); - if (ret) { - mutex_unlock(&nfc_dev->write_mutex); - pr_err("%s: error in mod_timer\n", __func__); - goto err; - } - } - } - - timeout = NCI_CMD_RSP_TIMEOUT_MS; - do { - /* call read api directly if reader thread is not blocked */ - if (mutex_trylock(&nfc_dev->read_mutex)) { - pr_debug("%s: reader thread not pending\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp, 3, - timeout); - mutex_unlock(&nfc_dev->read_mutex); - if (!ret) - break; - usleep_range(READ_RETRY_WAIT_TIME_US, - READ_RETRY_WAIT_TIME_US + 500); - /* Read pending response form the HAL service */ - } else if (!wait_event_interruptible_timeout( - cold_reset->read_wq, - cold_reset->rsp_pending == false, - msecs_to_jiffies(timeout))) { - pr_err("%s: cold reset/prot response timeout\n", __func__); - ret = -EAGAIN; - } - } while (ret == -ERESTARTSYS || ret == -EFAULT); - mutex_unlock(&nfc_dev->write_mutex); - - timeout = ESE_CLD_RST_REBOOT_GUARD_TIME_MS; - if (ret == 0) { /* success case */ - ret = cold_reset->status; - if (IS_RST_PROT_REQ(arg)) { - cold_reset->reset_protection = IS_RST_PROT_EN_REQ(arg); - cold_reset->rst_prot_src = IS_RST_PROT_EN_REQ(arg) ? - GET_SRC(arg) : - SRC_NONE; - /* wait for reboot guard timer */ - } else if (wait_event_interruptible_timeout( - cold_reset->read_wq, true, - msecs_to_jiffies(timeout)) == 0) { - pr_info("%s: reboot guard timer timeout\n", __func__); - } - } -err: - mutex_unlock(&nfc_dev->dev_ref_mutex); - return ret; -} - -/** - * nfc_ese_pwr() - power control for ese - * @nfc_dev: nfc device data structure - * @arg: mode that we want to move to - * - * Device power control. Depending on the arg value, device moves to - * different states, refer common_ese.h for args - * - * Return: -ENOIOCTLCMD if arg is not supported - * 0 if Success(or no issue) - * 0 or 1 in case of arg is ESE_POWER_STATE - * and error ret code otherwise - */ -int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) -{ - int ret = 0; - struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - - if (arg == ESE_POWER_ON) { - /* - * Let's store the NFC VEN pin state - * will check stored value in case of eSE power off request, - * to find out if NFC MW also sent request to set VEN HIGH - * VEN state will remain HIGH if NFC is enabled otherwise - * it will be set as LOW - */ - nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_gpio->ven); - if (!nfc_dev->nfc_ven_enabled) { - pr_debug("%s: ese hal service setting ven high\n", - __func__); - gpio_set_ven(nfc_dev, 1); - } else { - pr_debug("%s: ven already high\n", __func__); - } - } else if (arg == ESE_POWER_OFF) { - if (!nfc_dev->nfc_ven_enabled) { - pr_debug("%s: nfc not enabled, disabling ven\n", - __func__); - gpio_set_ven(nfc_dev, 0); - } else { - pr_debug("%s: keep ven high as nfc is enabled\n", - __func__); - } - } else if (arg == ESE_POWER_STATE) { - /* eSE get power state */ - ret = gpio_get_value(nfc_gpio->ven); - } else if (IS_CLD_RST_REQ(arg) || IS_RST_PROT_REQ(arg)) { - ret = perform_cold_reset_protection(nfc_dev, arg); - } else { - pr_err("%s: bad arg %lu\n", __func__, arg); - ret = -ENOIOCTLCMD; - } - return ret; -} -EXPORT_SYMBOL(nfc_ese_pwr); - -#define ESE_LEGACY_INTERFACE -#ifdef ESE_LEGACY_INTERFACE -static struct nfc_dev *nfc_dev_legacy; - -/****************************************************************************** - * perform_ese_cold_reset() - It shall be called by others driver(not nfc/ese) - * to perform cold reset only - * @arg: request of cold reset from other drivers should be ESE_CLD_RST_OTHER - * - * Returns:- 0 in case of success and negative values in case of failure - *****************************************************************************/ -int perform_ese_cold_reset(unsigned long arg) -{ - int ret = 0; - - if (nfc_dev_legacy) { - if (IS_CLD_RST_REQ(arg) && IS_SRC_OTHER(arg)) { - ret = nfc_ese_pwr(nfc_dev_legacy, arg); - } else { - pr_err("%s: operation not permitted\n", __func__); - return -EPERM; - } - } - pr_debug("%s: arg = %d ret = %lu\n", __func__, arg, ret); - return ret; -} -EXPORT_SYMBOL(perform_ese_cold_reset); -#endif /* ESE_LEGACY_INTERFACE */ - -void ese_cold_reset_release(struct nfc_dev *nfc_dev) -{ - struct cold_reset *cold_reset = &nfc_dev->cold_reset; - - cold_reset->rsp_pending = false; - cold_reset->in_progress = false; - if (timer_pending(&cold_reset->timer) == 1) - del_timer(&cold_reset->timer); -} - -void common_ese_init(struct nfc_dev *nfc_dev) -{ - struct cold_reset *cold_reset = &nfc_dev->cold_reset; - - cold_reset->reset_protection = false; - cold_reset->rst_prot_src = SRC_NONE; - init_waitqueue_head(&cold_reset->read_wq); - ese_cold_reset_release(nfc_dev); -#ifdef ESE_LEGACY_INTERFACE - nfc_dev_legacy = nfc_dev; -#endif /* ESE_LEGACY_INTERFACE */ -} - -void common_ese_exit(struct nfc_dev *nfc_dev) -{ -#ifdef ESE_LEGACY_INTERFACE - nfc_dev_legacy = NULL; -#endif /* ESE_LEGACY_INTERFACE */ -} diff --git a/nfc/common_ese.h b/nfc/common_ese.h deleted file mode 100644 index c8d563724b..0000000000 --- a/nfc/common_ese.h +++ /dev/null @@ -1,99 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2020-2021 NXP - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -#ifndef _COMMON_ESE_H_ -#define _COMMON_ESE_H_ - -#include "common.h" - -/* nci prop msg 1st byte */ -#define NCI_PROP_MSG_GID 0x0F -#define NCI_PROP_MSG_CMD (NCI_CMD | NCI_PROP_MSG_GID) -#define NCI_PROP_MSG_RSP (NCI_RSP | NCI_PROP_MSG_GID) - -/* nci prop msg 2nd byte */ -#define CLD_RST_OID 0x1E -#define RST_PROT_OID 0x1F - -/* nci prop msg 3rd byte */ -#define CLD_RST_PAYLOAD_SIZE 0x00 -#define RST_PROT_PAYLOAD_SIZE 0x01 - -/* nci prop msg response length */ -#define NCI_PROP_MSG_RSP_LEN 0x04 - -/* cold reset guard time to allow back to back cold reset after some time */ -#define ESE_CLD_RST_GUARD_TIME_MS (3000) -/* guard time to reboot after reset */ -#define ESE_CLD_RST_REBOOT_GUARD_TIME_MS (50) -/* sources of reset protection and cold reset */ -enum reset_source { - SRC_SPI = 0, - SRC_NFC = 0x10, - SRC_OTHER = 0x20, - SRC_NONE = 0x80, -}; - -enum ese_ioctl_request { - ESE_POWER_ON = 0, /* eSE POWER ON */ - ESE_POWER_OFF, /* eSE POWER OFF */ - ESE_POWER_STATE, /* eSE GET POWER STATE */ - - /* ese reset requests from eSE service/hal/driver */ - ESE_CLD_RST, /* eSE COLD RESET */ - ESE_RST_PROT_EN, /* eSE RESET PROTECTION ENABLE */ - ESE_RST_PROT_DIS, /* eSE RESET PROTECTION DISABLE */ - - /* similar ese reset requests from nfc service/hal/driver */ - ESE_CLD_RST_NFC = ESE_CLD_RST | SRC_NFC, - ESE_RST_PROT_EN_NFC = ESE_RST_PROT_EN | SRC_NFC, - ESE_RST_PROT_DIS_NFC = ESE_RST_PROT_DIS | SRC_NFC, - - /* similar ese reset requests from other service/hal/driver */ - ESE_CLD_RST_OTHER = ESE_CLD_RST | SRC_OTHER, -}; - -#define GET_SRC(arg) (arg & 0xF0) -#define IS_SRC(arg, src) (GET_SRC(arg) == src) -#define IS_SRC_SPI(arg) IS_SRC(arg, SRC_SPI) -#define IS_SRC_NFC(arg) IS_SRC(arg, SRC_NFC) -#define IS_SRC_OTHER(arg) IS_SRC(arg, SRC_OTHER) -#define IS_SRC_VALID(arg) (IS_SRC_SPI(arg) || \ - IS_SRC_NFC(arg) || \ - IS_SRC_OTHER(arg)) -#define IS_SRC_VALID_PROT(arg) (IS_SRC_SPI(arg) || \ - IS_SRC_NFC(arg)) - -#define IS_RST(arg, type) ((arg & 0xF) == type) -#define IS_CLD_RST_REQ(arg) IS_RST(arg, ESE_CLD_RST) -#define IS_RST_PROT_EN_REQ(arg) IS_RST(arg, ESE_RST_PROT_EN) -#define IS_RST_PROT_DIS_REQ(arg) IS_RST(arg, ESE_RST_PROT_DIS) -#define IS_RST_PROT_REQ(arg) (IS_RST_PROT_EN_REQ(arg) || \ - IS_RST_PROT_DIS_REQ(arg)) -/* This macro evaluates to 1 if prop cmd response is received */ -#define IS_PROP_CMD_RSP(buf) ((buf[0] == NCI_PROP_MSG_RSP) && \ - ((buf[1] == CLD_RST_OID) || \ - (buf[1] == RST_PROT_OID))) - -void wakeup_on_prop_rsp(struct nfc_dev *nfc_dev, uint8_t *buf); -int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg); -void ese_cold_reset_release(struct nfc_dev *nfc_dev); -void common_ese_init(struct nfc_dev *nfc_dev); -void common_ese_exit(struct nfc_dev *nfc_dev); - -#endif /* _COMMON_ESE_H_ */ diff --git a/nfc/common_nxp.c b/nfc/common_nxp.c new file mode 100644 index 0000000000..8211a7cab6 --- /dev/null +++ b/nfc/common_nxp.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021 NXP + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + ******************************************************************************/ +#include "common.h" +#include "common_nxp.h" + +/** + * get_nfcc_chip_type_dl() - get chip type in fw download command; + * @nfc_dev: nfc device data structure + * + * Perform get version command and determine chip + * type from response. + * + * @Return: enum chip_types value + * + */ +static enum chip_types get_nfcc_chip_type_dl(struct nfc_dev *nfc_dev) +{ + int ret = 0; + uint8_t *cmd = nfc_dev->write_kbuf; + uint8_t *rsp = nfc_dev->read_kbuf; + enum chip_types chip_type = CHIP_UNKNOWN; + + *cmd++ = DL_CMD; + *cmd++ = DL_GET_VERSION_CMD_PAYLOAD_LEN; + *cmd++ = DL_GET_VERSION_CMD_ID; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_GET_VERSION_CMD_CRC_1; + *cmd++ = DL_GET_VERSION_CMD_CRC_2; + + pr_debug("%s:Sending GET_VERSION cmd of size = %d\n", __func__, DL_GET_VERSION_CMD_LEN); + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, DL_GET_VERSION_CMD_LEN, + MAX_RETRY_COUNT); + if (ret <= 0) { + pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret); + goto err; + } + memset(rsp, 0x00, DL_GET_VERSION_RSP_LEN_2); + pr_debug("%s:Reading response of GET_VERSION cmd\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_VERSION_RSP_LEN_2, NCI_CMD_RSP_TIMEOUT_MS); + if (ret <= 0) { + pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret); + goto err; + } + if (rsp[0] == FW_MSG_CMD_RSP && ret >= DL_GET_VERSION_RSP_LEN_2) { + + nfc_dev->fw_major_version = rsp[FW_MAJOR_VER_OFFSET]; + + if (rsp[FW_ROM_CODE_VER_OFFSET] == SN1XX_ROM_VER && + rsp[FW_MAJOR_VER_OFFSET] == SN1xx_MAJOR_VER) + chip_type = CHIP_SN1XX; + else if (rsp[FW_ROM_CODE_VER_OFFSET] == SN220_ROM_VER && + rsp[FW_MAJOR_VER_OFFSET] == SN220_MAJOR_VER) + chip_type = CHIP_SN220; + + pr_debug("%s:NFC Chip Type 0x%02x Rom Version 0x%02x FW Minor 0x%02x Major 0x%02x\n", + __func__, rsp[GET_VERSION_RSP_CHIP_TYPE_OFFSET], + rsp[FW_ROM_CODE_VER_OFFSET], + rsp[GET_VERSION_RSP_MINOR_VERSION_OFFSET], + rsp[FW_MAJOR_VER_OFFSET]); + + nfc_dev->nqx_info.info.chip_type = rsp[GET_VERSION_RSP_CHIP_TYPE_OFFSET]; + nfc_dev->nqx_info.info.rom_version = rsp[FW_ROM_CODE_VER_OFFSET]; + nfc_dev->nqx_info.info.fw_minor = rsp[GET_VERSION_RSP_MINOR_VERSION_OFFSET]; + nfc_dev->nqx_info.info.fw_major = rsp[FW_MAJOR_VER_OFFSET]; + } +err: + return chip_type; +} + +/** + * get_nfcc_session_state_dl() - gets the session state + * @nfc_dev: nfc device data structure + * + * Performs get session command and determine + * the nfcc state based on session status. + * + * @Return nfcc state based on session status. + * NFC_STATE_FW_TEARED if sessionis not closed + * NFC_STATE_FW_DWL if session closed + * NFC_STATE_UNKNOWN in error cases. + */ +enum nfc_state_flags get_nfcc_session_state_dl(struct nfc_dev *nfc_dev) +{ + int ret = 0; + uint8_t *cmd = nfc_dev->write_kbuf; + uint8_t *rsp = nfc_dev->read_kbuf; + enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN; + + *cmd++ = DL_CMD; + *cmd++ = DL_GET_SESSION_STATE_CMD_PAYLOAD_LEN; + *cmd++ = DL_GET_SESSION_CMD_ID; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_PAYLOAD_BYTE_ZERO; + *cmd++ = DL_GET_SESSION_CMD_CRC_1; + *cmd++ = DL_GET_SESSION_CMD_CRC_2; + + pr_debug("%s:Sending GET_SESSION_STATE cmd of size = %d\n", __func__, + DL_GET_SESSION_STATE_CMD_LEN); + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, DL_GET_SESSION_STATE_CMD_LEN, + MAX_RETRY_COUNT); + if (ret <= 0) { + pr_err("%s: - nfc get session cmd error ret %d\n", __func__, ret); + goto err; + } + memset(rsp, 0x00, DL_GET_SESSION_STATE_RSP_LEN); + pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT_MS); + if (ret <= 0) { + pr_err("%s: - nfc get session rsp error ret %d\n", __func__, ret); + goto err; + } + if (rsp[0] != FW_MSG_CMD_RSP) { + pr_err("%s: - nfc invalid get session state rsp\n", __func__); + goto err; + } + pr_debug("Response bytes are %02x%02x%02x%02x%02x%02x%02x%02x\n", + rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6], rsp[7]); + /*verify fw in non-teared state */ + if (rsp[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) { + pr_err("%s NFCC booted in FW teared state\n", __func__); + nfc_state = NFC_STATE_FW_TEARED; + } else { + pr_info("%s NFCC booted in FW DN mode\n", __func__); + nfc_state = NFC_STATE_FW_DWL; + } +err: + return nfc_state; +} + +/** + * get_nfcc_chip_type() - get nfcc chip type in nci mode. + * @nfc_dev: nfc device data structure. + * + * Function to perform nci core reset and extract + * chip type from the response. + * + * @Return: enum chip_types value + * + */ +static enum chip_types get_nfcc_chip_type(struct nfc_dev *nfc_dev) +{ + int ret = 0; + uint8_t major_version = 0; + uint8_t rom_version = 0; + uint8_t *cmd = nfc_dev->write_kbuf; + uint8_t *rsp = nfc_dev->read_kbuf; + enum chip_types chip_type = CHIP_UNKNOWN; + + *cmd++ = NCI_CMD; + *cmd++ = NCI_CORE_RESET_CMD_OID; + *cmd++ = NCI_CORE_RESET_CMD_PAYLOAD_LEN; + *cmd++ = NCI_CORE_RESET_KEEP_CONFIG; + + pr_debug("%s:Sending NCI Core Reset cmd of size = %d\n", __func__, NCI_RESET_CMD_LEN); + ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, NCI_RESET_CMD_LEN, NO_RETRY); + if (ret <= 0) { + pr_err("%s: - nfc nci core reset cmd error ret %d\n", __func__, ret); + goto err; + } + + /* to flush out debug NTF this delay is required */ + usleep_range(NCI_RESET_RESP_READ_DELAY, NCI_RESET_RESP_READ_DELAY + 100); + nfc_dev->nfc_enable_intr(nfc_dev); + + memset(rsp, 0x00, NCI_RESET_RSP_LEN); + pr_debug("%s:Reading NCI Core Reset rsp\n", __func__); + ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_RSP_LEN, NCI_CMD_RSP_TIMEOUT_MS); + if (ret <= 0) { + pr_err("%s: - nfc nci core reset rsp error ret %d\n", __func__, ret); + goto err_disable_intr; + } + + pr_debug(" %s: nci core reset response 0x%02x%02x%02x%02x\n", + __func__, rsp[0], rsp[1], rsp[2], rsp[3]); + if (rsp[0] != NCI_RSP) { + /* reset response failed response*/ + pr_err("%s invalid nci core reset response\n", __func__); + goto err_disable_intr; + } + + memset(rsp, 0x00, NCI_RESET_NTF_LEN); + /* read nci rest response ntf */ + ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_NTF_LEN, NCI_CMD_RSP_TIMEOUT_MS); + if (ret <= 0) { + pr_err("%s - nfc nci rest rsp ntf error status %d\n", __func__, ret); + goto err_disable_intr; + } + + if (rsp[0] == NCI_NTF) { + /* read version info from NCI Reset Notification */ + rom_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 3]; + major_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 2]; + /* determine chip type based on version info */ + if (rom_version == SN1XX_ROM_VER && major_version == SN1xx_MAJOR_VER) + chip_type = CHIP_SN1XX; + else if (rom_version == SN220_ROM_VER && major_version == SN220_MAJOR_VER) + chip_type = CHIP_SN220; + pr_debug(" %s:NCI Core Reset ntf 0x%02x%02x%02x%02x\n", + __func__, rsp[0], rsp[1], rsp[2], rsp[3]); + + nfc_dev->nqx_info.info.chip_type = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - + NFC_CHIP_TYPE_OFF]; + nfc_dev->nqx_info.info.rom_version = rom_version; + nfc_dev->nqx_info.info.fw_major = major_version; + nfc_dev->nqx_info.info.fw_minor = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - + NFC_FW_MINOR_OFF]; + } +err_disable_intr: + nfc_dev->nfc_disable_intr(nfc_dev); +err: + return chip_type; +} + +/** + * validate_download_gpio() - validate download gpio. + * @nfc_dev: nfc_dev device data structure. + * @chip_type: chip type of the platform. + * + * Validates dwnld gpio should configured for supported and + * should not be configured for unsupported platform. + * + * @Return: true if gpio validation successful ortherwise + * false if validation fails. + */ +static bool validate_download_gpio(struct nfc_dev *nfc_dev, enum chip_types chip_type) +{ + bool status = false; + struct platform_gpio *nfc_gpio; + + if (nfc_dev == NULL) { + pr_err("%s nfc devices structure is null\n"); + return status; + } + nfc_gpio = &nfc_dev->configs.gpio; + if (chip_type == CHIP_SN1XX) { + /* gpio should be configured for SN1xx */ + status = gpio_is_valid(nfc_gpio->dwl_req); + } else if (chip_type == CHIP_SN220) { + /* gpio should not be configured for SN220 */ + set_valid_gpio(nfc_gpio->dwl_req, 0); + gpio_free(nfc_gpio->dwl_req); + nfc_gpio->dwl_req = -EINVAL; + status = true; + } + return status; +} + +/* Check for availability of NFC controller hardware */ +int nfcc_hw_check(struct nfc_dev *nfc_dev) +{ + int ret = 0; + enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN; + enum chip_types chip_type = CHIP_UNKNOWN; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + /*get fw version in nci mode*/ + gpio_set_ven(nfc_dev, 1); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + chip_type = get_nfcc_chip_type(nfc_dev); + + /*get fw version in fw dwl mode*/ + if (chip_type == CHIP_UNKNOWN) { + nfc_dev->nfc_enable_intr(nfc_dev); + /*Chip is unknown, initially assume with fw dwl pin enabled*/ + set_valid_gpio(nfc_gpio->dwl_req, 1); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + chip_type = get_nfcc_chip_type_dl(nfc_dev); + /*get the state of nfcc normal/teared in fw dwl mode*/ + } else { + nfc_state = NFC_STATE_NCI; + } + + /*validate gpio config required as per the chip*/ + if (!validate_download_gpio(nfc_dev, chip_type)) { + pr_info("%s gpio validation fail\n", __func__); + ret = -ENXIO; + goto err; + } + + /*check whether the NFCC is in FW DN or Teared state*/ + if (nfc_state != NFC_STATE_NCI) + nfc_state = get_nfcc_session_state_dl(nfc_dev); + + /*nfcc state specific operations */ + switch (nfc_state) { + case NFC_STATE_FW_TEARED: + pr_warn("%s: - NFCC FW Teared State\n", __func__); + case NFC_STATE_FW_DWL: + case NFC_STATE_NCI: + break; + case NFC_STATE_UNKNOWN: + default: + ret = -ENXIO; + pr_err("%s: - NFCC HW not available\n", __func__); + goto err; + } + nfc_dev->nfc_state = nfc_state; +err: + nfc_dev->nfc_disable_intr(nfc_dev); + set_valid_gpio(nfc_gpio->dwl_req, 0); + gpio_set_ven(nfc_dev, 0); + gpio_set_ven(nfc_dev, 1); + nfc_dev->nfc_ven_enabled = true; + return ret; +} diff --git a/nfc/common_nxp.h b/nfc/common_nxp.h new file mode 100644 index 0000000000..ad3e5aabfa --- /dev/null +++ b/nfc/common_nxp.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021 NXP + * + * This program 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 program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + ******************************************************************************/ + +#ifndef _COMMON_QCOM_H_ +#define _COMMON_QCOM_H_ + +#define NCI_RESET_CMD_LEN (4) +#define NCI_RESET_RSP_LEN (4) +#define NCI_CORE_RESET_CMD_OID (0x0) +#define NCI_CORE_RESET_CMD_PAYLOAD_LEN (0x1) +#define NCI_CORE_RESET_KEEP_CONFIG (0x0) +#define NCI_RESET_NTF_LEN (13) + +/*command response timeout*/ +#define NCI_CMD_RSP_TIMEOUT_MS (2000) //2s + +#define SN1XX_ROM_VER 0x01 +#define SN1xx_MAJOR_VER 0x10 +#define SN220_ROM_VER 0x01 +#define SN220_MAJOR_VER 0x01 +#define FW_ROM_CODE_VER_OFFSET 4 +#define FW_MAJOR_VER_OFFSET 7 +#define GET_VERSION_RSP_CHIP_TYPE_OFFSET 3 +#define GET_VERSION_RSP_MINOR_VERSION_OFFSET 6 +#define DL_GET_VERSION_CMD_LEN (8) +#define DL_GET_VERSION_RSP_LEN_1 (12) /* SN110 */ +#define DL_GET_VERSION_RSP_LEN_2 (20) /* SN220 */ +#define DL_GET_VERSION_CMD_PAYLOAD_LEN (4) +#define DL_GET_VERSION_CMD_ID (0xF1) +#define DL_GET_VERSION_CMD_CRC_1 (0x6E) +#define DL_GET_VERSION_CMD_CRC_2 (0xEF) + +#define DL_RESET_CMD_LEN (8) +#define DL_GET_SESSION_STATE_CMD_LEN (8) +#define DL_GET_SESSION_STATE_RSP_LEN (8) +#define DL_GET_SESSION_STATE_CMD_PAYLOAD_LEN (4) +#define DL_GET_SESSION_CMD_ID (0xF2) +#define DL_GET_SESSION_CMD_CRC_1 (0xF5) +#define DL_GET_SESSION_CMD_CRC_2 (0x33) +#define GET_SESSION_STS_OFF (3) +#define NFCC_SESSION_STS_CLOSED (0x0) + +/* Below offsets should be subtracted from NCI header length + payload length */ + +#define NFC_CHIP_TYPE_OFF (4) +#define NFC_FW_MINOR_OFF (1) + + +enum chip_types { + CHIP_SN1XX = 0x01, + CHIP_SN220 = 0x02, + CHIP_UNKNOWN = 0xFF, +}; + +#endif //_COMMON_QCOM_H_ diff --git a/nfc/common_qcom.c b/nfc/common_qcom.c new file mode 100644 index 0000000000..ef05d01394 --- /dev/null +++ b/nfc/common_qcom.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * + ***************************************************************************/ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + ***************************************************************************/ + +#include "common.h" + +/* + * Inside nfc_ioctl_nfcc_info + * + * @brief nfc_ioctl_nfcc_info + * + * Check the NFC Chipset and firmware version details + */ +unsigned int nfc_ioctl_nfcc_info(struct file *filp, unsigned long arg) +{ + unsigned int r = 0; + struct nfc_dev *nfc_dev = filp->private_data; + + r = nfc_dev->nqx_info.i; + pr_debug("nfc : %s r = 0x%x\n", __func__, r); + + return r; +} + +/* + * Inside is_nfc_data_available_for_read + * + * @nfc_dev: nfc device data structure + * + * Checks if the data is available for reading + * on waiting queue. + * + * @Return: status value + * + */ +int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev) +{ + int ret; + + nfc_dev->nfc_enable_intr(nfc_dev); + + ret = wait_event_interruptible_timeout(nfc_dev->read_wq, + !nfc_dev->i2c_dev.irq_enabled, + msecs_to_jiffies(MAX_IRQ_WAIT_TIME)); + return ret; +} + +/** + * nfc_ldo_vote() + * @nfc_dev: NFC device containing regulator handle + * + * LDO voting based on voltage and current entries in DT + * + * Return: 0 on success and -ve on failure + */ +int nfc_ldo_vote(struct nfc_dev *nfc_dev) +{ + int ret; + + ret = regulator_set_voltage(nfc_dev->reg, + nfc_dev->configs.ldo.vdd_levels[0], + nfc_dev->configs.ldo.vdd_levels[1]); + if (ret < 0) { + pr_err("%s: set voltage failed\n", __func__); + return ret; + } + + /* pass expected current from NFC in uA */ + ret = regulator_set_load(nfc_dev->reg, nfc_dev->configs.ldo.max_current); + if (ret < 0) { + pr_err("%s: set load failed\n", __func__); + return ret; + } + + ret = regulator_enable(nfc_dev->reg); + if (ret < 0) + pr_err("%s: regulator_enable failed\n", __func__); + else + nfc_dev->is_vreg_enabled = true; + return ret; +} + +/** + * nfc_ldo_config() + * @dev: device instance to read DT entry + * @nfc_dev: NFC device containing regulator handle + * + * Configure LDO if entry is present in DT file otherwise + * return with success as it's optional + * + * Return: 0 on success and -ve on failure + */ +int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev) +{ + int ret; + + if (of_get_property(dev->of_node, NFC_LDO_SUPPLY_NAME, NULL)) { + // Get the regulator handle + nfc_dev->reg = regulator_get(dev, NFC_LDO_SUPPLY_DT_NAME); + if (IS_ERR(nfc_dev->reg)) { + ret = PTR_ERR(nfc_dev->reg); + nfc_dev->reg = NULL; + pr_err("%s: regulator_get failed, ret = %d\n", + __func__, ret); + return ret; + } + } else { + nfc_dev->reg = NULL; + pr_err("%s: regulator entry not present\n", __func__); + // return success as it's optional to configure LDO + return 0; + } + + // LDO config supported by platform DT + ret = nfc_ldo_vote(nfc_dev); + if (ret < 0) { + pr_err("%s: LDO voting failed, ret = %d\n", __func__, ret); + regulator_put(nfc_dev->reg); + } + return ret; +} + +/** + * nfc_ldo_unvote() + * @nfc_dev: NFC device containing regulator handle + * + * set voltage and load to zero and disable regulator + * + * Return: 0 on success and -ve on failure + */ +int nfc_ldo_unvote(struct nfc_dev *nfc_dev) +{ + int ret; + + if (!nfc_dev->is_vreg_enabled) { + pr_err("%s: regulator already disabled\n", __func__); + return -EINVAL; + } + + ret = regulator_disable(nfc_dev->reg); + if (ret < 0) { + pr_err("%s: regulator_disable failed\n", __func__); + return ret; + } + nfc_dev->is_vreg_enabled = false; + + ret = regulator_set_voltage(nfc_dev->reg, 0, NFC_VDDIO_MAX); + if (ret < 0) { + pr_err("%s: set voltage failed\n", __func__); + return ret; + } + + ret = regulator_set_load(nfc_dev->reg, 0); + if (ret < 0) + pr_err("%s: set load failed\n", __func__); + return ret; +} diff --git a/qti/ese_cold_reset.c b/nfc/ese_cold_reset.c similarity index 83% rename from qti/ese_cold_reset.c rename to nfc/ese_cold_reset.c index 7d596ca27e..ad0aa2c6a3 100644 --- a/qti/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -1,12 +1,61 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. - */ + * + ***************************************************************************/ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + ***************************************************************************/ #include #include #include -#include "nfc_common.h" +#include "common.h" + +/* + * Power management of the eSE + * eSE and NFCC both are powered using VEN gpio, + * VEN HIGH - eSE and NFCC both are powered on + * VEN LOW - eSE and NFCC both are power down + */ +int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) +{ + int ret = 0; + + if (arg == ESE_POWER_ON) { + /* + * Let's store the NFC VEN pin state + * will check stored value in case of eSE power off request, + * to find out if NFC MW also sent request to set VEN HIGH + * VEN state will remain HIGH if NFC is enabled otherwise + * it will be set as LOW + */ + nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_dev->configs.gpio.ven); + if (!nfc_dev->nfc_ven_enabled) { + pr_debug("eSE HAL service setting ven HIGH\n"); + gpio_set_ven(nfc_dev, 1); + } else { + pr_debug("ven already HIGH\n"); + } + nfc_dev->is_ese_session_active = true; + } else if (arg == ESE_POWER_OFF) { + if (!nfc_dev->nfc_ven_enabled) { + pr_debug("NFC not enabled, disabling ven\n"); + gpio_set_ven(nfc_dev, 0); + } else { + pr_debug("keep ven high as NFC is enabled\n"); + } + nfc_dev->is_ese_session_active = false; + } else if (arg == ESE_POWER_STATE) { + /* get VEN gpio state for eSE, as eSE also enabled through same GPIO */ + ret = gpio_get_value(nfc_dev->configs.gpio.ven); + } else { + pr_err("%s bad arg %lu\n", __func__, arg); + ret = -ENOIOCTLCMD; + } + return ret; +} /** * send_ese_cmd() - Send eSE command to NFC controller. @@ -106,7 +155,7 @@ int read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header) ret = nfc_dev->nfc_read(nfc_dev, &rsp_buf[NCI_PAYLOAD_IDX], rsp_buf[NCI_PAYLOAD_LEN_IDX], - NCI_CMD_RSP_TIMEOUT); + NCI_CMD_RSP_TIMEOUT_MS); if (ret <= 0) { dev_err(nfc_dev->nfc_device, diff --git a/qti/ese_cold_reset.h b/nfc/ese_cold_reset.h similarity index 100% rename from qti/ese_cold_reset.h rename to nfc/ese_cold_reset.h diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 2792484263..d0e2d5a5f2 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -33,7 +33,11 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ + ****************************************************************************/ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + ****************************************************************************/ #include #include @@ -43,7 +47,7 @@ #ifdef CONFIG_COMPAT #include #endif -#include "common_ese.h" +#include "common.h" /** * i2c_disable_irq() @@ -108,6 +112,8 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) int ret; struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + uint16_t i = 0; + uint16_t disp_len = GET_IPCLOG_MAX_PKT_LEN(count); pr_debug("%s: reading %zu bytes.\n", __func__, count); @@ -174,34 +180,34 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) memset(buf, 0x00, count); /* Read data */ ret = i2c_master_recv(nfc_dev->i2c_dev.client, buf, count); + NFCLOG_IPC(nfc_dev, false, "%s of %d bytes, ret %d", __func__, count, + ret); if (ret <= 0) { pr_err("%s: returned %d\n", __func__, ret); goto err; } + + for (i = 0; i < disp_len; i++) + NFCLOG_IPC(nfc_dev, false, " %02x", buf[i]); + /* check if it's response of cold reset command * NFC HAL process shouldn't receive this data as - * command was sent by driver + * command was sent by esepowermanager */ - if (nfc_dev->cold_reset.rsp_pending) { - if (IS_PROP_CMD_RSP(buf)) { - /* Read data */ - ret = i2c_master_recv(nfc_dev->i2c_dev.client, - &buf[NCI_PAYLOAD_IDX], - buf[NCI_PAYLOAD_LEN_IDX]); - if (ret <= 0) { - pr_err("%s: error reading cold rst/prot rsp\n", - __func__); - goto err; - } - wakeup_on_prop_rsp(nfc_dev, buf); - /* - * NFC process doesn't know about cold reset command - * being sent as it was initiated by eSE process - * we shouldn't return any data to NFC process - */ - return 0; - } + if (nfc_dev->cold_reset.rsp_pending && nfc_dev->cold_reset.cmd_buf + && (buf[0] == PROP_NCI_RSP_GID) + && (buf[1] == nfc_dev->cold_reset.cmd_buf[1])) { + read_cold_reset_rsp(nfc_dev, buf); + nfc_dev->cold_reset.rsp_pending = false; + wake_up_interruptible(&nfc_dev->cold_reset.read_wq); + /* + * NFC process doesn't know about cold reset command + * being sent as it was initiated by eSE process + * we shouldn't return any data to NFC process + */ + return 0; } + err: return ret; } @@ -211,12 +217,18 @@ int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, { int ret = -EINVAL; int retry_cnt; + uint16_t i = 0; + uint16_t disp_len = GET_IPCLOG_MAX_PKT_LEN(count); struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; if (count > MAX_DL_BUFFER_SIZE) count = MAX_DL_BUFFER_SIZE; pr_debug("%s: writing %zu bytes.\n", __func__, count); + NFCLOG_IPC(nfc_dev, false, "%s sending %d B", __func__, count); + + for (i = 0; i < disp_len; i++) + NFCLOG_IPC(nfc_dev, false, " %02x", buf[i]); /* * Wait for any pending read for max 15ms before write * This is to avoid any packet corruption during read, when @@ -238,6 +250,7 @@ int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) { ret = i2c_master_send(nfc_dev->i2c_dev.client, buf, count); + NFCLOG_IPC(nfc_dev, false, "%s ret %d", __func__, ret); if (ret <= 0) { pr_warn("%s: write failed ret(%d), maybe in standby\n", __func__, ret); @@ -391,7 +404,6 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) mutex_init(&nfc_dev->write_mutex); mutex_init(&nfc_dev->dev_ref_mutex); spin_lock_init(&i2c_dev->irq_enabled_lock); - common_ese_init(nfc_dev); ret = nfc_misc_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT, NFC_CHAR_DEV_NAME, CLASS_NAME); if (ret) { @@ -408,15 +420,35 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_nfc_misc_unregister; } i2c_disable_irq(nfc_dev); + + ret = nfc_ldo_config(&client->dev, nfc_dev); + if (ret) { + pr_err("LDO config failed\n"); + goto err_ldo_config_failed; + } + ret = nfcc_hw_check(nfc_dev); + if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { + pr_err("nfc hw check failed ret %d\n", ret); + goto err_nfcc_hw_check; + } gpio_set_ven(nfc_dev, 1); gpio_set_ven(nfc_dev, 0); gpio_set_ven(nfc_dev, 1); device_init_wakeup(&client->dev, true); i2c_set_clientdata(client, nfc_dev); i2c_dev->irq_wake_up = false; + nfc_dev->is_ese_session_active = false; pr_info("%s: probing nfc i2c successfully\n", __func__); return 0; + +err_nfcc_hw_check: + if (nfc_dev->reg) { + nfc_ldo_unvote(nfc_dev); + regulator_put(nfc_dev->reg); + } +err_ldo_config_failed: + free_irq(client->irq, nfc_dev); err_nfc_misc_unregister: nfc_misc_unregister(nfc_dev, DEV_COUNT); err_mutex_destroy: @@ -452,9 +484,19 @@ int nfc_i2c_dev_remove(struct i2c_client *client) pr_err("%s: device already in use\n", __func__); return -EBUSY; } + + gpio_set_value(nfc_dev->configs.gpio.ven, 0); + // HW dependent delay before LDO goes into LPM mode + usleep_range(10000, 10100); + if (nfc_dev->reg) { + nfc_ldo_unvote(nfc_dev); + regulator_put(nfc_dev->reg); + } + device_init_wakeup(&client->dev, false); free_irq(client->irq, nfc_dev); nfc_misc_unregister(nfc_dev, DEV_COUNT); + mutex_destroy(&nfc_dev->dev_ref_mutex); mutex_destroy(&nfc_dev->read_mutex); mutex_destroy(&nfc_dev->write_mutex); gpio_free_all(nfc_dev); @@ -475,6 +517,9 @@ int nfc_i2c_dev_suspend(struct device *device) } i2c_dev = &nfc_dev->i2c_dev; + NFCLOG_IPC(nfc_dev, false, "%s: irq_enabled = %d", __func__, + i2c_dev->irq_enabled); + if (device_may_wakeup(&client->dev) && i2c_dev->irq_enabled) { if (!enable_irq_wake(client->irq)) i2c_dev->irq_wake_up = true; @@ -494,6 +539,9 @@ int nfc_i2c_dev_resume(struct device *device) } i2c_dev = &nfc_dev->i2c_dev; + NFCLOG_IPC(nfc_dev, false, "%s: irq_wake_up = %d", __func__, + i2c_dev->irq_wake_up); + if (device_may_wakeup(&client->dev) && i2c_dev->irq_wake_up) { if (!disable_irq_wake(client->irq)) i2c_dev->irq_wake_up = false; diff --git a/nfc/i2c_drv.h b/nfc/i2c_drv.h index 1508fd4163..3abb56bd0f 100644 --- a/nfc/i2c_drv.h +++ b/nfc/i2c_drv.h @@ -17,14 +17,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + ******************************************************************************/ #ifndef _I2C_DRV_H_ #define _I2C_DRV_H_ #include -/* kept same as dts */ -#define NFC_I2C_DRV_STR "nxp,pn544" -#define NFC_I2C_DEV_ID "pn553" +#define NFC_I2C_DRV_STR "qcom,sn-nci" /*kept same as dts */ +#define NFC_I2C_DEV_ID "sn-i2c" + +struct nfc_dev; /* Interface specific parameters */ struct i2c_dev { @@ -43,4 +48,14 @@ int nfc_i2c_dev_remove(struct i2c_client *client); int nfc_i2c_dev_suspend(struct device *device); int nfc_i2c_dev_resume(struct device *device); -#endif /* _I2C_DRV_H_ */ +#if IS_ENABLED(CONFIG_NXP_NFC_I2C) + +int i2c_enable_irq(struct nfc_dev *dev); +int i2c_disable_irq(struct nfc_dev *dev); +int i2c_write(struct nfc_dev *dev, const char *buf, size_t count, + int max_retry_cnt); +int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout); + +#endif + +#endif //_I2C_DRV_H_ diff --git a/nfc_kernel_dlkm_vendor_board.mk b/nfc_kernel_dlkm_vendor_board.mk index 933ebdca5d..eb7a015643 100644 --- a/nfc_kernel_dlkm_vendor_board.mk +++ b/nfc_kernel_dlkm_vendor_board.mk @@ -1,4 +1,4 @@ # Build NFC kernel driver ifeq ($(call is-board-platform-in-list, kalama),true) -BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nfc_i2c.ko +BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nxp-nci.ko endif diff --git a/nfc_kernel_dlkm_vendor_product.mk b/nfc_kernel_dlkm_vendor_product.mk index d8150bf3da..fc1442a8e1 100644 --- a/nfc_kernel_dlkm_vendor_product.mk +++ b/nfc_kernel_dlkm_vendor_product.mk @@ -1 +1 @@ -PRODUCT_PACKAGES += nfc_i2c.ko +PRODUCT_PACKAGES += nxp-nci.ko diff --git a/qti/nfc_common.c b/qti/nfc_common.c deleted file mode 100644 index 6db09e212f..0000000000 --- a/qti/nfc_common.c +++ /dev/null @@ -1,951 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2019-2021 NXP - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#include -#include -#include -#include "nfc_common.h" - -int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, - uint8_t interface) -{ - int ret; - struct device_node *np = dev->of_node; - struct platform_gpio *nfc_gpio = &nfc_configs->gpio; - struct platform_ldo *ldo = &nfc_configs->ldo; - - if (!np) { - pr_err("nfc of_node NULL\n"); - return -EINVAL; - } - - nfc_gpio->irq = -EINVAL; - nfc_gpio->dwl_req = -EINVAL; - nfc_gpio->ven = -EINVAL; - nfc_gpio->clkreq = -EINVAL; - - /* required for i2c based chips only */ - if (interface == PLATFORM_IF_I2C) { - nfc_gpio->irq = of_get_named_gpio(np, DTS_IRQ_GPIO_STR, 0); - if ((!gpio_is_valid(nfc_gpio->irq))) { - pr_err("nfc irq gpio invalid %d\n", nfc_gpio->irq); - return -EINVAL; - } - pr_info("%s: irq %d\n", __func__, nfc_gpio->irq); - } - nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); - if ((!gpio_is_valid(nfc_gpio->ven))) { - pr_err("nfc ven gpio invalid %d\n", nfc_gpio->ven); - return -EINVAL; - } - - nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); - - /* not returning failure for dwl gpio as it is optional for sn220 */ - if ((!gpio_is_valid(nfc_gpio->dwl_req))) - pr_warn("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req); - - nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0); - if (!gpio_is_valid(nfc_gpio->clkreq)) { - dev_err(dev, "clkreq gpio invalid %d\n", nfc_gpio->dwl_req); - return -EINVAL; - } - - pr_info("%s: ven %d, dwl req %d, clkreq %d\n", __func__, - nfc_gpio->ven, nfc_gpio->dwl_req, nfc_gpio->clkreq); - - // optional property - ret = of_property_read_u32_array(np, NFC_LDO_VOL_DT_NAME, - (u32 *) ldo->vdd_levels, - ARRAY_SIZE(ldo->vdd_levels)); - if (ret) { - dev_err(dev, "error reading NFC VDDIO min and max value\n"); - // set default as per datasheet - ldo->vdd_levels[0] = NFC_VDDIO_MIN; - ldo->vdd_levels[1] = NFC_VDDIO_MAX; - } - - // optional property - ret = of_property_read_u32(np, NFC_LDO_CUR_DT_NAME, &ldo->max_current); - if (ret) { - dev_err(dev, "error reading NFC current value\n"); - // set default as per datasheet - ldo->max_current = NFC_CURRENT_MAX; - } - - return 0; -} - -/** - * nfc_ldo_vote() - * @nfc_dev: NFC device containing regulator handle - * - * LDO voting based on voltage and current entries in DT - * - * Return: 0 on success and -ve on failure - */ -int nfc_ldo_vote(struct nfc_dev *nfc_dev) -{ - int ret; - - ret = regulator_set_voltage(nfc_dev->reg, - nfc_dev->configs.ldo.vdd_levels[0], - nfc_dev->configs.ldo.vdd_levels[1]); - if (ret < 0) { - pr_err("%s: set voltage failed\n", __func__); - return ret; - } - - /* pass expected current from NFC in uA */ - ret = regulator_set_load(nfc_dev->reg, nfc_dev->configs.ldo.max_current); - if (ret < 0) { - pr_err("%s: set load failed\n", __func__); - return ret; - } - - ret = regulator_enable(nfc_dev->reg); - if (ret < 0) - pr_err("%s: regulator_enable failed\n", __func__); - else - nfc_dev->is_vreg_enabled = true; - return ret; -} - -/** - * nfc_ldo_config() - * @dev: device instance to read DT entry - * @nfc_dev: NFC device containing regulator handle - * - * Configure LDO if entry is present in DT file otherwise - * return with success as it's optional - * - * Return: 0 on success and -ve on failure - */ -int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev) -{ - int ret; - - if (of_get_property(dev->of_node, NFC_LDO_SUPPLY_NAME, NULL)) { - // Get the regulator handle - nfc_dev->reg = regulator_get(dev, NFC_LDO_SUPPLY_DT_NAME); - if (IS_ERR(nfc_dev->reg)) { - ret = PTR_ERR(nfc_dev->reg); - nfc_dev->reg = NULL; - pr_err("%s: regulator_get failed, ret = %d\n", - __func__, ret); - return ret; - } - } else { - nfc_dev->reg = NULL; - pr_err("%s: regulator entry not present\n", __func__); - // return success as it's optional to configure LDO - return 0; - } - - // LDO config supported by platform DT - ret = nfc_ldo_vote(nfc_dev); - if (ret < 0) { - pr_err("%s: LDO voting failed, ret = %d\n", __func__, ret); - regulator_put(nfc_dev->reg); - } - return ret; -} - -/** - * nfc_ldo_unvote() - * @nfc_dev: NFC device containing regulator handle - * - * set voltage and load to zero and disable regulator - * - * Return: 0 on success and -ve on failure - */ -int nfc_ldo_unvote(struct nfc_dev *nfc_dev) -{ - int ret; - - if (!nfc_dev->is_vreg_enabled) { - pr_err("%s: regulator already disabled\n", __func__); - return -EINVAL; - } - - ret = regulator_disable(nfc_dev->reg); - if (ret < 0) { - pr_err("%s: regulator_disable failed\n", __func__); - return ret; - } - nfc_dev->is_vreg_enabled = false; - - ret = regulator_set_voltage(nfc_dev->reg, 0, NFC_VDDIO_MAX); - if (ret < 0) { - pr_err("%s: set voltage failed\n", __func__); - return ret; - } - - ret = regulator_set_load(nfc_dev->reg, 0); - if (ret < 0) - pr_err("%s: set load failed\n", __func__); - return ret; -} - -void set_valid_gpio(int gpio, int value) -{ - if (gpio_is_valid(gpio)) { - pr_debug("%s gpio %d value %d\n", __func__, gpio, value); - gpio_set_value(gpio, value); - /* hardware dependent delay */ - usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, - NFC_GPIO_SET_WAIT_TIME_USEC + 100); - } -} - -int get_valid_gpio(int gpio) -{ - int value = -EINVAL; - - if (gpio_is_valid(gpio)) { - value = gpio_get_value(gpio); - pr_debug("%s gpio %d value %d\n", __func__, gpio, value); - } - return value; -} - -void gpio_set_ven(struct nfc_dev *nfc_dev, int value) -{ - struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - - if (gpio_get_value(nfc_gpio->ven) != value) { - pr_debug("%s: value %d\n", __func__, value); - - gpio_set_value(nfc_gpio->ven, value); - /* hardware dependent delay */ - usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC, - NFC_GPIO_SET_WAIT_TIME_USEC + 100); - } -} - -int configure_gpio(unsigned int gpio, int flag) -{ - int ret; - - pr_debug("%s: nfc gpio [%d] flag [%01x]\n", __func__, gpio, flag); - - if (gpio_is_valid(gpio)) { - ret = gpio_request(gpio, "nfc_gpio"); - if (ret) { - pr_err("%s: unable to request nfc gpio [%d]\n", - __func__, gpio); - return ret; - } - /* set direction and value for output pin */ - if (flag & GPIO_OUTPUT) { - ret = gpio_direction_output(gpio, (GPIO_HIGH & flag)); - pr_debug("nfc o/p gpio %d level %d\n", gpio, gpio_get_value(gpio)); - } else { - ret = gpio_direction_input(gpio); - pr_debug("nfc i/p gpio %d\n", gpio); - } - - if (ret) { - pr_err - ("%s: unable to set direction for nfc gpio [%d]\n", - __func__, gpio); - gpio_free(gpio); - return ret; - } - // Consider value as control for input IRQ pin - if (flag & GPIO_IRQ) { - ret = gpio_to_irq(gpio); - if (ret < 0) { - pr_err("%s: unable to set irq for nfc gpio [%d]\n", - __func__, gpio); - gpio_free(gpio); - return ret; - } - pr_debug - ("%s: gpio_to_irq successful [%d]\n", - __func__, gpio); - return ret; - } - } else { - pr_err("%s: invalid gpio\n", __func__); - ret = -EINVAL; - } - return ret; -} - -void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count) -{ - pr_debug("%s: entry\n", __func__); - - kfree(nfc_dev->kbuf); - device_destroy(nfc_dev->nfc_class, nfc_dev->devno); - cdev_del(&nfc_dev->c_dev); - class_destroy(nfc_dev->nfc_class); - unregister_chrdev_region(nfc_dev->devno, count); - if (nfc_dev->ipcl) - ipc_log_context_destroy(nfc_dev->ipcl); -} - -int nfc_misc_register(struct nfc_dev *nfc_dev, - const struct file_operations *nfc_fops, int count, - char *devname, char *classname) -{ - int ret = 0; - - ret = alloc_chrdev_region(&nfc_dev->devno, 0, count, devname); - if (ret < 0) { - pr_err("%s: failed to alloc chrdev region ret %d\n", - __func__, ret); - return ret; - } - nfc_dev->nfc_class = class_create(THIS_MODULE, classname); - if (IS_ERR(nfc_dev->nfc_class)) { - ret = PTR_ERR(nfc_dev->nfc_class); - pr_err("%s: failed to register device class ret %d\n", - __func__, ret); - unregister_chrdev_region(nfc_dev->devno, count); - return ret; - } - cdev_init(&nfc_dev->c_dev, nfc_fops); - ret = cdev_add(&nfc_dev->c_dev, nfc_dev->devno, count); - if (ret < 0) { - pr_err("%s: failed to add cdev ret %d\n", __func__, ret); - class_destroy(nfc_dev->nfc_class); - unregister_chrdev_region(nfc_dev->devno, count); - return ret; - } - nfc_dev->nfc_device = device_create(nfc_dev->nfc_class, NULL, - nfc_dev->devno, nfc_dev, devname); - if (IS_ERR(nfc_dev->nfc_device)) { - ret = PTR_ERR(nfc_dev->nfc_device); - pr_err("%s: failed to create the device ret %d\n", - __func__, ret); - cdev_del(&nfc_dev->c_dev); - class_destroy(nfc_dev->nfc_class); - unregister_chrdev_region(nfc_dev->devno, count); - return ret; - } - - nfc_dev->ipcl = ipc_log_context_create(NUM_OF_IPC_LOG_PAGES, - dev_name(nfc_dev->nfc_device), 0); - - nfc_dev->kbuflen = MAX_BUFFER_SIZE; - nfc_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); - if (!nfc_dev->kbuf) { - nfc_misc_unregister(nfc_dev, count); - return -ENOMEM; - } - - nfc_dev->cold_reset.rsp_pending = false; - nfc_dev->cold_reset.is_nfc_enabled = false; - nfc_dev->cold_reset.is_crp_en = false; - nfc_dev->cold_reset.last_src_ese_prot = ESE_COLD_RESET_ORIGIN_NONE; - - init_waitqueue_head(&nfc_dev->cold_reset.read_wq); - - return 0; -} - -/* - * Power management of the eSE - * eSE and NFCC both are powered using VEN gpio, - * VEN HIGH - eSE and NFCC both are powered on - * VEN LOW - eSE and NFCC both are power down - */ -int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) -{ - int ret = 0; - - if (arg == ESE_POWER_ON) { - /* - * Let's store the NFC VEN pin state - * will check stored value in case of eSE power off request, - * to find out if NFC MW also sent request to set VEN HIGH - * VEN state will remain HIGH if NFC is enabled otherwise - * it will be set as LOW - */ - nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_dev->configs.gpio.ven); - if (!nfc_dev->nfc_ven_enabled) { - pr_debug("eSE HAL service setting ven HIGH\n"); - gpio_set_ven(nfc_dev, 1); - } else { - pr_debug("ven already HIGH\n"); - } - nfc_dev->is_ese_session_active = true; - } else if (arg == ESE_POWER_OFF) { - if (!nfc_dev->nfc_ven_enabled) { - pr_debug("NFC not enabled, disabling ven\n"); - gpio_set_ven(nfc_dev, 0); - } else { - pr_debug("keep ven high as NFC is enabled\n"); - } - nfc_dev->is_ese_session_active = false; - } else if (arg == ESE_POWER_STATE) { - /* get VEN gpio state for eSE, as eSE also enabled through same GPIO */ - ret = gpio_get_value(nfc_dev->configs.gpio.ven); - } else { - pr_err("%s bad arg %lu\n", __func__, arg); - ret = -ENOIOCTLCMD; - } - return ret; -} - -/* - * nfc_ioctl_power_states() - power control - * @nfc_dev: nfc device data structure - * @arg: mode that we want to move to - * - * Device power control. Depending on the arg value, device moves to - * different states, refer nfcc_ioctl_request in nfc_common.h for args - * - * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case - */ -static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) -{ - int ret = 0; - struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - - if (arg == NFC_POWER_OFF) { - /* - * We are attempting a hardware reset so let us disable - * interrupts to avoid spurious notifications to upper - * layers. - */ - nfc_dev->nfc_disable_intr(nfc_dev); - set_valid_gpio(nfc_gpio->dwl_req, 0); - gpio_set_ven(nfc_dev, 0); - nfc_dev->nfc_ven_enabled = false; - - } else if (arg == NFC_POWER_ON) { - nfc_dev->nfc_enable_intr(nfc_dev); - set_valid_gpio(nfc_gpio->dwl_req, 0); - - gpio_set_ven(nfc_dev, 1); - nfc_dev->nfc_ven_enabled = true; - - } else if (arg == NFC_FW_DWL_VEN_TOGGLE) { - /* - * We are switching to download Mode, toggle the enable pin - * in order to set the NFCC in the new mode - */ - nfc_dev->nfc_disable_intr(nfc_dev); - set_valid_gpio(nfc_gpio->dwl_req, 1); - nfc_dev->nfc_state = NFC_STATE_FW_DWL; - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - nfc_dev->nfc_enable_intr(nfc_dev); - } else if (arg == NFC_FW_DWL_HIGH) { - /* - * Setting firmware download gpio to HIGH - * before FW download start - */ - pr_debug("set fw gpio high\n"); - set_valid_gpio(nfc_gpio->dwl_req, 1); - nfc_dev->nfc_state = NFC_STATE_FW_DWL; - - } else if (arg == NFC_VEN_FORCED_HARD_RESET) { - nfc_dev->nfc_disable_intr(nfc_dev); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - nfc_dev->nfc_enable_intr(nfc_dev); - pr_info("%s VEN forced reset done\n", __func__); - - } else if (arg == NFC_FW_DWL_LOW) { - /* - * Setting firmware download gpio to LOW - * FW download finished - */ - pr_debug("set fw gpio LOW\n"); - set_valid_gpio(nfc_gpio->dwl_req, 0); - nfc_dev->nfc_state = NFC_STATE_NCI; - - } else if (arg == NFC_ENABLE) { - /* - * Setting flag true when NFC is enabled - */ - nfc_dev->cold_reset.is_nfc_enabled = true; - } else if (arg == NFC_DISABLE) { - /* - * Setting flag true when NFC is disabled - */ - nfc_dev->cold_reset.is_nfc_enabled = false; - } else { - pr_err("%s bad arg %lu\n", __func__, arg); - ret = -ENOIOCTLCMD; - } - return ret; -} - -/* - * Inside nfc_ioctl_nfcc_info - * - * @brief nfc_ioctl_nfcc_info - * - * Check the NFC Chipset and firmware version details - */ -unsigned int nfc_ioctl_nfcc_info(struct file *filp, unsigned long arg) -{ - unsigned int r = 0; - struct nfc_dev *nfc_dev = filp->private_data; - - r = nfc_dev->nqx_info.i; - pr_debug("nfc : %s r = 0x%x\n", __func__, r); - - return r; -} - -/** @brief IOCTL function to be used to set or get data from upper layer. - * - * @param pfile fil node for opened device. - * @cmd IOCTL type from upper layer. - * @arg IOCTL arg from upper layer. - * - * @return 0 on success, error code for failures. - */ -long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) -{ - int ret = 0; - struct nfc_dev *nfc_dev = pfile->private_data; - - if (!nfc_dev) - return -ENODEV; - - pr_debug("%s cmd = %x arg = %zx\n", __func__, cmd, arg); - - switch (cmd) { - case NFC_SET_PWR: - ret = nfc_ioctl_power_states(nfc_dev, arg); - break; - case ESE_SET_PWR: - ret = nfc_ese_pwr(nfc_dev, arg); - break; - case ESE_GET_PWR: - ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE); - break; - case NFCC_GET_INFO: - ret = nfc_ioctl_nfcc_info(pfile, arg); - break; - case NFC_GET_PLATFORM_TYPE: - ret = nfc_dev->interface; - break; - case ESE_COLD_RESET: - pr_debug("nfc ese cold reset ioctl\n"); - ret = ese_cold_reset_ioctl(nfc_dev, arg); - break; - case NFC_GET_IRQ_STATE: - ret = gpio_get_value(nfc_dev->configs.gpio.irq); - break; - default: - pr_err("%s Unsupported ioctl cmd 0x%x, arg %lu\n", - __func__, cmd, arg); - ret = -ENOIOCTLCMD; - } - return ret; -} - -int nfc_dev_open(struct inode *inode, struct file *filp) -{ - struct nfc_dev *nfc_dev = container_of(inode->i_cdev, - struct nfc_dev, c_dev); - - if (!nfc_dev) - return -ENODEV; - - pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); - - mutex_lock(&nfc_dev->dev_ref_mutex); - - filp->private_data = nfc_dev; - - if (nfc_dev->dev_ref_count == 0) { - set_valid_gpio(nfc_dev->configs.gpio.dwl_req, 0); - nfc_dev->nfc_enable_intr(nfc_dev); - } - nfc_dev->dev_ref_count = nfc_dev->dev_ref_count + 1; - - mutex_unlock(&nfc_dev->dev_ref_mutex); - - return 0; -} - -int nfc_dev_close(struct inode *inode, struct file *filp) -{ - struct nfc_dev *nfc_dev = container_of(inode->i_cdev, - struct nfc_dev, c_dev); - - if (!nfc_dev) - return -ENODEV; - - pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); - - mutex_lock(&nfc_dev->dev_ref_mutex); - - if (nfc_dev->dev_ref_count == 1) { - nfc_dev->nfc_disable_intr(nfc_dev); - set_valid_gpio(nfc_dev->configs.gpio.dwl_req, 0); - } - - if (nfc_dev->dev_ref_count > 0) - nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; - - filp->private_data = NULL; - - mutex_unlock(&nfc_dev->dev_ref_mutex); - - return 0; -} - -int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev) -{ - int ret; - - nfc_dev->nfc_enable_intr(nfc_dev); - - ret = wait_event_interruptible_timeout(nfc_dev->read_wq, - !nfc_dev->i2c_dev.irq_enabled, - msecs_to_jiffies(MAX_IRQ_WAIT_TIME)); - return ret; -} - -/** - * get_nfcc_chip_type_dl() - get chip type in fw download command; - * @nfc_dev: nfc device data structure - * - * Perform get version command and determine chip - * type from response. - * - * @Return: enum chip_types value - * - */ -static enum chip_types get_nfcc_chip_type_dl(struct nfc_dev *nfc_dev) -{ - int ret = 0; - uint8_t *cmd = nfc_dev->write_kbuf; - uint8_t *rsp = nfc_dev->read_kbuf; - enum chip_types chip_type = CHIP_UNKNOWN; - - *cmd++ = DL_CMD; - *cmd++ = DL_GET_VERSION_CMD_PAYLOAD_LEN; - *cmd++ = DL_GET_VERSION_CMD_ID; - *cmd++ = DL_PAYLOAD_BYTE_ZERO; - *cmd++ = DL_PAYLOAD_BYTE_ZERO; - *cmd++ = DL_PAYLOAD_BYTE_ZERO; - *cmd++ = DL_GET_VERSION_CMD_CRC_1; - *cmd++ = DL_GET_VERSION_CMD_CRC_2; - - pr_debug("%s:Sending GET_VERSION cmd of size = %d\n", __func__, DL_GET_VERSION_CMD_LEN); - ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, DL_GET_VERSION_CMD_LEN, - MAX_RETRY_COUNT); - if (ret <= 0) { - pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret); - goto err; - } - memset(rsp, 0x00, DL_GET_VERSION_RSP_LEN_2); - pr_debug("%s:Reading response of GET_VERSION cmd\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_VERSION_RSP_LEN_2, NCI_CMD_RSP_TIMEOUT); - if (ret <= 0) { - pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret); - goto err; - } - if (rsp[0] == FW_MSG_CMD_RSP && ret >= DL_GET_VERSION_RSP_LEN_2) { - - nfc_dev->fw_major_version = rsp[FW_MAJOR_VER_OFFSET]; - - if (rsp[FW_ROM_CODE_VER_OFFSET] == SN1XX_ROM_VER && - rsp[FW_MAJOR_VER_OFFSET] == SN1xx_MAJOR_VER) - chip_type = CHIP_SN1XX; - else if (rsp[FW_ROM_CODE_VER_OFFSET] == SN220_ROM_VER && - rsp[FW_MAJOR_VER_OFFSET] == SN220_MAJOR_VER) - chip_type = CHIP_SN220; - - pr_debug("%s:NFC Chip Type 0x%02x Rom Version 0x%02x FW Minor 0x%02x Major 0x%02x\n", - __func__, rsp[GET_VERSION_RSP_CHIP_TYPE_OFFSET], - rsp[FW_ROM_CODE_VER_OFFSET], - rsp[GET_VERSION_RSP_MINOR_VERSION_OFFSET], - rsp[FW_MAJOR_VER_OFFSET]); - - nfc_dev->nqx_info.info.chip_type = rsp[GET_VERSION_RSP_CHIP_TYPE_OFFSET]; - nfc_dev->nqx_info.info.rom_version = rsp[FW_ROM_CODE_VER_OFFSET]; - nfc_dev->nqx_info.info.fw_minor = rsp[GET_VERSION_RSP_MINOR_VERSION_OFFSET]; - nfc_dev->nqx_info.info.fw_major = rsp[FW_MAJOR_VER_OFFSET]; - } -err: - return chip_type; -} - -/** - * get_nfcc_session_state_dl() - gets the session state - * @nfc_dev: nfc device data structure - * - * Performs get session command and determine - * the nfcc state based on session status. - * - * @Return nfcc state based on session status. - * NFC_STATE_FW_TEARED if sessionis not closed - * NFC_STATE_FW_DWL if session closed - * NFC_STATE_UNKNOWN in error cases. - */ -enum nfc_state_flags get_nfcc_session_state_dl(struct nfc_dev *nfc_dev) -{ - int ret = 0; - uint8_t *cmd = nfc_dev->write_kbuf; - uint8_t *rsp = nfc_dev->read_kbuf; - enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN; - - *cmd++ = DL_CMD; - *cmd++ = DL_GET_SESSION_STATE_CMD_PAYLOAD_LEN; - *cmd++ = DL_GET_SESSION_CMD_ID; - *cmd++ = DL_PAYLOAD_BYTE_ZERO; - *cmd++ = DL_PAYLOAD_BYTE_ZERO; - *cmd++ = DL_PAYLOAD_BYTE_ZERO; - *cmd++ = DL_GET_SESSION_CMD_CRC_1; - *cmd++ = DL_GET_SESSION_CMD_CRC_2; - - pr_debug("%s:Sending GET_SESSION_STATE cmd of size = %d\n", __func__, - DL_GET_SESSION_STATE_CMD_LEN); - ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, DL_GET_SESSION_STATE_CMD_LEN, - MAX_RETRY_COUNT); - if (ret <= 0) { - pr_err("%s: - nfc get session cmd error ret %d\n", __func__, ret); - goto err; - } - memset(rsp, 0x00, DL_GET_SESSION_STATE_RSP_LEN); - pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT); - if (ret <= 0) { - pr_err("%s: - nfc get session rsp error ret %d\n", __func__, ret); - goto err; - } - if (rsp[0] != FW_MSG_CMD_RSP) { - pr_err("%s: - nfc invalid get session state rsp\n", __func__); - goto err; - } - pr_debug("Response bytes are %02x%02x%02x%02x%02x%02x%02x%02x\n", - rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6], rsp[7]); - /*verify fw in non-teared state */ - if (rsp[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) { - pr_err("%s NFCC booted in FW teared state\n", __func__); - nfc_state = NFC_STATE_FW_TEARED; - } else { - pr_info("%s NFCC booted in FW DN mode\n", __func__); - nfc_state = NFC_STATE_FW_DWL; - } -err: - return nfc_state; -} - -/** - * get_nfcc_chip_type() - get nfcc chip type in nci mode. - * @nfc_dev: nfc device data structure. - * - * Function to perform nci core reset and extract - * chip type from the response. - * - * @Return: enum chip_types value - * - */ -static enum chip_types get_nfcc_chip_type(struct nfc_dev *nfc_dev) -{ - int ret = 0; - uint8_t major_version = 0; - uint8_t rom_version = 0; - uint8_t *cmd = nfc_dev->write_kbuf; - uint8_t *rsp = nfc_dev->read_kbuf; - enum chip_types chip_type = CHIP_UNKNOWN; - - *cmd++ = NCI_MSG_CMD; - *cmd++ = NCI_CORE_RESET_CMD_OID; - *cmd++ = NCI_CORE_RESET_CMD_PAYLOAD_LEN; - *cmd++ = NCI_CORE_RESET_KEEP_CONFIG; - - pr_debug("%s:Sending NCI Core Reset cmd of size = %d\n", __func__, NCI_RESET_CMD_LEN); - ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, NCI_RESET_CMD_LEN, NO_RETRY); - if (ret <= 0) { - pr_err("%s: - nfc nci core reset cmd error ret %d\n", __func__, ret); - goto err; - } - - /* to flush out debug NTF this delay is required */ - usleep_range(NCI_RESET_RESP_READ_DELAY, NCI_RESET_RESP_READ_DELAY + 100); - nfc_dev->nfc_enable_intr(nfc_dev); - - memset(rsp, 0x00, NCI_RESET_RSP_LEN); - pr_debug("%s:Reading NCI Core Reset rsp\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_RSP_LEN, NCI_CMD_RSP_TIMEOUT); - if (ret <= 0) { - pr_err("%s: - nfc nci core reset rsp error ret %d\n", __func__, ret); - goto err_disable_intr; - } - - pr_debug(" %s: nci core reset response 0x%02x%02x%02x%02x\n", - __func__, rsp[0], rsp[1], rsp[2], rsp[3]); - if (rsp[0] != NCI_MSG_RSP) { - /* reset response failed response*/ - pr_err("%s invalid nci core reset response\n", __func__); - goto err_disable_intr; - } - - memset(rsp, 0x00, NCI_RESET_NTF_LEN); - /* read nci rest response ntf */ - ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_NTF_LEN, NCI_CMD_RSP_TIMEOUT); - if (ret <= 0) { - pr_err("%s - nfc nci rest rsp ntf error status %d\n", __func__, ret); - goto err_disable_intr; - } - - if (rsp[0] == NCI_MSG_NTF) { - /* read version info from NCI Reset Notification */ - rom_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 3]; - major_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 2]; - /* determine chip type based on version info */ - if (rom_version == SN1XX_ROM_VER && major_version == SN1xx_MAJOR_VER) - chip_type = CHIP_SN1XX; - else if (rom_version == SN220_ROM_VER && major_version == SN220_MAJOR_VER) - chip_type = CHIP_SN220; - pr_debug(" %s:NCI Core Reset ntf 0x%02x%02x%02x%02x\n", - __func__, rsp[0], rsp[1], rsp[2], rsp[3]); - - nfc_dev->nqx_info.info.chip_type = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - - NFC_CHIP_TYPE_OFF]; - nfc_dev->nqx_info.info.rom_version = rom_version; - nfc_dev->nqx_info.info.fw_major = major_version; - nfc_dev->nqx_info.info.fw_minor = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - - NFC_FW_MINOR_OFF]; - } -err_disable_intr: - nfc_dev->nfc_disable_intr(nfc_dev); -err: - return chip_type; -} - -/** - * validate_download_gpio() - validate download gpio. - * @nfc_dev: nfc_dev device data structure. - * @chip_type: chip type of the platform. - * - * Validates dwnld gpio should configured for supported and - * should not be configured for unsupported platform. - * - * @Return: true if gpio validation successful ortherwise - * false if validation fails. - */ -static bool validate_download_gpio(struct nfc_dev *nfc_dev, enum chip_types chip_type) -{ - bool status = false; - struct platform_gpio *nfc_gpio; - - if (nfc_dev == NULL) { - pr_err("%s nfc devices structure is null\n"); - return status; - } - nfc_gpio = &nfc_dev->configs.gpio; - if (chip_type == CHIP_SN1XX) { - /* gpio should be configured for SN1xx */ - status = gpio_is_valid(nfc_gpio->dwl_req); - } else if (chip_type == CHIP_SN220) { - /* gpio should not be configured for SN220 */ - set_valid_gpio(nfc_gpio->dwl_req, 0); - gpio_free(nfc_gpio->dwl_req); - nfc_gpio->dwl_req = -EINVAL; - status = true; - } - return status; -} - -/* Check for availability of NFC controller hardware */ -int nfcc_hw_check(struct nfc_dev *nfc_dev) -{ - int ret = 0; - enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN; - enum chip_types chip_type = CHIP_UNKNOWN; - struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - - /*get fw version in nci mode*/ - gpio_set_ven(nfc_dev, 1); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - chip_type = get_nfcc_chip_type(nfc_dev); - - /*get fw version in fw dwl mode*/ - if (chip_type == CHIP_UNKNOWN) { - nfc_dev->nfc_enable_intr(nfc_dev); - /*Chip is unknown, initially assume with fw dwl pin enabled*/ - set_valid_gpio(nfc_gpio->dwl_req, 1); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - chip_type = get_nfcc_chip_type_dl(nfc_dev); - /*get the state of nfcc normal/teared in fw dwl mode*/ - } else { - nfc_state = NFC_STATE_NCI; - } - - /*validate gpio config required as per the chip*/ - if (!validate_download_gpio(nfc_dev, chip_type)) { - pr_info("%s gpio validation fail\n", __func__); - ret = -ENXIO; - goto err; - } - - /*check whether the NFCC is in FW DN or Teared state*/ - if (nfc_state != NFC_STATE_NCI) - nfc_state = get_nfcc_session_state_dl(nfc_dev); - - /*nfcc state specific operations */ - switch (nfc_state) { - case NFC_STATE_FW_TEARED: - pr_warn("%s: - NFCC FW Teared State\n", __func__); - case NFC_STATE_FW_DWL: - case NFC_STATE_NCI: - break; - case NFC_STATE_UNKNOWN: - default: - ret = -ENXIO; - pr_err("%s: - NFCC HW not available\n", __func__); - goto err; - } - nfc_dev->nfc_state = nfc_state; -err: - nfc_dev->nfc_disable_intr(nfc_dev); - set_valid_gpio(nfc_gpio->dwl_req, 0); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); - nfc_dev->nfc_ven_enabled = true; - return ret; -} - -int validate_nfc_state_nci(struct nfc_dev *nfc_dev) -{ - struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - - if (!gpio_get_value(nfc_gpio->ven)) { - pr_err("VEN LOW - NFCC powered off\n"); - return -ENODEV; - } - if (get_valid_gpio(nfc_gpio->dwl_req) == 1) { - pr_err("FW download in-progress\n"); - return -EBUSY; - } - if (nfc_dev->nfc_state != NFC_STATE_NCI) { - pr_err("FW download state\n"); - return -EBUSY; - } - return 0; -} diff --git a/qti/nfc_common.h b/qti/nfc_common.h deleted file mode 100644 index eac4663b58..0000000000 --- a/qti/nfc_common.h +++ /dev/null @@ -1,346 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2019-2021 NXP - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#ifndef _NFC_COMMON_H_ -#define _NFC_COMMON_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "nfc_i2c_drv.h" -#include "ese_cold_reset.h" - -// Max device count for this driver -#define DEV_COUNT 1 - -// NFC device class -#define CLASS_NAME "qti-nfc" - -// NFC character device name, this will be in /dev/ -#define NFC_CHAR_DEV_NAME "nq-nci" - -// NCI packet details -#define NCI_MSG_CMD 0x20 -#define NCI_MSG_RSP 0x40 -#define NCI_MSG_NTF 0x60 -#define DL_CMD 0x00 -#define DL_PAYLOAD_BYTE_ZERO 0x00 -#define NCI_HDR_LEN 3 -#define NCI_PAYLOAD_IDX 3 -#define NCI_PAYLOAD_LEN_IDX 2 - -/*Time to wait for first NCI rest response*/ -#define NCI_RESET_RESP_READ_DELAY (10000) // 10ms -#define NCI_RESET_RESP_TIMEOUT (500) // 500ms - -// FW DNLD packet details -#define FW_MSG_CMD_RSP 0x00 -#define FW_HDR_LEN 2 -#define FW_PAYLOAD_LEN_IDX 1 -#define FW_CRC_LEN 2 - -#define NCI_RSP_PKT_TYPE (0x40) -#define FW_MIN_PAYLOAD_LEN 4 -#define MIN_NFC_DL_FRAME_SIZE 3 - -#define NCI_RESET_CMD_LEN (4) -#define NCI_RESET_RSP_LEN (4) -#define NCI_CORE_RESET_CMD_OID (0x0) -#define NCI_CORE_RESET_CMD_PAYLOAD_LEN (0x1) -#define NCI_CORE_RESET_KEEP_CONFIG (0x0) -#define NCI_RESET_NTF_LEN (13) -#define SN1XX_ROM_VER 0x01 -#define SN1xx_MAJOR_VER 0x10 -#define SN220_ROM_VER 0x01 -#define SN220_MAJOR_VER 0x01 -#define FW_ROM_CODE_VER_OFFSET 4 -#define FW_MAJOR_VER_OFFSET 7 -#define GET_VERSION_RSP_CHIP_TYPE_OFFSET 3 -#define GET_VERSION_RSP_MINOR_VERSION_OFFSET 6 -#define DL_GET_VERSION_CMD_LEN (8) -#define DL_GET_VERSION_RSP_LEN_1 (12) /* SN110 */ -#define DL_GET_VERSION_RSP_LEN_2 (20) /* SN220 */ -#define DL_GET_VERSION_CMD_PAYLOAD_LEN (4) -#define DL_GET_VERSION_CMD_ID (0xF1) -#define DL_GET_VERSION_CMD_CRC_1 (0x6E) -#define DL_GET_VERSION_CMD_CRC_2 (0xEF) - -#define DL_RESET_CMD_LEN (8) -#define DL_GET_SESSION_STATE_CMD_LEN (8) -#define DL_GET_SESSION_STATE_RSP_LEN (8) -#define DL_GET_SESSION_STATE_CMD_PAYLOAD_LEN (4) -#define DL_GET_SESSION_CMD_ID (0xF2) -#define DL_GET_SESSION_CMD_CRC_1 (0xF5) -#define DL_GET_SESSION_CMD_CRC_2 (0x33) -#define GET_SESSION_STS_OFF (3) -#define NFCC_SESSION_STS_CLOSED (0x0) - -/* Below offsets should be subtracted from NCI header length + payload length */ - -#define NFC_CHIP_TYPE_OFF (4) -#define NFC_FW_MINOR_OFF (1) - -#define GET_VERSION_CMD_LEN 8 -#define GET_SESSION_STATE_CMD_LEN 8 -#define MAX_NCI_PAYLOAD_LEN (255) -#define MAX_BUFFER_SIZE (NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN) -/* - * From MW 11.04 buffer size increased to support - * frame size of 554 in FW download mode - * Frame len(2) + Frame Header(6) + DATA(512) + HASH(32) + CRC(2) + RFU(4) - */ -#define MAX_DL_PAYLOAD_LEN (550) -#define MAX_DL_BUFFER_SIZE (FW_HDR_LEN + FW_CRC_LEN + MAX_DL_PAYLOAD_LEN) -// Maximum retry count for standby writes -#define MAX_RETRY_COUNT (3) - -// Retry count for normal write -#define NO_RETRY (1) -#define MAX_IRQ_WAIT_TIME (90) -#define WAKEUP_SRC_TIMEOUT (2000) - -/*command response timeout*/ -#define NCI_CMD_RSP_TIMEOUT (2000) //2s -/*Time to wait for NFCC to be ready again after any change in the GPIO*/ -#define NFC_GPIO_SET_WAIT_TIME_USEC (10000) -/*Time to wait after soft reset via any NCI/DL cmd*/ -#define NFC_SOFT_RESET_WAIT_TIME_USEC (5000) -/*Time to wait before retrying i2c writes*/ -#define WRITE_RETRY_WAIT_TIME_USEC (1000) -/*Time to wait before retrying read for some specific usecases*/ -#define READ_RETRY_WAIT_TIME_USEC (3500) -#define NFC_MAGIC 0xE9 - -// Ioctls -// The type should be aligned with MW HAL definitions - -#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, unsigned int) -#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, unsigned int) -#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, unsigned int) -#define NFC_GET_PLATFORM_TYPE _IO(NFC_MAGIC, 0x04) - -/* NFC HAL can call this ioctl to get the current IRQ state */ -#define NFC_GET_IRQ_STATE _IO(NFC_MAGIC, 0x06) - -#define DTS_IRQ_GPIO_STR "qcom,sn-irq" -#define DTS_VEN_GPIO_STR "qcom,sn-ven" -#define DTS_FWDN_GPIO_STR "qcom,sn-firm" -#define DTS_CLKREQ_GPIO_STR "qcom,sn-clkreq" -#define DTS_CLKSRC_GPIO_STR "qcom,clk-src" -#define NFC_LDO_SUPPLY_DT_NAME "qcom,sn-vdd-1p8" -#define NFC_LDO_SUPPLY_NAME "qcom,sn-vdd-1p8-supply" -#define NFC_LDO_VOL_DT_NAME "qcom,sn-vdd-1p8-voltage" -#define NFC_LDO_CUR_DT_NAME "qcom,sn-vdd-1p8-current" - -//as per SN1x0 datasheet -#define NFC_VDDIO_MIN 1650000 //in uV -#define NFC_VDDIO_MAX 1950000 //in uV -#define NFC_CURRENT_MAX 157000 //in uA - - -#define NUM_OF_IPC_LOG_PAGES (2) -#define PKT_MAX_LEN (4) // no of max bytes to print for cmd/resp - -#define GET_IPCLOG_MAX_PKT_LEN(c) ((c > PKT_MAX_LEN) ? PKT_MAX_LEN : c) - -#define NFCLOG_IPC(nfc_dev, log_to_dmesg, x...) \ -do { \ - ipc_log_string(nfc_dev->ipcl, x); \ - if (log_to_dmesg) { \ - if (nfc_dev->nfc_device) \ - dev_err((nfc_dev->nfc_device), x); \ - else \ - pr_err(x); \ - } \ -} while (0) - -enum ese_ioctl_request { - /* eSE POWER ON */ - ESE_POWER_ON = 0, - /* eSE POWER OFF */ - ESE_POWER_OFF, - /* eSE POWER STATE */ - ESE_POWER_STATE -}; - -enum nfcc_ioctl_request { - /* NFC disable request with VEN LOW */ - NFC_POWER_OFF = 0, - /* NFC enable request with VEN Toggle */ - NFC_POWER_ON, - /* firmware download request with VEN Toggle */ - NFC_FW_DWL_VEN_TOGGLE, - /* ISO reset request */ - NFC_ISO_RESET, - /* request for firmware download gpio HIGH */ - NFC_FW_DWL_HIGH, - /* VEN hard reset request */ - NFC_VEN_FORCED_HARD_RESET, - /* request for firmware download gpio LOW */ - NFC_FW_DWL_LOW, - /* NFC enable without VEN gpio modification */ - NFC_ENABLE, - /* NFC disable without VEN gpio modification */ - NFC_DISABLE, -}; - -/*nfc platform interface type*/ -enum interface_flags { - /*I2C physical IF for NFCC */ - PLATFORM_IF_I2C = 0, -}; - -/*nfc state flags*/ -enum nfc_state_flags { - /*nfc in unknown state */ - NFC_STATE_UNKNOWN = 0, - /*nfc in download mode */ - NFC_STATE_FW_DWL = 0x1, - /*nfc booted in NCI mode */ - NFC_STATE_NCI = 0x2, - /*nfc booted in Fw teared mode */ - NFC_STATE_FW_TEARED = 0x4, -}; -/* - * Power state for IBI handing, mainly needed to defer the IBI handling - * for the IBI received in suspend state to do it later in resume call - */ -enum pm_state_flags { - PM_STATE_NORMAL = 0, - PM_STATE_SUSPEND, - PM_STATE_IBI_BEFORE_RESUME, -}; - -/* Enum for GPIO values*/ -enum gpio_values { - GPIO_INPUT = 0x0, - GPIO_OUTPUT = 0x1, - GPIO_HIGH = 0x2, - GPIO_OUTPUT_HIGH = 0x3, - GPIO_IRQ = 0x4, -}; - -// NFC GPIO variables -struct platform_gpio { - unsigned int irq; - unsigned int ven; - unsigned int clkreq; - unsigned int dwl_req; -}; - -// NFC LDO entries from DT -struct platform_ldo { - int vdd_levels[2]; - int max_current; -}; - -// NFC Struct to get all the required configs from DTS -struct platform_configs { - struct platform_gpio gpio; - struct platform_ldo ldo; -}; - -enum chip_types { - CHIP_SN1XX = 0x01, - CHIP_SN220 = 0x02, - CHIP_UNKNOWN = 0xFF, -}; - -/* Device specific structure */ -struct nfc_dev { - wait_queue_head_t read_wq; - struct mutex read_mutex; - struct mutex write_mutex; - uint8_t *read_kbuf; - uint8_t *write_kbuf; - struct mutex dev_ref_mutex; - unsigned int dev_ref_count; - struct class *nfc_class; - struct device *nfc_device; - struct cdev c_dev; - dev_t devno; - /* Interface flag */ - uint8_t interface; - /* nfc state flags */ - uint8_t nfc_state; - /* NFC VEN pin state */ - bool nfc_ven_enabled; - /* current firmware major version */ - uint8_t fw_major_version; - bool is_vreg_enabled; - bool is_ese_session_active; - struct i2c_dev i2c_dev; - struct platform_configs configs; - struct cold_reset cold_reset; - struct regulator *reg; - - /* read buffer*/ - size_t kbuflen; - u8 *kbuf; - - union nqx_uinfo nqx_info; - - void *ipcl; - - int (*nfc_read)(struct nfc_dev *dev, char *buf, size_t count, int timeout); - int (*nfc_write)(struct nfc_dev *dev, const char *buf, const size_t count, - int max_retry_cnt); - int (*nfc_enable_intr)(struct nfc_dev *dev); - int (*nfc_disable_intr)(struct nfc_dev *dev); -}; - -int nfc_dev_open(struct inode *inode, struct file *filp); -int nfc_dev_close(struct inode *inode, struct file *filp); -long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); -int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, - uint8_t interface); -int nfc_misc_register(struct nfc_dev *nfc_dev, - const struct file_operations *nfc_fops, int count, char *devname, - char *classname); -void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count); -int configure_gpio(unsigned int gpio, int flag); -void gpio_set_ven(struct nfc_dev *nfc_dev, int value); -int nfcc_hw_check(struct nfc_dev *nfc_dev); -int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev); -int nfc_ldo_vote(struct nfc_dev *nfc_dev); -int nfc_ldo_unvote(struct nfc_dev *nfc_dev); -int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev); -int validate_nfc_state_nci(struct nfc_dev *nfc_dev); -void set_nfcc_state_from_rsp(struct nfc_dev *dev, const char *buf, - const int count); -void enable_dwnld_mode(struct nfc_dev *nfc_dev, bool value); -#endif //_NFC_COMMON_H_ diff --git a/qti/nfc_i2c_drv.c b/qti/nfc_i2c_drv.c deleted file mode 100644 index 58d318dd21..0000000000 --- a/qti/nfc_i2c_drv.c +++ /dev/null @@ -1,577 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2013-2021 NXP - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ -/* - * Copyright (C) 2010 Trusted Logic S.A. - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "nfc_common.h" - -/** - * i2c_disable_irq() - * - * Check if interrupt is disabled or not - * and disable interrupt - * - * Return: int - */ -int i2c_disable_irq(struct nfc_dev *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->i2c_dev.irq_enabled_lock, flags); - if (dev->i2c_dev.irq_enabled) { - disable_irq_nosync(dev->i2c_dev.client->irq); - dev->i2c_dev.irq_enabled = false; - } - spin_unlock_irqrestore(&dev->i2c_dev.irq_enabled_lock, flags); - - return 0; -} - -/** - * i2c_enable_irq() - * - * Check if interrupt is enabled or not - * and enable interrupt - * - * Return: int - */ -int i2c_enable_irq(struct nfc_dev *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->i2c_dev.irq_enabled_lock, flags); - if (!dev->i2c_dev.irq_enabled) { - dev->i2c_dev.irq_enabled = true; - enable_irq(dev->i2c_dev.client->irq); - } - spin_unlock_irqrestore(&dev->i2c_dev.irq_enabled_lock, flags); - - return 0; -} - -static irqreturn_t i2c_irq_handler(int irq, void *dev_id) -{ - struct nfc_dev *nfc_dev = dev_id; - struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; - - if (device_may_wakeup(&i2c_dev->client->dev)) - pm_wakeup_event(&i2c_dev->client->dev, WAKEUP_SRC_TIMEOUT); - - i2c_disable_irq(nfc_dev); - wake_up(&nfc_dev->read_wq); - - return IRQ_HANDLED; -} - -int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) -{ - int ret; - struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev; - struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - uint16_t i = 0; - uint16_t disp_len = GET_IPCLOG_MAX_PKT_LEN(count); - - pr_debug("%s : reading %zu bytes.\n", __func__, count); - - if (timeout > NCI_CMD_RSP_TIMEOUT) - timeout = NCI_CMD_RSP_TIMEOUT; - - if (count > MAX_BUFFER_SIZE) - count = MAX_BUFFER_SIZE; - - if (!gpio_get_value(nfc_gpio->irq)) { - while (1) { - ret = 0; - if (!i2c_dev->irq_enabled) { - i2c_dev->irq_enabled = true; - enable_irq(i2c_dev->client->irq); - } - if (!gpio_get_value(nfc_gpio->irq)) { - if (timeout) { - ret = wait_event_interruptible_timeout(nfc_dev->read_wq, - !i2c_dev->irq_enabled, msecs_to_jiffies(timeout)); - - if (ret <= 0) { - pr_err("%s timeout/error in read\n", __func__); - goto err; - } - } else { - ret = wait_event_interruptible(nfc_dev->read_wq, - !i2c_dev->irq_enabled); - if (ret) { - pr_err("%s error wakeup of read wq\n", __func__); - ret = -EINTR; - goto err; - } - } - } - i2c_disable_irq(nfc_dev); - - if (gpio_get_value(nfc_gpio->irq)) - break; - if (!gpio_get_value(nfc_gpio->ven)) { - pr_info("%s: releasing read\n", __func__); - ret = -EIO; - goto err; - } - pr_warn("%s: spurious interrupt detected\n", __func__); - } - } - - memset(buf, 0x00, count); - /* Read data */ - ret = i2c_master_recv(nfc_dev->i2c_dev.client, buf, count); - NFCLOG_IPC(nfc_dev, false, "%s of %d bytes, ret %d", __func__, count, - ret); - if (ret <= 0) { - pr_err("%s: returned %d\n", __func__, ret); - goto err; - } - - for (i = 0; i < disp_len; i++) - NFCLOG_IPC(nfc_dev, false, " %02x", buf[i]); - - /* check if it's response of cold reset command - * NFC HAL process shouldn't receive this data as - * command was esepowermanager - */ - if (nfc_dev->cold_reset.rsp_pending && nfc_dev->cold_reset.cmd_buf - && (buf[0] == PROP_NCI_RSP_GID) - && (buf[1] == nfc_dev->cold_reset.cmd_buf[1])) { - read_cold_reset_rsp(nfc_dev, buf); - nfc_dev->cold_reset.rsp_pending = false; - wake_up_interruptible(&nfc_dev->cold_reset.read_wq); - /* - * NFC process doesn't know about cold reset command - * being sent as it was initiated by eSE process - * we shouldn't return any data to NFC process - */ - return 0; - } - -err: - return ret; -} - -int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, - int max_retry_cnt) -{ - int ret = -EINVAL; - int retry_cnt; - uint16_t i = 0; - uint16_t disp_len = GET_IPCLOG_MAX_PKT_LEN(count); - - if (count > MAX_DL_BUFFER_SIZE) - count = MAX_DL_BUFFER_SIZE; - - pr_debug("%s : writing %zu bytes.\n", __func__, count); - - NFCLOG_IPC(nfc_dev, false, "%s sending %d B", __func__, count); - - for (i = 0; i < disp_len; i++) - NFCLOG_IPC(nfc_dev, false, " %02x", buf[i]); - - for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) { - - ret = i2c_master_send(nfc_dev->i2c_dev.client, buf, count); - NFCLOG_IPC(nfc_dev, false, "%s ret %d", __func__, ret); - if (ret <= 0) { - pr_warn("%s: write failed ret %d, Maybe in Standby Mode - Retry(%d)\n", - __func__, ret, retry_cnt); - usleep_range(WRITE_RETRY_WAIT_TIME_USEC, - WRITE_RETRY_WAIT_TIME_USEC + 100); - } else if (ret != count) { - pr_err("%s: failed to write %d\n", __func__, ret); - ret = -EIO; - } else if (ret == count) - break; - } - return ret; -} - -ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, - size_t count, loff_t *offset) -{ - int ret = 0; - struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; - - if (filp->f_flags & O_NONBLOCK) { - pr_err(":f_flag has O_NONBLOCK. EAGAIN\n"); - return -EAGAIN; - } - mutex_lock(&nfc_dev->read_mutex); - ret = i2c_read(nfc_dev, nfc_dev->read_kbuf, count, 0); - if (ret > 0) { - if (copy_to_user(buf, nfc_dev->read_kbuf, ret)) { - pr_warn("%s : failed to copy to user space\n", __func__); - ret = -EFAULT; - } - } - mutex_unlock(&nfc_dev->read_mutex); - return ret; -} - -ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *offset) -{ - int ret; - struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; - - if (count > MAX_DL_BUFFER_SIZE) - count = MAX_DL_BUFFER_SIZE; - - if (!nfc_dev) - return -ENODEV; - - mutex_lock(&nfc_dev->write_mutex); - if (copy_from_user(nfc_dev->write_kbuf, buf, count)) { - pr_err("%s : failed to copy from user space\n", __func__); - mutex_unlock(&nfc_dev->write_mutex); - return -EFAULT; - } - ret = i2c_write(nfc_dev, nfc_dev->write_kbuf, count, NO_RETRY); - mutex_unlock(&nfc_dev->write_mutex); - return ret; -} - -static const struct file_operations nfc_i2c_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = nfc_i2c_dev_read, - .write = nfc_i2c_dev_write, - .open = nfc_dev_open, - .release = nfc_dev_close, - .unlocked_ioctl = nfc_dev_ioctl, -}; - -int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - int ret = 0; - struct nfc_dev *nfc_dev = NULL; - struct i2c_dev *i2c_dev = NULL; - struct platform_configs nfc_configs; - struct platform_gpio *nfc_gpio = &nfc_configs.gpio; - - pr_debug("%s: enter\n", __func__); - - //retrieve details of gpios from dt - - ret = nfc_parse_dt(&client->dev, &nfc_configs, PLATFORM_IF_I2C); - if (ret) { - pr_err("%s : failed to parse dt\n", __func__); - goto err; - } - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s : need I2C_FUNC_I2C\n", __func__); - ret = -ENODEV; - goto err; - } - nfc_dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL); - if (nfc_dev == NULL) { - ret = -ENOMEM; - goto err; - } - nfc_dev->read_kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); - if (!nfc_dev->read_kbuf) { - ret = -ENOMEM; - goto err_free_nfc_dev; - } - nfc_dev->write_kbuf = kzalloc(MAX_DL_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); - if (!nfc_dev->write_kbuf) { - ret = -ENOMEM; - goto err_free_read_kbuf; - } - nfc_dev->interface = PLATFORM_IF_I2C; - nfc_dev->nfc_state = NFC_STATE_NCI; - nfc_dev->i2c_dev.client = client; - i2c_dev = &nfc_dev->i2c_dev; - nfc_dev->nfc_read = i2c_read; - nfc_dev->nfc_write = i2c_write; - nfc_dev->nfc_enable_intr = i2c_enable_irq; - nfc_dev->nfc_disable_intr = i2c_disable_irq; - nfc_dev->fw_major_version = 0; - ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT); - if (ret) { - pr_err("%s: unable to request nfc reset gpio [%d]\n", - __func__, nfc_gpio->ven); - goto err_free_write_kbuf; - } - ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ); - if (ret <= 0) { - pr_err("%s: unable to request nfc irq gpio [%d]\n", - __func__, nfc_gpio->irq); - goto err_free_ven; - } - client->irq = ret; - ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT); - if (ret) { - pr_err("%s: unable to request nfc firm downl gpio [%d]\n", - __func__, nfc_gpio->dwl_req); - //not returning failure here as dwl gpio is a optional gpio for sn220 - } - - ret = configure_gpio(nfc_gpio->clkreq, GPIO_INPUT); - if (ret) { - pr_err("%s: unable to request nfc clkreq gpio [%d]\n", - __func__, nfc_gpio->clkreq); - goto err_free_dwl_req; - } - - /*copy the retrieved gpio details from DT */ - memcpy(&nfc_dev->configs, &nfc_configs, sizeof(struct platform_configs)); - - /* init mutex and queues */ - init_waitqueue_head(&nfc_dev->read_wq); - mutex_init(&nfc_dev->read_mutex); - mutex_init(&nfc_dev->write_mutex); - mutex_init(&nfc_dev->dev_ref_mutex); - spin_lock_init(&i2c_dev->irq_enabled_lock); - ret = nfc_misc_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT, - NFC_CHAR_DEV_NAME, CLASS_NAME); - if (ret) { - pr_err("%s: nfc_misc_register failed\n", __func__); - goto err_mutex_destroy; - } - /* interrupt initializations */ - pr_info("%s : requesting IRQ %d\n", __func__, client->irq); - i2c_dev->irq_enabled = true; - ret = request_irq(client->irq, i2c_irq_handler, - IRQF_TRIGGER_HIGH, client->name, nfc_dev); - if (ret) { - pr_err("%s: request_irq failed\n", __func__); - goto err_nfc_misc_unregister; - } - i2c_disable_irq(nfc_dev); - i2c_set_clientdata(client, nfc_dev); - - ret = nfc_ldo_config(&client->dev, nfc_dev); - if (ret) { - pr_err("LDO config failed\n"); - goto err_ldo_config_failed; - } - - ret = nfcc_hw_check(nfc_dev); - if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { - pr_err("nfc hw check failed ret %d\n", ret); - goto err_nfcc_hw_check; - } - - device_init_wakeup(&client->dev, true); - i2c_dev->irq_wake_up = false; - nfc_dev->is_ese_session_active = false; - - pr_info("%s success\n", __func__); - return 0; - -err_nfcc_hw_check: - if (nfc_dev->reg) { - nfc_ldo_unvote(nfc_dev); - regulator_put(nfc_dev->reg); - } -err_ldo_config_failed: - free_irq(client->irq, nfc_dev); -err_nfc_misc_unregister: - nfc_misc_unregister(nfc_dev, DEV_COUNT); -err_mutex_destroy: - mutex_destroy(&nfc_dev->dev_ref_mutex); - mutex_destroy(&nfc_dev->read_mutex); - mutex_destroy(&nfc_dev->write_mutex); - gpio_free(nfc_gpio->clkreq); -err_free_dwl_req: - if (gpio_is_valid(nfc_gpio->dwl_req)) - gpio_free(nfc_gpio->dwl_req); - gpio_free(nfc_gpio->irq); -err_free_ven: - gpio_free(nfc_gpio->ven); -err_free_write_kbuf: - kfree(nfc_dev->write_kbuf); -err_free_read_kbuf: - kfree(nfc_dev->read_kbuf); -err_free_nfc_dev: - kfree(nfc_dev); -err: - pr_err("%s: failed\n", __func__); - return ret; -} - -int nfc_i2c_dev_remove(struct i2c_client *client) -{ - int ret = 0; - struct nfc_dev *nfc_dev = NULL; - - pr_info("%s: remove device\n", __func__); - nfc_dev = i2c_get_clientdata(client); - if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); - ret = -ENODEV; - return ret; - } - - if (nfc_dev->dev_ref_count > 0) { - pr_err("%s: device already in use\n", __func__); - return -EBUSY; - } - - gpio_set_value(nfc_dev->configs.gpio.ven, 0); - // HW dependent delay before LDO goes into LPM mode - usleep_range(10000, 10100); - if (nfc_dev->reg) { - nfc_ldo_unvote(nfc_dev); - regulator_put(nfc_dev->reg); - } - - device_init_wakeup(&client->dev, false); - free_irq(client->irq, nfc_dev); - nfc_misc_unregister(nfc_dev, DEV_COUNT); - mutex_destroy(&nfc_dev->dev_ref_mutex); - mutex_destroy(&nfc_dev->read_mutex); - mutex_destroy(&nfc_dev->write_mutex); - - if (gpio_is_valid(nfc_dev->configs.gpio.clkreq)) - gpio_free(nfc_dev->configs.gpio.clkreq); - - if (gpio_is_valid(nfc_dev->configs.gpio.dwl_req)) - gpio_free(nfc_dev->configs.gpio.dwl_req); - - if (gpio_is_valid(nfc_dev->configs.gpio.irq)) - gpio_free(nfc_dev->configs.gpio.irq); - - if (gpio_is_valid(nfc_dev->configs.gpio.ven)) - gpio_free(nfc_dev->configs.gpio.ven); - - kfree(nfc_dev->read_kbuf); - kfree(nfc_dev->write_kbuf); - kfree(nfc_dev); - return ret; -} - -int nfc_i2c_dev_suspend(struct device *device) -{ - struct i2c_client *client = to_i2c_client(device); - struct nfc_dev *nfc_dev = i2c_get_clientdata(client); - struct i2c_dev *i2c_dev = NULL; - - if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); - return -ENODEV; - } - - i2c_dev = &nfc_dev->i2c_dev; - - NFCLOG_IPC(nfc_dev, false, "%s: irq_enabled = %d", __func__, - i2c_dev->irq_enabled); - - if (device_may_wakeup(&client->dev) && i2c_dev->irq_enabled) { - if (!enable_irq_wake(client->irq)) - i2c_dev->irq_wake_up = true; - } - return 0; -} - -int nfc_i2c_dev_resume(struct device *device) -{ - struct i2c_client *client = to_i2c_client(device); - struct nfc_dev *nfc_dev = i2c_get_clientdata(client); - struct i2c_dev *i2c_dev = NULL; - - if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); - return -ENODEV; - } - - i2c_dev = &nfc_dev->i2c_dev; - - NFCLOG_IPC(nfc_dev, false, "%s: irq_wake_up = %d", __func__, - i2c_dev->irq_wake_up); - - if (device_may_wakeup(&client->dev) && i2c_dev->irq_wake_up) { - if (!disable_irq_wake(client->irq)) - i2c_dev->irq_wake_up = false; - } - return 0; -} - -static const struct i2c_device_id nfc_i2c_dev_id[] = { - {NFC_I2C_DEV_ID, 0}, - {} -}; - -static const struct of_device_id nfc_i2c_dev_match_table[] = { - {.compatible = NFC_I2C_DRV_STR,}, - {} -}; - -static const struct dev_pm_ops nfc_i2c_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(nfc_i2c_dev_suspend, nfc_i2c_dev_resume) -}; - -static struct i2c_driver nfc_i2c_dev_driver = { - .id_table = nfc_i2c_dev_id, - .probe = nfc_i2c_dev_probe, - .remove = nfc_i2c_dev_remove, - .driver = { - .name = NFC_I2C_DRV_STR, - .pm = &nfc_i2c_dev_pm_ops, - .of_match_table = nfc_i2c_dev_match_table, - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - }, -}; - -MODULE_DEVICE_TABLE(of, nfc_i2c_dev_match_table); - -static int __init nfc_i2c_dev_init(void) -{ - int ret = 0; - - ret = i2c_add_driver(&nfc_i2c_dev_driver); - if (ret != 0) - pr_err("NFC I2C add driver error ret %d\n", ret); - return ret; -} - -module_init(nfc_i2c_dev_init); - -static void __exit nfc_i2c_dev_exit(void) -{ - pr_debug("Unloading NFC I2C driver\n"); - i2c_del_driver(&nfc_i2c_dev_driver); -} - -module_exit(nfc_i2c_dev_exit); - -MODULE_DESCRIPTION("QTI NFC I2C driver"); -MODULE_LICENSE("GPL v2"); diff --git a/qti/nfc_i2c_drv.h b/qti/nfc_i2c_drv.h deleted file mode 100644 index 5ba871a1e4..0000000000 --- a/qti/nfc_i2c_drv.h +++ /dev/null @@ -1,81 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2019-2021 NXP - * - * This program 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 program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ******************************************************************************/ - -#ifndef _NFC_I2C_DRV_H_ -#define _NFC_I2C_DRV_H_ -#include - -#define NFC_I2C_DRV_STR "qcom,sn-nci" /*kept same as dts */ -#define NFC_I2C_DEV_ID "sn-i2c" - -struct nfc_dev; - -//Interface specific parameters -struct i2c_dev { - struct i2c_client *client; - /*IRQ parameters */ - bool irq_enabled; - spinlock_t irq_enabled_lock; - /* NFC_IRQ wake-up state */ - bool irq_wake_up; -}; - -long nfc_i2c_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); -int nfc_i2c_dev_probe(struct i2c_client *client, - const struct i2c_device_id *id); -int nfc_i2c_dev_remove(struct i2c_client *client); -int nfc_i2c_dev_suspend(struct device *device); -int nfc_i2c_dev_resume(struct device *device); - -#if IS_ENABLED(CONFIG_NFC_QTI_I2C) - -int i2c_enable_irq(struct nfc_dev *dev); -int i2c_disable_irq(struct nfc_dev *dev); -int i2c_write(struct nfc_dev *dev, const char *buf, size_t count, - int max_retry_cnt); -int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout); - -#else - -static inline int i2c_enable_irq(struct nfc_dev *dev) -{ - return -ENXIO; -} - -static inline int i2c_disable_irq(struct nfc_dev *dev) -{ - return -ENXIO; -} - -static inline int i2c_write(struct nfc_dev *dev, const char *buf, - size_t count, int max_retry_cnt) -{ - return -ENXIO; -} - -static inline int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout) -{ - return -ENXIO; -} - -#endif - -#endif //_NFC_I2C_DRV_H_ From 414ee1d6684ec2e1ed62c99f63bff05a93e2224c Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Thu, 17 Feb 2022 14:54:11 +0530 Subject: [PATCH 051/100] NFC: Driver: Add SW WAR to enable and disable NFC clock Added SW WAR to enable NFC clock at NFC ON and disable NFC clock at NFC OFF. Change-Id: Id617efb53ba06caa735927b4d271990be7e4766c --- nfc/common.c | 27 +++++++++++++++++++++------ nfc/common.h | 11 +++++++++++ nfc/common_qcom.c | 41 +++++++++++++++++++++++++++++++++++++++++ nfc/i2c_drv.c | 6 ++++++ 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index c9b37cdcbb..6a1f5329d8 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -66,6 +66,13 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, pr_warn("%s: nfc dwl_req gpio invalid %d\n", __func__, nfc_gpio->dwl_req); + if (of_property_read_string(np, DTS_CLKSRC_GPIO_STR, &nfc_configs->clk_src_name)) { + nfc_configs->clk_pin_voting = false; + } + else { + nfc_configs->clk_pin_voting = true; + } + pr_info("%s: irq %d, ven %d, dwl %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven, nfc_gpio->dwl_req); @@ -329,14 +336,22 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) nfc_dev->nfc_state = NFC_STATE_NCI; } else if (arg == NFC_ENABLE) { - /* - * Setting flag true when NFC is enabled - */ + if(nfc_dev->configs.clk_pin_voting) { + /* Enabling nfc clock */ + ret = nfc_clock_select(nfc_dev); + if (ret) + pr_err("%s unable to select clock\n", __func__); + } + /* Setting flag true when NFC is enabled */ nfc_dev->cold_reset.is_nfc_enabled = true; } else if (arg == NFC_DISABLE) { - /* - * Setting flag true when NFC is disabled - */ + if(nfc_dev->configs.clk_pin_voting) { + /* Disabling nfc clock */ + ret = nfc_clock_deselect(nfc_dev); + if (ret) + pr_err("%s unable to disable clock\n", __func__); + } + /* Setting flag true when NFC is disabled */ nfc_dev->cold_reset.is_nfc_enabled = false; } else { pr_err("%s bad arg %lu\n", __func__, arg); diff --git a/nfc/common.h b/nfc/common.h index 1c723bf79c..29c0c49028 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "i2c_drv.h" #include "ese_cold_reset.h" @@ -111,6 +112,7 @@ #define DTS_IRQ_GPIO_STR "qcom,sn-irq" #define DTS_VEN_GPIO_STR "qcom,sn-ven" #define DTS_FWDN_GPIO_STR "qcom,sn-firm" +#define DTS_CLKSRC_GPIO_STR "qcom,clk-src" #define NFC_LDO_SUPPLY_DT_NAME "qcom,sn-vdd-1p8" #define NFC_LDO_SUPPLY_NAME "qcom,sn-vdd-1p8-supply" #define NFC_LDO_VOL_DT_NAME "qcom,sn-vdd-1p8-voltage" @@ -221,6 +223,9 @@ struct platform_ldo { struct platform_configs { struct platform_gpio gpio; struct platform_ldo ldo; + const char *clk_src_name; + /* NFC_CLK pin voting state */ + bool clk_pin_voting; }; @@ -261,6 +266,10 @@ struct nfc_dev { union nqx_uinfo nqx_info; + /* CLK control */ + bool clk_run; + struct clk *s_clk; + void *ipcl; /* function pointers for the common i2c functionality */ @@ -296,4 +305,6 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg); int nfc_ldo_unvote(struct nfc_dev *nfc_dev); int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev); int validate_nfc_state_nci(struct nfc_dev *nfc_dev); +int nfc_clock_select(struct nfc_dev *nfc_dev); +int nfc_clock_deselect(struct nfc_dev *nfc_dev); #endif /* _COMMON_H_ */ diff --git a/nfc/common_qcom.c b/nfc/common_qcom.c index ef05d01394..9ba42863ad 100644 --- a/nfc/common_qcom.c +++ b/nfc/common_qcom.c @@ -161,3 +161,44 @@ int nfc_ldo_unvote(struct nfc_dev *nfc_dev) pr_err("%s: set load failed\n", __func__); return ret; } + +/* + * Routine to enable clock. + * this routine can be extended to select from multiple + * sources based on clk name. + */ +int nfc_clock_select(struct nfc_dev *nfc_dev) +{ + int r = 0; + + nfc_dev->s_clk = clk_get(&nfc_dev->i2c_dev.client->dev, "nfc_ref_clk"); + + if (IS_ERR(nfc_dev->s_clk)) + return PTR_ERR(nfc_dev->s_clk); + + if (!nfc_dev->clk_run) + r = clk_prepare_enable(nfc_dev->s_clk); + + if (r) + return r; + + nfc_dev->clk_run = true; + return r; +} + +/* + * Routine to disable clocks + */ +int nfc_clock_deselect(struct nfc_dev *nfc_dev) +{ + int r = -EINVAL; + + if (nfc_dev->s_clk != NULL) { + if (nfc_dev->clk_run) { + clk_disable_unprepare(nfc_dev->s_clk); + nfc_dev->clk_run = false; + } + return 0; + } + return r; +} diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index d0e2d5a5f2..4ab1f00063 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -431,6 +431,12 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) pr_err("nfc hw check failed ret %d\n", ret); goto err_nfcc_hw_check; } + + if(nfc_dev->configs.clk_pin_voting) + nfc_dev->clk_run = false; + else + nfc_dev->clk_run = true; + gpio_set_ven(nfc_dev, 1); gpio_set_ven(nfc_dev, 0); gpio_set_ven(nfc_dev, 1); From 71fa3f1d6bda19888c900244da173a0ee0a142d2 Mon Sep 17 00:00:00 2001 From: nxf24591 Date: Tue, 1 Mar 2022 15:12:06 +0530 Subject: [PATCH 052/100] Updated corresponding to - NFC_AR_00_E800_13.03.00_OpnSrc --- nfc/common.h | 8 +++----- nfc/i2c_drv.c | 10 +++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/nfc/common.h b/nfc/common.h index 675e06ccd4..4899c0d92c 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -1,6 +1,6 @@ /****************************************************************************** * Copyright (C) 2015, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2021 NXP + * Copyright (C) 2019-2022 NXP * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -64,10 +64,8 @@ #define NCI_CMD_RSP_TIMEOUT_MS (2000) /* Time to wait for NFCC to be ready again after any change in the GPIO */ #define NFC_GPIO_SET_WAIT_TIME_US (10000) -/* Time to wait for IRQ low during write 5*3ms */ -#define NFC_WRITE_IRQ_WAIT_TIME_US (3000) -/* Time to wait before retrying i2c/I3C writes */ -#define WRITE_RETRY_WAIT_TIME_US (1000) +/* Time to wait before retrying writes */ +#define WRITE_RETRY_WAIT_TIME_US (3000) /* Time to wait before retrying read for some specific usecases */ #define READ_RETRY_WAIT_TIME_US (3500) #define NFC_MAGIC (0xE9) diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 32cfc43a4c..f335386e6d 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -1,6 +1,6 @@ /****************************************************************************** * Copyright (C) 2015, The Linux Foundation. All rights reserved. - * Copyright (C) 2013-2021 NXP + * Copyright (C) 2013-2022 NXP * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -225,8 +225,8 @@ int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, for (retry_cnt = 1; retry_cnt <= MAX_WRITE_IRQ_COUNT; retry_cnt++) { if (gpio_get_value(nfc_gpio->irq)) { pr_warn("%s: irq high during write, wait\n", __func__); - usleep_range(NFC_WRITE_IRQ_WAIT_TIME_US, - NFC_WRITE_IRQ_WAIT_TIME_US + 100); + usleep_range(WRITE_RETRY_WAIT_TIME_US, + WRITE_RETRY_WAIT_TIME_US + 100); } else { break; } @@ -337,12 +337,12 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) ret = nfc_parse_dt(&client->dev,nfc_configs, PLATFORM_IF_I2C); if (ret) { pr_err("%s: failed to parse dt\n", __func__); - goto err; + goto err_free_nfc_dev; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { pr_err("%s: need I2C_FUNC_I2C\n", __func__); ret = -ENODEV; - goto err; + goto err_free_nfc_dev; } nfc_dev->read_kbuf = kzalloc(MAX_NCI_BUFFER_SIZE, GFP_DMA | GFP_KERNEL); if (!nfc_dev->read_kbuf) { From 2c07f5c6651d330179b4c5e7d6db9bccf4c31443 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Fri, 25 Mar 2022 11:51:02 +0530 Subject: [PATCH 053/100] NFC: Driver: Remove unused macros and update ioctls arguments Removed unused macros and updated ioctls arguments as per HAL. Change-Id: Ie6ef3a26c93b17147751d50e533b05f561376ced --- nfc/common.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/nfc/common.h b/nfc/common.h index b834f7defc..e0ac089e49 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -59,15 +59,9 @@ // FW DNLD packet details #define FW_MSG_CMD_RSP 0x00 #define DL_HDR_LEN (2) -#define FW_PAYLOAD_LEN_IDX 1 #define DL_CRC_LEN (2) #define NCI_RSP_PKT_TYPE (0x40) -#define FW_MIN_PAYLOAD_LEN 4 -#define MIN_NFC_DL_FRAME_SIZE 3 - -#define GET_VERSION_CMD_LEN 8 -#define GET_SESSION_STATE_CMD_LEN 8 #define MAX_NCI_PAYLOAD_LEN (255) #define MAX_NCI_BUFFER_SIZE (NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN) /* @@ -100,9 +94,9 @@ // Ioctls // The type should be aligned with MW HAL definitions -#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, unsigned int) -#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, unsigned int) -#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, unsigned int) +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) +#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) +#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) #define DTS_IRQ_GPIO_STR "qcom,sn-irq" #define DTS_VEN_GPIO_STR "qcom,sn-ven" From eba3412350fcd7fc4f995488ccb7296dd9d33227 Mon Sep 17 00:00:00 2001 From: Mallikarjun S T Date: Sat, 9 Apr 2022 21:09:35 +0530 Subject: [PATCH 054/100] NFC: driver: FR63179 Add NFC dynamic protection control Implemented NFC dynamic protection control feature in driver; performing Ven GPIO enable/disable post TZ notifications in non-secure/secure zone respectively. Change-Id: I13dedf23987ce0b3b2a53881d35f6c3cf462cd92 --- nfc/common.c | 127 +++++++++++++++++++++++++++++++++++++++++++ nfc/common.h | 6 ++ nfc/ese_cold_reset.c | 2 + nfc/i2c_drv.c | 29 ++-------- 4 files changed, 139 insertions(+), 25 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 6a1f5329d8..6539cf617d 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -27,6 +27,8 @@ #include "common.h" +static int secure_zone = 1; + int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface) { @@ -385,6 +387,120 @@ long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, } #endif +/** + * nfc_post_init() - Configuraing Ven GPIO and hardware check + * @nfc_dev: nfc device data structure + * + * Configure GPIOs post notification from TZ, ensuring it's a non-secure zone. + * + * Return: 0 if Success(or no issue) and error ret code otherwise + */ +int nfc_post_init(struct nfc_dev *nfc_dev) +{ + int ret=0; + struct platform_configs nfc_configs; + struct platform_gpio *nfc_gpio; + + if (!nfc_dev) + return -ENODEV; + + memcpy(&nfc_configs, &nfc_dev->configs, sizeof(struct platform_configs)); + nfc_gpio = &nfc_configs.gpio; + + ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc reset gpio [%d]\n", + __func__, nfc_gpio->ven); + return ret; + } + + ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT); + if (ret) { + pr_err("%s: unable to request nfc firm downl gpio [%d]\n", + __func__, nfc_gpio->dwl_req); + } + + ret = nfcc_hw_check(nfc_dev); + if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { + pr_err("nfc hw check failed ret %d\n", ret); + gpio_free(nfc_gpio->dwl_req); + gpio_free(nfc_gpio->ven); + return ret; + } + + /*Initialising sempahore to disbale NFC Ven GPIO only after eSE is power off flag is set */ + sema_init(&sem_eSE_pwr_off,0); + + pr_info("%s success\n", __func__); + return 0; + + +} + +/** + * nfc_dynamic_protection_ioctl() - dynamic protection control + * @nfc_dev: nfc device data structure + * @sec_zone_trans: mode that we want to move to + * If sec_zone_trans = 1; transition from non-secure zone to secure zone + * If sec_zone_trans = 0; transition from secure zone to non - secure zone + * + * nfc periheral dynamic protection control. Depending on the sec_zone_trans value, device moves to + * secure zone and non-secure zone + * + * Return: -ENOIOCTLCMD if sec_zone_trans val is not supported, 0 if Success(or no issue) + * and error ret code otherwise + */ +int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans) +{ + int ret = 0; + + static int init_flag=1; + + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + if(sec_zone_trans == 1) { + /*check NFC is disabled, only then set Ven GPIO low*/ + if(nfc_dev->cold_reset.is_nfc_enabled == false) { + pr_debug("%s: value %d\n", __func__, gpio_get_value(nfc_gpio->ven)); + + chk_eSE_pwr_off = 1; + /*check if eSE is active, if yes, wait max of 1sec, until it's inactive */ + if(nfc_dev->is_ese_session_active == true) { + if(down_timeout(&sem_eSE_pwr_off, msecs_to_jiffies(1000))) { + /*waited for 1sec yet eSE not turned off, so, ignoring eSE power off*/ + pr_info("Forcefull shutdown of eSE\n"); + } + } + ret = nfc_ioctl_power_states(nfc_dev, 0); + /*set driver as secure zone, such that no ioctl calls are allowed*/ + secure_zone=1; + pr_info("Driver Secure flag set successful\n"); + } else { + ret = -1; + } + } + else if(sec_zone_trans == 0) { + chk_eSE_pwr_off = 0; + secure_zone=0; + + if(init_flag) { + /*Initialize once,only during the first non-secure entry*/ + ret = nfc_post_init(nfc_dev); + if(ret == 0) + init_flag=0; + } + else { + ret = nfc_ioctl_power_states(nfc_dev, 1); + } + pr_info("Func Driver Secure flag clear successful\n"); + } else { + pr_info("INVALID ARG\n"); + ret = -ENOIOCTLCMD; + } + + return ret; +} + /** * nfc_dev_ioctl - used to set or get data from upper layer. * @pfile file node for opened device. @@ -406,6 +522,14 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) if (!nfc_dev) return -ENODEV; + /*Avoiding ioctl call in secure zone*/ + if(secure_zone) { + if(cmd!=NFC_SECURE_ZONE) { + pr_debug("nfc_dev_ioctl failed\n"); + return -1; + } + } + pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg); switch (cmd) { case NFC_SET_PWR: @@ -424,6 +548,9 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) pr_debug("nfc ese cold reset ioctl\n"); ret = ese_cold_reset_ioctl(nfc_dev, arg); break; + case NFC_SECURE_ZONE: + ret = nfc_dynamic_protection_ioctl(nfc_dev, arg); + break; default: pr_err("%s: bad cmd %lu\n", __func__, arg); ret = -ENOIOCTLCMD; diff --git a/nfc/common.h b/nfc/common.h index ee2b55d05f..6e4ed15996 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -98,6 +98,7 @@ #define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) #define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) #define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) +#define NFC_SECURE_ZONE _IOW(NFC_MAGIC, 0x0A, uint32_t) #define DTS_IRQ_GPIO_STR "qcom,sn-irq" #define DTS_VEN_GPIO_STR "qcom,sn-ven" @@ -130,6 +131,9 @@ do { \ } \ } while (0) +static struct semaphore sem_eSE_pwr_off; +static chk_eSE_pwr_off; + enum ese_ioctl_request { /* eSE POWER ON */ ESE_POWER_ON = 0, @@ -297,4 +301,6 @@ int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev); int validate_nfc_state_nci(struct nfc_dev *nfc_dev); int nfc_clock_select(struct nfc_dev *nfc_dev); int nfc_clock_deselect(struct nfc_dev *nfc_dev); +int nfc_post_init(struct nfc_dev *nfc_dev); +int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans); #endif /* _COMMON_H_ */ diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index ad0aa2c6a3..309f245101 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -47,6 +47,8 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) pr_debug("keep ven high as NFC is enabled\n"); } nfc_dev->is_ese_session_active = false; + if(chk_eSE_pwr_off) + up(&sem_eSE_pwr_off); } else if (arg == ESE_POWER_STATE) { /* get VEN gpio state for eSE, as eSE also enabled through same GPIO */ ret = gpio_get_value(nfc_dev->configs.gpio.ven); diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 30a2828c62..4b47ef10a5 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -375,12 +375,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) nfc_dev->nfc_write = i2c_write; nfc_dev->nfc_enable_intr = i2c_enable_irq; nfc_dev->nfc_disable_intr = i2c_disable_irq; - ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT); - if (ret) { - pr_err("%s: unable to request nfc reset gpio [%d]\n", __func__, - nfc_gpio->ven); - goto err_free_write_kbuf; - } + ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ); if (ret <= 0) { pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__, @@ -388,11 +383,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_free_gpio; } client->irq = ret; - ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT); - if (ret) { - pr_err("%s: unable to request nfc firm downl gpio [%d]\n", - __func__, nfc_gpio->dwl_req); - } + /* init mutex and queues */ init_waitqueue_head(&nfc_dev->read_wq); mutex_init(&nfc_dev->read_mutex); @@ -421,20 +412,13 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) pr_err("LDO config failed\n"); goto err_ldo_config_failed; } - ret = nfcc_hw_check(nfc_dev); - if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { - pr_err("nfc hw check failed ret %d\n", ret); - goto err_nfcc_hw_check; - } if(nfc_dev->configs.clk_pin_voting) nfc_dev->clk_run = false; else nfc_dev->clk_run = true; - gpio_set_ven(nfc_dev, 1); - gpio_set_ven(nfc_dev, 0); - gpio_set_ven(nfc_dev, 1); + device_init_wakeup(&client->dev, true); i2c_set_clientdata(client, nfc_dev); i2c_dev->irq_wake_up = false; @@ -443,11 +427,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) pr_info("%s: probing nfc i2c successfully\n", __func__); return 0; -err_nfcc_hw_check: - if (nfc_dev->reg) { - nfc_ldo_unvote(nfc_dev); - regulator_put(nfc_dev->reg); - } + err_ldo_config_failed: free_irq(client->irq, nfc_dev); err_nfc_misc_unregister: @@ -458,7 +438,6 @@ err_mutex_destroy: mutex_destroy(&nfc_dev->write_mutex); err_free_gpio: gpio_free_all(nfc_dev); -err_free_write_kbuf: kfree(nfc_dev->write_kbuf); err_free_read_kbuf: kfree(nfc_dev->read_kbuf); From ade85437e36c6d419a56c5fc2b437c6f58804265 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Tue, 7 Jun 2022 19:09:03 +0530 Subject: [PATCH 055/100] NFC: Driver: Add clock request gpio configurations Added clock request gpio configuration for kalama R2. Change-Id: I61fe3e0d252e7b6bacd8be437725430d0c7def8e --- nfc/common.c | 24 +++++++++++++++++++++--- nfc/common.h | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 6539cf617d..10bd17f17e 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -45,6 +45,7 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, nfc_gpio->irq = -EINVAL; nfc_gpio->dwl_req = -EINVAL; nfc_gpio->ven = -EINVAL; + nfc_gpio->clkreq = -EINVAL; /* irq required for i2c based chips only */ if (interface == PLATFORM_IF_I2C) { @@ -67,16 +68,21 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, if ((!gpio_is_valid(nfc_gpio->dwl_req))) pr_warn("%s: nfc dwl_req gpio invalid %d\n", __func__, nfc_gpio->dwl_req); - + /* Read clock request gpio configuration if MGPIO configurations are not preasent */ if (of_property_read_string(np, DTS_CLKSRC_GPIO_STR, &nfc_configs->clk_src_name)) { nfc_configs->clk_pin_voting = false; + nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0); + if (!gpio_is_valid(nfc_gpio->clkreq)) { + dev_err(dev, "clkreq gpio invalid %d\n", nfc_gpio->clkreq); + return -EINVAL; + } } else { nfc_configs->clk_pin_voting = true; } - pr_info("%s: irq %d, ven %d, dwl %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven, - nfc_gpio->dwl_req); + pr_info("%s: irq %d, ven %d, dwl %d, clkreq %d, clk_pin_voting %d \n", __func__, nfc_gpio->irq, nfc_gpio->ven, + nfc_gpio->dwl_req, nfc_gpio->clkreq, nfc_configs->clk_pin_voting); /* optional property */ ret = of_property_read_u32_array(np, NFC_LDO_VOL_DT_NAME, @@ -188,6 +194,9 @@ void gpio_free_all(struct nfc_dev *nfc_dev) { struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + if (gpio_is_valid(nfc_gpio->clkreq)) + gpio_free(nfc_gpio->clkreq); + if (gpio_is_valid(nfc_gpio->dwl_req)) gpio_free(nfc_gpio->dwl_req); @@ -420,6 +429,15 @@ int nfc_post_init(struct nfc_dev *nfc_dev) __func__, nfc_gpio->dwl_req); } + if(!(nfc_configs.clk_pin_voting)){ + ret = configure_gpio(nfc_gpio->clkreq, GPIO_INPUT); + if (ret) { + pr_err("%s: unable to request nfc clkreq gpio [%d]\n", + __func__, nfc_gpio->clkreq); + return ret; + } + } + ret = nfcc_hw_check(nfc_dev); if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { pr_err("nfc hw check failed ret %d\n", ret); diff --git a/nfc/common.h b/nfc/common.h index 6e4ed15996..32c923f667 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -103,6 +103,7 @@ #define DTS_IRQ_GPIO_STR "qcom,sn-irq" #define DTS_VEN_GPIO_STR "qcom,sn-ven" #define DTS_FWDN_GPIO_STR "qcom,sn-firm" +#define DTS_CLKREQ_GPIO_STR "qcom,sn-clkreq" #define DTS_CLKSRC_GPIO_STR "qcom,clk-src" #define NFC_LDO_SUPPLY_DT_NAME "qcom,sn-vdd-1p8" #define NFC_LDO_SUPPLY_NAME "qcom,sn-vdd-1p8-supply" @@ -204,6 +205,7 @@ enum gpio_values { struct platform_gpio { unsigned int irq; unsigned int ven; + unsigned int clkreq; unsigned int dwl_req; }; From 3963d26d457aa14b38796df4277abfbb111c085b Mon Sep 17 00:00:00 2001 From: Tapas Dey Date: Mon, 6 Jun 2022 13:34:14 +0530 Subject: [PATCH 056/100] NFC: Fix to resolve abnormal read thread exit During hiberantion/suspend, freezer process sends fake signals to all running processes to put the device into system wide sleep, which leads to ungraceful exit of I2c read thread leaving the upper layer retry the I2C access & ends up with excessive error logging on the console. Modified code to set/unset the no-freeze flag to ensure such freezer fake signals can be avoided when NFC is enabled & vice versa. Change-Id: If0b8814daa172b3734a331ad9ab225c714e11e43 Signed-off-by: Tapas Dey --- nfc/common.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/nfc/common.c b/nfc/common.c index 10bd17f17e..7e82bfe86b 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -586,6 +586,15 @@ int nfc_dev_open(struct inode *inode, struct file *filp) pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); + /* Set flag to block freezer fake signal if not set already. + * Without this Signal being set, Driver is trying to do a read + * which is causing the delay in moving to Hibernate Mode. + */ + if (!(current->flags & PF_NOFREEZE)) { + current->flags |= PF_NOFREEZE; + pr_debug("%s: current->flags 0x%x. \n", __func__, current->flags); + } + mutex_lock(&nfc_dev->dev_ref_mutex); filp->private_data = nfc_dev; @@ -632,6 +641,13 @@ int nfc_dev_close(struct inode *inode, struct file *filp) return -ENODEV; pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); + + /* unset the flag to restore to previous state */ + if (current->flags & PF_NOFREEZE) { + current->flags &= ~PF_NOFREEZE; + pr_debug("%s: current->flags 0x%x. \n", __func__, current->flags); + } + mutex_lock(&nfc_dev->dev_ref_mutex); if (nfc_dev->dev_ref_count == 1) { nfc_dev->nfc_disable_intr(nfc_dev); From 0ff0ebef92ad15e3c80f1ca0d16f7cddf9f0c596 Mon Sep 17 00:00:00 2001 From: Tapas Dey Date: Mon, 11 Jul 2022 12:26:36 +0530 Subject: [PATCH 057/100] NFC: driver: Add a local flag to enable/disable compilation Modified code to add a local flag to enable or disable module compilation based on system-wide global flags for different targets. Change-Id: I52ee08ed82a0d40999cfbd0e8969d43801f29d95 --- Android.mk | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Android.mk b/Android.mk index 3913c583d8..dbc37f40b0 100644 --- a/Android.mk +++ b/Android.mk @@ -11,4 +11,18 @@ LOCAL_MODULE := nxp-nci.ko LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*) -include $(DLKM_DIR)/Build_external_kernelmodule.mk +NFC_DLKM_ENABLED := false + +########## Check and set local DLKM flag based on system-wide global flags ########## +ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true) + ifeq ($(TARGET_KERNEL_DLKM_NFC_OVERRIDE), true) + NFC_DLKM_ENABLED := true + endif +else + NFC_DLKM_ENABLED := true +endif + +########## Build kernel module based on local DLKM flag status ########## +ifeq ($(NFC_DLKM_ENABLED), true) + include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif From 9beac5423ea3d3e27f482854faa34004832f4b69 Mon Sep 17 00:00:00 2001 From: Mallikarjun S T Date: Wed, 20 Jul 2022 11:35:00 +0530 Subject: [PATCH 058/100] NFC: driver: Add NFC secure zone status query in driver Implemented secure zone status query calls in NFC driver Change-Id: If41681ec14dbc53401182667df1256d5818f8576 --- Android.mk | 5 +++ Kbuild | 3 ++ nfc/common.c | 104 ++++++++++++++++++++++++++++++++++++++++++-------- nfc/common.h | 17 +++++++++ nfc/i2c_drv.c | 19 +++++++-- 5 files changed, 128 insertions(+), 20 deletions(-) diff --git a/Android.mk b/Android.mk index dbc37f40b0..c7c41cddd1 100644 --- a/Android.mk +++ b/Android.mk @@ -5,6 +5,11 @@ DLKM_DIR := $(TOP)/device/qcom/common/dlkm LOCAL_PATH := $(call my-dir) +KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS=$(PWD)/$(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers + +LOCAL_REQUIRED_MODULES := sec-module-symvers +LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers + include $(CLEAR_VARS) LOCAL_MODULE := nxp-nci.ko diff --git a/Kbuild b/Kbuild index 93012c8f01..616e151d33 100644 --- a/Kbuild +++ b/Kbuild @@ -6,6 +6,9 @@ LINUXINCLUDE += -I$(NFC_ROOT)/include/uapi/linux/nfc LINUXINCLUDE += -include $(NFC_ROOT)/config/gki_nfc_conf.h +LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/smcinvoke/ +LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/linux/ + obj-$(CONFIG_NXP_NFC_I2C) += nxp-nci.o #source files diff --git a/nfc/common.c b/nfc/common.c index 7e82bfe86b..6e03a97918 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -27,7 +27,6 @@ #include "common.h" -static int secure_zone = 1; int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface) @@ -131,14 +130,15 @@ int get_valid_gpio(int gpio) void gpio_set_ven(struct nfc_dev *nfc_dev, int value) { struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + if(!nfc_dev->secure_zone) { + if (gpio_get_value(nfc_gpio->ven) != value) { + pr_debug("%s: value %d\n", __func__, value); - if (gpio_get_value(nfc_gpio->ven) != value) { - pr_debug("%s: value %d\n", __func__, value); - - gpio_set_value(nfc_gpio->ven, value); - /* hardware dependent delay */ - usleep_range(NFC_GPIO_SET_WAIT_TIME_US, - NFC_GPIO_SET_WAIT_TIME_US + 100); + gpio_set_value(nfc_gpio->ven, value); + /* hardware dependent delay */ + usleep_range(NFC_GPIO_SET_WAIT_TIME_US, + NFC_GPIO_SET_WAIT_TIME_US + 100); + } } } @@ -407,9 +407,12 @@ long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, int nfc_post_init(struct nfc_dev *nfc_dev) { int ret=0; + static int post_init_success; struct platform_configs nfc_configs; struct platform_gpio *nfc_gpio; + if(post_init_success) + return 0; if (!nfc_dev) return -ENODEV; @@ -449,12 +452,79 @@ int nfc_post_init(struct nfc_dev *nfc_dev) /*Initialising sempahore to disbale NFC Ven GPIO only after eSE is power off flag is set */ sema_init(&sem_eSE_pwr_off,0); + post_init_success = 1; pr_info("%s success\n", __func__); return 0; } +/** + * nfc_hw_secure_check() - Checks the NFC secure zone status + * + * Queries the TZ secure libraries if NFC is in secure zone statue or not. + * + * Return: 0 if FEATURE_NOT_SUPPORTED/PERIPHERAL_NOT_FOUND/state is 2 and + * return 1(non-secure) otherwise + */ + + bool nfc_hw_secure_check(void) + { + struct Object client_env; + struct Object app_object; + u32 wifi_uid = HW_NFC_UID; + union ObjectArg obj_arg[2] = {{{0, 0}}}; + int ret; + bool retstat = 1; + u8 state = 0; + + /* get rootObj */ + ret = get_client_env_object(&client_env); + if (ret) { + pr_err("Failed to get client_env_object, ret: %d\n", ret); + return 1; + } + + ret = IClientEnv_open(client_env, HW_STATE_UID, &app_object); + if (ret) { + pr_debug("Failed to get app_object, ret: %d\n", ret); + if (ret == FEATURE_NOT_SUPPORTED) { + retstat = 0; /* Do not Assert */ + pr_debug("Secure HW feature not supported\n"); + } + goto exit_release_clientenv; + } + + obj_arg[0].b = (struct ObjectBuf) {&wifi_uid, sizeof(u32)}; + obj_arg[1].b = (struct ObjectBuf) {&state, sizeof(u8)}; + ret = Object_invoke(app_object, HW_OP_GET_STATE, obj_arg, + ObjectCounts_pack(1, 1, 0, 0)); + + pr_info("SMC invoke ret: %d state: %d\n", ret, state); + if (ret) { + if (ret == PERIPHERAL_NOT_FOUND) { + retstat = 0; /* Do not Assert */ + pr_debug("Secure HW mode is not updated. Peripheral not found\n"); + } + goto exit_release_app_obj; + } + + if (state == 1) { + /*Secure Zone*/ + retstat = 1; + } else { + /*Non-Secure Zone*/ + retstat = 0; + } + +exit_release_app_obj: + Object_release(app_object); +exit_release_clientenv: + Object_release(client_env); + + return retstat; + } + /** * nfc_dynamic_protection_ioctl() - dynamic protection control * @nfc_dev: nfc device data structure @@ -491,7 +561,7 @@ int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone } ret = nfc_ioctl_power_states(nfc_dev, 0); /*set driver as secure zone, such that no ioctl calls are allowed*/ - secure_zone=1; + nfc_dev->secure_zone = true; pr_info("Driver Secure flag set successful\n"); } else { ret = -1; @@ -499,7 +569,7 @@ int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone } else if(sec_zone_trans == 0) { chk_eSE_pwr_off = 0; - secure_zone=0; + nfc_dev->secure_zone = false; if(init_flag) { /*Initialize once,only during the first non-secure entry*/ @@ -508,7 +578,8 @@ int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone init_flag=0; } else { - ret = nfc_ioctl_power_states(nfc_dev, 1); + if(!gpio_get_value(nfc_gpio->ven)) + ret = nfc_ioctl_power_states(nfc_dev, 1); } pr_info("Func Driver Secure flag clear successful\n"); } else { @@ -541,7 +612,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) return -ENODEV; /*Avoiding ioctl call in secure zone*/ - if(secure_zone) { + if(nfc_dev->secure_zone) { if(cmd!=NFC_SECURE_ZONE) { pr_debug("nfc_dev_ioctl failed\n"); return -1; @@ -665,10 +736,11 @@ int nfc_dev_close(struct inode *inode, struct file *filp) int validate_nfc_state_nci(struct nfc_dev *nfc_dev) { struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - - if (!gpio_get_value(nfc_gpio->ven)) { - pr_err("%s: ven low - nfcc powered off\n", __func__); - return -ENODEV; + if(!nfc_dev->secure_zone) { + if (!gpio_get_value(nfc_gpio->ven)) { + pr_err("%s: ven low - nfcc powered off\n", __func__); + return -ENODEV; + } } if (get_valid_gpio(nfc_gpio->dwl_req) == 1) { pr_err("%s: fw download in-progress\n", __func__); diff --git a/nfc/common.h b/nfc/common.h index 32c923f667..404333f120 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -33,6 +33,11 @@ #include "i2c_drv.h" #include "ese_cold_reset.h" +/*secure library headers*/ +#include "smcinvoke.h" +#include "smcinvoke_object.h" +#include "IClientEnv.h" + /* Max device count for this driver */ #define DEV_COUNT 1 /* i2c device class */ @@ -115,6 +120,13 @@ #define NFC_VDDIO_MAX 1950000 //in uV #define NFC_CURRENT_MAX 157000 //in uA +//NFC ID for registration with secure libraries +#define HW_STATE_UID 0x108 +#define HW_OP_GET_STATE 1 +#define HW_NFC_UID 0x506 +#define FEATURE_NOT_SUPPORTED 12 +#define PERIPHERAL_NOT_FOUND 10 + #define NUM_OF_IPC_LOG_PAGES (2) #define PKT_MAX_LEN (4) // no of max bytes to print for cmd/resp @@ -135,6 +147,7 @@ do { \ static struct semaphore sem_eSE_pwr_off; static chk_eSE_pwr_off; + enum ese_ioctl_request { /* eSE POWER ON */ ESE_POWER_ON = 0, @@ -262,6 +275,9 @@ struct nfc_dev { union nqx_uinfo nqx_info; + /*secure zone state*/ + bool secure_zone; + /* CLK control */ bool clk_run; struct clk *s_clk; @@ -305,4 +321,5 @@ int nfc_clock_select(struct nfc_dev *nfc_dev); int nfc_clock_deselect(struct nfc_dev *nfc_dev); int nfc_post_init(struct nfc_dev *nfc_dev); int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans); +bool nfc_hw_secure_check(void); #endif /* _COMMON_H_ */ diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 4b47ef10a5..7c9108ac90 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -156,10 +156,12 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) if (gpio_get_value(nfc_gpio->irq)) break; - if (!gpio_get_value(nfc_gpio->ven)) { - pr_info("%s: releasing read\n", __func__); - ret = -EIO; - goto err; + if(!nfc_dev->secure_zone) { + if (!gpio_get_value(nfc_gpio->ven)) { + pr_info("%s: releasing read\n", __func__); + ret = -EIO; + goto err; + } } /* * NFC service wanted to close the driver so, @@ -413,6 +415,15 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_ldo_config_failed; } + /*Check NFC Secure Zone status*/ + if(!nfc_hw_secure_check()) { + nfc_post_init(nfc_dev); + nfc_dev->secure_zone = false; + } + else + nfc_dev->secure_zone = true; + pr_info("%s:nfc_dev->secure_zone = %s", __func__, nfc_dev->secure_zone ? "true" : "false"); + if(nfc_dev->configs.clk_pin_voting) nfc_dev->clk_run = false; else From 7dd0b7d5465df472af3bffe588e0c240861ad6b1 Mon Sep 17 00:00:00 2001 From: nxf24591 Date: Fri, 29 Jul 2022 19:28:34 +0530 Subject: [PATCH 059/100] Updated corresponding to - NFC_AR_00_1E800_13.09.00_OpnSrc --- nfc/Kbuild | 2 ++ nfc/common.c | 13 ++++++------- nfc/common.h | 2 +- nfc/common_ese.c | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/nfc/Kbuild b/nfc/Kbuild index 9a4e9a23da..02db26ac5d 100644 --- a/nfc/Kbuild +++ b/nfc/Kbuild @@ -4,3 +4,5 @@ nfc_i2c-y := common.o \ common_ese.o \ i2c_drv.o +ccflags-y += -DDYNAMIC_DEBUG_MODULE + diff --git a/nfc/common.c b/nfc/common.c index a4f8029fa1..5b47e373c3 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -1,6 +1,6 @@ /****************************************************************************** * Copyright (C) 2015, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2021 NXP + * Copyright (C) 2019-2022 NXP * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,14 +44,14 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, if ((!gpio_is_valid(nfc_gpio->irq))) { pr_err("%s: irq gpio invalid %d\n", __func__, nfc_gpio->irq); - return -EINVAL; + return nfc_gpio->irq; } pr_info("%s: irq %d\n", __func__, nfc_gpio->irq); } nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->ven))) { pr_err("%s: ven gpio invalid %d\n", __func__, nfc_gpio->ven); - return -EINVAL; + return nfc_gpio->ven; } /* some products like sn220 does not required fw dwl pin */ nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); @@ -410,10 +410,6 @@ int nfc_dev_close(struct inode *inode, struct file *filp) if (nfc_dev->dev_ref_count == 1) { nfc_dev->nfc_disable_intr(nfc_dev); set_valid_gpio(nfc_dev->configs.gpio.dwl_req, 0); - } - if (nfc_dev->dev_ref_count > 0) - nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; - else { /* * Use "ESE_RST_PROT_DIS" as argument * if eSE calls flow is via NFC driver @@ -421,6 +417,9 @@ int nfc_dev_close(struct inode *inode, struct file *filp) */ nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS_NFC); } + if (nfc_dev->dev_ref_count > 0) + nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; + filp->private_data = NULL; mutex_unlock(&nfc_dev->dev_ref_mutex); diff --git a/nfc/common.h b/nfc/common.h index 4899c0d92c..bd6759a966 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -27,7 +27,7 @@ /* Max device count for this driver */ #define DEV_COUNT 1 /* i2c device class */ -#define CLASS_NAME "nfc" +#define CLASS_NAME "nxpnfc" /* NFC character device name, this will be in /dev/ */ #define NFC_CHAR_DEV_NAME "nxp-nci" diff --git a/nfc/common_ese.c b/nfc/common_ese.c index 5c725a6845..9be98e2445 100644 --- a/nfc/common_ese.c +++ b/nfc/common_ese.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (C) 2020-2021 NXP + * Copyright (C) 2020-2022 NXP * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -135,6 +135,7 @@ static int validate_cold_reset_protection_request(struct cold_reset *cold_reset, IS_SRC(arg, cold_reset->rst_prot_src)) { pr_debug("%s: enable reset protection from same src\n", __func__); + ret = -EINVAL; } else { pr_err("%s: operation not permitted\n", __func__); ret = -EPERM; @@ -161,7 +162,6 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, /* check if NFCC not in the FW download or hard reset state */ ret = validate_cold_reset_protection_request(cold_reset, arg); if (ret < 0) { - pr_err("%s: invalid cmd\n", __func__); goto err; } From 3651ea69749a17932323ca743b4805530f26d197 Mon Sep 17 00:00:00 2001 From: Devendar Gali Date: Thu, 18 Aug 2022 13:07:01 +0530 Subject: [PATCH 060/100] NFC: Fix to reslove the slab-out-bound issue When received the read count from application more than MAX_NCI_BUFFER_SIZE limiting the read count to MAX_NCI_BUFFER_SIZE. Change-Id: Ib060b3b20fedc77a2e7a13bd1ac2b4c64da87a81 --- nfc/i2c_drv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 7c9108ac90..54a008b149 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -278,6 +278,9 @@ ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, size_t count, return -ENODEV; } mutex_lock(&nfc_dev->read_mutex); + if (count > MAX_NCI_BUFFER_SIZE) + count = MAX_NCI_BUFFER_SIZE; + if (filp->f_flags & O_NONBLOCK) { ret = i2c_master_recv(nfc_dev->i2c_dev.client, nfc_dev->read_kbuf, count); pr_debug("%s: NONBLOCK read ret = %d\n", __func__, ret); From 54561969eb6f9594db410df63515cdb8cf06e2a0 Mon Sep 17 00:00:00 2001 From: PRANAY BHARGAV BHAVARAJU Date: Wed, 27 Jul 2022 11:13:47 +0530 Subject: [PATCH 061/100] Driver: eSE : checking NULL pointer NFC: set the rsp buffer to null set the response buffer to null in order to avoid invalid free Change-Id: Id92aca9255e4e58cc03822a1af1adf6fbbdfa443 Signed-off-by: PRANAY BHARGAV BHAVARAJU --- nfc/ese_cold_reset.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index 309f245101..c96675d00f 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -375,11 +375,12 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) pr_debug("ese cmd is %d\n", cold_reset_arg->sub_cmd); ret = nfc_dev->cold_reset.status; + err: kfree(nfc_dev->cold_reset.cmd_buf); + nfc_dev->cold_reset.cmd_buf = NULL; kfree(cold_reset_arg); cold_reset_arg = NULL; - nfc_dev->cold_reset.cmd_buf = NULL; return ret; } From 5cc720117c46c68d9e80e7ff3531cd661f1a5620 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Fri, 12 Aug 2022 12:01:53 +0530 Subject: [PATCH 062/100] NFC: Driver: Enable NFC driver for bengal Added entry in board .mk file to load NFC driver Change-Id: I11864caa589fb93bdcaaa4313cdd73a6a3ed6161 --- nfc_kernel_dlkm_vendor_board.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nfc_kernel_dlkm_vendor_board.mk b/nfc_kernel_dlkm_vendor_board.mk index eb7a015643..f75f447281 100644 --- a/nfc_kernel_dlkm_vendor_board.mk +++ b/nfc_kernel_dlkm_vendor_board.mk @@ -1,4 +1,5 @@ # Build NFC kernel driver -ifeq ($(call is-board-platform-in-list, kalama),true) +ifeq ($(call is-board-platform-in-list, kalama bengal),true) BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nxp-nci.ko endif + From 2eb1087f53f9c2c1f9c01fd4193f85c8354bc7a0 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Tue, 6 Sep 2022 13:04:01 +0530 Subject: [PATCH 063/100] NFC: Driver: Add secure zone status check Added secure zone status check before calling secure zone APIs Change-Id: I09247c75233da257f3d8da569df21b2236d55772 --- nfc/common.c | 32 +++++++++++++++++++++----------- nfc/common.h | 6 +++--- nfc/ese_cold_reset.c | 7 +++++-- nfc/i2c_drv.c | 20 ++++++++++++-------- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 6e03a97918..cc6185ed8c 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -80,6 +80,12 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, nfc_configs->clk_pin_voting = true; } + /* Read DTS_SZONE_STR to check secure zone support */ + if (of_property_read_string(np, DTS_SZONE_STR, &nfc_configs->szone)) { + nfc_configs->CNSS_NFC_HW_SECURE_ENABLE = false; + }else + nfc_configs->CNSS_NFC_HW_SECURE_ENABLE = true; + pr_info("%s: irq %d, ven %d, dwl %d, clkreq %d, clk_pin_voting %d \n", __func__, nfc_gpio->irq, nfc_gpio->ven, nfc_gpio->dwl_req, nfc_gpio->clkreq, nfc_configs->clk_pin_voting); @@ -450,7 +456,9 @@ int nfc_post_init(struct nfc_dev *nfc_dev) } /*Initialising sempahore to disbale NFC Ven GPIO only after eSE is power off flag is set */ - sema_init(&sem_eSE_pwr_off,0); + if (nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { + sema_init(&sem_eSE_pwr_off,0); + } post_init_success = 1; pr_info("%s success\n", __func__); @@ -477,7 +485,6 @@ int nfc_post_init(struct nfc_dev *nfc_dev) int ret; bool retstat = 1; u8 state = 0; - /* get rootObj */ ret = get_client_env_object(&client_env); if (ret) { @@ -545,7 +552,6 @@ int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone static int init_flag=1; struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - if(sec_zone_trans == 1) { /*check NFC is disabled, only then set Ven GPIO low*/ if(nfc_dev->cold_reset.is_nfc_enabled == false) { @@ -590,6 +596,7 @@ int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone return ret; } + /** * nfc_dev_ioctl - used to set or get data from upper layer. * @pfile file node for opened device. @@ -610,13 +617,14 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) if (!nfc_dev) return -ENODEV; - - /*Avoiding ioctl call in secure zone*/ - if(nfc_dev->secure_zone) { - if(cmd!=NFC_SECURE_ZONE) { - pr_debug("nfc_dev_ioctl failed\n"); - return -1; - } + if( nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { + /*Avoiding ioctl call in secure zone*/ + if(nfc_dev->secure_zone) { + if(cmd!=NFC_SECURE_ZONE) { + pr_debug("nfc_dev_ioctl failed\n"); + return -1; + } + } } pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg); @@ -638,7 +646,9 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) ret = ese_cold_reset_ioctl(nfc_dev, arg); break; case NFC_SECURE_ZONE: - ret = nfc_dynamic_protection_ioctl(nfc_dev, arg); + if( nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { + ret = nfc_dynamic_protection_ioctl(nfc_dev, arg); + } break; default: pr_err("%s: bad cmd %lu\n", __func__, arg); diff --git a/nfc/common.h b/nfc/common.h index 404333f120..d5c4a58ec3 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -110,6 +110,7 @@ #define DTS_FWDN_GPIO_STR "qcom,sn-firm" #define DTS_CLKREQ_GPIO_STR "qcom,sn-clkreq" #define DTS_CLKSRC_GPIO_STR "qcom,clk-src" +#define DTS_SZONE_STR "qcom,sn-szone" #define NFC_LDO_SUPPLY_DT_NAME "qcom,sn-vdd-1p8" #define NFC_LDO_SUPPLY_NAME "qcom,sn-vdd-1p8-supply" #define NFC_LDO_VOL_DT_NAME "qcom,sn-vdd-1p8-voltage" @@ -127,7 +128,6 @@ #define FEATURE_NOT_SUPPORTED 12 #define PERIPHERAL_NOT_FOUND 10 - #define NUM_OF_IPC_LOG_PAGES (2) #define PKT_MAX_LEN (4) // no of max bytes to print for cmd/resp @@ -147,7 +147,6 @@ do { \ static struct semaphore sem_eSE_pwr_off; static chk_eSE_pwr_off; - enum ese_ioctl_request { /* eSE POWER ON */ ESE_POWER_ON = 0, @@ -235,6 +234,8 @@ struct platform_configs { const char *clk_src_name; /* NFC_CLK pin voting state */ bool clk_pin_voting; + const char *szone; + bool CNSS_NFC_HW_SECURE_ENABLE; }; @@ -274,7 +275,6 @@ struct nfc_dev { u8 *kbuf; union nqx_uinfo nqx_info; - /*secure zone state*/ bool secure_zone; diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index c96675d00f..e6dd80a3d6 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -47,8 +47,11 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) pr_debug("keep ven high as NFC is enabled\n"); } nfc_dev->is_ese_session_active = false; - if(chk_eSE_pwr_off) - up(&sem_eSE_pwr_off); + if (nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { + if(chk_eSE_pwr_off) + up(&sem_eSE_pwr_off); + } + } else if (arg == ESE_POWER_STATE) { /* get VEN gpio state for eSE, as eSE also enabled through same GPIO */ ret = gpio_get_value(nfc_dev->configs.gpio.ven); diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 54a008b149..55ebc62aa2 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -418,27 +418,31 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_ldo_config_failed; } - /*Check NFC Secure Zone status*/ - if(!nfc_hw_secure_check()) { + if( nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { + /*Check NFC Secure Zone status*/ + if(!nfc_hw_secure_check()) { + nfc_post_init(nfc_dev); + nfc_dev->secure_zone = false; + } + else { + nfc_dev->secure_zone = true; + } + pr_info("%s:nfc_dev->secure_zone = %s", __func__, nfc_dev->secure_zone ? "true" : "false"); + }else { nfc_post_init(nfc_dev); - nfc_dev->secure_zone = false; } - else - nfc_dev->secure_zone = true; - pr_info("%s:nfc_dev->secure_zone = %s", __func__, nfc_dev->secure_zone ? "true" : "false"); if(nfc_dev->configs.clk_pin_voting) nfc_dev->clk_run = false; else nfc_dev->clk_run = true; - device_init_wakeup(&client->dev, true); i2c_set_clientdata(client, nfc_dev); i2c_dev->irq_wake_up = false; nfc_dev->is_ese_session_active = false; - pr_info("%s: probing nfc i2c successfully\n", __func__); + pr_info("%s: probing nfc i2c success\n", __func__); return 0; From 585ccc9bf8875e67749fce2bc3037848fd67d639 Mon Sep 17 00:00:00 2001 From: Bhuvan Varshney Date: Fri, 12 Aug 2022 11:17:16 +0530 Subject: [PATCH 064/100] NFC: Avoid Null pointer de-referencing Null pointer check is added in the send_ese_cmd function to avoid null pointer dereferencing. Change-Id: Ia577ba3b649b2a33076a2b33c3b20c3f1fffac85 --- nfc/ese_cold_reset.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index e6dd80a3d6..caa52308f4 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -82,6 +82,8 @@ static int send_ese_cmd(struct nfc_dev *nfc_dev) "cannot send ese cmd as NFCC powered off\n"); return -ENODEV; } + if (nfc_dev->cold_reset.cmd_buf == NULL) + return -EFAULT; ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->cold_reset.cmd_buf, nfc_dev->cold_reset.cmd_len, From a6d8f76e521b08856ff1da319efd4fd55c4d56de Mon Sep 17 00:00:00 2001 From: PRANAY BHARGAV BHAVARAJU Date: Fri, 19 Aug 2022 11:27:11 +0530 Subject: [PATCH 065/100] NFC: Avoid slab out of bound chages done to ese_cold_reset c file to avoid slabout of bound issues. Change-Id: Idbc72acc16c8a2f55d982015b69e196d38ddc199 Signed-off-by: PRANAY BHARGAV BHAVARAJU --- nfc/ese_cold_reset.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index caa52308f4..4850eb843e 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -109,6 +109,13 @@ int read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header) struct cold_reset *cold_rst = &nfc_dev->cold_reset; char *rsp_buf = NULL; + if (cold_rst->rsp_len < COLD_RESET_RSP_LEN) { + dev_err(nfc_dev->nfc_device, + "%s: received cold reset rsp buffer length is invalid \n", + __func__); + return -EINVAL; + } + rsp_buf = kzalloc(cold_rst->rsp_len, GFP_DMA | GFP_KERNEL); if (!rsp_buf) return -ENOMEM; From 6de117e3c9183466a23432e8df3e136b032f2c11 Mon Sep 17 00:00:00 2001 From: PRANAY BHARGAV BHAVARAJU Date: Thu, 1 Sep 2022 20:57:35 +0530 Subject: [PATCH 066/100] nfc driver: Added mutex lock Added mutex loc in the fucntion ese_cold_reset_ioctl to avoid double free issues Change-Id: I1ba7187f8339a6de5a31ef009b45556ceab46989 Signed-off-by: PRANAY BHARGAV BHAVARAJU --- nfc/ese_cold_reset.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index 4850eb843e..086b566c6c 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -222,6 +222,7 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) if (!cold_reset_arg) return -ENOMEM; + mutex_lock(&nfc_dev->write_mutex); ret = copy_struct_from_user(cold_reset_arg, sizeof(struct ese_cold_reset_arg), u64_to_user_ptr(ioctl_arg.buf), @@ -394,5 +395,7 @@ err: kfree(cold_reset_arg); cold_reset_arg = NULL; + mutex_unlock(&nfc_dev->write_mutex); + return ret; } From 072edd2c88b6e757a3f85eed389bccd9cac16575 Mon Sep 17 00:00:00 2001 From: nxf24591 Date: Wed, 12 Oct 2022 13:14:25 +0530 Subject: [PATCH 067/100] Updated corresponding to - NFC_AR_00_1E800_13.0B.00_OpnSrc --- nfc/common.c | 24 +++++++++++++++++--- nfc/common.h | 16 ++++++++----- nfc/common_ese.c | 58 ++++++++++++++++++++++++++++-------------------- 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 5b47e373c3..5425efa6d3 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -127,7 +127,7 @@ int configure_gpio(unsigned int gpio, int flag) if (ret) { pr_err("%s: unable to set direction for nfc gpio [%d]\n", - __func__, gpio); + __func__, gpio); gpio_free(gpio); return ret; } @@ -301,10 +301,11 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) * and error ret code otherwise */ long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, - unsigned long arg) + unsigned long arg) { int ret = 0; - arg = (compat_u64)arg; + + arg = (compat_u64) arg; pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg); ret = nfc_dev_ioctl(pfile, cmd, arg); return ret; @@ -337,6 +338,19 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) case NFC_SET_PWR: ret = nfc_ioctl_power_states(nfc_dev, arg); break; + case NFC_SET_RESET_READ_PENDING: + if (arg == NFC_SET_READ_PENDING) { + nfc_dev->cold_reset.is_nfc_read_pending = true; + /* Set default NFC state as NCI for Nfc read pending request */ + nfc_dev->nfc_state = NFC_STATE_NCI; + } + else if (arg == NFC_RESET_READ_PENDING){ + nfc_dev->cold_reset.is_nfc_read_pending = false; + } + else { + ret = -EINVAL; + } + break; case ESE_SET_PWR: ret = nfc_ese_pwr(nfc_dev, arg); break; @@ -353,6 +367,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) int nfc_dev_open(struct inode *inode, struct file *filp) { struct nfc_dev *nfc_dev = NULL; + nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev); if (!nfc_dev) @@ -400,6 +415,7 @@ int nfc_dev_flush(struct file *pfile, fl_owner_t id) int nfc_dev_close(struct inode *inode, struct file *filp) { struct nfc_dev *nfc_dev = NULL; + nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev); if (!nfc_dev) @@ -415,7 +431,9 @@ int nfc_dev_close(struct inode *inode, struct file *filp) * if eSE calls flow is via NFC driver * i.e. direct calls from SPI HAL to NFC driver */ + mutex_unlock(&nfc_dev->dev_ref_mutex); nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS_NFC); + mutex_lock(&nfc_dev->dev_ref_mutex); } if (nfc_dev->dev_ref_count > 0) nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1; diff --git a/nfc/common.h b/nfc/common.h index bd6759a966..2c82394cc0 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -51,7 +51,6 @@ #define MAX_DL_BUFFER_SIZE (DL_HDR_LEN + DL_CRC_LEN + \ MAX_DL_PAYLOAD_LEN) - /* Retry count for normal write */ #define NO_RETRY (1) /* Maximum retry count for standby writes */ @@ -72,9 +71,10 @@ /* Ioctls */ /* The type should be aligned with MW HAL definitions */ -#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) -#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) -#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) +#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) +#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) +#define NFC_SET_RESET_READ_PENDING _IOW(NFC_MAGIC, 0x04, uint32_t) #define DTS_IRQ_GPIO_STR "nxp,sn-irq" #define DTS_VEN_GPIO_STR "nxp,sn-ven-rstn" @@ -97,6 +97,11 @@ enum nfcc_ioctl_request { NFC_FW_DWL_LOW, }; +enum nfc_read_pending { + NFC_RESET_READ_PENDING, + NFC_SET_READ_PENDING, +}; + /* nfc platform interface type */ enum interface_flags { /* I2C physical IF for NFCC */ @@ -154,6 +159,7 @@ struct cold_reset { uint8_t rst_prot_src; /* reset protection source (SPI, NFC) */ struct timer_list timer; wait_queue_head_t read_wq; + bool is_nfc_read_pending; }; /* Device specific structure */ @@ -195,7 +201,7 @@ int nfc_dev_open(struct inode *inode, struct file *filp); int nfc_dev_flush(struct file *pfile, fl_owner_t id); int nfc_dev_close(struct inode *inode, struct file *filp); long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, - unsigned long arg); + unsigned long arg); long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface); diff --git a/nfc/common_ese.c b/nfc/common_ese.c index 9be98e2445..b67f93d175 100644 --- a/nfc/common_ese.c +++ b/nfc/common_ese.c @@ -56,11 +56,11 @@ static int send_cold_reset_protection_cmd(struct nfc_dev *nfc_dev, *cmd++ = NCI_PROP_MSG_CMD; - if (requestType) { /* reset protection */ + if (requestType) { /* reset protection */ *cmd++ = RST_PROT_OID; *cmd++ = RST_PROT_PAYLOAD_SIZE; *cmd++ = (!cold_reset->reset_protection) ? 1 : 0; - } else { /* cold reset */ + } else { /* cold reset */ *cmd++ = CLD_RST_OID; *cmd++ = CLD_RST_PAYLOAD_SIZE; } @@ -149,6 +149,7 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, { int ret = 0; int timeout = 0; + int retry_cnt = 0; char *rsp = nfc_dev->read_kbuf; struct cold_reset *cold_reset = &nfc_dev->cold_reset; @@ -203,41 +204,50 @@ static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, } timeout = NCI_CMD_RSP_TIMEOUT_MS; + mutex_lock(&nfc_dev->dev_ref_mutex); do { - /* call read api directly if reader thread is not blocked */ - if (mutex_trylock(&nfc_dev->read_mutex)) { - pr_debug("%s: reader thread not pending\n", __func__); - ret = nfc_dev->nfc_read(nfc_dev, rsp, 3, - timeout); - mutex_unlock(&nfc_dev->read_mutex); + if (nfc_dev->cold_reset.is_nfc_read_pending) { + if (!wait_event_interruptible_timeout + (cold_reset->read_wq, + cold_reset->rsp_pending == false, + msecs_to_jiffies(timeout))) { + pr_err("%s: cold reset/prot response timeout\n", + __func__); + if (retry_cnt <= 1) { + retry_cnt = retry_cnt + 1; + ret = -EAGAIN; + } else { + pr_debug("%s: Maximum retry reached", + __func__); + ret = -ETIMEDOUT; + } + } + } else { + ret = nfc_dev->nfc_read(nfc_dev, rsp, 3, timeout); if (!ret) break; usleep_range(READ_RETRY_WAIT_TIME_US, - READ_RETRY_WAIT_TIME_US + 500); - /* Read pending response form the HAL service */ - } else if (!wait_event_interruptible_timeout( - cold_reset->read_wq, - cold_reset->rsp_pending == false, - msecs_to_jiffies(timeout))) { - pr_err("%s: cold reset/prot response timeout\n", __func__); - ret = -EAGAIN; + READ_RETRY_WAIT_TIME_US + 500); } - } while (ret == -ERESTARTSYS || ret == -EFAULT); + } while (ret == -ERESTARTSYS || ret == -EFAULT || ret == -EAGAIN); + mutex_unlock(&nfc_dev->dev_ref_mutex); mutex_unlock(&nfc_dev->write_mutex); timeout = ESE_CLD_RST_REBOOT_GUARD_TIME_MS; - if (ret == 0) { /* success case */ + if (ret == 0) { /* success case */ ret = cold_reset->status; if (IS_RST_PROT_REQ(arg)) { cold_reset->reset_protection = IS_RST_PROT_EN_REQ(arg); cold_reset->rst_prot_src = IS_RST_PROT_EN_REQ(arg) ? - GET_SRC(arg) : - SRC_NONE; + GET_SRC(arg) : SRC_NONE; /* wait for reboot guard timer */ - } else if (wait_event_interruptible_timeout( - cold_reset->read_wq, true, - msecs_to_jiffies(timeout)) == 0) { - pr_info("%s: reboot guard timer timeout\n", __func__); + } else { + if (wait_event_interruptible_timeout + (cold_reset->read_wq, true, + msecs_to_jiffies(timeout)) == 0) { + pr_info("%s: reboot guard timer timeout\n", + __func__); + } } } err: From 5343706ca7ce54b0a7eacfa94b578db0a229c649 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Thu, 1 Dec 2022 20:47:32 +0530 Subject: [PATCH 068/100] NFC: Driver: configure NFC_CLK_REQ GPIO to wakeup capable Configure NFC_CLK_REQ GPIO (GPIO_35) to wakeup capable by calling msm_gpio_mpm_wake_set(). Change-Id: Ic3f5a7caffc4de376dbcc00123fddeb6fd4fefa8 --- nfc/common.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/nfc/common.c b/nfc/common.c index cc6185ed8c..9154fbdfb7 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -24,7 +24,7 @@ #include #include #include - +#include #include "common.h" @@ -413,6 +413,7 @@ long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, int nfc_post_init(struct nfc_dev *nfc_dev) { int ret=0; + unsigned int clkreq_gpio = 0; static int post_init_success; struct platform_configs nfc_configs; struct platform_gpio *nfc_gpio; @@ -445,6 +446,22 @@ int nfc_post_init(struct nfc_dev *nfc_dev) __func__, nfc_gpio->clkreq); return ret; } + + /* Read clkreq GPIO number from device tree*/ + ret = of_property_read_u32_index(nfc_dev->i2c_dev.client->dev.of_node, DTS_CLKREQ_GPIO_STR, 1, &clkreq_gpio); + if (ret < 0) { + pr_err("%s Failed to read clkreq gipo number, ret: %d\n", __func__, ret); + return ret; + } + + /* configure clkreq GPIO as wakeup capable */ + ret = msm_gpio_mpm_wake_set(clkreq_gpio, true); + if (ret < 0) { + pr_err("%s Failed to setup clkreq gpio %d as wakeup capable, ret: %d\n", __func__, clkreq_gpio , ret); + return ret; + } else { + pr_info("%s clkreq gpio %d successfully setup for wakeup capable\n", __func__, clkreq_gpio); + } } ret = nfcc_hw_check(nfc_dev); From c755b03abb25a7b3de136ad0dd313909b741a8e7 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Fri, 11 Nov 2022 13:23:32 +0530 Subject: [PATCH 069/100] NFC: Driver: NFC Driver compilation issues on Pineapple Added fix for compilation issue on Pineapple. Change-Id: I8d39dbec75af8e44e6478b7d06e886196e1624fe --- nfc/common.h | 2 +- nfc/common_nxp.c | 5 +++-- nfc/ese_cold_reset.c | 3 ++- nfc_kernel_dlkm_vendor_board.mk | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/nfc/common.h b/nfc/common.h index d5c4a58ec3..81cff58e4c 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -145,7 +145,7 @@ do { \ } while (0) static struct semaphore sem_eSE_pwr_off; -static chk_eSE_pwr_off; +static bool chk_eSE_pwr_off; enum ese_ioctl_request { /* eSE POWER ON */ diff --git a/nfc/common_nxp.c b/nfc/common_nxp.c index 8211a7cab6..474dc96892 100644 --- a/nfc/common_nxp.c +++ b/nfc/common_nxp.c @@ -253,7 +253,7 @@ static bool validate_download_gpio(struct nfc_dev *nfc_dev, enum chip_types chip struct platform_gpio *nfc_gpio; if (nfc_dev == NULL) { - pr_err("%s nfc devices structure is null\n"); + pr_err("%s nfc devices structure is null\n", __func__); return status; } nfc_gpio = &nfc_dev->configs.gpio; @@ -312,9 +312,10 @@ int nfcc_hw_check(struct nfc_dev *nfc_dev) switch (nfc_state) { case NFC_STATE_FW_TEARED: pr_warn("%s: - NFCC FW Teared State\n", __func__); + break; case NFC_STATE_FW_DWL: case NFC_STATE_NCI: - break; + break; case NFC_STATE_UNKNOWN: default: ret = -ENXIO; diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index 086b566c6c..a0dcdff479 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -284,7 +284,8 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) /* free buffers and exit with pass */ goto err; } - + /* Temp fix to avoid compilation issues */ + break; case ESE_COLD_RESET_PROTECT_DIS: if (nfc_dev->cold_reset.is_crp_en && diff --git a/nfc_kernel_dlkm_vendor_board.mk b/nfc_kernel_dlkm_vendor_board.mk index f75f447281..899347b59c 100644 --- a/nfc_kernel_dlkm_vendor_board.mk +++ b/nfc_kernel_dlkm_vendor_board.mk @@ -1,5 +1,5 @@ # Build NFC kernel driver -ifeq ($(call is-board-platform-in-list, kalama bengal),true) +ifeq ($(call is-board-platform-in-list, pineapple),true) BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nxp-nci.ko endif From 56a5be9c849abb9cd003f0ac1f98e2bf93431b0f Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Sun, 11 Dec 2022 23:02:11 +0530 Subject: [PATCH 070/100] Updated corresponding to - NFC_AR_00_1E800_13.0B.00_OpnSrc merged NFC_AR_00_1E800_13.0B.00_OpnSrc --- nfc/common.c | 13 +++++++++++++ nfc/common.h | 14 ++++++++++---- nfc/ese_cold_reset.h | 1 + 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 9154fbdfb7..49485d6f87 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -649,6 +649,19 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) case NFC_SET_PWR: ret = nfc_ioctl_power_states(nfc_dev, arg); break; + case NFC_SET_RESET_READ_PENDING: + if (arg == NFC_SET_READ_PENDING) { + nfc_dev->cold_reset.is_nfc_read_pending = true; + /* Set default NFC state as NCI for Nfc read pending request */ + nfc_dev->nfc_state = NFC_STATE_NCI; + } + else if (arg == NFC_RESET_READ_PENDING){ + nfc_dev->cold_reset.is_nfc_read_pending = false; + } + else { + ret = -EINVAL; + } + break; case ESE_SET_PWR: ret = nfc_ese_pwr(nfc_dev, arg); break; diff --git a/nfc/common.h b/nfc/common.h index 81cff58e4c..014042fc89 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -100,10 +100,11 @@ // Ioctls // The type should be aligned with MW HAL definitions -#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) -#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) -#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) -#define NFC_SECURE_ZONE _IOW(NFC_MAGIC, 0x0A, uint32_t) +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) +#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) +#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) +#define NFC_SET_RESET_READ_PENDING _IOW(NFC_MAGIC, 0x04, uint32_t) +#define NFC_SECURE_ZONE _IOW(NFC_MAGIC, 0x0A, uint32_t) #define DTS_IRQ_GPIO_STR "qcom,sn-irq" #define DTS_VEN_GPIO_STR "qcom,sn-ven" @@ -177,6 +178,11 @@ enum nfcc_ioctl_request { NFC_DISABLE, }; +enum nfc_read_pending { + NFC_RESET_READ_PENDING, + NFC_SET_READ_PENDING, +}; + /* nfc platform interface type */ enum interface_flags { /* I2C physical IF for NFCC */ diff --git a/nfc/ese_cold_reset.h b/nfc/ese_cold_reset.h index 3cf2507407..77e03b9ef3 100644 --- a/nfc/ese_cold_reset.h +++ b/nfc/ese_cold_reset.h @@ -71,6 +71,7 @@ struct cold_reset { bool rsp_pending; /* Is NFC enabled from UI */ bool is_nfc_enabled; + bool is_nfc_read_pending; }; struct nfc_dev; From 2adc70e604ce07dfd91833332346d67877dca69f Mon Sep 17 00:00:00 2001 From: Smita Ghosh Date: Wed, 7 Dec 2022 11:03:50 -0800 Subject: [PATCH 071/100] NXP: Add new path for smcinvoke headers Add new path for the headers. Leaving the previous ones to maintain backward compatibility. --- Kbuild | 1 + 1 file changed, 1 insertion(+) diff --git a/Kbuild b/Kbuild index 616e151d33..1e4a75aad8 100644 --- a/Kbuild +++ b/Kbuild @@ -8,6 +8,7 @@ LINUXINCLUDE += -include $(NFC_ROOT)/config/gki_nfc_conf.h LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/smcinvoke/ LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/linux/ +LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/include/linux/ obj-$(CONFIG_NXP_NFC_I2C) += nxp-nci.o From f616cf76bd9b245f32d197015f3e36b6c529848e Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Tue, 13 Dec 2022 13:03:02 +0530 Subject: [PATCH 072/100] NFC: Driver: Remove SW WAR to enable NFC Clock Removed SW WAR to enable NFC Clock, this feature not required on Pineapple Change-Id: I118502df98293a48f58569c91444b415076329c4 --- nfc/common.c | 69 +++++++++++++++-------------------------------- nfc/common.h | 10 ------- nfc/common_qcom.c | 40 --------------------------- nfc/i2c_drv.c | 5 ---- 4 files changed, 21 insertions(+), 103 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 49485d6f87..3932dbeeda 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -64,21 +64,16 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, /* some products like sn220 does not required fw dwl pin */ nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); /* not returning failure for dwl gpio as it is optional for sn220 */ - if ((!gpio_is_valid(nfc_gpio->dwl_req))) + if ((!gpio_is_valid(nfc_gpio->dwl_req))){ pr_warn("%s: nfc dwl_req gpio invalid %d\n", __func__, nfc_gpio->dwl_req); - /* Read clock request gpio configuration if MGPIO configurations are not preasent */ - if (of_property_read_string(np, DTS_CLKSRC_GPIO_STR, &nfc_configs->clk_src_name)) { - nfc_configs->clk_pin_voting = false; - nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0); - if (!gpio_is_valid(nfc_gpio->clkreq)) { + } + /* Read clkreq GPIO pin number from DTSI */ + nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0); + if (!gpio_is_valid(nfc_gpio->clkreq)) { dev_err(dev, "clkreq gpio invalid %d\n", nfc_gpio->clkreq); return -EINVAL; - } - } - else { - nfc_configs->clk_pin_voting = true; - } + } /* Read DTS_SZONE_STR to check secure zone support */ if (of_property_read_string(np, DTS_SZONE_STR, &nfc_configs->szone)) { @@ -86,8 +81,8 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, }else nfc_configs->CNSS_NFC_HW_SECURE_ENABLE = true; - pr_info("%s: irq %d, ven %d, dwl %d, clkreq %d, clk_pin_voting %d \n", __func__, nfc_gpio->irq, nfc_gpio->ven, - nfc_gpio->dwl_req, nfc_gpio->clkreq, nfc_configs->clk_pin_voting); + pr_info("%s: irq %d, ven %d, dwl %d, clkreq %d \n", __func__, nfc_gpio->irq, nfc_gpio->ven, + nfc_gpio->dwl_req, nfc_gpio->clkreq); /* optional property */ ret = of_property_read_u32_array(np, NFC_LDO_VOL_DT_NAME, @@ -353,21 +348,9 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) nfc_dev->nfc_state = NFC_STATE_NCI; } else if (arg == NFC_ENABLE) { - if(nfc_dev->configs.clk_pin_voting) { - /* Enabling nfc clock */ - ret = nfc_clock_select(nfc_dev); - if (ret) - pr_err("%s unable to select clock\n", __func__); - } /* Setting flag true when NFC is enabled */ nfc_dev->cold_reset.is_nfc_enabled = true; } else if (arg == NFC_DISABLE) { - if(nfc_dev->configs.clk_pin_voting) { - /* Disabling nfc clock */ - ret = nfc_clock_deselect(nfc_dev); - if (ret) - pr_err("%s unable to disable clock\n", __func__); - } /* Setting flag true when NFC is disabled */ nfc_dev->cold_reset.is_nfc_enabled = false; } else { @@ -439,29 +422,19 @@ int nfc_post_init(struct nfc_dev *nfc_dev) __func__, nfc_gpio->dwl_req); } - if(!(nfc_configs.clk_pin_voting)){ - ret = configure_gpio(nfc_gpio->clkreq, GPIO_INPUT); - if (ret) { - pr_err("%s: unable to request nfc clkreq gpio [%d]\n", - __func__, nfc_gpio->clkreq); - return ret; - } - - /* Read clkreq GPIO number from device tree*/ - ret = of_property_read_u32_index(nfc_dev->i2c_dev.client->dev.of_node, DTS_CLKREQ_GPIO_STR, 1, &clkreq_gpio); - if (ret < 0) { - pr_err("%s Failed to read clkreq gipo number, ret: %d\n", __func__, ret); - return ret; - } - - /* configure clkreq GPIO as wakeup capable */ - ret = msm_gpio_mpm_wake_set(clkreq_gpio, true); - if (ret < 0) { - pr_err("%s Failed to setup clkreq gpio %d as wakeup capable, ret: %d\n", __func__, clkreq_gpio , ret); - return ret; - } else { - pr_info("%s clkreq gpio %d successfully setup for wakeup capable\n", __func__, clkreq_gpio); - } + /* Read clkreq GPIO number from device tree*/ + ret = of_property_read_u32_index(nfc_dev->i2c_dev.client->dev.of_node, DTS_CLKREQ_GPIO_STR, 1, &clkreq_gpio); + if (ret < 0) { + pr_err("%s Failed to read clkreq gipo number, ret: %d\n", __func__, ret); + return ret; + } + /* configure clkreq GPIO as wakeup capable */ + ret = msm_gpio_mpm_wake_set(clkreq_gpio, true); + if (ret < 0) { + pr_err("%s Failed to setup clkreq gpio %d as wakeup capable, ret: %d\n", __func__, clkreq_gpio , ret); + return ret; + } else { + pr_info("%s clkreq gpio %d successfully setup for wakeup capable\n", __func__, clkreq_gpio); } ret = nfcc_hw_check(nfc_dev); diff --git a/nfc/common.h b/nfc/common.h index 014042fc89..3bae9b38cb 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -110,7 +110,6 @@ #define DTS_VEN_GPIO_STR "qcom,sn-ven" #define DTS_FWDN_GPIO_STR "qcom,sn-firm" #define DTS_CLKREQ_GPIO_STR "qcom,sn-clkreq" -#define DTS_CLKSRC_GPIO_STR "qcom,clk-src" #define DTS_SZONE_STR "qcom,sn-szone" #define NFC_LDO_SUPPLY_DT_NAME "qcom,sn-vdd-1p8" #define NFC_LDO_SUPPLY_NAME "qcom,sn-vdd-1p8-supply" @@ -237,9 +236,6 @@ struct platform_ldo { struct platform_configs { struct platform_gpio gpio; struct platform_ldo ldo; - const char *clk_src_name; - /* NFC_CLK pin voting state */ - bool clk_pin_voting; const char *szone; bool CNSS_NFC_HW_SECURE_ENABLE; }; @@ -284,10 +280,6 @@ struct nfc_dev { /*secure zone state*/ bool secure_zone; - /* CLK control */ - bool clk_run; - struct clk *s_clk; - void *ipcl; /* function pointers for the common i2c functionality */ @@ -323,8 +315,6 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg); int nfc_ldo_unvote(struct nfc_dev *nfc_dev); int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev); int validate_nfc_state_nci(struct nfc_dev *nfc_dev); -int nfc_clock_select(struct nfc_dev *nfc_dev); -int nfc_clock_deselect(struct nfc_dev *nfc_dev); int nfc_post_init(struct nfc_dev *nfc_dev); int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans); bool nfc_hw_secure_check(void); diff --git a/nfc/common_qcom.c b/nfc/common_qcom.c index 9ba42863ad..6be7bbf444 100644 --- a/nfc/common_qcom.c +++ b/nfc/common_qcom.c @@ -162,43 +162,3 @@ int nfc_ldo_unvote(struct nfc_dev *nfc_dev) return ret; } -/* - * Routine to enable clock. - * this routine can be extended to select from multiple - * sources based on clk name. - */ -int nfc_clock_select(struct nfc_dev *nfc_dev) -{ - int r = 0; - - nfc_dev->s_clk = clk_get(&nfc_dev->i2c_dev.client->dev, "nfc_ref_clk"); - - if (IS_ERR(nfc_dev->s_clk)) - return PTR_ERR(nfc_dev->s_clk); - - if (!nfc_dev->clk_run) - r = clk_prepare_enable(nfc_dev->s_clk); - - if (r) - return r; - - nfc_dev->clk_run = true; - return r; -} - -/* - * Routine to disable clocks - */ -int nfc_clock_deselect(struct nfc_dev *nfc_dev) -{ - int r = -EINVAL; - - if (nfc_dev->s_clk != NULL) { - if (nfc_dev->clk_run) { - clk_disable_unprepare(nfc_dev->s_clk); - nfc_dev->clk_run = false; - } - return 0; - } - return r; -} diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 55ebc62aa2..b00794dd94 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -432,11 +432,6 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) nfc_post_init(nfc_dev); } - if(nfc_dev->configs.clk_pin_voting) - nfc_dev->clk_run = false; - else - nfc_dev->clk_run = true; - device_init_wakeup(&client->dev, true); i2c_set_clientdata(client, nfc_dev); i2c_dev->irq_wake_up = false; From da89b093114cbce525056ec4068f7b1d7d83d69b Mon Sep 17 00:00:00 2001 From: nxf24591 Date: Fri, 16 Dec 2022 13:44:14 +0530 Subject: [PATCH 073/100] Updated corresponding to - NFC_AR_00_1E800_14.02.00_OpnSrc --- nfc/common.c | 57 ++++++++++++++++++++++++++++++++++++++++++++-------- nfc/common.h | 5 +++++ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 5425efa6d3..f34baa9a5b 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -126,8 +126,7 @@ int configure_gpio(unsigned int gpio, int flag) } if (ret) { - pr_err("%s: unable to set direction for nfc gpio [%d]\n", - __func__, gpio); + pr_err("%s: unable to set direction for nfc gpio [%d]\n", __func__, gpio); gpio_free(gpio); return ret; } @@ -215,6 +214,45 @@ int nfc_misc_register(struct nfc_dev *nfc_dev, } return 0; } +/** + * nfc_gpio_info() - gets the status of nfc gpio pins and encodes into a byte. + * @nfc_dev: nfc device data structure + * @arg: userspace buffer + * + * Encoding can be done in following manner + * 1) map the gpio value into INVALID(-2), SET(1), RESET(0). + * 2) mask the first 2 bits of gpio. + * 3) left shift the 2 bits as multiple of 2. + * 4) multiply factor can be defined as position of gpio pin in struct platform_gpio + * + * Return: -EFAULT, if unable to copy the data from kernel space to userspace, 0 + * if Success(or no issue) + */ + +static int nfc_gpio_info(struct nfc_dev *nfc_dev, unsigned long arg) +{ + unsigned int gpios_status = 0; + int value = 0; + int gpio_no = 0; + int i; + int ret = 0; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + for (i = 0; i < sizeof(struct platform_gpio) / sizeof(unsigned int); + i++) { + gpio_no = *((unsigned int *)nfc_gpio + i); + value = get_valid_gpio(gpio_no); + if (value < 0) + value = -2; + gpios_status |= (value & GPIO_STATUS_MASK_BITS)<<(GPIO_POS_SHIFT_VAL*i); + } + ret = copy_to_user((uint32_t *) arg, &gpios_status, sizeof(value)); + if (ret < 0) { + pr_err("%s : Unable to copy data from kernel space to user space"); + return -EFAULT; + } + return 0; +} /** * nfc_ioctl_power_states() - power control @@ -242,12 +280,14 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) set_valid_gpio(nfc_gpio->dwl_req, 0); gpio_set_ven(nfc_dev, 0); nfc_dev->nfc_ven_enabled = false; + nfc_dev->nfc_state = NFC_STATE_NCI; } else if (arg == NFC_POWER_ON) { nfc_dev->nfc_enable_intr(nfc_dev); set_valid_gpio(nfc_gpio->dwl_req, 0); gpio_set_ven(nfc_dev, 1); nfc_dev->nfc_ven_enabled = true; + nfc_dev->nfc_state = NFC_STATE_NCI; } else if (arg == NFC_FW_DWL_VEN_TOGGLE) { /* * We are switching to download Mode, toggle the enable pin @@ -341,13 +381,11 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) case NFC_SET_RESET_READ_PENDING: if (arg == NFC_SET_READ_PENDING) { nfc_dev->cold_reset.is_nfc_read_pending = true; - /* Set default NFC state as NCI for Nfc read pending request */ + /* Set default NFC state as NCI for Nfc read pending request */ nfc_dev->nfc_state = NFC_STATE_NCI; - } - else if (arg == NFC_RESET_READ_PENDING){ + } else if (arg == NFC_RESET_READ_PENDING) { nfc_dev->cold_reset.is_nfc_read_pending = false; - } - else { + } else { ret = -EINVAL; } break; @@ -357,6 +395,9 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) case ESE_GET_PWR: ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE); break; + case NFC_GET_GPIO_STATUS: + ret = nfc_gpio_info(nfc_dev, arg); + break; default: pr_err("%s: bad cmd %lu\n", __func__, arg); ret = -ENOIOCTLCMD; @@ -431,7 +472,7 @@ int nfc_dev_close(struct inode *inode, struct file *filp) * if eSE calls flow is via NFC driver * i.e. direct calls from SPI HAL to NFC driver */ - mutex_unlock(&nfc_dev->dev_ref_mutex); + mutex_unlock(&nfc_dev->dev_ref_mutex); nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS_NFC); mutex_lock(&nfc_dev->dev_ref_mutex); } diff --git a/nfc/common.h b/nfc/common.h index 2c82394cc0..91c043b313 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -75,10 +75,15 @@ #define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) #define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) #define NFC_SET_RESET_READ_PENDING _IOW(NFC_MAGIC, 0x04, uint32_t) +#define NFC_GET_GPIO_STATUS _IOR(NFC_MAGIC, 0x05, uint32_t) #define DTS_IRQ_GPIO_STR "nxp,sn-irq" #define DTS_VEN_GPIO_STR "nxp,sn-ven-rstn" #define DTS_FWDN_GPIO_STR "nxp,sn-dwl-req" +/* Each GPIO occupies consecutive two bits */ +#define GPIO_POS_SHIFT_VAL 2 +/* Two bits to indicate GPIO status (Invalid(-2), Set(1) or Reset(0)) */ +#define GPIO_STATUS_MASK_BITS 3 enum nfcc_ioctl_request { /* NFC disable request with VEN LOW */ From 767acc6b4a6bca71553ad0766966945089ed4565 Mon Sep 17 00:00:00 2001 From: nxf24591 Date: Wed, 21 Dec 2022 13:35:51 +0530 Subject: [PATCH 074/100] Updated corresponding to - GITHUB_CODE_DROP --- nfc/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nfc/common.h b/nfc/common.h index 91c043b313..306415ba3b 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -57,7 +57,7 @@ #define MAX_RETRY_COUNT (3) #define MAX_WRITE_IRQ_COUNT (5) #define MAX_IRQ_WAIT_TIME (90) -#define WAKEUP_SRC_TIMEOUT (2000) +#define WAKEUP_SRC_TIMEOUT (100) /* command response timeout */ #define NCI_CMD_RSP_TIMEOUT_MS (2000) From e24f9d0b477c1376661d60f39bceebfbba375dee Mon Sep 17 00:00:00 2001 From: Maria Yu Date: Wed, 14 Dec 2022 22:03:59 +0800 Subject: [PATCH 075/100] NFC: driver: Support new i2c_driver remove api "struct i2c_driver".remove function's return type is changed from int to void in kernel version 6.1.0. Support new i2c_driver remove API for NFC driver. Change-Id: I2fc0d4a044afd49cc08c8b2486ce355a5857e202 Signed-off-by: Maria Yu Signed-off-by: Amruth Naga --- nfc/i2c_drv.c | 16 ++++++++++++---- nfc/i2c_drv.h | 5 +++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index b00794dd94..0623e5c390 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -461,21 +461,27 @@ err: return ret; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) +void nfc_i2c_dev_remove(struct i2c_client *client) +#else int nfc_i2c_dev_remove(struct i2c_client *client) +#endif { - int ret = 0; struct nfc_dev *nfc_dev = NULL; pr_info("%s: remove device\n", __func__); nfc_dev = i2c_get_clientdata(client); if (!nfc_dev) { pr_err("%s: device doesn't exist anymore\n", __func__); - ret = -ENODEV; - return ret; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + return -ENODEV; +#endif } if (nfc_dev->dev_ref_count > 0) { pr_err("%s: device already in use\n", __func__); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) return -EBUSY; +#endif } gpio_set_value(nfc_dev->configs.gpio.ven, 0); @@ -496,7 +502,9 @@ int nfc_i2c_dev_remove(struct i2c_client *client) kfree(nfc_dev->read_kbuf); kfree(nfc_dev->write_kbuf); kfree(nfc_dev); - return ret; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + return 0; +#endif } int nfc_i2c_dev_suspend(struct device *device) diff --git a/nfc/i2c_drv.h b/nfc/i2c_drv.h index 3abb56bd0f..3809c44fdb 100644 --- a/nfc/i2c_drv.h +++ b/nfc/i2c_drv.h @@ -25,6 +25,7 @@ #define _I2C_DRV_H_ #include +#include #define NFC_I2C_DRV_STR "qcom,sn-nci" /*kept same as dts */ #define NFC_I2C_DEV_ID "sn-i2c" @@ -44,7 +45,11 @@ struct i2c_dev { long nfc_i2c_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) +void nfc_i2c_dev_remove(struct i2c_client *client); +#else int nfc_i2c_dev_remove(struct i2c_client *client); +#endif int nfc_i2c_dev_suspend(struct device *device); int nfc_i2c_dev_resume(struct device *device); From fcc9dd09720918aa90a17c6c6fd104543437b430 Mon Sep 17 00:00:00 2001 From: Mohammed Athar Date: Fri, 16 Dec 2022 11:38:41 -0800 Subject: [PATCH 076/100] Added to fix compilation error on GKI build Change-Id: I4ae342aa9c6f76f2f84d2f1538a86eb67b67532b Signed-off-by: Amruth Naga --- Android.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Android.mk b/Android.mk index c7c41cddd1..c7ea788e0f 100644 --- a/Android.mk +++ b/Android.mk @@ -7,11 +7,11 @@ LOCAL_PATH := $(call my-dir) KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS=$(PWD)/$(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers +include $(CLEAR_VARS) +ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) LOCAL_REQUIRED_MODULES := sec-module-symvers LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers - -include $(CLEAR_VARS) - +endif LOCAL_MODULE := nxp-nci.ko LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*) From f9075847af91b78d50df553fb65a4fa4409567fa Mon Sep 17 00:00:00 2001 From: PRANAY BHARGAV BHAVARAJU Date: Sat, 17 Dec 2022 16:24:27 +0530 Subject: [PATCH 077/100] NFC: Driver: Added Fall through To avoid code compilation issues NFC team added break in eSE cold reset file as temperory fix. Replacing the break with Fall through. Change-Id: Ieb6a5f105a71ae0533f746f6c56479c56a68cd2c --- nfc/ese_cold_reset.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index a0dcdff479..0b8854316e 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -284,8 +284,8 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) /* free buffers and exit with pass */ goto err; } - /* Temp fix to avoid compilation issues */ - break; + fallthrough; + case ESE_COLD_RESET_PROTECT_DIS: if (nfc_dev->cold_reset.is_crp_en && From a3c87684dc24d5cb9232cc69be035db78b99c6c4 Mon Sep 17 00:00:00 2001 From: Mallikarjun S T Date: Wed, 14 Sep 2022 12:13:43 +0530 Subject: [PATCH 078/100] NFC: driver: correcting prints corrected few prints and variable names. Change-Id: Ic870a46eedde3a85d668cf4f13c99d94353a195a --- nfc/common.c | 12 ++++++------ nfc/i2c_drv.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 5416ec1b8a..3e41b8d23e 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -504,15 +504,15 @@ int nfc_post_init(struct nfc_dev *nfc_dev) * * Queries the TZ secure libraries if NFC is in secure zone statue or not. * - * Return: 0 if FEATURE_NOT_SUPPORTED/PERIPHERAL_NOT_FOUND/state is 2 and - * return 1(non-secure) otherwise + * Return: 0 if FEATURE_NOT_SUPPORTED or PERIPHERAL_NOT_FOUND or state = 2(non-secure zone) and + * return 1 if state = 1(secure zone) or error otherwise */ bool nfc_hw_secure_check(void) { struct Object client_env; struct Object app_object; - u32 wifi_uid = HW_NFC_UID; + u32 nfc_uid = HW_NFC_UID; union ObjectArg obj_arg[2] = {{{0, 0}}}; int ret; bool retstat = 1; @@ -521,7 +521,7 @@ int nfc_post_init(struct nfc_dev *nfc_dev) ret = get_client_env_object(&client_env); if (ret) { pr_err("Failed to get client_env_object, ret: %d\n", ret); - return 1; + return retstat; } ret = IClientEnv_open(client_env, HW_STATE_UID, &app_object); @@ -534,12 +534,12 @@ int nfc_post_init(struct nfc_dev *nfc_dev) goto exit_release_clientenv; } - obj_arg[0].b = (struct ObjectBuf) {&wifi_uid, sizeof(u32)}; + obj_arg[0].b = (struct ObjectBuf) {&nfc_uid, sizeof(u32)}; obj_arg[1].b = (struct ObjectBuf) {&state, sizeof(u8)}; ret = Object_invoke(app_object, HW_OP_GET_STATE, obj_arg, ObjectCounts_pack(1, 1, 0, 0)); - pr_info("SMC invoke ret: %d state: %d\n", ret, state); + pr_info("TZ ret: %d state: %d\n", ret, state); if (ret) { if (ret == PERIPHERAL_NOT_FOUND) { retstat = 0; /* Do not Assert */ diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 0623e5c390..94f1b88f4c 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -427,7 +427,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) else { nfc_dev->secure_zone = true; } - pr_info("%s:nfc_dev->secure_zone = %s", __func__, nfc_dev->secure_zone ? "true" : "false"); + pr_info("%s:nfc secure_zone = %s", __func__, nfc_dev->secure_zone ? "true" : "false"); }else { nfc_post_init(nfc_dev); } From d77433930ff6e8ff0e3a787fdc5e4b1a8e0369c4 Mon Sep 17 00:00:00 2001 From: Mallikarjun S T Date: Mon, 31 Oct 2022 14:53:49 +0530 Subject: [PATCH 079/100] NFC: driver: secure status check while reset gpio write Implemented code snippet to query secure status while writing into NFC reset GPIO pin. Change-Id: I7b5ae69e5f6497d0f427559405f589578482d2e1 --- nfc/common.c | 53 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 3e41b8d23e..710dff3c63 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -26,6 +26,7 @@ #include #include #include "common.h" +bool secure_peripheral_not_found = true; int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, @@ -131,15 +132,22 @@ int get_valid_gpio(int gpio) void gpio_set_ven(struct nfc_dev *nfc_dev, int value) { struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - if(!nfc_dev->secure_zone) { - if (gpio_get_value(nfc_gpio->ven) != value) { - pr_debug("%s: value %d\n", __func__, value); - + if (gpio_get_value(nfc_gpio->ven) != value) { + pr_debug("%s: value %d\n", __func__, value); + if(secure_peripheral_not_found) + { + /*secure peripheral feature is not enabled*/ gpio_set_value(nfc_gpio->ven, value); - /* hardware dependent delay */ - usleep_range(NFC_GPIO_SET_WAIT_TIME_US, - NFC_GPIO_SET_WAIT_TIME_US + 100); } + else + { + /*secure peripheral feature is enabled*/ + if(!nfc_hw_secure_check()) + gpio_set_value(nfc_gpio->ven, value); + } + /* hardware dependent delay */ + usleep_range(NFC_GPIO_SET_WAIT_TIME_US, + NFC_GPIO_SET_WAIT_TIME_US + 100); } } @@ -504,19 +512,19 @@ int nfc_post_init(struct nfc_dev *nfc_dev) * * Queries the TZ secure libraries if NFC is in secure zone statue or not. * - * Return: 0 if FEATURE_NOT_SUPPORTED or PERIPHERAL_NOT_FOUND or state = 2(non-secure zone) and - * return 1 if state = 1(secure zone) or error otherwise + * Return: 0 if FEATURE_NOT_SUPPORTED or PERIPHERAL_NOT_FOUND or nfc_sec_state = 2(non-secure zone) and + * return 1 if nfc_sec_state = 1(secure zone) or error otherwise */ - bool nfc_hw_secure_check(void) - { +bool nfc_hw_secure_check(void) +{ struct Object client_env; struct Object app_object; u32 nfc_uid = HW_NFC_UID; union ObjectArg obj_arg[2] = {{{0, 0}}}; int ret; bool retstat = 1; - u8 state = 0; + u8 nfc_sec_state = 0; /* get rootObj */ ret = get_client_env_object(&client_env); if (ret) { @@ -535,11 +543,11 @@ int nfc_post_init(struct nfc_dev *nfc_dev) } obj_arg[0].b = (struct ObjectBuf) {&nfc_uid, sizeof(u32)}; - obj_arg[1].b = (struct ObjectBuf) {&state, sizeof(u8)}; + obj_arg[1].b = (struct ObjectBuf) {&nfc_sec_state, sizeof(u8)}; ret = Object_invoke(app_object, HW_OP_GET_STATE, obj_arg, ObjectCounts_pack(1, 1, 0, 0)); - pr_info("TZ ret: %d state: %d\n", ret, state); + pr_info("TZ ret: %d nfc_sec_state: %d\n", ret, nfc_sec_state); if (ret) { if (ret == PERIPHERAL_NOT_FOUND) { retstat = 0; /* Do not Assert */ @@ -548,7 +556,12 @@ int nfc_post_init(struct nfc_dev *nfc_dev) goto exit_release_app_obj; } - if (state == 1) { + secure_peripheral_not_found = false; + + /* Refer peripheral state utilities for different states of NFC peripherals; + * path: vendor/qcom/proprietary/securemsm/peripheralStateUtils/inc/peripheralStateUtils.h + */ + if (nfc_sec_state == 1) { /*Secure Zone*/ retstat = 1; } else { @@ -556,13 +569,13 @@ int nfc_post_init(struct nfc_dev *nfc_dev) retstat = 0; } -exit_release_app_obj: - Object_release(app_object); -exit_release_clientenv: - Object_release(client_env); + exit_release_app_obj: + Object_release(app_object); + exit_release_clientenv: + Object_release(client_env); return retstat; - } +} /** * nfc_dynamic_protection_ioctl() - dynamic protection control From 38edb908ea30a463f70e749a5aaf8a5a4a7b740a Mon Sep 17 00:00:00 2001 From: Mallikarjun S T Date: Sat, 18 Feb 2023 09:53:34 +0530 Subject: [PATCH 080/100] NFC: driver: remove proprietary path comment Removed proprietary path mentioned in cmments. Change-Id: I688688aa0e88d717e1536d637b6eeec947c6a061 --- nfc/common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 710dff3c63..65687b1bb3 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -558,9 +558,7 @@ bool nfc_hw_secure_check(void) secure_peripheral_not_found = false; - /* Refer peripheral state utilities for different states of NFC peripherals; - * path: vendor/qcom/proprietary/securemsm/peripheralStateUtils/inc/peripheralStateUtils.h - */ + /* Refer peripheral state utilities for different states of NFC peripherals */ if (nfc_sec_state == 1) { /*Secure Zone*/ retstat = 1; From 3b1ddde8242015f6494bbb003263814504793ed0 Mon Sep 17 00:00:00 2001 From: Mallikarjun S T Date: Wed, 8 Feb 2023 17:41:13 +0530 Subject: [PATCH 081/100] NFC: driver: use SMEM to getPeripheralStatus at bootup Updated getPeripheralStatus call to use SMEM, instead of sending a secure monitor call to QTEE. Change-Id: Id2be09aa10f00bf4a2373e4056c0e9533c9f3ac2 --- Kbuild | 4 --- nfc/common.c | 86 +++++++++++++-------------------------------------- nfc/common.h | 7 +---- nfc/i2c_drv.c | 2 +- 4 files changed, 24 insertions(+), 75 deletions(-) diff --git a/Kbuild b/Kbuild index 1e4a75aad8..93012c8f01 100644 --- a/Kbuild +++ b/Kbuild @@ -6,10 +6,6 @@ LINUXINCLUDE += -I$(NFC_ROOT)/include/uapi/linux/nfc LINUXINCLUDE += -include $(NFC_ROOT)/config/gki_nfc_conf.h -LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/smcinvoke/ -LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/linux/ -LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/include/linux/ - obj-$(CONFIG_NXP_NFC_I2C) += nxp-nci.o #source files diff --git a/nfc/common.c b/nfc/common.c index 65687b1bb3..0c89b7e6aa 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -18,7 +18,7 @@ * ******************************************************************************/ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * *****************************************************************************/ #include @@ -26,6 +26,9 @@ #include #include #include "common.h" + +#include +#define PERISEC_SMEM_ID 651 bool secure_peripheral_not_found = true; @@ -141,9 +144,10 @@ void gpio_set_ven(struct nfc_dev *nfc_dev, int value) } else { - /*secure peripheral feature is enabled*/ - if(!nfc_hw_secure_check()) + if(!nfc_hw_secure_check_smem()) { + /*gpio val is set only if nfc is in non-secure zone*/ gpio_set_value(nfc_gpio->ven, value); + } } /* hardware dependent delay */ usleep_range(NFC_GPIO_SET_WAIT_TIME_US, @@ -508,71 +512,25 @@ int nfc_post_init(struct nfc_dev *nfc_dev) } /** - * nfc_hw_secure_check() - Checks the NFC secure zone status + * nfc_hw_secure_check_smem() - Checks SMEM to get NFC secure zone status * - * Queries the TZ secure libraries if NFC is in secure zone statue or not. + * Reads Variable shared between QTEE & HLOS, if NFC is in secure zone statue or not. * - * Return: 0 if FEATURE_NOT_SUPPORTED or PERIPHERAL_NOT_FOUND or nfc_sec_state = 2(non-secure zone) and - * return 1 if nfc_sec_state = 1(secure zone) or error otherwise + * Return: false - FEATURE_NOT_SUPPORTED/PERIPHERAL_NOT_FOUND/NON-SECURE + * true - SECURE */ -bool nfc_hw_secure_check(void) +bool nfc_hw_secure_check_smem(void) { - struct Object client_env; - struct Object app_object; - u32 nfc_uid = HW_NFC_UID; - union ObjectArg obj_arg[2] = {{{0, 0}}}; - int ret; - bool retstat = 1; - u8 nfc_sec_state = 0; - /* get rootObj */ - ret = get_client_env_object(&client_env); - if (ret) { - pr_err("Failed to get client_env_object, ret: %d\n", ret); - return retstat; + uint32_t * peripheralStateInfo = NULL; + size_t size = 0; + + peripheralStateInfo = qcom_smem_get(QCOM_SMEM_HOST_ANY, PERISEC_SMEM_ID, &size); + if (peripheralStateInfo) { + secure_peripheral_not_found = false; + return ((*peripheralStateInfo >> (HW_NFC_UID - 0x500)) & 0x1); } - - ret = IClientEnv_open(client_env, HW_STATE_UID, &app_object); - if (ret) { - pr_debug("Failed to get app_object, ret: %d\n", ret); - if (ret == FEATURE_NOT_SUPPORTED) { - retstat = 0; /* Do not Assert */ - pr_debug("Secure HW feature not supported\n"); - } - goto exit_release_clientenv; - } - - obj_arg[0].b = (struct ObjectBuf) {&nfc_uid, sizeof(u32)}; - obj_arg[1].b = (struct ObjectBuf) {&nfc_sec_state, sizeof(u8)}; - ret = Object_invoke(app_object, HW_OP_GET_STATE, obj_arg, - ObjectCounts_pack(1, 1, 0, 0)); - - pr_info("TZ ret: %d nfc_sec_state: %d\n", ret, nfc_sec_state); - if (ret) { - if (ret == PERIPHERAL_NOT_FOUND) { - retstat = 0; /* Do not Assert */ - pr_debug("Secure HW mode is not updated. Peripheral not found\n"); - } - goto exit_release_app_obj; - } - - secure_peripheral_not_found = false; - - /* Refer peripheral state utilities for different states of NFC peripherals */ - if (nfc_sec_state == 1) { - /*Secure Zone*/ - retstat = 1; - } else { - /*Non-Secure Zone*/ - retstat = 0; - } - - exit_release_app_obj: - Object_release(app_object); - exit_release_clientenv: - Object_release(client_env); - - return retstat; + return false; } /** @@ -662,7 +620,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) return -ENODEV; if( nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { /*Avoiding ioctl call in secure zone*/ - if(nfc_dev->secure_zone) { + if(nfc_hw_secure_check_smem()) { if(cmd!=NFC_SECURE_ZONE) { pr_debug("nfc_dev_ioctl failed\n"); return -1; @@ -805,7 +763,7 @@ int nfc_dev_close(struct inode *inode, struct file *filp) int validate_nfc_state_nci(struct nfc_dev *nfc_dev) { struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - if(!nfc_dev->secure_zone) { + if(!nfc_hw_secure_check_smem()) { if (!gpio_get_value(nfc_gpio->ven)) { pr_err("%s: ven low - nfcc powered off\n", __func__); return -ENODEV; diff --git a/nfc/common.h b/nfc/common.h index 5f5f5bbdaf..5e912585cb 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -33,11 +33,6 @@ #include "i2c_drv.h" #include "ese_cold_reset.h" -/*secure library headers*/ -#include "smcinvoke.h" -#include "smcinvoke_object.h" -#include "IClientEnv.h" - /* Max device count for this driver */ #define DEV_COUNT 1 /* i2c device class */ @@ -324,5 +319,5 @@ int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev); int validate_nfc_state_nci(struct nfc_dev *nfc_dev); int nfc_post_init(struct nfc_dev *nfc_dev); int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans); -bool nfc_hw_secure_check(void); +bool nfc_hw_secure_check_smem(void); #endif /* _COMMON_H_ */ diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 94f1b88f4c..de86026b27 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -420,7 +420,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) if( nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { /*Check NFC Secure Zone status*/ - if(!nfc_hw_secure_check()) { + if(!nfc_hw_secure_check_smem()) { nfc_post_init(nfc_dev); nfc_dev->secure_zone = false; } From 025e9f7e0b66725521d83e0331ae01fd943ac930 Mon Sep 17 00:00:00 2001 From: Mallikarjun S T Date: Sat, 18 Feb 2023 09:53:34 +0530 Subject: [PATCH 082/100] NFC: driver: remove proprietary path comment Removed proprietary path mentioned in cmments. Change-Id: I688688aa0e88d717e1536d637b6eeec947c6a061 --- nfc/common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 710dff3c63..65687b1bb3 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -558,9 +558,7 @@ bool nfc_hw_secure_check(void) secure_peripheral_not_found = false; - /* Refer peripheral state utilities for different states of NFC peripherals; - * path: vendor/qcom/proprietary/securemsm/peripheralStateUtils/inc/peripheralStateUtils.h - */ + /* Refer peripheral state utilities for different states of NFC peripherals */ if (nfc_sec_state == 1) { /*Secure Zone*/ retstat = 1; From 771f608e7fc6de751c6cecc36ff39e9de9baf1a9 Mon Sep 17 00:00:00 2001 From: Madan Koyyalamudi Date: Mon, 27 Feb 2023 09:46:13 -0800 Subject: [PATCH 083/100] Revert "NFC: driver: use SMEM to getPeripheralStatus at bootup" This reverts commit 3b1ddde8242015f6494bbb003263814504793ed0. Change-Id: Id7c99947e9faf5edb76a5878a13e4abb11f2dbd6 --- Kbuild | 4 +++ nfc/common.c | 86 ++++++++++++++++++++++++++++++++++++++------------- nfc/common.h | 7 ++++- nfc/i2c_drv.c | 2 +- 4 files changed, 75 insertions(+), 24 deletions(-) diff --git a/Kbuild b/Kbuild index 93012c8f01..1e4a75aad8 100644 --- a/Kbuild +++ b/Kbuild @@ -6,6 +6,10 @@ LINUXINCLUDE += -I$(NFC_ROOT)/include/uapi/linux/nfc LINUXINCLUDE += -include $(NFC_ROOT)/config/gki_nfc_conf.h +LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/smcinvoke/ +LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/linux/ +LINUXINCLUDE += -I$(NFC_ROOT)/../../../qcom/opensource/securemsm-kernel/include/linux/ + obj-$(CONFIG_NXP_NFC_I2C) += nxp-nci.o #source files diff --git a/nfc/common.c b/nfc/common.c index 0c89b7e6aa..65687b1bb3 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -18,7 +18,7 @@ * ******************************************************************************/ /* - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * *****************************************************************************/ #include @@ -26,9 +26,6 @@ #include #include #include "common.h" - -#include -#define PERISEC_SMEM_ID 651 bool secure_peripheral_not_found = true; @@ -144,10 +141,9 @@ void gpio_set_ven(struct nfc_dev *nfc_dev, int value) } else { - if(!nfc_hw_secure_check_smem()) { - /*gpio val is set only if nfc is in non-secure zone*/ + /*secure peripheral feature is enabled*/ + if(!nfc_hw_secure_check()) gpio_set_value(nfc_gpio->ven, value); - } } /* hardware dependent delay */ usleep_range(NFC_GPIO_SET_WAIT_TIME_US, @@ -512,25 +508,71 @@ int nfc_post_init(struct nfc_dev *nfc_dev) } /** - * nfc_hw_secure_check_smem() - Checks SMEM to get NFC secure zone status + * nfc_hw_secure_check() - Checks the NFC secure zone status * - * Reads Variable shared between QTEE & HLOS, if NFC is in secure zone statue or not. + * Queries the TZ secure libraries if NFC is in secure zone statue or not. * - * Return: false - FEATURE_NOT_SUPPORTED/PERIPHERAL_NOT_FOUND/NON-SECURE - * true - SECURE + * Return: 0 if FEATURE_NOT_SUPPORTED or PERIPHERAL_NOT_FOUND or nfc_sec_state = 2(non-secure zone) and + * return 1 if nfc_sec_state = 1(secure zone) or error otherwise */ -bool nfc_hw_secure_check_smem(void) +bool nfc_hw_secure_check(void) { - uint32_t * peripheralStateInfo = NULL; - size_t size = 0; - - peripheralStateInfo = qcom_smem_get(QCOM_SMEM_HOST_ANY, PERISEC_SMEM_ID, &size); - if (peripheralStateInfo) { - secure_peripheral_not_found = false; - return ((*peripheralStateInfo >> (HW_NFC_UID - 0x500)) & 0x1); + struct Object client_env; + struct Object app_object; + u32 nfc_uid = HW_NFC_UID; + union ObjectArg obj_arg[2] = {{{0, 0}}}; + int ret; + bool retstat = 1; + u8 nfc_sec_state = 0; + /* get rootObj */ + ret = get_client_env_object(&client_env); + if (ret) { + pr_err("Failed to get client_env_object, ret: %d\n", ret); + return retstat; } - return false; + + ret = IClientEnv_open(client_env, HW_STATE_UID, &app_object); + if (ret) { + pr_debug("Failed to get app_object, ret: %d\n", ret); + if (ret == FEATURE_NOT_SUPPORTED) { + retstat = 0; /* Do not Assert */ + pr_debug("Secure HW feature not supported\n"); + } + goto exit_release_clientenv; + } + + obj_arg[0].b = (struct ObjectBuf) {&nfc_uid, sizeof(u32)}; + obj_arg[1].b = (struct ObjectBuf) {&nfc_sec_state, sizeof(u8)}; + ret = Object_invoke(app_object, HW_OP_GET_STATE, obj_arg, + ObjectCounts_pack(1, 1, 0, 0)); + + pr_info("TZ ret: %d nfc_sec_state: %d\n", ret, nfc_sec_state); + if (ret) { + if (ret == PERIPHERAL_NOT_FOUND) { + retstat = 0; /* Do not Assert */ + pr_debug("Secure HW mode is not updated. Peripheral not found\n"); + } + goto exit_release_app_obj; + } + + secure_peripheral_not_found = false; + + /* Refer peripheral state utilities for different states of NFC peripherals */ + if (nfc_sec_state == 1) { + /*Secure Zone*/ + retstat = 1; + } else { + /*Non-Secure Zone*/ + retstat = 0; + } + + exit_release_app_obj: + Object_release(app_object); + exit_release_clientenv: + Object_release(client_env); + + return retstat; } /** @@ -620,7 +662,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) return -ENODEV; if( nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { /*Avoiding ioctl call in secure zone*/ - if(nfc_hw_secure_check_smem()) { + if(nfc_dev->secure_zone) { if(cmd!=NFC_SECURE_ZONE) { pr_debug("nfc_dev_ioctl failed\n"); return -1; @@ -763,7 +805,7 @@ int nfc_dev_close(struct inode *inode, struct file *filp) int validate_nfc_state_nci(struct nfc_dev *nfc_dev) { struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; - if(!nfc_hw_secure_check_smem()) { + if(!nfc_dev->secure_zone) { if (!gpio_get_value(nfc_gpio->ven)) { pr_err("%s: ven low - nfcc powered off\n", __func__); return -ENODEV; diff --git a/nfc/common.h b/nfc/common.h index 5e912585cb..5f5f5bbdaf 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -33,6 +33,11 @@ #include "i2c_drv.h" #include "ese_cold_reset.h" +/*secure library headers*/ +#include "smcinvoke.h" +#include "smcinvoke_object.h" +#include "IClientEnv.h" + /* Max device count for this driver */ #define DEV_COUNT 1 /* i2c device class */ @@ -319,5 +324,5 @@ int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev); int validate_nfc_state_nci(struct nfc_dev *nfc_dev); int nfc_post_init(struct nfc_dev *nfc_dev); int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans); -bool nfc_hw_secure_check_smem(void); +bool nfc_hw_secure_check(void); #endif /* _COMMON_H_ */ diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index de86026b27..94f1b88f4c 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -420,7 +420,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) if( nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { /*Check NFC Secure Zone status*/ - if(!nfc_hw_secure_check_smem()) { + if(!nfc_hw_secure_check()) { nfc_post_init(nfc_dev); nfc_dev->secure_zone = false; } From 130c0698d1cc66d7f907c0f715ef1d2015317546 Mon Sep 17 00:00:00 2001 From: Bruce Levy Date: Fri, 17 Mar 2023 15:37:50 -0700 Subject: [PATCH 084/100] Revert "NFC: driver: remove proprietary path comment" This reverts commit 025e9f7e0b66725521d83e0331ae01fd943ac930. --- nfc/common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nfc/common.c b/nfc/common.c index 65687b1bb3..710dff3c63 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -558,7 +558,9 @@ bool nfc_hw_secure_check(void) secure_peripheral_not_found = false; - /* Refer peripheral state utilities for different states of NFC peripherals */ + /* Refer peripheral state utilities for different states of NFC peripherals; + * path: vendor/qcom/proprietary/securemsm/peripheralStateUtils/inc/peripheralStateUtils.h + */ if (nfc_sec_state == 1) { /*Secure Zone*/ retstat = 1; From a122ef7c7ae52ec4db9145bb2a8c27cf6a555905 Mon Sep 17 00:00:00 2001 From: Mallikarjun S T Date: Sat, 18 Feb 2023 09:53:34 +0530 Subject: [PATCH 085/100] NFC: driver: remove proprietary path comment Removed proprietary path mentioned in cmments. --- nfc/common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 710dff3c63..65687b1bb3 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -558,9 +558,7 @@ bool nfc_hw_secure_check(void) secure_peripheral_not_found = false; - /* Refer peripheral state utilities for different states of NFC peripherals; - * path: vendor/qcom/proprietary/securemsm/peripheralStateUtils/inc/peripheralStateUtils.h - */ + /* Refer peripheral state utilities for different states of NFC peripherals */ if (nfc_sec_state == 1) { /*Secure Zone*/ retstat = 1; From 0a8de6d2bdb8ea7862c329d56831a40822b1fa29 Mon Sep 17 00:00:00 2001 From: Linux Image Build Automation Date: Fri, 7 Apr 2023 11:42:28 -0700 Subject: [PATCH 086/100] Revert "NFC: driver: remove proprietary path comment" This reverts commit a122ef7c7ae52ec4db9145bb2a8c27cf6a555905. Change-Id: Icfc0d503af94c931584f8b9bb60ba768b01e4339 Signed-off-by: Linux Image Build Automation --- nfc/common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nfc/common.c b/nfc/common.c index 65687b1bb3..710dff3c63 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -558,7 +558,9 @@ bool nfc_hw_secure_check(void) secure_peripheral_not_found = false; - /* Refer peripheral state utilities for different states of NFC peripherals */ + /* Refer peripheral state utilities for different states of NFC peripherals; + * path: vendor/qcom/proprietary/securemsm/peripheralStateUtils/inc/peripheralStateUtils.h + */ if (nfc_sec_state == 1) { /*Secure Zone*/ retstat = 1; From 6a667b7bc47afcb2037b13ced1b7fce451882707 Mon Sep 17 00:00:00 2001 From: Amruth Naga Date: Thu, 4 May 2023 12:33:12 +0530 Subject: [PATCH 087/100] [NFC]: Add NxpDrv sting in driver logs Added NxpDrv sring in all driver logs Change-Id: I6751475aaddd9713c50b18daf4b9d038fa24f0a5 --- nfc/common.c | 122 +++++++++++++++++++++++----------------------- nfc/common_nxp.c | 50 +++++++++---------- nfc/common_qcom.c | 22 ++++----- nfc/i2c_drv.c | 76 ++++++++++++++--------------- 4 files changed, 135 insertions(+), 135 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 65687b1bb3..772f05160a 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -38,7 +38,7 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, struct platform_ldo *ldo = &nfc_configs->ldo; if (!np) { - pr_err("%s: nfc of_node NULL\n", __func__); + pr_err("NxpDrv: %s: nfc of_node NULL\n", __func__); return -EINVAL; } @@ -51,28 +51,28 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, if (interface == PLATFORM_IF_I2C) { nfc_gpio->irq = of_get_named_gpio(np, DTS_IRQ_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->irq))) { - pr_err("%s: irq gpio invalid %d\n", __func__, + pr_err("NxpDrv: %s: irq gpio invalid %d\n", __func__, nfc_gpio->irq); return nfc_gpio->irq; } - pr_info("%s: irq %d\n", __func__, nfc_gpio->irq); + pr_info("NxpDrv: %s: irq %d\n", __func__, nfc_gpio->irq); } nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->ven))) { - pr_err("%s: ven gpio invalid %d\n", __func__, nfc_gpio->ven); + pr_err("NxpDrv: %s: ven gpio invalid %d\n", __func__, nfc_gpio->ven); return nfc_gpio->ven; } /* some products like sn220 does not required fw dwl pin */ nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); /* not returning failure for dwl gpio as it is optional for sn220 */ if ((!gpio_is_valid(nfc_gpio->dwl_req))) { - pr_warn("%s: dwl_req gpio invalid %d\n", __func__, + pr_warn("NxpDrv: %s: dwl_req gpio invalid %d\n", __func__, nfc_gpio->dwl_req); } /* Read clkreq GPIO pin number from DTSI */ nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0); if (!gpio_is_valid(nfc_gpio->clkreq)) { - dev_err(dev, "clkreq gpio invalid %d\n", nfc_gpio->clkreq); + dev_err(dev, "NxpDrv: clkreq gpio invalid %d\n", nfc_gpio->clkreq); return -EINVAL; } @@ -82,7 +82,7 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, }else nfc_configs->CNSS_NFC_HW_SECURE_ENABLE = true; - pr_info("%s: irq %d, ven %d, dwl %d, clkreq %d \n", __func__, nfc_gpio->irq, nfc_gpio->ven, + pr_info("NxpDrv: %s: irq %d, ven %d, dwl %d, clkreq %d \n", __func__, nfc_gpio->irq, nfc_gpio->ven, nfc_gpio->dwl_req, nfc_gpio->clkreq); /* optional property */ @@ -90,7 +90,7 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, (u32 *) ldo->vdd_levels, ARRAY_SIZE(ldo->vdd_levels)); if (ret) { - dev_err(dev, "error reading NFC VDDIO min and max value\n"); + dev_err(dev, "NxpDrv: error reading NFC VDDIO min and max value\n"); // set default as per datasheet ldo->vdd_levels[0] = NFC_VDDIO_MIN; ldo->vdd_levels[1] = NFC_VDDIO_MAX; @@ -99,7 +99,7 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, /* optional property */ ret = of_property_read_u32(np, NFC_LDO_CUR_DT_NAME, &ldo->max_current); if (ret) { - dev_err(dev, "error reading NFC current value\n"); + dev_err(dev, "NxpDrv: error reading NFC current value\n"); // set default as per datasheet ldo->max_current = NFC_CURRENT_MAX; } @@ -110,7 +110,7 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, void set_valid_gpio(int gpio, int value) { if (gpio_is_valid(gpio)) { - pr_debug("%s: gpio %d value %d\n", __func__, gpio, value); + pr_debug("NxpDrv: %s: gpio %d value %d\n", __func__, gpio, value); gpio_set_value(gpio, value); /* hardware dependent delay */ usleep_range(NFC_GPIO_SET_WAIT_TIME_US, @@ -124,7 +124,7 @@ int get_valid_gpio(int gpio) if (gpio_is_valid(gpio)) { value = gpio_get_value(gpio); - pr_debug("%s: gpio %d value %d\n", __func__, gpio, value); + pr_debug("NxpDrv: %s: gpio %d value %d\n", __func__, gpio, value); } return value; } @@ -133,7 +133,7 @@ void gpio_set_ven(struct nfc_dev *nfc_dev, int value) { struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; if (gpio_get_value(nfc_gpio->ven) != value) { - pr_debug("%s: value %d\n", __func__, value); + pr_debug("NxpDrv: %s: value %d\n", __func__, value); if(secure_peripheral_not_found) { /*secure peripheral feature is not enabled*/ @@ -155,26 +155,26 @@ int configure_gpio(unsigned int gpio, int flag) { int ret; - pr_debug("%s: nfc gpio [%d] flag [%01x]\n", __func__, gpio, flag); + pr_debug("NxpDrv: %s: nfc gpio [%d] flag [%01x]\n", __func__, gpio, flag); if (gpio_is_valid(gpio)) { ret = gpio_request(gpio, "nfc_gpio"); if (ret) { - pr_err("%s: unable to request nfc gpio [%d]\n", + pr_err("NxpDrv: %s: unable to request nfc gpio [%d]\n", __func__, gpio); return ret; } /* set direction and value for output pin */ if (flag & GPIO_OUTPUT) { ret = gpio_direction_output(gpio, (GPIO_HIGH & flag)); - pr_debug("%s: nfc o/p gpio %d level %d\n", __func__, + pr_debug("NxpDrv: %s: nfc o/p gpio %d level %d\n", __func__, gpio, gpio_get_value(gpio)); } else { ret = gpio_direction_input(gpio); - pr_debug("%s: nfc i/p gpio %d\n", __func__, gpio); + pr_debug("NxpDrv: %s: nfc i/p gpio %d\n", __func__, gpio); } if (ret) { - pr_err("%s: unable to set direction for nfc gpio [%d]\n", __func__, gpio); + pr_err("NxpDrv: %s: unable to set direction for nfc gpio [%d]\n", __func__, gpio); gpio_free(gpio); return ret; } @@ -182,17 +182,17 @@ int configure_gpio(unsigned int gpio, int flag) if (flag & GPIO_IRQ) { ret = gpio_to_irq(gpio); if (ret < 0) { - pr_err("%s: unable to set irq [%d]\n", __func__, + pr_err("NxpDrv: %s: unable to set irq [%d]\n", __func__, gpio); gpio_free(gpio); return ret; } - pr_debug("%s: gpio_to_irq successful [%d]\n", __func__, + pr_debug("NxpDrv: %s: gpio_to_irq successful [%d]\n", __func__, gpio); return ret; } } else { - pr_err("%s: invalid gpio\n", __func__); + pr_err("NxpDrv: %s: invalid gpio\n", __func__); ret = -EINVAL; } return ret; @@ -217,7 +217,7 @@ void gpio_free_all(struct nfc_dev *nfc_dev) void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count) { - pr_debug("%s: entry\n", __func__); + pr_debug("NxpDrv: %s: entry\n", __func__); kfree(nfc_dev->kbuf); device_destroy(nfc_dev->nfc_class, nfc_dev->devno); cdev_del(&nfc_dev->c_dev); @@ -235,14 +235,14 @@ int nfc_misc_register(struct nfc_dev *nfc_dev, ret = alloc_chrdev_region(&nfc_dev->devno, 0, count, devname); if (ret < 0) { - pr_err("%s: failed to alloc chrdev region ret %d\n", __func__, + pr_err("NxpDrv: %s: failed to alloc chrdev region ret %d\n", __func__, ret); return ret; } nfc_dev->nfc_class = class_create(THIS_MODULE, classname); if (IS_ERR(nfc_dev->nfc_class)) { ret = PTR_ERR(nfc_dev->nfc_class); - pr_err("%s: failed to register device class ret %d\n", __func__, + pr_err("NxpDrv: %s: failed to register device class ret %d\n", __func__, ret); unregister_chrdev_region(nfc_dev->devno, count); return ret; @@ -250,7 +250,7 @@ int nfc_misc_register(struct nfc_dev *nfc_dev, cdev_init(&nfc_dev->c_dev, nfc_fops); ret = cdev_add(&nfc_dev->c_dev, nfc_dev->devno, count); if (ret < 0) { - pr_err("%s: failed to add cdev ret %d\n", __func__, ret); + pr_err("NxpDrv: %s: failed to add cdev ret %d\n", __func__, ret); class_destroy(nfc_dev->nfc_class); unregister_chrdev_region(nfc_dev->devno, count); return ret; @@ -259,7 +259,7 @@ int nfc_misc_register(struct nfc_dev *nfc_dev, nfc_dev->devno, nfc_dev, devname); if (IS_ERR(nfc_dev->nfc_device)) { ret = PTR_ERR(nfc_dev->nfc_device); - pr_err("%s: failed to create the device ret %d\n", __func__, + pr_err("NxpDrv: %s: failed to create the device ret %d\n", __func__, ret); cdev_del(&nfc_dev->c_dev); class_destroy(nfc_dev->nfc_class); @@ -320,7 +320,7 @@ static int nfc_gpio_info(struct nfc_dev *nfc_dev, unsigned long arg) } ret = copy_to_user((uint32_t *) arg, &gpios_status, sizeof(value)); if (ret < 0) { - pr_err("%s : Unable to copy data from kernel space to user space", __func__); + pr_err("NxpDrv: %s : Unable to copy data from kernel space to user space", __func__); return -EFAULT; } return 0; @@ -376,7 +376,7 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) * Setting firmware download gpio to HIGH * before FW download start */ - pr_debug("set fw gpio high\n"); + pr_debug("NxpDrv: set fw gpio high\n"); set_valid_gpio(nfc_gpio->dwl_req, 1); nfc_dev->nfc_state = NFC_STATE_FW_DWL; @@ -385,14 +385,14 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) gpio_set_ven(nfc_dev, 0); gpio_set_ven(nfc_dev, 1); nfc_dev->nfc_enable_intr(nfc_dev); - pr_info("%s VEN forced reset done\n", __func__); + pr_info("NxpDrv: %s VEN forced reset done\n", __func__); } else if (arg == NFC_FW_DWL_LOW) { /* * Setting firmware download gpio to LOW * FW download finished */ - pr_debug("set fw gpio LOW\n"); + pr_debug("NxpDrv: set fw gpio LOW\n"); set_valid_gpio(nfc_gpio->dwl_req, 0); nfc_dev->nfc_state = NFC_STATE_NCI; @@ -403,7 +403,7 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) /* Setting flag true when NFC is disabled */ nfc_dev->cold_reset.is_nfc_enabled = false; } else { - pr_err("%s: bad arg %lu\n", __func__, arg); + pr_err("NxpDrv: %s: bad arg %lu\n", __func__, arg); ret = -ENOIOCTLCMD; } return ret; @@ -429,7 +429,7 @@ long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, int ret = 0; arg = (compat_u64) arg; - pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg); + pr_debug("NxpDrv: %s: cmd = %x arg = %zx\n", __func__, cmd, arg); ret = nfc_dev_ioctl(pfile, cmd, arg); return ret; } @@ -461,35 +461,35 @@ int nfc_post_init(struct nfc_dev *nfc_dev) ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT); if (ret) { - pr_err("%s: unable to request nfc reset gpio [%d]\n", + pr_err("NxpDrv: %s: unable to request nfc reset gpio [%d]\n", __func__, nfc_gpio->ven); return ret; } ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT); if (ret) { - pr_err("%s: unable to request nfc firm downl gpio [%d]\n", + pr_err("NxpDrv: %s: unable to request nfc firm downl gpio [%d]\n", __func__, nfc_gpio->dwl_req); } /* Read clkreq GPIO number from device tree*/ ret = of_property_read_u32_index(nfc_dev->i2c_dev.client->dev.of_node, DTS_CLKREQ_GPIO_STR, 1, &clkreq_gpio); if (ret < 0) { - pr_err("%s Failed to read clkreq gipo number, ret: %d\n", __func__, ret); + pr_err("NxpDrv: %s Failed to read clkreq gipo number, ret: %d\n", __func__, ret); return ret; } /* configure clkreq GPIO as wakeup capable */ ret = msm_gpio_mpm_wake_set(clkreq_gpio, true); if (ret < 0) { - pr_err("%s Failed to setup clkreq gpio %d as wakeup capable, ret: %d\n", __func__, clkreq_gpio , ret); + pr_err("NxpDrv: %s Failed to setup clkreq gpio %d as wakeup capable, ret: %d\n", __func__, clkreq_gpio , ret); return ret; } else { - pr_info("%s clkreq gpio %d successfully setup for wakeup capable\n", __func__, clkreq_gpio); + pr_info("NxpDrv: %s clkreq gpio %d successfully setup for wakeup capable\n", __func__, clkreq_gpio); } ret = nfcc_hw_check(nfc_dev); if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { - pr_err("nfc hw check failed ret %d\n", ret); + pr_err("NxpDrv: nfc hw check failed ret %d\n", ret); gpio_free(nfc_gpio->dwl_req); gpio_free(nfc_gpio->ven); return ret; @@ -501,7 +501,7 @@ int nfc_post_init(struct nfc_dev *nfc_dev) } post_init_success = 1; - pr_info("%s success\n", __func__); + pr_info("NxpDrv: %s success\n", __func__); return 0; @@ -528,16 +528,16 @@ bool nfc_hw_secure_check(void) /* get rootObj */ ret = get_client_env_object(&client_env); if (ret) { - pr_err("Failed to get client_env_object, ret: %d\n", ret); + pr_err("NxpDrv: Failed to get client_env_object, ret: %d\n", ret); return retstat; } ret = IClientEnv_open(client_env, HW_STATE_UID, &app_object); if (ret) { - pr_debug("Failed to get app_object, ret: %d\n", ret); + pr_debug("NxpDrv: Failed to get app_object, ret: %d\n", ret); if (ret == FEATURE_NOT_SUPPORTED) { retstat = 0; /* Do not Assert */ - pr_debug("Secure HW feature not supported\n"); + pr_debug("NxpDrv: Secure HW feature not supported\n"); } goto exit_release_clientenv; } @@ -547,11 +547,11 @@ bool nfc_hw_secure_check(void) ret = Object_invoke(app_object, HW_OP_GET_STATE, obj_arg, ObjectCounts_pack(1, 1, 0, 0)); - pr_info("TZ ret: %d nfc_sec_state: %d\n", ret, nfc_sec_state); + pr_info("NxpDrv: TZ ret: %d nfc_sec_state: %d\n", ret, nfc_sec_state); if (ret) { if (ret == PERIPHERAL_NOT_FOUND) { retstat = 0; /* Do not Assert */ - pr_debug("Secure HW mode is not updated. Peripheral not found\n"); + pr_debug("NxpDrv: Secure HW mode is not updated. Peripheral not found\n"); } goto exit_release_app_obj; } @@ -598,20 +598,20 @@ int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone if(sec_zone_trans == 1) { /*check NFC is disabled, only then set Ven GPIO low*/ if(nfc_dev->cold_reset.is_nfc_enabled == false) { - pr_debug("%s: value %d\n", __func__, gpio_get_value(nfc_gpio->ven)); + pr_debug("NxpDrv: %s: value %d\n", __func__, gpio_get_value(nfc_gpio->ven)); chk_eSE_pwr_off = 1; /*check if eSE is active, if yes, wait max of 1sec, until it's inactive */ if(nfc_dev->is_ese_session_active == true) { if(down_timeout(&sem_eSE_pwr_off, msecs_to_jiffies(1000))) { /*waited for 1sec yet eSE not turned off, so, ignoring eSE power off*/ - pr_info("Forcefull shutdown of eSE\n"); + pr_info("NxpDrv: Forcefull shutdown of eSE\n"); } } ret = nfc_ioctl_power_states(nfc_dev, 0); /*set driver as secure zone, such that no ioctl calls are allowed*/ nfc_dev->secure_zone = true; - pr_info("Driver Secure flag set successful\n"); + pr_info("NxpDrv: Driver Secure flag set successful\n"); } else { ret = -1; } @@ -630,9 +630,9 @@ int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone if(!gpio_get_value(nfc_gpio->ven)) ret = nfc_ioctl_power_states(nfc_dev, 1); } - pr_info("Func Driver Secure flag clear successful\n"); + pr_info("NxpDrv: Func Driver Secure flag clear successful\n"); } else { - pr_info("INVALID ARG\n"); + pr_info("NxpDrv: INVALID ARG\n"); ret = -ENOIOCTLCMD; } @@ -664,13 +664,13 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) /*Avoiding ioctl call in secure zone*/ if(nfc_dev->secure_zone) { if(cmd!=NFC_SECURE_ZONE) { - pr_debug("nfc_dev_ioctl failed\n"); + pr_debug("NxpDrv: nfc_dev_ioctl failed\n"); return -1; } } } - pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg); + pr_debug("NxpDrv: %s: cmd = %x arg = %zx\n", __func__, cmd, arg); switch (cmd) { case NFC_SET_PWR: ret = nfc_ioctl_power_states(nfc_dev, arg); @@ -699,7 +699,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) ret = nfc_ioctl_nfcc_info(pfile, arg); break; case ESE_COLD_RESET: - pr_debug("nfc ese cold reset ioctl\n"); + pr_debug("NxpDrv: nfc ese cold reset ioctl\n"); ret = ese_cold_reset_ioctl(nfc_dev, arg); break; case NFC_SECURE_ZONE: @@ -708,7 +708,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) } break; default: - pr_err("%s: bad cmd %lu\n", __func__, arg); + pr_err("NxpDrv: %s: bad cmd %lu\n", __func__, arg); ret = -ENOIOCTLCMD; } return ret; @@ -723,7 +723,7 @@ int nfc_dev_open(struct inode *inode, struct file *filp) if (!nfc_dev) return -ENODEV; - pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); + pr_debug("NxpDrv: %s: %d, %d\n", __func__, imajor(inode), iminor(inode)); /* Set flag to block freezer fake signal if not set already. * Without this Signal being set, Driver is trying to do a read @@ -731,7 +731,7 @@ int nfc_dev_open(struct inode *inode, struct file *filp) */ if (!(current->flags & PF_NOFREEZE)) { current->flags |= PF_NOFREEZE; - pr_debug("%s: current->flags 0x%x. \n", __func__, current->flags); + pr_debug("NxpDrv: %s: current->flags 0x%x. \n", __func__, current->flags); } mutex_lock(&nfc_dev->dev_ref_mutex); @@ -761,11 +761,11 @@ int nfc_dev_flush(struct file *pfile, fl_owner_t id) nfc_dev->release_read = true; nfc_dev->nfc_disable_intr(nfc_dev); wake_up(&nfc_dev->read_wq); - pr_debug("%s: waiting for release of blocked read\n", __func__); + pr_debug("NxpDrv: %s: waiting for release of blocked read\n", __func__); mutex_lock(&nfc_dev->read_mutex); nfc_dev->release_read = false; } else { - pr_debug("%s: read thread already released\n", __func__); + pr_debug("NxpDrv: %s: read thread already released\n", __func__); } mutex_unlock(&nfc_dev->read_mutex); return 0; @@ -780,12 +780,12 @@ int nfc_dev_close(struct inode *inode, struct file *filp) if (!nfc_dev) return -ENODEV; - pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode)); + pr_debug("NxpDrv: %s: %d, %d\n", __func__, imajor(inode), iminor(inode)); /* unset the flag to restore to previous state */ if (current->flags & PF_NOFREEZE) { current->flags &= ~PF_NOFREEZE; - pr_debug("%s: current->flags 0x%x. \n", __func__, current->flags); + pr_debug("NxpDrv: %s: current->flags 0x%x. \n", __func__, current->flags); } mutex_lock(&nfc_dev->dev_ref_mutex); @@ -807,16 +807,16 @@ int validate_nfc_state_nci(struct nfc_dev *nfc_dev) struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; if(!nfc_dev->secure_zone) { if (!gpio_get_value(nfc_gpio->ven)) { - pr_err("%s: ven low - nfcc powered off\n", __func__); + pr_err("NxpDrv: %s: ven low - nfcc powered off\n", __func__); return -ENODEV; } } if (get_valid_gpio(nfc_gpio->dwl_req) == 1) { - pr_err("%s: fw download in-progress\n", __func__); + pr_err("NxpDrv: %s: fw download in-progress\n", __func__); return -EBUSY; } if (nfc_dev->nfc_state != NFC_STATE_NCI) { - pr_err("%s: fw download state\n", __func__); + pr_err("NxpDrv: %s: fw download state\n", __func__); return -EBUSY; } return 0; diff --git a/nfc/common_nxp.c b/nfc/common_nxp.c index 474dc96892..e9ee2f71af 100644 --- a/nfc/common_nxp.c +++ b/nfc/common_nxp.c @@ -51,18 +51,18 @@ static enum chip_types get_nfcc_chip_type_dl(struct nfc_dev *nfc_dev) *cmd++ = DL_GET_VERSION_CMD_CRC_1; *cmd++ = DL_GET_VERSION_CMD_CRC_2; - pr_debug("%s:Sending GET_VERSION cmd of size = %d\n", __func__, DL_GET_VERSION_CMD_LEN); + pr_debug("NxpDrv: %s:Sending GET_VERSION cmd of size = %d\n", __func__, DL_GET_VERSION_CMD_LEN); ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, DL_GET_VERSION_CMD_LEN, MAX_RETRY_COUNT); if (ret <= 0) { - pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret); + pr_err("NxpDrv: %s: - nfc get version cmd error ret %d\n", __func__, ret); goto err; } memset(rsp, 0x00, DL_GET_VERSION_RSP_LEN_2); - pr_debug("%s:Reading response of GET_VERSION cmd\n", __func__); + pr_debug("NxpDrv: %s:Reading response of GET_VERSION cmd\n", __func__); ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_VERSION_RSP_LEN_2, NCI_CMD_RSP_TIMEOUT_MS); if (ret <= 0) { - pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret); + pr_err("NxpDrv: %s: - nfc get version rsp error ret %d\n", __func__, ret); goto err; } if (rsp[0] == FW_MSG_CMD_RSP && ret >= DL_GET_VERSION_RSP_LEN_2) { @@ -76,7 +76,7 @@ static enum chip_types get_nfcc_chip_type_dl(struct nfc_dev *nfc_dev) rsp[FW_MAJOR_VER_OFFSET] == SN220_MAJOR_VER) chip_type = CHIP_SN220; - pr_debug("%s:NFC Chip Type 0x%02x Rom Version 0x%02x FW Minor 0x%02x Major 0x%02x\n", + pr_debug("NxpDrv: %s:NFC Chip Type 0x%02x Rom Version 0x%02x FW Minor 0x%02x Major 0x%02x\n", __func__, rsp[GET_VERSION_RSP_CHIP_TYPE_OFFSET], rsp[FW_ROM_CODE_VER_OFFSET], rsp[GET_VERSION_RSP_MINOR_VERSION_OFFSET], @@ -119,33 +119,33 @@ enum nfc_state_flags get_nfcc_session_state_dl(struct nfc_dev *nfc_dev) *cmd++ = DL_GET_SESSION_CMD_CRC_1; *cmd++ = DL_GET_SESSION_CMD_CRC_2; - pr_debug("%s:Sending GET_SESSION_STATE cmd of size = %d\n", __func__, + pr_debug("NxpDrv: %s:Sending GET_SESSION_STATE cmd of size = %d\n", __func__, DL_GET_SESSION_STATE_CMD_LEN); ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, DL_GET_SESSION_STATE_CMD_LEN, MAX_RETRY_COUNT); if (ret <= 0) { - pr_err("%s: - nfc get session cmd error ret %d\n", __func__, ret); + pr_err("NxpDrv: %s: - nfc get session cmd error ret %d\n", __func__, ret); goto err; } memset(rsp, 0x00, DL_GET_SESSION_STATE_RSP_LEN); - pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__); + pr_debug("NxpDrv: %s:Reading response of GET_SESSION_STATE cmd\n", __func__); ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT_MS); if (ret <= 0) { - pr_err("%s: - nfc get session rsp error ret %d\n", __func__, ret); + pr_err("NxpDrv: %s: - nfc get session rsp error ret %d\n", __func__, ret); goto err; } if (rsp[0] != FW_MSG_CMD_RSP) { - pr_err("%s: - nfc invalid get session state rsp\n", __func__); + pr_err("NxpDrv: %s: - nfc invalid get session state rsp\n", __func__); goto err; } - pr_debug("Response bytes are %02x%02x%02x%02x%02x%02x%02x%02x\n", + pr_debug("NxpDrv: Response bytes are %02x%02x%02x%02x%02x%02x%02x%02x\n", rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6], rsp[7]); /*verify fw in non-teared state */ if (rsp[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) { - pr_err("%s NFCC booted in FW teared state\n", __func__); + pr_err("NxpDrv: %s NFCC booted in FW teared state\n", __func__); nfc_state = NFC_STATE_FW_TEARED; } else { - pr_info("%s NFCC booted in FW DN mode\n", __func__); + pr_info("NxpDrv: %s NFCC booted in FW DN mode\n", __func__); nfc_state = NFC_STATE_FW_DWL; } err: @@ -176,10 +176,10 @@ static enum chip_types get_nfcc_chip_type(struct nfc_dev *nfc_dev) *cmd++ = NCI_CORE_RESET_CMD_PAYLOAD_LEN; *cmd++ = NCI_CORE_RESET_KEEP_CONFIG; - pr_debug("%s:Sending NCI Core Reset cmd of size = %d\n", __func__, NCI_RESET_CMD_LEN); + pr_debug("NxpDrv: %s:Sending NCI Core Reset cmd of size = %d\n", __func__, NCI_RESET_CMD_LEN); ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, NCI_RESET_CMD_LEN, NO_RETRY); if (ret <= 0) { - pr_err("%s: - nfc nci core reset cmd error ret %d\n", __func__, ret); + pr_err("NxpDrv: %s: - nfc nci core reset cmd error ret %d\n", __func__, ret); goto err; } @@ -188,18 +188,18 @@ static enum chip_types get_nfcc_chip_type(struct nfc_dev *nfc_dev) nfc_dev->nfc_enable_intr(nfc_dev); memset(rsp, 0x00, NCI_RESET_RSP_LEN); - pr_debug("%s:Reading NCI Core Reset rsp\n", __func__); + pr_debug("NxpDrv: %s:Reading NCI Core Reset rsp\n", __func__); ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_RSP_LEN, NCI_CMD_RSP_TIMEOUT_MS); if (ret <= 0) { - pr_err("%s: - nfc nci core reset rsp error ret %d\n", __func__, ret); + pr_err("NxpDrv: %s: - nfc nci core reset rsp error ret %d\n", __func__, ret); goto err_disable_intr; } - pr_debug(" %s: nci core reset response 0x%02x%02x%02x%02x\n", + pr_debug("NxpDrv: %s: nci core reset response 0x%02x%02x%02x%02x\n", __func__, rsp[0], rsp[1], rsp[2], rsp[3]); if (rsp[0] != NCI_RSP) { /* reset response failed response*/ - pr_err("%s invalid nci core reset response\n", __func__); + pr_err("NxpDrv: %s invalid nci core reset response\n", __func__); goto err_disable_intr; } @@ -207,7 +207,7 @@ static enum chip_types get_nfcc_chip_type(struct nfc_dev *nfc_dev) /* read nci rest response ntf */ ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_NTF_LEN, NCI_CMD_RSP_TIMEOUT_MS); if (ret <= 0) { - pr_err("%s - nfc nci rest rsp ntf error status %d\n", __func__, ret); + pr_err("NxpDrv: %s - nfc nci rest rsp ntf error status %d\n", __func__, ret); goto err_disable_intr; } @@ -220,7 +220,7 @@ static enum chip_types get_nfcc_chip_type(struct nfc_dev *nfc_dev) chip_type = CHIP_SN1XX; else if (rom_version == SN220_ROM_VER && major_version == SN220_MAJOR_VER) chip_type = CHIP_SN220; - pr_debug(" %s:NCI Core Reset ntf 0x%02x%02x%02x%02x\n", + pr_debug("NxpDrv: %s:NCI Core Reset ntf 0x%02x%02x%02x%02x\n", __func__, rsp[0], rsp[1], rsp[2], rsp[3]); nfc_dev->nqx_info.info.chip_type = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - @@ -253,7 +253,7 @@ static bool validate_download_gpio(struct nfc_dev *nfc_dev, enum chip_types chip struct platform_gpio *nfc_gpio; if (nfc_dev == NULL) { - pr_err("%s nfc devices structure is null\n", __func__); + pr_err("NxpDrv: %s nfc devices structure is null\n", __func__); return status; } nfc_gpio = &nfc_dev->configs.gpio; @@ -299,7 +299,7 @@ int nfcc_hw_check(struct nfc_dev *nfc_dev) /*validate gpio config required as per the chip*/ if (!validate_download_gpio(nfc_dev, chip_type)) { - pr_info("%s gpio validation fail\n", __func__); + pr_info("NxpDrv: %s gpio validation fail\n", __func__); ret = -ENXIO; goto err; } @@ -311,7 +311,7 @@ int nfcc_hw_check(struct nfc_dev *nfc_dev) /*nfcc state specific operations */ switch (nfc_state) { case NFC_STATE_FW_TEARED: - pr_warn("%s: - NFCC FW Teared State\n", __func__); + pr_warn("NxpDrv: %s: - NFCC FW Teared State\n", __func__); break; case NFC_STATE_FW_DWL: case NFC_STATE_NCI: @@ -319,7 +319,7 @@ int nfcc_hw_check(struct nfc_dev *nfc_dev) case NFC_STATE_UNKNOWN: default: ret = -ENXIO; - pr_err("%s: - NFCC HW not available\n", __func__); + pr_err("NxpDrv: %s: - NFCC HW not available\n", __func__); goto err; } nfc_dev->nfc_state = nfc_state; diff --git a/nfc/common_qcom.c b/nfc/common_qcom.c index 6be7bbf444..7ca25b22dc 100644 --- a/nfc/common_qcom.c +++ b/nfc/common_qcom.c @@ -23,7 +23,7 @@ unsigned int nfc_ioctl_nfcc_info(struct file *filp, unsigned long arg) struct nfc_dev *nfc_dev = filp->private_data; r = nfc_dev->nqx_info.i; - pr_debug("nfc : %s r = 0x%x\n", __func__, r); + pr_debug("NxpDrv: nfc : %s r = 0x%x\n", __func__, r); return r; } @@ -67,20 +67,20 @@ int nfc_ldo_vote(struct nfc_dev *nfc_dev) nfc_dev->configs.ldo.vdd_levels[0], nfc_dev->configs.ldo.vdd_levels[1]); if (ret < 0) { - pr_err("%s: set voltage failed\n", __func__); + pr_err("NxpDrv: %s: set voltage failed\n", __func__); return ret; } /* pass expected current from NFC in uA */ ret = regulator_set_load(nfc_dev->reg, nfc_dev->configs.ldo.max_current); if (ret < 0) { - pr_err("%s: set load failed\n", __func__); + pr_err("NxpDrv: %s: set load failed\n", __func__); return ret; } ret = regulator_enable(nfc_dev->reg); if (ret < 0) - pr_err("%s: regulator_enable failed\n", __func__); + pr_err("NxpDrv: %s: regulator_enable failed\n", __func__); else nfc_dev->is_vreg_enabled = true; return ret; @@ -106,13 +106,13 @@ int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev) if (IS_ERR(nfc_dev->reg)) { ret = PTR_ERR(nfc_dev->reg); nfc_dev->reg = NULL; - pr_err("%s: regulator_get failed, ret = %d\n", + pr_err("NxpDrv: %s: regulator_get failed, ret = %d\n", __func__, ret); return ret; } } else { nfc_dev->reg = NULL; - pr_err("%s: regulator entry not present\n", __func__); + pr_err("NxpDrv: %s: regulator entry not present\n", __func__); // return success as it's optional to configure LDO return 0; } @@ -120,7 +120,7 @@ int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev) // LDO config supported by platform DT ret = nfc_ldo_vote(nfc_dev); if (ret < 0) { - pr_err("%s: LDO voting failed, ret = %d\n", __func__, ret); + pr_err("NxpDrv: %s: LDO voting failed, ret = %d\n", __func__, ret); regulator_put(nfc_dev->reg); } return ret; @@ -139,26 +139,26 @@ int nfc_ldo_unvote(struct nfc_dev *nfc_dev) int ret; if (!nfc_dev->is_vreg_enabled) { - pr_err("%s: regulator already disabled\n", __func__); + pr_err("NxpDrv: %s: regulator already disabled\n", __func__); return -EINVAL; } ret = regulator_disable(nfc_dev->reg); if (ret < 0) { - pr_err("%s: regulator_disable failed\n", __func__); + pr_err("NxpDrv: %s: regulator_disable failed\n", __func__); return ret; } nfc_dev->is_vreg_enabled = false; ret = regulator_set_voltage(nfc_dev->reg, 0, NFC_VDDIO_MAX); if (ret < 0) { - pr_err("%s: set voltage failed\n", __func__); + pr_err("NxpDrv: %s: set voltage failed\n", __func__); return ret; } ret = regulator_set_load(nfc_dev->reg, 0); if (ret < 0) - pr_err("%s: set load failed\n", __func__); + pr_err("NxpDrv: %s: set load failed\n", __func__); return ret; } diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 94f1b88f4c..c1dc018533 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -115,7 +115,7 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) uint16_t i = 0; uint16_t disp_len = GET_IPCLOG_MAX_PKT_LEN(count); - pr_debug("%s: reading %zu bytes.\n", __func__, count); + pr_debug("NxpDrv: %s: reading %zu bytes.\n", __func__, count); if (timeout > NCI_CMD_RSP_TIMEOUT_MS) timeout = NCI_CMD_RSP_TIMEOUT_MS; @@ -137,7 +137,7 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) !i2c_dev->irq_enabled, msecs_to_jiffies(timeout)); if (ret <= 0) { - pr_err("%s: timeout error\n", + pr_err("NxpDrv: %s: timeout error\n", __func__); goto err; } @@ -146,7 +146,7 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) nfc_dev->read_wq, !i2c_dev->irq_enabled); if (ret) { - pr_err("%s: err wakeup of wq\n", + pr_err("NxpDrv: %s: err wakeup of wq\n", __func__); goto err; } @@ -158,7 +158,7 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) break; if(!nfc_dev->secure_zone) { if (!gpio_get_value(nfc_gpio->ven)) { - pr_info("%s: releasing read\n", __func__); + pr_info("NxpDrv: %s: releasing read\n", __func__); ret = -EIO; goto err; } @@ -172,10 +172,10 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) * will again call read system call */ if (nfc_dev->release_read) { - pr_debug("%s: releasing read\n", __func__); + pr_debug("NxpDrv: %s: releasing read\n", __func__); return 0; } - pr_warn("%s: spurious interrupt detected\n", __func__); + pr_warn("NxpDrv: %s: spurious interrupt detected\n", __func__); } } @@ -185,7 +185,7 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout) NFCLOG_IPC(nfc_dev, false, "%s of %d bytes, ret %d", __func__, count, ret); if (ret <= 0) { - pr_err("%s: returned %d\n", __func__, ret); + pr_err("NxpDrv: %s: returned %d\n", __func__, ret); goto err; } @@ -226,7 +226,7 @@ int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, if (count > MAX_DL_BUFFER_SIZE) count = MAX_DL_BUFFER_SIZE; - pr_debug("%s: writing %zu bytes.\n", __func__, count); + pr_debug("NxpDrv: %s: writing %zu bytes.\n", __func__, count); NFCLOG_IPC(nfc_dev, false, "%s sending %d B", __func__, count); for (i = 0; i < disp_len; i++) @@ -238,7 +238,7 @@ int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, */ for (retry_cnt = 1; retry_cnt <= MAX_WRITE_IRQ_COUNT; retry_cnt++) { if (gpio_get_value(nfc_gpio->irq)) { - pr_warn("%s: irq high during write, wait\n", __func__); + pr_warn("NxpDrv: %s: irq high during write, wait\n", __func__); usleep_range(WRITE_RETRY_WAIT_TIME_US, WRITE_RETRY_WAIT_TIME_US + 100); } else { @@ -246,7 +246,7 @@ int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, } if (retry_cnt == MAX_WRITE_IRQ_COUNT && gpio_get_value(nfc_gpio->irq)) { - pr_warn("%s: allow after maximum wait\n", __func__); + pr_warn("NxpDrv: %s: allow after maximum wait\n", __func__); } } @@ -254,12 +254,12 @@ int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count, ret = i2c_master_send(nfc_dev->i2c_dev.client, buf, count); NFCLOG_IPC(nfc_dev, false, "%s ret %d", __func__, ret); if (ret <= 0) { - pr_warn("%s: write failed ret(%d), maybe in standby\n", + pr_warn("NxpDrv: %s: write failed ret(%d), maybe in standby\n", __func__, ret); usleep_range(WRITE_RETRY_WAIT_TIME_US, WRITE_RETRY_WAIT_TIME_US + 100); } else if (ret != count) { - pr_err("%s: failed to write %d\n", __func__, ret); + pr_err("NxpDrv: %s: failed to write %d\n", __func__, ret); ret = -EIO; } else if (ret == count) break; @@ -274,7 +274,7 @@ ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, size_t count, struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data; if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); + pr_err("NxpDrv: %s: device doesn't exist anymore\n", __func__); return -ENODEV; } mutex_lock(&nfc_dev->read_mutex); @@ -283,13 +283,13 @@ ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, size_t count, if (filp->f_flags & O_NONBLOCK) { ret = i2c_master_recv(nfc_dev->i2c_dev.client, nfc_dev->read_kbuf, count); - pr_debug("%s: NONBLOCK read ret = %d\n", __func__, ret); + pr_debug("NxpDrv: %s: NONBLOCK read ret = %d\n", __func__, ret); } else { ret = i2c_read(nfc_dev, nfc_dev->read_kbuf, count, 0); } if (ret > 0) { if (copy_to_user(buf, nfc_dev->read_kbuf, ret)) { - pr_warn("%s: failed to copy to user space\n", __func__); + pr_warn("NxpDrv: %s: failed to copy to user space\n", __func__); ret = -EFAULT; } } @@ -307,13 +307,13 @@ ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf, count = MAX_DL_BUFFER_SIZE; if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); + pr_err("NxpDrv: %s: device doesn't exist anymore\n", __func__); return -ENODEV; } mutex_lock(&nfc_dev->write_mutex); if (copy_from_user(nfc_dev->write_kbuf, buf, count)) { - pr_err("%s: failed to copy from user space\n", __func__); + pr_err("NxpDrv: %s: failed to copy from user space\n", __func__); mutex_unlock(&nfc_dev->write_mutex); return -EFAULT; } @@ -343,7 +343,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) struct i2c_dev *i2c_dev = NULL; struct platform_configs *nfc_configs = NULL; struct platform_gpio *nfc_gpio = NULL; - pr_debug("%s: enter\n", __func__); + pr_debug("NxpDrv: %s: enter\n", __func__); nfc_dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL); if (nfc_dev == NULL) { ret = -ENOMEM; @@ -354,11 +354,11 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) /* retrieve details of gpios from dt */ ret = nfc_parse_dt(&client->dev,nfc_configs, PLATFORM_IF_I2C); if (ret) { - pr_err("%s: failed to parse dt\n", __func__); + pr_err("NxpDrv: %s: failed to parse dt\n", __func__); goto err_free_nfc_dev; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - pr_err("%s: need I2C_FUNC_I2C\n", __func__); + pr_err("NxpDrv: %s: need I2C_FUNC_I2C\n", __func__); ret = -ENODEV; goto err_free_nfc_dev; } @@ -383,7 +383,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ); if (ret <= 0) { - pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__, + pr_err("NxpDrv: %s: unable to request nfc irq gpio [%d]\n", __func__, nfc_gpio->irq); goto err_free_gpio; } @@ -398,23 +398,23 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) ret = nfc_misc_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT, NFC_CHAR_DEV_NAME, CLASS_NAME); if (ret) { - pr_err("%s: nfc_misc_register failed\n", __func__); + pr_err("NxpDrv: %s: nfc_misc_register failed\n", __func__); goto err_mutex_destroy; } /* interrupt initializations */ - pr_info("%s: requesting IRQ %d\n", __func__, client->irq); + pr_info("NxpDrv: %s: requesting IRQ %d\n", __func__, client->irq); i2c_dev->irq_enabled = true; ret = request_irq(client->irq, i2c_irq_handler, IRQF_TRIGGER_HIGH, client->name, nfc_dev); if (ret) { - pr_err("%s: request_irq failed\n", __func__); + pr_err("NxpDrv: %s: request_irq failed\n", __func__); goto err_nfc_misc_unregister; } i2c_disable_irq(nfc_dev); ret = nfc_ldo_config(&client->dev, nfc_dev); if (ret) { - pr_err("LDO config failed\n"); + pr_err("NxpDrv: LDO config failed\n"); goto err_ldo_config_failed; } @@ -427,7 +427,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) else { nfc_dev->secure_zone = true; } - pr_info("%s:nfc secure_zone = %s", __func__, nfc_dev->secure_zone ? "true" : "false"); + pr_info("NxpDrv: %s:nfc secure_zone = %s", __func__, nfc_dev->secure_zone ? "true" : "false"); }else { nfc_post_init(nfc_dev); } @@ -437,7 +437,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) i2c_dev->irq_wake_up = false; nfc_dev->is_ese_session_active = false; - pr_info("%s: probing nfc i2c success\n", __func__); + pr_info("NxpDrv: %s: probing nfc i2c success\n", __func__); return 0; @@ -457,7 +457,7 @@ err_free_read_kbuf: err_free_nfc_dev: kfree(nfc_dev); err: - pr_err("%s: probing not successful, check hardware\n", __func__); + pr_err("NxpDrv: %s: probing not successful, check hardware\n", __func__); return ret; } @@ -469,16 +469,16 @@ int nfc_i2c_dev_remove(struct i2c_client *client) { struct nfc_dev *nfc_dev = NULL; - pr_info("%s: remove device\n", __func__); + pr_info("NxpDrv: %s: remove device\n", __func__); nfc_dev = i2c_get_clientdata(client); if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); + pr_err("NxpDrv: %s: device doesn't exist anymore\n", __func__); #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) return -ENODEV; #endif } if (nfc_dev->dev_ref_count > 0) { - pr_err("%s: device already in use\n", __func__); + pr_err("NxpDrv: %s: device already in use\n", __func__); #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) return -EBUSY; #endif @@ -513,7 +513,7 @@ int nfc_i2c_dev_suspend(struct device *device) struct nfc_dev *nfc_dev = i2c_get_clientdata(client); struct i2c_dev *i2c_dev = NULL; if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); + pr_err("NxpDrv: %s: device doesn't exist anymore\n", __func__); return -ENODEV; } i2c_dev = &nfc_dev->i2c_dev; @@ -525,7 +525,7 @@ int nfc_i2c_dev_suspend(struct device *device) if (!enable_irq_wake(client->irq)) i2c_dev->irq_wake_up = true; } - pr_debug("%s: irq_wake_up = %d", __func__, i2c_dev->irq_wake_up); + pr_debug("NxpDrv: %s: irq_wake_up = %d", __func__, i2c_dev->irq_wake_up); return 0; } @@ -535,7 +535,7 @@ int nfc_i2c_dev_resume(struct device *device) struct nfc_dev *nfc_dev = i2c_get_clientdata(client); struct i2c_dev *i2c_dev = NULL; if (!nfc_dev) { - pr_err("%s: device doesn't exist anymore\n", __func__); + pr_err("NxpDrv: %s: device doesn't exist anymore\n", __func__); return -ENODEV; } i2c_dev = &nfc_dev->i2c_dev; @@ -547,7 +547,7 @@ int nfc_i2c_dev_resume(struct device *device) if (!disable_irq_wake(client->irq)) i2c_dev->irq_wake_up = false; } - pr_debug("%s: irq_wake_up = %d", __func__, i2c_dev->irq_wake_up); + pr_debug("NxpDrv: %s: irq_wake_up = %d", __func__, i2c_dev->irq_wake_up); return 0; } @@ -582,10 +582,10 @@ static int __init nfc_i2c_dev_init(void) { int ret = 0; - pr_info("%s: Loading NXP NFC I2C driver\n", __func__); + pr_info("NxpDrv: %s: Loading NXP NFC I2C driver\n", __func__); ret = i2c_add_driver(&nfc_i2c_dev_driver); if (ret != 0) - pr_err("%s: NFC I2C add driver error ret %d\n", __func__, ret); + pr_err("NxpDrv: %s: NFC I2C add driver error ret %d\n", __func__, ret); return ret; } @@ -593,7 +593,7 @@ module_init(nfc_i2c_dev_init); static void __exit nfc_i2c_dev_exit(void) { - pr_info("%s: Unloading NXP NFC I2C driver\n", __func__); + pr_info("NxpDrv: %s: Unloading NXP NFC I2C driver\n", __func__); i2c_del_driver(&nfc_i2c_dev_driver); } From ed7c9fa23c011db78b5071090f3cc6e4fd7c2da6 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Fri, 31 Mar 2023 22:51:57 +0530 Subject: [PATCH 088/100] nxp-nci-driver - BAZEL based compilation for nxp-nci.ko Added build files for bazel based compilation of nxp-nci Steps to test 1. Create symlink cd kernel_platform mkdir techpacks cd techpacks mkdir nxpnci_driver-kernel cd nxpnci_driver-kernel ln -s ../../../vendor/nxp/opensource/driver/* . 2. To compile cd kernel_platfrom ./tools/bazel build --lto=thin //techpacks/nxpnci_driver-kernel:pineapple_consolidate_nxp-nci ./tools/bazel run --lto=thin //techpacks/nxpnci_driver-kernel:pineapple_consolidate_nxp-nci_dist 3. Test done: Able to compile nxp-nci DLKM out/target/product//dlkm/lib/modules Change-Id: Iaf6f05d9228e1cc2ddd717de8d748238bb6082fe --- Android.mk | 1 + BUILD.bazel | 7 +++++++ define_modules.bzl | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 BUILD.bazel create mode 100644 define_modules.bzl diff --git a/Android.mk b/Android.mk index c7ea788e0f..f78e71d327 100644 --- a/Android.mk +++ b/Android.mk @@ -29,5 +29,6 @@ endif ########## Build kernel module based on local DLKM flag status ########## ifeq ($(NFC_DLKM_ENABLED), true) + LOCAL_MODULE_DDK_BUILD := true include $(DLKM_DIR)/Build_external_kernelmodule.mk endif diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 0000000000..8ee0b465eb --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,7 @@ +load("//build/kernel/kleaf:kernel.bzl", "ddk_headers") +load(":define_modules.bzl", "define_modules") + +define_modules("pineapple", "consolidate") +define_modules("pineapple", "gki") + + diff --git a/define_modules.bzl b/define_modules.bzl new file mode 100644 index 0000000000..a4070f155d --- /dev/null +++ b/define_modules.bzl @@ -0,0 +1,38 @@ +load("//build/kernel/kleaf:kernel.bzl", "ddk_module") +load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir") + +def define_modules(target, variant): + tv = "{}_{}".format(target, variant) + + ddk_module( + name = "{}_nxp-nci".format(tv), + out = "nxp-nci.ko", + srcs = ["nfc/common.c", + "nfc/common_nxp.c", + "nfc/common_qcom.c", + "nfc/ese_cold_reset.c", + "nfc/i2c_drv.c", + "nfc/common.h", + "nfc/common_nxp.h", + "nfc/ese_cold_reset.h", + "nfc/i2c_drv.h" + ], + hdrs = ["include/uapi/linux/nfc/nfcinfo.h"], + includes = [".", "linux", "nfc", "include/uapi/linux/nfc"], + deps = ["//msm-kernel:all_headers", + "//vendor/qcom/opensource/securemsm-kernel:smcinvoke_kernel_headers", + "//vendor/qcom/opensource/securemsm-kernel:{}_smcinvoke_dlkm".format(tv)], + kernel_build = "//msm-kernel:{}".format(tv), + visibility = ["//visibility:public"] + ) + + copy_to_dist_dir( + name = "{}_nxp-nci_dist".format(tv), + data = [":{}_nxp-nci".format(tv)], + dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(target), + flat = True, + wipe_dist_dir = False, + allow_duplicate_filenames = False, + mode_overrides = {"**/*": "644"}, + ) + From 215e40c3bcfa275e69a342d263320e866a84f5e0 Mon Sep 17 00:00:00 2001 From: Mallikarjun S T Date: Wed, 17 May 2023 13:09:44 +0530 Subject: [PATCH 089/100] NFC: driver: Add compilation flag for secure module lib dependencies Implemented compilation flag for secure module libraries dependencies nfc driver. Change-Id: I63d5feb1bf5c8e84748529b55e8b9b6832ae27e4 --- Android.mk | 13 ++++++++----- nfc/common.c | 20 ++++++++++++++++---- nfc/common.h | 10 ++++++++++ nfc/ese_cold_reset.c | 3 ++- nfc/i2c_drv.c | 7 +++++-- nfc_kernel_dlkm_vendor_board.mk | 2 +- 6 files changed, 42 insertions(+), 13 deletions(-) diff --git a/Android.mk b/Android.mk index f78e71d327..3f8003d245 100644 --- a/Android.mk +++ b/Android.mk @@ -5,13 +5,16 @@ DLKM_DIR := $(TOP)/device/qcom/common/dlkm LOCAL_PATH := $(call my-dir) -KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS=$(PWD)/$(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers - include $(CLEAR_VARS) -ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) -LOCAL_REQUIRED_MODULES := sec-module-symvers -LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers +ifeq ($(TARGET_ENABLE_PERIPHERAL_CONTROL), true) + LOCAL_CFLAGS := -DNFC_SECURE_PERIPHERAL_ENABLED + KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS=$(PWD)/$(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers + ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) + LOCAL_REQUIRED_MODULES := sec-module-symvers + LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers + endif endif + LOCAL_MODULE := nxp-nci.ko LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*) diff --git a/nfc/common.c b/nfc/common.c index 772f05160a..8c5ed3bf00 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -76,12 +76,13 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, return -EINVAL; } +#ifdef NFC_SECURE_PERIPHERAL_ENABLED /* Read DTS_SZONE_STR to check secure zone support */ if (of_property_read_string(np, DTS_SZONE_STR, &nfc_configs->szone)) { nfc_configs->CNSS_NFC_HW_SECURE_ENABLE = false; }else nfc_configs->CNSS_NFC_HW_SECURE_ENABLE = true; - +#endif pr_info("NxpDrv: %s: irq %d, ven %d, dwl %d, clkreq %d \n", __func__, nfc_gpio->irq, nfc_gpio->ven, nfc_gpio->dwl_req, nfc_gpio->clkreq); @@ -134,6 +135,7 @@ void gpio_set_ven(struct nfc_dev *nfc_dev, int value) struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; if (gpio_get_value(nfc_gpio->ven) != value) { pr_debug("NxpDrv: %s: value %d\n", __func__, value); +#ifdef NFC_SECURE_PERIPHERAL_ENABLED if(secure_peripheral_not_found) { /*secure peripheral feature is not enabled*/ @@ -145,6 +147,10 @@ void gpio_set_ven(struct nfc_dev *nfc_dev, int value) if(!nfc_hw_secure_check()) gpio_set_value(nfc_gpio->ven, value); } +#else + gpio_set_value(nfc_gpio->ven, value); +#endif + /* hardware dependent delay */ usleep_range(NFC_GPIO_SET_WAIT_TIME_US, NFC_GPIO_SET_WAIT_TIME_US + 100); @@ -495,11 +501,12 @@ int nfc_post_init(struct nfc_dev *nfc_dev) return ret; } +#ifdef NFC_SECURE_PERIPHERAL_ENABLED /*Initialising sempahore to disbale NFC Ven GPIO only after eSE is power off flag is set */ if (nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { sema_init(&sem_eSE_pwr_off,0); } - +#endif post_init_success = 1; pr_info("NxpDrv: %s success\n", __func__); return 0; @@ -507,6 +514,7 @@ int nfc_post_init(struct nfc_dev *nfc_dev) } +#ifdef NFC_SECURE_PERIPHERAL_ENABLED /** * nfc_hw_secure_check() - Checks the NFC secure zone status * @@ -638,7 +646,7 @@ int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone return ret; } - +#endif /** * nfc_dev_ioctl - used to set or get data from upper layer. @@ -660,6 +668,8 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) if (!nfc_dev) return -ENODEV; + +#ifdef NFC_SECURE_PERIPHERAL_ENABLED if( nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { /*Avoiding ioctl call in secure zone*/ if(nfc_dev->secure_zone) { @@ -669,7 +679,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) } } } - +#endif pr_debug("NxpDrv: %s: cmd = %x arg = %zx\n", __func__, cmd, arg); switch (cmd) { case NFC_SET_PWR: @@ -702,11 +712,13 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) pr_debug("NxpDrv: nfc ese cold reset ioctl\n"); ret = ese_cold_reset_ioctl(nfc_dev, arg); break; +#ifdef NFC_SECURE_PERIPHERAL_ENABLED case NFC_SECURE_ZONE: if( nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { ret = nfc_dynamic_protection_ioctl(nfc_dev, arg); } break; +#endif default: pr_err("NxpDrv: %s: bad cmd %lu\n", __func__, arg); ret = -ENOIOCTLCMD; diff --git a/nfc/common.h b/nfc/common.h index 5f5f5bbdaf..7b2098a433 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -33,10 +33,12 @@ #include "i2c_drv.h" #include "ese_cold_reset.h" +#ifdef NFC_SECURE_PERIPHERAL_ENABLED /*secure library headers*/ #include "smcinvoke.h" #include "smcinvoke_object.h" #include "IClientEnv.h" +#endif /* Max device count for this driver */ #define DEV_COUNT 1 @@ -106,7 +108,9 @@ #define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) #define NFC_SET_RESET_READ_PENDING _IOW(NFC_MAGIC, 0x04, uint32_t) #define NFC_GET_GPIO_STATUS _IOR(NFC_MAGIC, 0x05, uint32_t) +#ifdef NFC_SECURE_PERIPHERAL_ENABLED #define NFC_SECURE_ZONE _IOW(NFC_MAGIC, 0x0A, uint32_t) +#endif #define DTS_IRQ_GPIO_STR "qcom,sn-irq" #define DTS_VEN_GPIO_STR "qcom,sn-ven" @@ -128,12 +132,14 @@ /* Two bits to indicate GPIO status (Invalid(-2), Set(1) or Reset(0)) */ #define GPIO_STATUS_MASK_BITS 3 +#ifdef NFC_SECURE_PERIPHERAL_ENABLED //NFC ID for registration with secure libraries #define HW_STATE_UID 0x108 #define HW_OP_GET_STATE 1 #define HW_NFC_UID 0x506 #define FEATURE_NOT_SUPPORTED 12 #define PERIPHERAL_NOT_FOUND 10 +#endif #define NUM_OF_IPC_LOG_PAGES (2) #define PKT_MAX_LEN (4) // no of max bytes to print for cmd/resp @@ -151,8 +157,10 @@ do { \ } \ } while (0) +#ifdef NFC_SECURE_PERIPHERAL_ENABLED static struct semaphore sem_eSE_pwr_off; static bool chk_eSE_pwr_off; +#endif enum ese_ioctl_request { /* eSE POWER ON */ @@ -244,7 +252,9 @@ struct platform_configs { struct platform_gpio gpio; struct platform_ldo ldo; const char *szone; +#ifdef NFC_SECURE_PERIPHERAL_ENABLED bool CNSS_NFC_HW_SECURE_ENABLE; +#endif }; diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index 0b8854316e..420563ead4 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -47,11 +47,12 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg) pr_debug("keep ven high as NFC is enabled\n"); } nfc_dev->is_ese_session_active = false; +#ifdef NFC_SECURE_PERIPHERAL_ENABLED if (nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { if(chk_eSE_pwr_off) up(&sem_eSE_pwr_off); } - +#endif } else if (arg == ESE_POWER_STATE) { /* get VEN gpio state for eSE, as eSE also enabled through same GPIO */ ret = gpio_get_value(nfc_dev->configs.gpio.ven); diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index c1dc018533..3300861c01 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -417,7 +417,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) pr_err("NxpDrv: LDO config failed\n"); goto err_ldo_config_failed; } - +#ifdef NFC_SECURE_PERIPHERAL_ENABLED if( nfc_dev->configs.CNSS_NFC_HW_SECURE_ENABLE == true) { /*Check NFC Secure Zone status*/ if(!nfc_hw_secure_check()) { @@ -431,7 +431,10 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) }else { nfc_post_init(nfc_dev); } - +#else + nfc_dev->secure_zone = false; + nfc_post_init(nfc_dev); +#endif device_init_wakeup(&client->dev, true); i2c_set_clientdata(client, nfc_dev); i2c_dev->irq_wake_up = false; diff --git a/nfc_kernel_dlkm_vendor_board.mk b/nfc_kernel_dlkm_vendor_board.mk index 899347b59c..503d543e9f 100644 --- a/nfc_kernel_dlkm_vendor_board.mk +++ b/nfc_kernel_dlkm_vendor_board.mk @@ -1,5 +1,5 @@ # Build NFC kernel driver -ifeq ($(call is-board-platform-in-list, pineapple),true) +ifeq ($(call is-board-platform-in-list, pineapple blair),true) BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nxp-nci.ko endif From 06aaa9ef5d6b83185aabed9bf7617d5e5ef4eb49 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Thu, 8 Jun 2023 20:24:21 +0530 Subject: [PATCH 090/100] nfc: driver: Fix vedor checker errors Added fix to Vendor checker compilation errors. Change-Id: I6e743dbf098d70e2d9f4791c5aed16c8e725230d Signed-off-by: Khageswararao Rao B --- define_modules.bzl | 3 ++- include/uapi/linux/nfc/sn_uapi.h | 39 ++++++++++++++++++++++++++++++++ nfc/common.c | 2 +- nfc/common.h | 17 ++------------ nfc/ese_cold_reset.c | 2 +- nfc/i2c_drv.c | 2 +- 6 files changed, 46 insertions(+), 19 deletions(-) create mode 100644 include/uapi/linux/nfc/sn_uapi.h diff --git a/define_modules.bzl b/define_modules.bzl index a4070f155d..609f5d4eb3 100644 --- a/define_modules.bzl +++ b/define_modules.bzl @@ -17,7 +17,8 @@ def define_modules(target, variant): "nfc/ese_cold_reset.h", "nfc/i2c_drv.h" ], - hdrs = ["include/uapi/linux/nfc/nfcinfo.h"], + hdrs = ["include/uapi/linux/nfc/nfcinfo.h", + "include/uapi/linux/nfc/sn_uapi.h"], includes = [".", "linux", "nfc", "include/uapi/linux/nfc"], deps = ["//msm-kernel:all_headers", "//vendor/qcom/opensource/securemsm-kernel:smcinvoke_kernel_headers", diff --git a/include/uapi/linux/nfc/sn_uapi.h b/include/uapi/linux/nfc/sn_uapi.h new file mode 100644 index 0000000000..f89812e8b6 --- /dev/null +++ b/include/uapi/linux/nfc/sn_uapi.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/****************************************************************************** + * Copyright (C) 2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2019-2022 NXP + * + * This program 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 program 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. + * + ******************************************************************************/ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + ****************************************************************************/ + +#ifndef _UAPI_SN_UAPI_H_ +#define _UAPI_SN_UAPI_H_ + +#include + +/* Ioctls + * The type should be aligned with MW HAL definitions + */ + +#define NFC_MAGIC (0xE9) + +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) +#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) +#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) +#define NFC_SET_RESET_READ_PENDING _IOW(NFC_MAGIC, 0x04, uint32_t) +#define NFC_GET_GPIO_STATUS _IOR(NFC_MAGIC, 0x05, uint32_t) +#define NFC_SECURE_ZONE _IOW(NFC_MAGIC, 0x0A, uint32_t) + +#endif diff --git a/nfc/common.c b/nfc/common.c index 8c5ed3bf00..a2306f7e82 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -18,7 +18,7 @@ * ******************************************************************************/ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * *****************************************************************************/ #include diff --git a/nfc/common.h b/nfc/common.h index 7b2098a433..065e4f08f1 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -18,8 +18,7 @@ * ******************************************************************************/ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. - * + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. *****************************************************************************/ #ifndef _COMMON_H_ #define _COMMON_H_ @@ -30,6 +29,7 @@ #include #include #include +#include #include "i2c_drv.h" #include "ese_cold_reset.h" @@ -98,19 +98,6 @@ #define WRITE_RETRY_WAIT_TIME_US (3000) /* Time to wait before retrying read for some specific usecases */ #define READ_RETRY_WAIT_TIME_US (3500) -#define NFC_MAGIC (0xE9) - -// Ioctls -// The type should be aligned with MW HAL definitions - -#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t) -#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) -#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) -#define NFC_SET_RESET_READ_PENDING _IOW(NFC_MAGIC, 0x04, uint32_t) -#define NFC_GET_GPIO_STATUS _IOR(NFC_MAGIC, 0x05, uint32_t) -#ifdef NFC_SECURE_PERIPHERAL_ENABLED -#define NFC_SECURE_ZONE _IOW(NFC_MAGIC, 0x0A, uint32_t) -#endif #define DTS_IRQ_GPIO_STR "qcom,sn-irq" #define DTS_VEN_GPIO_STR "qcom,sn-ven" diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index 420563ead4..0359d5459e 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -4,7 +4,7 @@ * ***************************************************************************/ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * ***************************************************************************/ diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 3300861c01..9acd14aed9 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -35,7 +35,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ****************************************************************************/ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * ****************************************************************************/ From 871583af474e93b12b832499fb53189802f0b3dd Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Wed, 14 Jun 2023 23:16:20 +0530 Subject: [PATCH 091/100] NFC: driver: Add compilation flag in bazel for secure module lib Added compilation flag for secure module librarie dependencies. Change-Id: If810b7376fc079307ca6d55abca4f3f97699f41c Signed-off-by: Khageswararao Rao B --- define_modules.bzl | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/define_modules.bzl b/define_modules.bzl index 609f5d4eb3..37aa03dae9 100644 --- a/define_modules.bzl +++ b/define_modules.bzl @@ -3,6 +3,14 @@ load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir") def define_modules(target, variant): tv = "{}_{}".format(target, variant) + copts = [] + deps = ["//msm-kernel:all_headers"] + + if target == "pineapple": + copts.append("-DNFC_SECURE_PERIPHERAL_ENABLED") + deps += ["//vendor/qcom/opensource/securemsm-kernel:smcinvoke_kernel_headers", + "//vendor/qcom/opensource/securemsm-kernel:{}_smcinvoke_dlkm".format(tv) + ] ddk_module( name = "{}_nxp-nci".format(tv), @@ -20,10 +28,9 @@ def define_modules(target, variant): hdrs = ["include/uapi/linux/nfc/nfcinfo.h", "include/uapi/linux/nfc/sn_uapi.h"], includes = [".", "linux", "nfc", "include/uapi/linux/nfc"], - deps = ["//msm-kernel:all_headers", - "//vendor/qcom/opensource/securemsm-kernel:smcinvoke_kernel_headers", - "//vendor/qcom/opensource/securemsm-kernel:{}_smcinvoke_dlkm".format(tv)], - kernel_build = "//msm-kernel:{}".format(tv), + copts = copts, + deps = deps, + kernel_build= "//msm-kernel:{}".format(tv), visibility = ["//visibility:public"] ) From 27989fc132fe3bec2b4887db9cd90ee22f1323da Mon Sep 17 00:00:00 2001 From: Devendar Date: Tue, 27 Jun 2023 10:29:01 +0530 Subject: [PATCH 092/100] blair: Disable secure peripheral framework for NFC Disabled secure peripheral feature on NFC for Strait target. Change-Id: I47b8d52d79a33f9189ba0d4c579b7085b697f293 Signed-off-by: Devendar --- include/uapi/linux/nfc/sn_uapi.h | 1 + nfc/ese_cold_reset.h | 2 +- nfc_kernel_dlkm_vendor_board.mk | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/nfc/sn_uapi.h b/include/uapi/linux/nfc/sn_uapi.h index f89812e8b6..cc87bc449e 100644 --- a/include/uapi/linux/nfc/sn_uapi.h +++ b/include/uapi/linux/nfc/sn_uapi.h @@ -35,5 +35,6 @@ #define NFC_SET_RESET_READ_PENDING _IOW(NFC_MAGIC, 0x04, uint32_t) #define NFC_GET_GPIO_STATUS _IOR(NFC_MAGIC, 0x05, uint32_t) #define NFC_SECURE_ZONE _IOW(NFC_MAGIC, 0x0A, uint32_t) +#define ESE_COLD_RESET _IOWR(NFCC_MAGIC, 0x08, struct ese_ioctl_arg) #endif diff --git a/nfc/ese_cold_reset.h b/nfc/ese_cold_reset.h index 77e03b9ef3..4d3b811a70 100644 --- a/nfc/ese_cold_reset.h +++ b/nfc/ese_cold_reset.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __ESE_COLD_RESET_H @@ -22,7 +23,6 @@ #define COLD_RESET_OID 0x1E #define COLD_RESET_PROT_OID 0x1F -#define ESE_COLD_RESET _IOWR(NFCC_MAGIC, 0x08, struct ese_ioctl_arg) enum ese_ioctl_arg_type { ESE_ARG_TYPE_COLD_RESET = 0, diff --git a/nfc_kernel_dlkm_vendor_board.mk b/nfc_kernel_dlkm_vendor_board.mk index 503d543e9f..59b4ff169a 100644 --- a/nfc_kernel_dlkm_vendor_board.mk +++ b/nfc_kernel_dlkm_vendor_board.mk @@ -3,3 +3,6 @@ ifeq ($(call is-board-platform-in-list, pineapple blair),true) BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nxp-nci.ko endif +ifeq ($(call is-board-platform-in-list, blair),true) +TARGET_ENABLE_PERIPHERAL_CONTROL := false +endif From fe2e65e65f01a7aca0cc1d1c8df48c064f0a9146 Mon Sep 17 00:00:00 2001 From: Om Prakash Singh Date: Wed, 3 May 2023 12:57:03 +0530 Subject: [PATCH 093/100] NFC: avoid freeing unallocated memory Issue: In function ese_cold_reset_ioctl, kfree is getting call for nfc_dev->cold_reset.cmd_buf in case of early failure in the function. Fix: Add check NULL check before calling kfree Change-Id: Ic3e86494f65330ff58a0deb394b3a654f0a395db Signed-off-by: Om Prakash Singh --- nfc/ese_cold_reset.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/nfc/ese_cold_reset.c b/nfc/ese_cold_reset.c index 0359d5459e..1e8a018543 100644 --- a/nfc/ese_cold_reset.c +++ b/nfc/ese_cold_reset.c @@ -392,10 +392,14 @@ int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg) ret = nfc_dev->cold_reset.status; err: - kfree(nfc_dev->cold_reset.cmd_buf); - nfc_dev->cold_reset.cmd_buf = NULL; - kfree(cold_reset_arg); - cold_reset_arg = NULL; + if (nfc_dev->cold_reset.cmd_buf != NULL) { + kfree(nfc_dev->cold_reset.cmd_buf); + nfc_dev->cold_reset.cmd_buf = NULL; + } + if (cold_reset_arg != NULL) { + kfree(cold_reset_arg); + cold_reset_arg = NULL; + } mutex_unlock(&nfc_dev->write_mutex); From 501c2f8a3978a61f8de014412d8b46c41df75cc2 Mon Sep 17 00:00:00 2001 From: Devendar Date: Thu, 27 Jul 2023 23:28:29 +0530 Subject: [PATCH 094/100] NFC: Driver Compilation fix Fixed the compilation issue when TARGET_KERNEL_DLKM_NFC_OVERRIDE set to false. Change-Id: I45eec0e2d39fe36eeb99f0af5a71cd5706d7843a Signed-off-by: Devendar --- Android.mk | 18 +++--------------- nfc_kernel_dlkm_vendor_board.mk | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Android.mk b/Android.mk index 3f8003d245..45262c6e68 100644 --- a/Android.mk +++ b/Android.mk @@ -1,6 +1,7 @@ # Android makefile for nfc kernel modules # Path to DLKM make scripts +ifeq ($(strip $(NFC_DLKM_ENABLED)),true) DLKM_DIR := $(TOP)/device/qcom/common/dlkm LOCAL_PATH := $(call my-dir) @@ -19,19 +20,6 @@ LOCAL_MODULE := nxp-nci.ko LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*) -NFC_DLKM_ENABLED := false - -########## Check and set local DLKM flag based on system-wide global flags ########## -ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true) - ifeq ($(TARGET_KERNEL_DLKM_NFC_OVERRIDE), true) - NFC_DLKM_ENABLED := true - endif -else - NFC_DLKM_ENABLED := true -endif - -########## Build kernel module based on local DLKM flag status ########## -ifeq ($(NFC_DLKM_ENABLED), true) - LOCAL_MODULE_DDK_BUILD := true - include $(DLKM_DIR)/Build_external_kernelmodule.mk +LOCAL_MODULE_DDK_BUILD := true +include $(DLKM_DIR)/Build_external_kernelmodule.mk endif diff --git a/nfc_kernel_dlkm_vendor_board.mk b/nfc_kernel_dlkm_vendor_board.mk index 59b4ff169a..05cbb29090 100644 --- a/nfc_kernel_dlkm_vendor_board.mk +++ b/nfc_kernel_dlkm_vendor_board.mk @@ -1,6 +1,20 @@ # Build NFC kernel driver +NFC_DLKM_ENABLED := false + +########## Check and set local DLKM flag based on system-wide global flags ########## +ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true) + ifeq ($(TARGET_KERNEL_DLKM_NFC_OVERRIDE), true) + NFC_DLKM_ENABLED := true + endif +else + NFC_DLKM_ENABLED := true +endif + +########## Build kernel module based on local DLKM flag status ########## +ifeq ($(NFC_DLKM_ENABLED), true) ifeq ($(call is-board-platform-in-list, pineapple blair),true) -BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nxp-nci.ko + BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nxp-nci.ko +endif endif ifeq ($(call is-board-platform-in-list, blair),true) From e0b07081b7dba7df6d71bd4eda7b7e8ac7154b3e Mon Sep 17 00:00:00 2001 From: Amruth Naga Date: Tue, 8 Aug 2023 12:06:16 +0530 Subject: [PATCH 095/100] [NFC]: Bazel changes for blair Adding bazel support for blair target. Change-Id: I79be45d22206d39a4814ac5647d4cdfa0237f81e Signed-off-by: Amruth Naga --- BUILD.bazel | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BUILD.bazel b/BUILD.bazel index 8ee0b465eb..dd3213e2a7 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -4,4 +4,6 @@ load(":define_modules.bzl", "define_modules") define_modules("pineapple", "consolidate") define_modules("pineapple", "gki") +define_modules("blair", "consolidate") +define_modules("blair", "gki") From bd2c8acbe7f37e163964670597bc62e196df4b2e Mon Sep 17 00:00:00 2001 From: Reut Zysman Date: Wed, 5 Jul 2023 10:08:06 -0700 Subject: [PATCH 096/100] NFC: driver: Remove unused dependency Remove dependency on smcinvoke.h. Change-Id: Icc948b645712ca0a3425e7f3445776369c1437f9 Signed-off-by: Reut Zysman --- nfc/common.h | 1 - 1 file changed, 1 deletion(-) diff --git a/nfc/common.h b/nfc/common.h index 065e4f08f1..d8362224f7 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -35,7 +35,6 @@ #ifdef NFC_SECURE_PERIPHERAL_ENABLED /*secure library headers*/ -#include "smcinvoke.h" #include "smcinvoke_object.h" #include "IClientEnv.h" #endif From 1680e1885fe59dc31944910b2594d10d24b5db99 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Wed, 31 Jan 2024 09:03:02 +0530 Subject: [PATCH 097/100] NFC: driver: Add SW WAR to enable and disable NFC clock Added SW WAR to enable NFC clock at NFC ON and disable NFC clock at NFC OFF. Change-Id: I74fd9fa58f9875e91807c4f06735b2c62867aaf7 Signed-off-by: Khageswararao Rao B --- BUILD.bazel | 2 ++ nfc/common.c | 61 +++++++++++++++++++++------------ nfc/common.h | 12 ++++++- nfc/common_qcom.c | 42 ++++++++++++++++++++++- nfc/i2c_drv.c | 11 +++--- nfc_kernel_dlkm_vendor_board.mk | 4 +-- 6 files changed, 103 insertions(+), 29 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index dd3213e2a7..786eaababc 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -7,3 +7,5 @@ define_modules("pineapple", "gki") define_modules("blair", "consolidate") define_modules("blair", "gki") +define_modules("pitti", "consolidate") +define_modules("pitti", "gki") diff --git a/nfc/common.c b/nfc/common.c index a2306f7e82..64a57c3e2a 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -18,7 +18,7 @@ * ******************************************************************************/ /* - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. * *****************************************************************************/ #include @@ -69,12 +69,16 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, pr_warn("NxpDrv: %s: dwl_req gpio invalid %d\n", __func__, nfc_gpio->dwl_req); } - /* Read clkreq GPIO pin number from DTSI */ - nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0); - if (!gpio_is_valid(nfc_gpio->clkreq)) { - dev_err(dev, "NxpDrv: clkreq gpio invalid %d\n", nfc_gpio->clkreq); - return -EINVAL; - } + /* Read clock request gpio configuration if MGPIO configurations are not preasent */ + if (of_property_read_string(np, DTS_CLKSRC_GPIO_STR, &nfc_configs->clk_src_name)) { + nfc_configs->clk_pin_voting = false; + nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0); + if (!gpio_is_valid(nfc_gpio->clkreq)) { + dev_err(dev, "NxpDrv: clkreq gpio invalid %d\n", nfc_gpio->clkreq); + return -EINVAL; + } + } else + nfc_configs->clk_pin_voting = true; #ifdef NFC_SECURE_PERIPHERAL_ENABLED /* Read DTS_SZONE_STR to check secure zone support */ @@ -403,9 +407,21 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) nfc_dev->nfc_state = NFC_STATE_NCI; } else if (arg == NFC_ENABLE) { + if (nfc_dev->configs.clk_pin_voting) { + /* Enabling nfc clock */ + ret = nfc_clock_select(nfc_dev); + if (ret) + pr_err("%s unable to select clock\n", __func__); + } /* Setting flag true when NFC is enabled */ nfc_dev->cold_reset.is_nfc_enabled = true; } else if (arg == NFC_DISABLE) { + if (nfc_dev->configs.clk_pin_voting) { + /* Disabling nfc clock */ + ret = nfc_clock_deselect(nfc_dev); + if (ret) + pr_err("%s unable to disable clock\n", __func__); + } /* Setting flag true when NFC is disabled */ nfc_dev->cold_reset.is_nfc_enabled = false; } else { @@ -478,20 +494,23 @@ int nfc_post_init(struct nfc_dev *nfc_dev) __func__, nfc_gpio->dwl_req); } - /* Read clkreq GPIO number from device tree*/ - ret = of_property_read_u32_index(nfc_dev->i2c_dev.client->dev.of_node, DTS_CLKREQ_GPIO_STR, 1, &clkreq_gpio); - if (ret < 0) { - pr_err("NxpDrv: %s Failed to read clkreq gipo number, ret: %d\n", __func__, ret); - return ret; - } - /* configure clkreq GPIO as wakeup capable */ - ret = msm_gpio_mpm_wake_set(clkreq_gpio, true); - if (ret < 0) { - pr_err("NxpDrv: %s Failed to setup clkreq gpio %d as wakeup capable, ret: %d\n", __func__, clkreq_gpio , ret); - return ret; - } else { - pr_info("NxpDrv: %s clkreq gpio %d successfully setup for wakeup capable\n", __func__, clkreq_gpio); - } + if (!(nfc_configs.clk_pin_voting)) { + /* Read clkreq GPIO number from device tree*/ + ret = of_property_read_u32_index(nfc_dev->i2c_dev.client->dev.of_node, + DTS_CLKREQ_GPIO_STR, 1, &clkreq_gpio); + if (ret < 0) { + pr_err("NxpDrv: %s Failed to read clkreq gipo number, ret: %d\n", + __func__, ret); + return ret; + } + /* configure clkreq GPIO as wakeup capable */ + ret = msm_gpio_mpm_wake_set(clkreq_gpio, true); + if (ret < 0) { + pr_err("NxpDrv: %s clkreq gpio %d as wakeup capable failed, ret: %d\n", + __func__, clkreq_gpio, ret); + return ret; + } + } ret = nfcc_hw_check(nfc_dev); if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) { diff --git a/nfc/common.h b/nfc/common.h index d8362224f7..3c745eb9b7 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -18,7 +18,7 @@ * ******************************************************************************/ /* - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. *****************************************************************************/ #ifndef _COMMON_H_ #define _COMMON_H_ @@ -102,6 +102,7 @@ #define DTS_VEN_GPIO_STR "qcom,sn-ven" #define DTS_FWDN_GPIO_STR "qcom,sn-firm" #define DTS_CLKREQ_GPIO_STR "qcom,sn-clkreq" +#define DTS_CLKSRC_GPIO_STR "qcom,clk-src" #define DTS_SZONE_STR "qcom,sn-szone" #define NFC_LDO_SUPPLY_DT_NAME "qcom,sn-vdd-1p8" #define NFC_LDO_SUPPLY_NAME "qcom,sn-vdd-1p8-supply" @@ -237,6 +238,9 @@ struct platform_ldo { struct platform_configs { struct platform_gpio gpio; struct platform_ldo ldo; + const char *clk_src_name; + /* NFC_CLK pin voting state */ + bool clk_pin_voting; const char *szone; #ifdef NFC_SECURE_PERIPHERAL_ENABLED bool CNSS_NFC_HW_SECURE_ENABLE; @@ -283,6 +287,10 @@ struct nfc_dev { /*secure zone state*/ bool secure_zone; + /* CLK control */ + bool clk_run; + struct clk *s_clk; + void *ipcl; /* function pointers for the common i2c functionality */ @@ -318,6 +326,8 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg); int nfc_ldo_unvote(struct nfc_dev *nfc_dev); int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev); int validate_nfc_state_nci(struct nfc_dev *nfc_dev); +int nfc_clock_select(struct nfc_dev *nfc_dev); +int nfc_clock_deselect(struct nfc_dev *nfc_dev); int nfc_post_init(struct nfc_dev *nfc_dev); int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans); bool nfc_hw_secure_check(void); diff --git a/nfc/common_qcom.c b/nfc/common_qcom.c index 7ca25b22dc..1e35e63096 100644 --- a/nfc/common_qcom.c +++ b/nfc/common_qcom.c @@ -4,7 +4,7 @@ * ***************************************************************************/ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. * ***************************************************************************/ @@ -162,3 +162,43 @@ int nfc_ldo_unvote(struct nfc_dev *nfc_dev) return ret; } +/* + * Routine to enable clock. + * this routine can be extended to select from multiple + * sources based on clk name. + */ +int nfc_clock_select(struct nfc_dev *nfc_dev) +{ + int r = 0; + + nfc_dev->s_clk = clk_get(&nfc_dev->i2c_dev.client->dev, "nfc_ref_clk"); + + if (IS_ERR(nfc_dev->s_clk)) + return PTR_ERR(nfc_dev->s_clk); + + if (!nfc_dev->clk_run) + r = clk_prepare_enable(nfc_dev->s_clk); + + if (r) + return r; + + nfc_dev->clk_run = true; + return r; +} + +/* + * Routine to disable clocks + */ +int nfc_clock_deselect(struct nfc_dev *nfc_dev) +{ + int r = -EINVAL; + + if (nfc_dev->s_clk != NULL) { + if (nfc_dev->clk_run) { + clk_disable_unprepare(nfc_dev->s_clk); + nfc_dev->clk_run = false; + } + return 0; + } + return r; +} diff --git a/nfc/i2c_drv.c b/nfc/i2c_drv.c index 9acd14aed9..4bf45e7b74 100644 --- a/nfc/i2c_drv.c +++ b/nfc/i2c_drv.c @@ -30,12 +30,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ****************************************************************************/ /* - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. * ****************************************************************************/ @@ -435,6 +432,12 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) nfc_dev->secure_zone = false; nfc_post_init(nfc_dev); #endif + + if (nfc_dev->configs.clk_pin_voting) + nfc_dev->clk_run = false; + else + nfc_dev->clk_run = true; + device_init_wakeup(&client->dev, true); i2c_set_clientdata(client, nfc_dev); i2c_dev->irq_wake_up = false; diff --git a/nfc_kernel_dlkm_vendor_board.mk b/nfc_kernel_dlkm_vendor_board.mk index 05cbb29090..d50b91b595 100644 --- a/nfc_kernel_dlkm_vendor_board.mk +++ b/nfc_kernel_dlkm_vendor_board.mk @@ -12,11 +12,11 @@ endif ########## Build kernel module based on local DLKM flag status ########## ifeq ($(NFC_DLKM_ENABLED), true) -ifeq ($(call is-board-platform-in-list, pineapple blair),true) +ifeq ($(call is-board-platform-in-list, pineapple blair pitti),true) BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nxp-nci.ko endif endif -ifeq ($(call is-board-platform-in-list, blair),true) +ifeq ($(call is-board-platform-in-list, blair pitti),true) TARGET_ENABLE_PERIPHERAL_CONTROL := false endif From f238c7389c4cc2657e3b47cfbd506293284da017 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Tue, 19 Mar 2024 23:30:47 +0530 Subject: [PATCH 098/100] nfc driver: Enable nfc clk request gpio and RF_CLK3 configuration Enabled nfc clk request gpio and RF_CLK3 configuration for pitti. Change-Id: I540a09798777b05f2a1b82e6d89c0641e3fe1da3 Signed-off-by: Khageswararao Rao B --- nfc/common.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/nfc/common.c b/nfc/common.c index 64a57c3e2a..b3f08038a6 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -69,17 +69,20 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, pr_warn("NxpDrv: %s: dwl_req gpio invalid %d\n", __func__, nfc_gpio->dwl_req); } + /* Read clock request gpio configuration if MGPIO configurations are not preasent */ if (of_property_read_string(np, DTS_CLKSRC_GPIO_STR, &nfc_configs->clk_src_name)) { nfc_configs->clk_pin_voting = false; - nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0); - if (!gpio_is_valid(nfc_gpio->clkreq)) { - dev_err(dev, "NxpDrv: clkreq gpio invalid %d\n", nfc_gpio->clkreq); - return -EINVAL; - } } else nfc_configs->clk_pin_voting = true; + /* Read clkreq GPIO pin number from DTSI */ + nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0); + if (!gpio_is_valid(nfc_gpio->clkreq)) { + dev_err(dev, "NxpDrv: clkreq gpio invalid %d\n", nfc_gpio->clkreq); + return -EINVAL; + } + #ifdef NFC_SECURE_PERIPHERAL_ENABLED /* Read DTS_SZONE_STR to check secure zone support */ if (of_property_read_string(np, DTS_SZONE_STR, &nfc_configs->szone)) { @@ -494,22 +497,20 @@ int nfc_post_init(struct nfc_dev *nfc_dev) __func__, nfc_gpio->dwl_req); } - if (!(nfc_configs.clk_pin_voting)) { - /* Read clkreq GPIO number from device tree*/ - ret = of_property_read_u32_index(nfc_dev->i2c_dev.client->dev.of_node, + /* Read clkreq GPIO number from device tree*/ + ret = of_property_read_u32_index(nfc_dev->i2c_dev.client->dev.of_node, DTS_CLKREQ_GPIO_STR, 1, &clkreq_gpio); - if (ret < 0) { - pr_err("NxpDrv: %s Failed to read clkreq gipo number, ret: %d\n", + if (ret < 0) { + pr_err("NxpDrv: %s Failed to read clkreq gipo number, ret: %d\n", __func__, ret); - return ret; - } - /* configure clkreq GPIO as wakeup capable */ - ret = msm_gpio_mpm_wake_set(clkreq_gpio, true); - if (ret < 0) { - pr_err("NxpDrv: %s clkreq gpio %d as wakeup capable failed, ret: %d\n", + return ret; + } + /* configure clkreq GPIO as wakeup capable */ + ret = msm_gpio_mpm_wake_set(clkreq_gpio, true); + if (ret < 0) { + pr_err("NxpDrv: %s clkreq gpio %d as wakeup capable failed, ret: %d\n", __func__, clkreq_gpio, ret); - return ret; - } + return ret; } ret = nfcc_hw_check(nfc_dev); From 346a46787c5a166abe820f21bbc217c9f01a19ec Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Wed, 27 Mar 2024 22:22:41 +0530 Subject: [PATCH 099/100] Nfc driver: Configure clk request gpio Configured NFC clk request gpio as input gpio. Change-Id: I4fe970e109706e1c11cf38684a5fe2d0faa3088f Signed-off-by: Khageswararao Rao B --- nfc/common.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nfc/common.c b/nfc/common.c index b3f08038a6..c78d6d3a6c 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -497,6 +497,12 @@ int nfc_post_init(struct nfc_dev *nfc_dev) __func__, nfc_gpio->dwl_req); } + ret = configure_gpio(nfc_gpio->clkreq, GPIO_INPUT); + if (ret) { + pr_err("NxpDrv: %s: unable to request nfc clkreq gpio [%d]\n", + __func__, nfc_gpio->clkreq); + } + /* Read clkreq GPIO number from device tree*/ ret = of_property_read_u32_index(nfc_dev->i2c_dev.client->dev.of_node, DTS_CLKREQ_GPIO_STR, 1, &clkreq_gpio); @@ -505,6 +511,7 @@ int nfc_post_init(struct nfc_dev *nfc_dev) __func__, ret); return ret; } + /* configure clkreq GPIO as wakeup capable */ ret = msm_gpio_mpm_wake_set(clkreq_gpio, true); if (ret < 0) { From 2d62c2bdfd82e5c57cab6984d9376c898986ff68 Mon Sep 17 00:00:00 2001 From: Khageswararao Rao B Date: Wed, 10 Apr 2024 17:04:29 +0530 Subject: [PATCH 100/100] nfc driver: Enable NFC driver for volcano Enabled NFC driver to support volcano target. Change-Id: I4cc44d737fdb344df3d881c747785bd2461cfeef Signed-off-by: Khageswararao Rao B --- BUILD.bazel | 3 +++ nfc_kernel_dlkm_vendor_board.mk | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 786eaababc..8079cdcf6c 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -9,3 +9,6 @@ define_modules("blair", "gki") define_modules("pitti", "consolidate") define_modules("pitti", "gki") + +define_modules("volcano", "consolidate") +define_modules("volcano", "gki") diff --git a/nfc_kernel_dlkm_vendor_board.mk b/nfc_kernel_dlkm_vendor_board.mk index d50b91b595..548400b0ef 100644 --- a/nfc_kernel_dlkm_vendor_board.mk +++ b/nfc_kernel_dlkm_vendor_board.mk @@ -12,11 +12,11 @@ endif ########## Build kernel module based on local DLKM flag status ########## ifeq ($(NFC_DLKM_ENABLED), true) -ifeq ($(call is-board-platform-in-list, pineapple blair pitti),true) +ifeq ($(call is-board-platform-in-list, pineapple blair pitti volcano),true) BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nxp-nci.ko endif endif -ifeq ($(call is-board-platform-in-list, blair pitti),true) +ifeq ($(call is-board-platform-in-list, blair pitti volcano),true) TARGET_ENABLE_PERIPHERAL_CONTROL := false endif